UNPKG

@bananahq/banana-sdk

Version:

Smart contract wallet sdk package by Banana Wallet

193 lines 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BananaSigner = void 0; const ethers_1 = require("ethers"); const sdk_1 = require("@account-abstraction/sdk"); const sendUserOp_1 = require("./bundler/sendUserOp"); const getRequestData_1 = require("./paymaster/getRequestData"); const getPaymasterAndData_1 = require("./paymaster/getPaymasterAndData"); const paymasterServiceStatus_1 = require("./utils/paymasterServiceStatus"); const Constants_1 = require("./Constants"); class BananaSigner extends sdk_1.ERC4337EthersSigner { constructor(config, originalSigner, erc4337provider, httpRpcClient, smartAccountAPI, provider, _paymasterOption) { super(config, originalSigner, erc4337provider, httpRpcClient, smartAccountAPI); this.config = config; this.originalSigner = originalSigner; this.erc4337provider = erc4337provider; this.httpRpcClient = httpRpcClient; this.smartAccountAPI = smartAccountAPI; this.jsonRpcProvider = provider; this.paymasterOption = _paymasterOption; this.ownerSigner = originalSigner; this.getAddress(); } // need to do some changes in it async sendTransaction(transaction) { const tx = await this.populateTransaction(transaction); await this.verifyAllNecessaryFields(tx); let userOperation = await this.smartAccountAPI.createUnsignedUserOp({ target: tx.to ?? "", data: tx.data?.toString() ?? "", value: tx.value, gasLimit: tx.gasLimit, }); userOperation.verificationGasLimit = 1.5e6; userOperation.preVerificationGas = ethers_1.ethers.BigNumber.from(await userOperation.preVerificationGas).add(5000); let minGasRequired = ethers_1.ethers.BigNumber.from(userOperation?.callGasLimit) .add(ethers_1.ethers.BigNumber.from(userOperation?.verificationGasLimit)) .add(ethers_1.ethers.BigNumber.from(userOperation?.callGasLimit)) .add(ethers_1.ethers.BigNumber.from(userOperation?.preVerificationGas)); let currentGasPrice = await this.jsonRpcProvider.getGasPrice(); let minBalanceRequiredForGas = minGasRequired.mul(currentGasPrice); //@ts-ignore let userBalance = await this.jsonRpcProvider.getBalance(userOperation?.sender); const networkInfo = await this.jsonRpcProvider.getNetwork(); const paymasterStatus = await (0, paymasterServiceStatus_1.paymasterServiceStatus)(this.paymasterOption); if (this.paymasterOption && paymasterStatus) { const requestData = await (0, getRequestData_1.getRequestDataForPaymaster)(userOperation, this.paymasterOption); const paymasterAndData = await (0, getPaymasterAndData_1.getPaymasterAndData)(this.paymasterOption, requestData); (userOperation || { paymasterAndData: null }).paymasterAndData = paymasterAndData || ""; } ; let fundForTransaction = minBalanceRequiredForGas; let fundsForTxn = parseFloat(ethers_1.ethers.utils.formatEther(fundForTransaction)); let factor = 0; if (userOperation.initCode === '0x') { factor = Constants_1.SCALING_FACTOR.find(scalingFactor => scalingFactor.chainId === networkInfo.chainId)?.txnFactor; } else { factor = Constants_1.SCALING_FACTOR.find(scalingFactor => scalingFactor.chainId === networkInfo.chainId)?.deploymentTxnFactor; } ; //@ts-ignore fundsForTxn = fundsForTxn + (fundsForTxn * factor); fundForTransaction = ethers_1.ethers.utils.parseEther(fundsForTxn.toFixed(18)); if (!paymasterStatus && (userBalance.lt(minBalanceRequiredForGas))) { const fundTransaction = { to: userOperation.sender, value: ethers_1.ethers.utils.parseEther(String(parseInt(fundForTransaction._hex) / 10 ** 18)), data: '0x', gasLimit: '0x55555', }; const txnResponse = await this.originalSigner.sendTransaction(fundTransaction); const txnReceipt = await txnResponse.wait(); } const message = await this.smartAccountAPI.getUserOpHash(userOperation); let signatureObtained; try { signatureObtained = await this.smartAccountAPI.signUserOpHash(message); userOperation.signature = signatureObtained; } catch (err) { return Promise.reject(err); } let transactionResponse = await this.erc4337provider.constructUserOpTransactionResponse(userOperation); try { if (networkInfo.chainId === 81 || networkInfo.chainId === 592) { //! sending UserOp directly to ep for shibuya const receipt = await (0, sendUserOp_1.sendTransaction)(userOperation, this.jsonRpcProvider); transactionResponse = receipt; } else { await this.httpRpcClient.sendUserOpToBundler(userOperation); const userOpHash = transactionResponse.hash; let transactionReceipt = await this.erc4337provider.waitForTransaction(userOpHash, 0, 10000000); transactionResponse.hash = transactionReceipt.logs[0].transactionHash; } } catch (error) { console.error("sendUserOpToBundler failed", error); throw this.unwrapError(error); } // TODO: handle errors - transaction that is "rejected" by bundler is _not likely_ to ever resolve its "wait()" return transactionResponse; } async sendBatchTransaction(transactions) { let txns = []; for (let i = 0; i < transactions.length; i++) { const txn = await this.populateTransaction(transactions[i]); await this.verifyAllNecessaryFields(txn); txns.push(txn); } const info = txns.map((txn) => { return { target: txn.to ?? "", data: txn.data?.toString() ?? "", value: txn.value, gasLimit: txn.gasLimit, }; }); let userOperation = await this.smartAccountAPI.createUnsignedUserOpForBatchedTransaction(info); let minGasRequired = ethers_1.ethers.BigNumber.from(userOperation?.callGasLimit) .add(ethers_1.ethers.BigNumber.from(userOperation?.verificationGasLimit)) .add(ethers_1.ethers.BigNumber.from(userOperation?.callGasLimit)) .add(ethers_1.ethers.BigNumber.from(userOperation?.preVerificationGas)); let currentGasPrice = await this.jsonRpcProvider.getGasPrice(); let minBalanceRequiredForGas = minGasRequired.mul(currentGasPrice); //@ts-ignore let userBalance = await this.jsonRpcProvider.getBalance(userOperation?.sender); const networkInfo = await this.jsonRpcProvider.getNetwork(); const paymasterStatus = await (0, paymasterServiceStatus_1.paymasterServiceStatus)(this.paymasterOption); if (this.paymasterOption && paymasterStatus) { const requestData = await (0, getRequestData_1.getRequestDataForPaymaster)(userOperation, this.paymasterOption); const paymasterAndData = await (0, getPaymasterAndData_1.getPaymasterAndData)(this.paymasterOption, requestData); (userOperation || { paymasterAndData: null }).paymasterAndData = paymasterAndData || ""; } let fundForTransaction = minBalanceRequiredForGas; let fundsForTxn = parseFloat(ethers_1.ethers.utils.formatEther(fundForTransaction)); let factor = 0; if (userOperation.initCode === '0x') { factor = Constants_1.SCALING_FACTOR.find(scalingFactor => scalingFactor.chainId === networkInfo.chainId)?.txnFactor; } else { factor = Constants_1.SCALING_FACTOR.find(scalingFactor => scalingFactor.chainId === networkInfo.chainId)?.deploymentTxnFactor; } ; //@ts-ignore fundsForTxn = fundsForTxn + (fundsForTxn * factor); fundForTransaction = ethers_1.ethers.utils.parseEther(fundsForTxn.toFixed(18)); if (!paymasterStatus && (userBalance.lt(minBalanceRequiredForGas))) { const fundTransaction = { to: userOperation.sender, value: ethers_1.ethers.utils.parseEther(String(parseInt(fundForTransaction._hex) / 10 ** 18)), data: '0x', gasLimit: '0x55555', }; const txnResponse = await this.originalSigner.sendTransaction(fundTransaction); const txnReceipt = await txnResponse.wait(); } const message = await this.smartAccountAPI.getUserOpHash(userOperation); let signatureObtained; try { signatureObtained = await this.smartAccountAPI.signUserOpHash(message); userOperation.signature = signatureObtained; } catch (err) { return Promise.reject(err); } let transactionResponse = await this.erc4337provider.constructUserOpTransactionResponse(userOperation); try { if (networkInfo.chainId === 81 || networkInfo.chainId === 592) { //! sending UserOp directly to ep for shibuya const receipt = await (0, sendUserOp_1.sendTransaction)(userOperation, this.jsonRpcProvider); transactionResponse = receipt; } else { await this.httpRpcClient.sendUserOpToBundler(userOperation); const userOpHash = transactionResponse.hash; let transactionReceipt = await this.erc4337provider.waitForTransaction(userOpHash, 0, 10000000); transactionResponse.hash = transactionReceipt.logs[0].transactionHash; } } catch (error) { console.error("sendUserOpToBundler failed", error); throw this.unwrapError(error); } // TODO: handle errors - transaction that is "rejected" by bundler is _not likely_ to ever resolve its "wait()" return transactionResponse; } } exports.BananaSigner = BananaSigner; //# sourceMappingURL=BananaSigner.js.map