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

942 lines (929 loc) • 23 kB
import { providers, Contract, utils } from 'ethers'; import { s as setAnalyticsHeaders } from './headers-733a8199.browser.esm.js'; import { i as isTwUrl } from './url-a45219bd.browser.esm.js'; import { chainIdToThirdwebRpc } from '../evm/wallets/abstract/dist/thirdweb-dev-wallets-evm-wallets-abstract.browser.esm.js'; import { isContractDeployed, getChainProvider, ThirdwebSDK } from '@thirdweb-dev/sdk'; import { EntryPoint__factory } from '@account-abstraction/contracts'; const EIP1271_ABI = ["function isValidSignature(bytes32 _hash, bytes _signature) public view returns (bytes4)"]; const EIP1271_MAGICVALUE = "0x1626ba7e"; async function checkContractWalletSignature(message, signature, address, chainId, clientId, secretKey) { // TODO: remove below `skipFetchSetup` logic when ethers.js v6 support arrives let _skipFetchSetup = false; if (typeof globalThis !== "undefined" && "TW_SKIP_FETCH_SETUP" in globalThis && typeof globalThis.TW_SKIP_FETCH_SETUP === "boolean") { _skipFetchSetup = globalThis.TW_SKIP_FETCH_SETUP; } const rpcUrl = chainIdToThirdwebRpc(chainId, clientId); const headers = {}; if (isTwUrl(rpcUrl)) { 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); } const provider = new providers.StaticJsonRpcProvider({ url: rpcUrl, skipFetchSetup: _skipFetchSetup, headers }, chainId); const walletContract = new Contract(address, EIP1271_ABI, provider); try { const res = await walletContract.isValidSignature(utils.hashMessage(message), signature); return res === EIP1271_MAGICVALUE; } catch { return false; } } const ENTRYPOINT_ADDRESS = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // v0.6 const ERC6551_REGISTRY = "0x02101dfB77FDE026414827Fdc604ddAF224F0921"; const MANAGED_ACCOUNT_GAS_BUFFER = 50000; const DEFAULT_FACTORY_ADDRESS = "0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00"; const ACCOUNT_CORE_ABI = [{ type: "constructor", inputs: [{ name: "_entrypoint", type: "address", internalType: "contract IEntryPoint" }, { name: "_factory", type: "address", internalType: "address" }], stateMutability: "nonpayable" }, { type: "receive", stateMutability: "payable" }, { type: "function", name: "addDeposit", inputs: [], outputs: [], stateMutability: "payable" }, { type: "function", name: "contractURI", inputs: [], outputs: [{ name: "", type: "string", internalType: "string" }], stateMutability: "view" }, { type: "function", name: "entryPoint", inputs: [], outputs: [{ name: "", type: "address", internalType: "contract IEntryPoint" }], stateMutability: "view" }, { type: "function", name: "execute", inputs: [{ name: "_target", type: "address", internalType: "address" }, { name: "_value", type: "uint256", internalType: "uint256" }, { name: "_calldata", type: "bytes", internalType: "bytes" }], outputs: [], stateMutability: "nonpayable" }, { type: "function", name: "executeBatch", inputs: [{ name: "_target", type: "address[]", internalType: "address[]" }, { name: "_value", type: "uint256[]", internalType: "uint256[]" }, { name: "_calldata", type: "bytes[]", internalType: "bytes[]" }], outputs: [], stateMutability: "nonpayable" }, { type: "function", name: "factory", inputs: [], outputs: [{ name: "", type: "address", internalType: "address" }], stateMutability: "view" }, { type: "function", name: "getAllActiveSigners", inputs: [], outputs: [{ name: "signers", type: "tuple[]", internalType: "struct IAccountPermissions.SignerPermissions[]", components: [{ name: "signer", type: "address", internalType: "address" }, { name: "approvedTargets", type: "address[]", internalType: "address[]" }, { name: "nativeTokenLimitPerTransaction", type: "uint256", internalType: "uint256" }, { name: "startTimestamp", type: "uint128", internalType: "uint128" }, { name: "endTimestamp", type: "uint128", internalType: "uint128" }] }], stateMutability: "view" }, { type: "function", name: "getAllAdmins", inputs: [], outputs: [{ name: "", type: "address[]", internalType: "address[]" }], stateMutability: "view" }, { type: "function", name: "getAllSigners", inputs: [], outputs: [{ name: "signers", type: "tuple[]", internalType: "struct IAccountPermissions.SignerPermissions[]", components: [{ name: "signer", type: "address", internalType: "address" }, { name: "approvedTargets", type: "address[]", internalType: "address[]" }, { name: "nativeTokenLimitPerTransaction", type: "uint256", internalType: "uint256" }, { name: "startTimestamp", type: "uint128", internalType: "uint128" }, { name: "endTimestamp", type: "uint128", internalType: "uint128" }] }], stateMutability: "view" }, { type: "function", name: "getMessageHash", inputs: [{ name: "_hash", type: "bytes32", internalType: "bytes32" }], outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }], stateMutability: "view" }, { type: "function", name: "getNonce", inputs: [], outputs: [{ name: "", type: "uint256", internalType: "uint256" }], stateMutability: "view" }, { type: "function", name: "getPermissionsForSigner", inputs: [{ name: "signer", type: "address", internalType: "address" }], outputs: [{ name: "", type: "tuple", internalType: "struct IAccountPermissions.SignerPermissions", components: [{ name: "signer", type: "address", internalType: "address" }, { name: "approvedTargets", type: "address[]", internalType: "address[]" }, { name: "nativeTokenLimitPerTransaction", type: "uint256", internalType: "uint256" }, { name: "startTimestamp", type: "uint128", internalType: "uint128" }, { name: "endTimestamp", type: "uint128", internalType: "uint128" }] }], stateMutability: "view" }, { type: "function", name: "initialize", inputs: [{ name: "_defaultAdmin", type: "address", internalType: "address" }, { name: "_data", type: "bytes", internalType: "bytes" }], outputs: [], stateMutability: "nonpayable" }, { type: "function", name: "isActiveSigner", inputs: [{ name: "signer", type: "address", internalType: "address" }], outputs: [{ name: "", type: "bool", internalType: "bool" }], stateMutability: "view" }, { type: "function", name: "isAdmin", inputs: [{ name: "_account", type: "address", internalType: "address" }], outputs: [{ name: "", type: "bool", internalType: "bool" }], stateMutability: "view" }, { type: "function", name: "isValidSignature", inputs: [{ name: "_hash", type: "bytes32", internalType: "bytes32" }, { name: "_signature", type: "bytes", internalType: "bytes" }], outputs: [{ name: "magicValue", type: "bytes4", internalType: "bytes4" }], stateMutability: "view" }, { type: "function", name: "isValidSigner", inputs: [{ name: "_signer", type: "address", internalType: "address" }, { name: "_userOp", type: "tuple", internalType: "struct UserOperation", components: [{ name: "sender", type: "address", internalType: "address" }, { name: "nonce", type: "uint256", internalType: "uint256" }, { name: "initCode", type: "bytes", internalType: "bytes" }, { name: "callData", type: "bytes", internalType: "bytes" }, { name: "callGasLimit", type: "uint256", internalType: "uint256" }, { name: "verificationGasLimit", type: "uint256", internalType: "uint256" }, { name: "preVerificationGas", type: "uint256", internalType: "uint256" }, { name: "maxFeePerGas", type: "uint256", internalType: "uint256" }, { name: "maxPriorityFeePerGas", type: "uint256", internalType: "uint256" }, { name: "paymasterAndData", type: "bytes", internalType: "bytes" }, { name: "signature", type: "bytes", internalType: "bytes" }] }], outputs: [{ name: "", type: "bool", internalType: "bool" }], stateMutability: "view" }, { type: "function", name: "multicall", inputs: [{ name: "data", type: "bytes[]", internalType: "bytes[]" }], outputs: [{ name: "results", type: "bytes[]", internalType: "bytes[]" }], stateMutability: "nonpayable" }, { type: "function", name: "onERC1155BatchReceived", inputs: [{ name: "", type: "address", internalType: "address" }, { name: "", type: "address", internalType: "address" }, { name: "", type: "uint256[]", internalType: "uint256[]" }, { name: "", type: "uint256[]", internalType: "uint256[]" }, { name: "", type: "bytes", internalType: "bytes" }], outputs: [{ name: "", type: "bytes4", internalType: "bytes4" }], stateMutability: "nonpayable" }, { type: "function", name: "onERC1155Received", inputs: [{ name: "", type: "address", internalType: "address" }, { name: "", type: "address", internalType: "address" }, { name: "", type: "uint256", internalType: "uint256" }, { name: "", type: "uint256", internalType: "uint256" }, { name: "", type: "bytes", internalType: "bytes" }], outputs: [{ name: "", type: "bytes4", internalType: "bytes4" }], stateMutability: "nonpayable" }, { type: "function", name: "onERC721Received", inputs: [{ name: "", type: "address", internalType: "address" }, { name: "", type: "address", internalType: "address" }, { name: "", type: "uint256", internalType: "uint256" }, { name: "", type: "bytes", internalType: "bytes" }], outputs: [{ name: "", type: "bytes4", internalType: "bytes4" }], stateMutability: "nonpayable" }, { type: "function", name: "setContractURI", inputs: [{ name: "_uri", type: "string", internalType: "string" }], outputs: [], stateMutability: "nonpayable" }, { type: "function", name: "setEntrypointOverride", inputs: [{ name: "_entrypointOverride", type: "address", internalType: "contract IEntryPoint" }], outputs: [], stateMutability: "nonpayable" }, { type: "function", name: "setPermissionsForSigner", inputs: [{ name: "_req", type: "tuple", internalType: "struct IAccountPermissions.SignerPermissionRequest", components: [{ name: "signer", type: "address", internalType: "address" }, { name: "isAdmin", type: "uint8", internalType: "uint8" }, { name: "approvedTargets", type: "address[]", internalType: "address[]" }, { name: "nativeTokenLimitPerTransaction", type: "uint256", internalType: "uint256" }, { name: "permissionStartTimestamp", type: "uint128", internalType: "uint128" }, { name: "permissionEndTimestamp", type: "uint128", internalType: "uint128" }, { name: "reqValidityStartTimestamp", type: "uint128", internalType: "uint128" }, { name: "reqValidityEndTimestamp", type: "uint128", internalType: "uint128" }, { name: "uid", type: "bytes32", internalType: "bytes32" }] }, { name: "_signature", type: "bytes", internalType: "bytes" }], outputs: [], stateMutability: "nonpayable" }, { type: "function", name: "supportsInterface", inputs: [{ name: "interfaceId", type: "bytes4", internalType: "bytes4" }], outputs: [{ name: "", type: "bool", internalType: "bool" }], stateMutability: "view" }, { type: "function", name: "validateUserOp", inputs: [{ name: "userOp", type: "tuple", internalType: "struct UserOperation", components: [{ name: "sender", type: "address", internalType: "address" }, { name: "nonce", type: "uint256", internalType: "uint256" }, { name: "initCode", type: "bytes", internalType: "bytes" }, { name: "callData", type: "bytes", internalType: "bytes" }, { name: "callGasLimit", type: "uint256", internalType: "uint256" }, { name: "verificationGasLimit", type: "uint256", internalType: "uint256" }, { name: "preVerificationGas", type: "uint256", internalType: "uint256" }, { name: "maxFeePerGas", type: "uint256", internalType: "uint256" }, { name: "maxPriorityFeePerGas", type: "uint256", internalType: "uint256" }, { name: "paymasterAndData", type: "bytes", internalType: "bytes" }, { name: "signature", type: "bytes", internalType: "bytes" }] }, { name: "userOpHash", type: "bytes32", internalType: "bytes32" }, { name: "missingAccountFunds", type: "uint256", internalType: "uint256" }], outputs: [{ name: "validationData", type: "uint256", internalType: "uint256" }], stateMutability: "nonpayable" }, { type: "function", name: "verifySignerPermissionRequest", inputs: [{ name: "req", type: "tuple", internalType: "struct IAccountPermissions.SignerPermissionRequest", components: [{ name: "signer", type: "address", internalType: "address" }, { name: "isAdmin", type: "uint8", internalType: "uint8" }, { name: "approvedTargets", type: "address[]", internalType: "address[]" }, { name: "nativeTokenLimitPerTransaction", type: "uint256", internalType: "uint256" }, { name: "permissionStartTimestamp", type: "uint128", internalType: "uint128" }, { name: "permissionEndTimestamp", type: "uint128", internalType: "uint128" }, { name: "reqValidityStartTimestamp", type: "uint128", internalType: "uint128" }, { name: "reqValidityEndTimestamp", type: "uint128", internalType: "uint128" }, { name: "uid", type: "bytes32", internalType: "bytes32" }] }, { name: "signature", type: "bytes", internalType: "bytes" }], outputs: [{ name: "success", type: "bool", internalType: "bool" }, { name: "signer", type: "address", internalType: "address" }], stateMutability: "view" }, { type: "function", name: "withdrawDepositTo", inputs: [{ name: "withdrawAddress", type: "address", internalType: "address payable" }, { name: "amount", type: "uint256", internalType: "uint256" }], outputs: [], stateMutability: "nonpayable" }, { type: "event", name: "AdminUpdated", inputs: [{ name: "signer", type: "address", indexed: true, internalType: "address" }, { name: "isAdmin", type: "bool", indexed: false, internalType: "bool" }], anonymous: false }, { type: "event", name: "ContractURIUpdated", inputs: [{ name: "prevURI", type: "string", indexed: false, internalType: "string" }, { name: "newURI", type: "string", indexed: false, internalType: "string" }], anonymous: false }, { type: "event", name: "Initialized", inputs: [{ name: "version", type: "uint8", indexed: false, internalType: "uint8" }], anonymous: false }, { type: "event", name: "SignerPermissionsUpdated", inputs: [{ name: "authorizingSigner", type: "address", indexed: true, internalType: "address" }, { name: "targetSigner", type: "address", indexed: true, internalType: "address" }, { name: "permissions", type: "tuple", indexed: false, internalType: "struct IAccountPermissions.SignerPermissionRequest", components: [{ name: "signer", type: "address", internalType: "address" }, { name: "isAdmin", type: "uint8", internalType: "uint8" }, { name: "approvedTargets", type: "address[]", internalType: "address[]" }, { name: "nativeTokenLimitPerTransaction", type: "uint256", internalType: "uint256" }, { name: "permissionStartTimestamp", type: "uint128", internalType: "uint128" }, { name: "permissionEndTimestamp", type: "uint128", internalType: "uint128" }, { name: "reqValidityStartTimestamp", type: "uint128", internalType: "uint128" }, { name: "reqValidityEndTimestamp", type: "uint128", internalType: "uint128" }, { name: "uid", type: "bytes32", internalType: "bytes32" }] }], anonymous: false }]; const sdkCache = new Map(); function getSDK(chain) { const cached = sdkCache.get(chain); if (cached) { return cached; } const sdk = new ThirdwebSDK(chain); sdkCache.set(chain, sdk); return sdk; } /** * Get all the signers added to the given smart wallet (excluding owner) * @param chain - The chain to use * @param factoryAddress - The factory address * @param smartWalletAddress - The smart wallet address * @returns The list of signers */ async function getAllSigners(chain, factoryAddress, smartWalletAddress) { const readOnlySDK = getSDK(chain); const factoryContract = await readOnlySDK.getContract(factoryAddress); const signers = await factoryContract.call("getSignersOfAccount", [smartWalletAddress]); return signers; } /** * Get all the smart wallets associated with a personal wallet address * @param chain - The chain to use * @param factoryAddress - The factory address * @param personalWalletAddress - The personal wallet address * @returns The list of smart wallets */ async function getAllSmartWallets(chain, factoryAddress, personalWalletAddress) { const readOnlySDK = getSDK(chain); const factoryContract = await readOnlySDK.getContract(factoryAddress); const ownedAccount = await getSmartWalletAddress(chain, factoryAddress, personalWalletAddress); const accessibleAccounts = await factoryContract.call("getAccountsOfSigner", [personalWalletAddress]); return { owned: ownedAccount, hasSignerRole: accessibleAccounts }; } /** * Check if a smart wallet is deployed for a given personal wallet address * @param chain - The chain to use * @param factoryAddress - The factory address * @param personalWalletAddress - The personal wallet address * @returns True if the smart wallet is deployed */ async function isSmartWalletDeployed(chain, factoryAddress, personalWalletAddress) { let data = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "0x"; const readOnlySDK = getSDK(chain); const factoryContract = await readOnlySDK.getContract(factoryAddress); const accountAddress = await factoryContract.call("getAddress", [personalWalletAddress, data]); const isDeployed = await isContractDeployed(accountAddress, readOnlySDK.getProvider()); return isDeployed; } async function isZkSyncChain(network, clientId, secretKey) { const provider = getChainProvider(network, { clientId, secretKey }); const chainId = (await provider.getNetwork()).chainId; return chainId === 324 || chainId === 300 || chainId === 302; } /** * Get the associated smart wallet address for a given personal wallet address * @param chain - The chain to use * @param factoryAddress - The factory address * @param personalWalletAddress - The personal wallet address * @returns The smart wallet address */ async function getSmartWalletAddress(chain, factoryAddress, personalWalletAddress) { let data = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "0x"; const readOnlySDK = getSDK(chain); const factoryContract = await readOnlySDK.getContract(factoryAddress); const accountAddress = await factoryContract.call("getAddress", [personalWalletAddress, data]); return accountAddress; } async function getUserOpReceipt(chain, userOpHash) { let timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 30000; let interval = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 2000; let entryPointAddress = arguments.length > 4 ? arguments[4] : undefined; const readOnlySDK = getSDK(chain); const entrypoint = await readOnlySDK.getContract(entryPointAddress || ENTRYPOINT_ADDRESS, EntryPoint__factory.abi); // do a first check for the last 5000 blocks const pastEvents = await entrypoint.events.getEvents("UserOperationEvent", { fromBlock: -9000, // look at the last 9000 blocks filters: { userOpHash } }); if (pastEvents[0]) { return pastEvents[0].transaction.transactionHash; } // if not found, query the last 100 blocks every 2 seconds for the next 30 seconds const endtime = Date.now() + timeout; while (Date.now() < endtime) { const events = await entrypoint.events.getEvents("UserOperationEvent", { fromBlock: -100, filters: { userOpHash } }); if (events[0]) { return events[0].transaction.transactionHash; } await new Promise(resolve => setTimeout(resolve, interval)); } return null; } export { ACCOUNT_CORE_ABI as A, DEFAULT_FACTORY_ADDRESS as D, ERC6551_REGISTRY as E, MANAGED_ACCOUNT_GAS_BUFFER as M, getAllSmartWallets as a, getSmartWalletAddress as b, checkContractWalletSignature as c, getUserOpReceipt as d, isZkSyncChain as e, ENTRYPOINT_ADDRESS as f, getAllSigners as g, isSmartWalletDeployed as i };