UNPKG

@thirdweb-dev/wallets

Version:

<p align="center"> <br /> <a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/legacy_packages/sdk/logo.svg?raw=true" width="200" alt=""/></a> <br /> </p> <h1 align="center">thirdweb Wallet SDK</h1> <p align="center"> <a h

207 lines (197 loc) • 7.44 kB
import { utils, BigNumber, providers } from 'ethers'; import { i as isTwUrl } from './url-a45219bd.browser.esm.js'; import { s as setAnalyticsHeaders } from './headers-733a8199.browser.esm.js'; import { e as isZkSyncChain, M as MANAGED_ACCOUNT_GAS_BUFFER } from './utils-f58e7acc.browser.esm.js'; async function hexlifyUserOp( // TODO: types op) { const userOp = await utils.resolveProperties(op); return Object.keys(userOp).map(key => { let val = userOp[key]; if (typeof val !== "string" || !val.startsWith("0x")) { val = utils.hexValue(val); } return [key, val]; }).reduce((set, _ref) => { let [k, v] = _ref; return { ...set, [k]: v }; }, {}); } // v0.6 userOpHash calculation async function getUserOpHashV06(userOp, entryPoint, chainId) { const op = await utils.resolveProperties(userOp); const hashedUserOp = { sender: op.sender, nonce: op.nonce, initCodeHash: utils.keccak256(op.initCode), callDataHash: utils.keccak256(op.callData), callGasLimit: op.callGasLimit, verificationGasLimit: op.verificationGasLimit, preVerificationGas: op.preVerificationGas, maxFeePerGas: op.maxFeePerGas, maxPriorityFeePerGas: op.maxPriorityFeePerGas, paymasterAndDataHash: utils.keccak256(op.paymasterAndData) }; const userOpType = { components: [{ type: "address", name: "sender" }, { type: "uint256", name: "nonce" }, { type: "bytes32", name: "initCodeHash" }, { type: "bytes32", name: "callDataHash" }, { type: "uint256", name: "callGasLimit" }, { type: "uint256", name: "verificationGasLimit" }, { type: "uint256", name: "preVerificationGas" }, { type: "uint256", name: "maxFeePerGas" }, { type: "uint256", name: "maxPriorityFeePerGas" }, { type: "bytes32", name: "paymasterAndDataHash" }], name: "hashedUserOp", type: "tuple" }; const encoded = utils.defaultAbiCoder.encode([userOpType], [{ ...hashedUserOp }]); // remove leading word (total length) and trailing word (zero-length signature) const userOpHash = utils.keccak256(encoded); const enc = utils.defaultAbiCoder.encode(["bytes32", "address", "uint256"], [userOpHash, entryPoint, chainId]); return utils.keccak256(enc); } const generateRandomUint192 = () => { const rand1 = BigInt(Math.floor(Math.random() * 0x100000000)); const rand2 = BigInt(Math.floor(Math.random() * 0x100000000)); const rand3 = BigInt(Math.floor(Math.random() * 0x100000000)); const rand4 = BigInt(Math.floor(Math.random() * 0x100000000)); const rand5 = BigInt(Math.floor(Math.random() * 0x100000000)); const rand6 = BigInt(Math.floor(Math.random() * 0x100000000)); return rand1 << BigInt(160) | rand2 << BigInt(128) | rand3 << BigInt(96) | rand4 << BigInt(64) | rand5 << BigInt(32) | rand6; }; const randomNonce = () => { let hexString = generateRandomUint192().toString(16); if (hexString.length % 2 !== 0) { hexString = "0" + hexString; } hexString = "0x" + hexString; return BigNumber.from(utils.concat([hexString, "0x0000000000000000"])); }; const DEBUG = false; // TODO set as public flag class HttpRpcClient { constructor(bundlerUrl, entryPointAddress, chainId, clientId, secretKey) { this.bundlerUrl = bundlerUrl; this.entryPointAddress = entryPointAddress; this.chainId = chainId; const headers = {}; if (isTwUrl(this.bundlerUrl)) { const bundleId = typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis ? globalThis.APP_BUNDLE_ID : undefined; if (secretKey) { headers["x-secret-key"] = secretKey; } else if (clientId) { headers["x-client-id"] = clientId; if (bundleId) { headers["x-bundle-id"] = bundleId; } } // Dashboard token if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis && typeof globalThis.TW_AUTH_TOKEN === "string") { headers["authorization"] = `Bearer ${globalThis.TW_AUTH_TOKEN}`; } // CLI token if (typeof globalThis !== "undefined" && "TW_CLI_AUTH_TOKEN" in globalThis && typeof globalThis.TW_CLI_AUTH_TOKEN === "string") { headers["authorization"] = `Bearer ${globalThis.TW_CLI_AUTH_TOKEN}`; headers["x-authorize-wallet"] = "true"; } setAnalyticsHeaders(headers); } this.userOpJsonRpcProvider = new providers.StaticJsonRpcProvider({ url: this.bundlerUrl, headers }, { name: "Connected bundler network", chainId }); this.initializing = this.validateChainId(); } async validateChainId() { if (await isZkSyncChain(this.chainId)) { return; } // validate chainId is in sync with expected chainid const chain = await this.userOpJsonRpcProvider.send("eth_chainId", []); const bundlerChain = parseInt(chain); if (bundlerChain !== this.chainId) { throw new Error(`bundler ${this.bundlerUrl} is on chainId ${bundlerChain}, but provider is on chainId ${this.chainId}`); } } /** * send a UserOperation to the bundler * @param userOp1 - The UserOperation to send * @returns userOpHash the id of this operation, for getUserOperationTransaction */ async sendUserOpToBundler(userOp1) { await this.initializing; const hexifiedUserOp = await hexlifyUserOp(userOp1); const jsonRequestData = [hexifiedUserOp, this.entryPointAddress]; await this.printUserOperation("eth_sendUserOperation", jsonRequestData); return await this.userOpJsonRpcProvider.send("eth_sendUserOperation", [hexifiedUserOp, this.entryPointAddress]); } async estimateUserOpGas(userOp) { await this.initializing; const hexifiedUserOp = await hexlifyUserOp(userOp); const jsonRequestData = [hexifiedUserOp, this.entryPointAddress]; await this.printUserOperation("eth_estimateUserOperationGas", jsonRequestData); const data = await this.userOpJsonRpcProvider.send("eth_estimateUserOperationGas", [hexifiedUserOp, this.entryPointAddress]); // adds gas buffer to callGasLimit to account for ManagedAccountFactory delegate calls return { preVerificationGas: BigNumber.from(data.preVerificationGas), verificationGas: BigNumber.from(data.verificationGas), verificationGasLimit: BigNumber.from(data.verificationGasLimit), callGasLimit: BigNumber.from(data.callGasLimit).add(MANAGED_ACCOUNT_GAS_BUFFER) }; } async getUserOperationGasPrice() { await this.initializing; return await this.userOpJsonRpcProvider.send("thirdweb_getUserOperationGasPrice", []); } async getUserOperationReceipt(userOpHash) { await this.initializing; return await this.userOpJsonRpcProvider.send("eth_getUserOperationReceipt", [userOpHash]); } async zkPaymasterData(transactionInput) { await this.initializing; return await this.userOpJsonRpcProvider.send("zk_paymasterData", [await hexlifyUserOp({ ...transactionInput, gas: transactionInput.gasLimit })]); } async zkBroadcastTransaction(transactionInput) { await this.initializing; return await this.userOpJsonRpcProvider.send("zk_broadcastTransaction", [transactionInput]); } async printUserOperation(method, _ref) { { return; } } } export { DEBUG as D, HttpRpcClient as H, getUserOpHashV06 as g, hexlifyUserOp as h, randomNonce as r };