@rize-labs/banana-wallet-sdk-astar-test
Version:
Smart contract wallet sdk package by Banana Wallet
345 lines • 18.2 kB
JavaScript
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Banana_isUserNameRequested;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Banana = void 0;
const ethers_1 = require("ethers");
const contracts_1 = require("@account-abstraction/contracts");
const MyPayMasterApi_1 = require("./MyPayMasterApi");
const MyWalletApi_1 = require("./MyWalletApi");
const HttpRpcClient_1 = require("@account-abstraction/sdk/dist/src/HttpRpcClient");
const Constants_1 = require("./Constants");
const WebAuthnContext_1 = require("./WebAuthnContext");
const types_1 = require("./types");
const BananaCookie_1 = require("./BananaCookie");
const Controller_1 = require("./Controller");
const factories_1 = require("./types/factories");
const BananaWallet_1 = require("./BananaWallet");
const Banana4337Provider_1 = require("./Banana4337Provider");
const walletNameInput_1 = require("./utils/walletNameInput");
class Banana {
constructor(chain) {
this.chain = chain;
_Banana_isUserNameRequested.set(this, false);
/**
* @method getTouchIdSafeWalletContractProxyFactory
* @params { Signer | JsonRpcProvider } signerOrProvider
* @returns { BananaAccountProxyFactory } TouchIdSafeWalletContractProxyFactory
* create factory contract instance for factory contract factory types.
*/
this.getTouchIdSafeWalletContractProxyFactory = (signerOrProvider) => {
const TouchIdSafeWalletContractProxyFactory = factories_1.BananaAccountProxyFactory__factory.connect(this.addresses.TouchIdSafeWalletContractProxyFactoryAddress, signerOrProvider);
return TouchIdSafeWalletContractProxyFactory;
};
/**
* @method setCookieAfterAddressCreation
* @params { string } walletIdentifier
* @returns none
* Set cookie to local and global storage after wallet creation.
*/
this.setCookieAfterAddressCreation = async (walletIdentifier, saltNonce) => {
this.cookieObject = {
q0: this.publicKey.q0,
q1: this.publicKey.q1,
walletAddress: this.walletAddress,
initcode: false,
encodedId: this.publicKey.encodedId,
username: walletIdentifier,
saltNonce: saltNonce.toString() //! Need to make changes to the mapper code for this additional property
};
// saving cookie correspond to user Identifier in cookie
this.cookie.setCookie("bananaUser", JSON.stringify(walletIdentifier));
this.cookie.setCookie(walletIdentifier, JSON.stringify(this.cookieObject));
const setCredentialsStatus = await (0, Controller_1.setUserCredentials)(walletIdentifier, this.cookieObject);
if (!setCredentialsStatus.success)
throw new Error("Error: db update failure");
};
/**
* @method createSignerAndCookieObject
* @params { string } walletIdentifier
* @returns none
* Create cookie object and create secure enclave based transaction signer for user's wallet.
*/
this.createSignerAndCookieObject = async (walletIdentifier) => {
const walletName = this.cookie.getCookie("bananaUser");
if (!!walletName) {
this.cookieObject = this.cookie.getCookie(walletName);
if (this.cookieObject) {
const q0Value = this.cookieObject.q0;
const q1Value = this.cookieObject.q1;
const encodedId = this.cookieObject.encodedId;
this.publicKey = {
q0: q0Value,
q1: q1Value,
encodedId: encodedId,
};
this.walletIdentifier = walletName;
// this.createBananaSignerInstance();
return;
}
else {
const walletCreds = await (0, Controller_1.getUserCredentials)(walletIdentifier);
// get and check cred here
// else of below if should not be triggered as we are already getting wallet name from cookie means the creds are initialized
if (!!walletCreds) {
this.cookieObject = walletCreds;
const q0Value = this.cookieObject.q0;
const q1Value = this.cookieObject.q1;
const encodedId = this.cookieObject.encodedId;
this.publicKey = {
q0: q0Value,
q1: q1Value,
encodedId: encodedId,
};
this.walletIdentifier = walletName;
// this.createBananaSignerInstance();
return;
}
}
}
else {
// when nothing in cookie or cred is there but with no username in that case fetching key from user provided walletname
const walletCreds = await (0, Controller_1.getUserCredentials)(walletIdentifier);
if (!!walletCreds) {
this.cookieObject = walletCreds;
const q0Value = this.cookieObject.q0;
const q1Value = this.cookieObject.q1;
const encodedId = this.cookieObject.encodedId;
this.publicKey = {
q0: q0Value,
q1: q1Value,
encodedId: encodedId,
};
this.walletIdentifier = walletIdentifier;
return;
}
// he must have sent the username for registering wallet
}
this.walletIdentifier = walletIdentifier;
this.publicKey = await (0, WebAuthnContext_1.registerFingerprint)();
const EC = types_1.EllipticCurve__factory.connect(this.addresses.Elliptic, this.jsonRpcProvider);
const isPointOnCurve = await EC.isOnCurve(this.publicKey.q0, this.publicKey.q1);
if (!isPointOnCurve) {
throw new Error("ERROR: Device does not support R1 curve");
}
};
/**
* @method getBananaProvider
* @params none
* @returns { ERC4337EthersProvider } bananaProvider
* create ERC4337Provider instance of user's smart contract wallet. Used as BananaProvider.
*/
this.getBananaProvider = async () => {
if (this.bananaProvider)
return this.bananaProvider;
let network = await this.jsonRpcProvider.getNetwork();
const entryPoint = contracts_1.EntryPoint__factory.connect(this.Provider.entryPointAddress, this.jsonRpcProvider);
const TouchIdSafeWalletContractProxyFactory = this.getTouchIdSafeWalletContractProxyFactory(this.jsonRpcProvider);
const TouchIdSafeWalletContractProxyFactoryAddress = TouchIdSafeWalletContractProxyFactory.address;
const myPaymasterApi = new MyPayMasterApi_1.MyPaymasterApi();
const smartWalletAPI = new MyWalletApi_1.MyWalletApi({
provider: this.jsonRpcProvider,
entryPointAddress: this.Provider.entryPointAddress,
accountAddress: this.walletAddress,
owner: this.jsonRpcProvider.getSigner(),
factoryAddress: TouchIdSafeWalletContractProxyFactoryAddress,
paymasterAPI: myPaymasterApi,
_qValues: [this.publicKey.q0, this.publicKey.q1],
_singletonTouchIdSafeAddress: this.addresses.TouchIdSafeWalletContractSingletonAddress,
_ownerAddress: this.getAddress(),
_fallBackHandler: this.addresses.fallBackHandlerAddress,
_saltNonce: this.cookieObject.saltNonce
});
this.accountApi = smartWalletAPI;
const httpRpcClient = new HttpRpcClient_1.HttpRpcClient(this.Provider.bundlerUrl, this.Provider.entryPointAddress, network.chainId);
this.httpRpcClient = httpRpcClient;
this.bananaProvider = await new Banana4337Provider_1.Banana4337Provider(network.chainId, this.Provider, this.jsonRpcProvider.getSigner(), this.jsonRpcProvider, httpRpcClient, entryPoint, smartWalletAPI, this.publicKey, this.jsonRpcProvider).init();
return this.bananaProvider;
};
/**
* @method getTouchIdSafeWalletContractInitializer
* @params none
* @returns { string } TouchIdSafeWalletContractInitializer
* create initializer which is callData for setupWithEntrypoint function
*/
this.getTouchIdSafeWalletContractInitializer = () => {
const TouchIdSafeWalletContractSingleton = factories_1.BananaAccount__factory.connect(this.addresses.TouchIdSafeWalletContractSingletonAddress, this.jsonRpcProvider);
const TouchIdSafeWalletContractQValuesArray = [this.publicKey.q0, this.publicKey.q1];
//@ts-ignore
const TouchIdSafeWalletContractInitializer = TouchIdSafeWalletContractSingleton.interface.encodeFunctionData('setupWithEntrypoint', [
[this.getAddress()],
1,
"0x0000000000000000000000000000000000000000",
"0x",
this.addresses.fallBackHandlerAddress,
"0x0000000000000000000000000000000000000000",
0,
"0x0000000000000000000000000000000000000000",
this.Provider.entryPointAddress,
// @ts-ignore
TouchIdSafeWalletContractQValuesArray, // q values
]);
return TouchIdSafeWalletContractInitializer;
};
/**
* @method createWallet
* @param { string } walletIdentifier
* @returns
* sucess: returns { status: success, address: walletAddress }
* error: returns { status: error, address: "" }
* setup signers and provider along with it create walletmetadata corresponding to the new wallet request.
*/
this.createWallet = async () => {
__classPrivateFieldSet(this, _Banana_isUserNameRequested, true, "f");
const walletIdentifier = await (0, walletNameInput_1.walletNameInput)();
await this.createSignerAndCookieObject(walletIdentifier);
this.walletIdentifier = walletIdentifier;
const TouchIdSafeWalletContractProxyFactory = this.getTouchIdSafeWalletContractProxyFactory(this.jsonRpcProvider);
const TouchIdSafeWalletContractInitializer = this.getTouchIdSafeWalletContractInitializer();
let saltNonce = 0;
let isAddressUnique = false;
let TouchIdSafeWalletContractAddress;
while (!isAddressUnique) {
TouchIdSafeWalletContractAddress = await TouchIdSafeWalletContractProxyFactory.getAddress(this.addresses.TouchIdSafeWalletContractSingletonAddress, saltNonce.toString(), TouchIdSafeWalletContractInitializer);
isAddressUnique = true;
//! No need to check address for now
// await NetworkAddressChecker(TouchIdSafeWalletContractAddress)
if (!isAddressUnique)
saltNonce++;
}
if (TouchIdSafeWalletContractAddress) {
this.walletAddress = TouchIdSafeWalletContractAddress;
}
this.setCookieAfterAddressCreation(walletIdentifier, saltNonce);
this.bananaProvider = await this.getBananaProvider();
this.postCookieChecks(walletIdentifier);
//! for now our wallet is chainSpecific
return new BananaWallet_1.Wallet(this.walletAddress, this.bananaProvider, this.network);
};
/**
* @method connectWallet
* @param { string } walletIdentifier
* @returns
* sucess: returns { status: success, address: walletAddress }
* error: returns { status: error, address: "" }
* setup providers and signers at the sdk end in case user's already has a wallet created before.
*/
this.connectWallet = async (walletIdentifier) => {
await this.createSignerAndCookieObject(walletIdentifier);
this.bananaProvider = await this.getBananaProvider();
this.walletAddress = this.cookieObject.walletAddress;
this.postCookieChecks(walletIdentifier);
return new BananaWallet_1.Wallet(this.walletAddress, this.bananaProvider, this.network);
};
/**
* @method resetWallet
* @param none
* @returns { string } walletName
* method to remove current wallet metadata from browser
*/
this.resetWallet = () => {
try {
const walletName = this.cookie.getCookie("bananaUser");
this.cookie.deleteCookie(walletName);
this.cookie.deleteCookie("bananaUser");
__classPrivateFieldSet(this, _Banana_isUserNameRequested, false, "f");
return { success: true };
}
catch (err) {
return { success: false, error: err };
}
};
/**
* @method getWalletName
* @param none
* @returns { string } walletName
* method to getWalletName stored in user's cookie storage against bananaUser key
*/
this.getWalletName = () => {
const walletName = this.cookie.getCookie("bananaUser");
return walletName;
};
/**
* @method getOwnerAddress
* @param { string } walletName
* @returns { string } eoaAddress
* method to return the hardware address for a specific walletName.
*/
this.getEOAAddress = async () => {
const walletMetaData = await (0, Controller_1.getUserCredentials)(this.walletIdentifier);
return [walletMetaData.q0, walletMetaData.q1];
};
/**
* @method verify
* @param { string } signaure, { string } messageSigned, { string } eoaAddress
* @returns { boolean } isVerified
* method to verify message against signature
*/
//! for now assigned eoaAddress as any type
this.verifySignature = async (signature, messageSigned, eoaAddress) => {
const rValue = ethers_1.ethers.BigNumber.from("0x" + signature.slice(2, 66));
const sValue = ethers_1.ethers.BigNumber.from("0x" + signature.slice(66, 132));
const EC = types_1.EllipticCurve__factory.connect(this.addresses.Elliptic, this.jsonRpcProvider);
const isVerified = await EC.validateSignature(messageSigned, [rValue, sValue], eoaAddress);
return isVerified;
};
/**
* @method postCookieChecks
* @param { string } walletIdentifier
* @returns none
* handles cookie update
*/
this.postCookieChecks = async (walletIdentifier) => {
// check for username
const walletName = this.cookie.getCookie("bananaUser");
if (!!walletName) {
this.cookie.setCookie(walletName, JSON.stringify(this.cookieObject));
return;
}
this.cookie.setCookie("bananaUser", JSON.stringify(walletIdentifier));
this.cookie.setCookie(walletIdentifier, JSON.stringify(this.cookieObject));
};
/**
* @method isWalletNameUnique
* @param { string } walletName
* @returns { boolean } isWalletNameTaken
* check isWalletName user is giving is already taken or not
*/
this.isWalletNameUnique = async (walletName) => {
try {
const isWalletNameTaken = await (0, Controller_1.checkIsWalletNameExist)(walletName);
return isWalletNameTaken;
}
catch (err) {
console.log(err);
throw err;
}
};
this.Provider = (0, Constants_1.getClientConfigInfo)(chain);
this.addresses = (0, Constants_1.getChainSpecificAddress)(chain);
this.jsonRpcProviderUrl = (0, Constants_1.getChainSpecificConfig)(chain).jsonRpcUrl;
this.jsonRpcProvider = new ethers_1.ethers.providers.JsonRpcProvider(this.jsonRpcProviderUrl);
this.cookie = new BananaCookie_1.BananaCookie();
this.network = chain;
}
getAddress() {
const uncompressedPublicKey = `0x04${this.publicKey.q0.slice(2)}${this.publicKey.q1.slice(2)}`;
return ethers_1.ethers.utils.computeAddress(uncompressedPublicKey);
}
getUsernameRequestStatus() {
return __classPrivateFieldGet(this, _Banana_isUserNameRequested, "f");
}
}
exports.Banana = Banana;
_Banana_isUserNameRequested = new WeakMap();
//# sourceMappingURL=BananaProvider.js.map