UNPKG

@zerodev/sdk

Version:

A utility library for working with ERC-4337

529 lines 23.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createKernelAccount = exports.KERNEL_ADDRESSES = void 0; const semver_1 = require("semver"); const viem_1 = require("viem"); const account_abstraction_1 = require("viem/account-abstraction"); const actions_1 = require("viem/actions"); const utils_1 = require("viem/utils"); const index_js_1 = require("../../actions/public/index.js"); const constants_js_1 = require("../../constants.js"); const utils_js_1 = require("../../utils.js"); const utils_js_2 = require("../../utils.js"); const toSigner_js_1 = require("../../utils/toSigner.js"); const addressToEmptyAccount_js_1 = require("../addressToEmptyAccount.js"); const signerTo7702Validator_js_1 = require("../utils/signerTo7702Validator.js"); const toKernelPluginManager_js_1 = require("../utils/toKernelPluginManager.js"); const KernelAccountAbi_js_1 = require("./abi/KernelAccountAbi.js"); const KernelAccountAbi_js_2 = require("./abi/kernel_v_3_0_0/KernelAccountAbi.js"); const KernelFactoryAbi_js_1 = require("./abi/kernel_v_3_0_0/KernelFactoryAbi.js"); const KernelFactoryStakerAbi_js_1 = require("./abi/kernel_v_3_0_0/KernelFactoryStakerAbi.js"); const KernelAccountAbi_js_3 = require("./abi/kernel_v_3_1/KernelAccountAbi.js"); const encodeCallData_js_1 = require("./utils/account/ep0_6/encodeCallData.js"); const encodeDeployCallData_js_1 = require("./utils/account/ep0_6/encodeDeployCallData.js"); const encodeCallData_js_2 = require("./utils/account/ep0_7/encodeCallData.js"); const encodeDeployCallData_js_2 = require("./utils/account/ep0_7/encodeDeployCallData.js"); const accountMetadata_js_1 = require("./utils/common/accountMetadata.js"); const eip712WrapHash_js_1 = require("./utils/common/eip712WrapHash.js"); const getPluginInstallCallData_js_1 = require("./utils/plugins/ep0_7/getPluginInstallCallData.js"); const createAccountAbi = [ { inputs: [ { internalType: "address", name: "_implementation", type: "address" }, { internalType: "bytes", name: "_data", type: "bytes" }, { internalType: "uint256", name: "_index", type: "uint256" } ], name: "createAccount", outputs: [ { internalType: "address", name: "proxy", type: "address" } ], stateMutability: "payable", type: "function" } ]; exports.KERNEL_ADDRESSES = { ACCOUNT_LOGIC_V0_6: "0xd3082872F8B06073A021b4602e022d5A070d7cfC", ACCOUNT_LOGIC_V0_7: "0x94F097E1ebEB4ecA3AAE54cabb08905B239A7D27", FACTORY_ADDRESS_V0_6: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3", FACTORY_ADDRESS_V0_7: "0x6723b44Abeec4E71eBE3232BD5B455805baDD22f", FACTORY_STAKER: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" }; const getKernelInitData = async ({ entryPointVersion: _entryPointVersion, kernelPluginManager, initHook, kernelVersion, initConfig }) => { const { enableData, identifier, validatorAddress, initConfig: initConfig_ } = await kernelPluginManager.getValidatorInitData(); if (_entryPointVersion === "0.6") { return (0, viem_1.encodeFunctionData)({ abi: KernelAccountAbi_js_1.KernelInitAbi, functionName: "initialize", args: [validatorAddress, enableData] }); } if (kernelVersion === "0.3.0") { return (0, viem_1.encodeFunctionData)({ abi: KernelAccountAbi_js_2.KernelV3InitAbi, functionName: "initialize", args: [ identifier, initHook && kernelPluginManager.hook ? kernelPluginManager.hook?.getIdentifier() : viem_1.zeroAddress, enableData, initHook && kernelPluginManager.hook ? await kernelPluginManager.hook?.getEnableData() : "0x" ] }); } return (0, viem_1.encodeFunctionData)({ abi: KernelAccountAbi_js_3.KernelV3_1AccountAbi, functionName: "initialize", args: [ identifier, initHook && kernelPluginManager.hook ? kernelPluginManager.hook?.getIdentifier() : viem_1.zeroAddress, enableData, initHook && kernelPluginManager.hook ? await kernelPluginManager.hook?.getEnableData() : "0x", initConfig ?? initConfig_ ?? [] ] }); }; const getAccountInitCode = async ({ index, factoryAddress, accountImplementationAddress, entryPointVersion: _entryPointVersion, kernelPluginManager, initHook, kernelVersion, initConfig, useMetaFactory }) => { const initialisationData = await getKernelInitData({ entryPointVersion: _entryPointVersion, kernelPluginManager, initHook, kernelVersion, initConfig }); if (_entryPointVersion === "0.6") { return (0, viem_1.encodeFunctionData)({ abi: createAccountAbi, functionName: "createAccount", args: [accountImplementationAddress, initialisationData, index] }); } if (!useMetaFactory) { return (0, viem_1.encodeFunctionData)({ abi: KernelFactoryAbi_js_1.KernelV3FactoryAbi, functionName: "createAccount", args: [initialisationData, (0, viem_1.toHex)(index, { size: 32 })] }); } return (0, viem_1.encodeFunctionData)({ abi: KernelFactoryStakerAbi_js_1.KernelFactoryStakerAbi, functionName: "deployWithFactory", args: [factoryAddress, initialisationData, (0, viem_1.toHex)(index, { size: 32 })] }); }; const getDefaultAddresses = (entryPointVersion, kernelVersion, { accountImplementationAddress, factoryAddress, metaFactoryAddress }) => { (0, utils_js_2.validateKernelVersionWithEntryPoint)(entryPointVersion, kernelVersion); const addresses = constants_js_1.KernelVersionToAddressesMap[kernelVersion]; if (!addresses) { throw new Error(`No addresses found for kernel version ${kernelVersion}`); } return { accountImplementationAddress: accountImplementationAddress ?? addresses.accountImplementationAddress, factoryAddress: factoryAddress ?? addresses.factoryAddress, metaFactoryAddress: metaFactoryAddress ?? addresses.metaFactoryAddress ?? viem_1.zeroAddress }; }; async function createKernelAccount(client, { plugins, entryPoint, index = 0n, factoryAddress: _factoryAddress, accountImplementationAddress: _accountImplementationAddress, metaFactoryAddress: _metaFactoryAddress, address, kernelVersion, initConfig, useMetaFactory: _useMetaFactory = true, eip7702Auth, eip7702Account, pluginMigrations }) { const isEip7702 = !!eip7702Account || !!eip7702Auth; if (isEip7702 && !(0, semver_1.satisfies)(kernelVersion, ">=0.3.3")) { throw new Error("EIP-7702 is recommended for kernel version >=0.3.3"); } const localAccount = eip7702Account ? await (0, toSigner_js_1.toSigner)({ signer: eip7702Account, address }) : undefined; let eip7702Validator; if (localAccount) { eip7702Validator = await (0, signerTo7702Validator_js_1.signerTo7702Validator)(client, { signer: localAccount, entryPoint, kernelVersion }); } let useMetaFactory = _useMetaFactory; const { accountImplementationAddress, factoryAddress, metaFactoryAddress } = getDefaultAddresses(entryPoint.version, kernelVersion, { accountImplementationAddress: _accountImplementationAddress, factoryAddress: _factoryAddress, metaFactoryAddress: _metaFactoryAddress }); let chainId; let cachedAccountMetadata; const getMemoizedChainId = async () => { if (chainId) return chainId; chainId = client.chain ? client.chain.id : await (0, utils_1.getAction)(client, actions_1.getChainId, "getChainId")({}); return chainId; }; const getMemoizedAccountMetadata = async () => { if (cachedAccountMetadata) return cachedAccountMetadata; cachedAccountMetadata = await (0, accountMetadata_js_1.accountMetadata)(client, accountAddress, kernelVersion, await getMemoizedChainId()); return cachedAccountMetadata; }; const kernelPluginManager = (0, toKernelPluginManager_js_1.isKernelPluginManager)(plugins) ? plugins : await (0, toKernelPluginManager_js_1.toKernelPluginManager)(client, { sudo: localAccount ? eip7702Validator : plugins?.sudo, regular: plugins?.regular, hook: plugins?.hook, action: plugins?.action, pluginEnableSignature: plugins?.pluginEnableSignature, entryPoint, kernelVersion, chainId: await getMemoizedChainId() }); const initHook = Boolean((0, toKernelPluginManager_js_1.isKernelPluginManager)(plugins) ? plugins.hook && plugins.getIdentifier() === plugins.sudoValidator?.getIdentifier() : plugins?.hook && !plugins?.regular); const generateInitCode = async () => { if (isEip7702) { return "0x"; } if (!accountImplementationAddress || !factoryAddress) throw new Error("Missing account logic address or factory address"); return getAccountInitCode({ index, factoryAddress, accountImplementationAddress, entryPointVersion: entryPoint.version, kernelPluginManager, initHook, kernelVersion, initConfig, useMetaFactory }); }; const getFactoryArgs = async () => { if (isEip7702) { return { factory: undefined, factoryData: undefined }; } return { factory: entryPoint.version === "0.6" || useMetaFactory === false ? factoryAddress : metaFactoryAddress, factoryData: await generateInitCode() }; }; let accountAddress = address ?? (isEip7702 ? (localAccount?.address ?? viem_1.zeroAddress) : await (async () => { const { factory, factoryData } = await getFactoryArgs(); if (!factory || !factoryData) { throw new Error("Missing factory address or factory data"); } return await (0, index_js_1.getSenderAddress)(client, { factory, factoryData, entryPointAddress: entryPoint.address }); })()); if ((0, viem_1.isAddressEqual)(accountAddress, viem_1.zeroAddress) && useMetaFactory) { useMetaFactory = false; accountAddress = await (0, index_js_1.getSenderAddress)(client, { factory: factoryAddress, factoryData: await generateInitCode(), entryPointAddress: entryPoint.address }); if ((0, viem_1.isAddressEqual)(accountAddress, viem_1.zeroAddress)) { useMetaFactory = true; } } const _entryPoint = { address: entryPoint?.address ?? account_abstraction_1.entryPoint07Address, abi: ((entryPoint?.version ?? "0.7") === "0.6" ? account_abstraction_1.entryPoint06Abi : account_abstraction_1.entryPoint07Abi), version: entryPoint?.version ?? "0.7" }; const pluginCache = { pendingPlugins: pluginMigrations || [], allInstalled: false }; const checkPluginInstallationStatus = async () => { if (!pluginCache.pendingPlugins.length || pluginCache.allInstalled) { pluginCache.allInstalled = true; return; } const installationResults = await Promise.all(pluginCache.pendingPlugins.map((plugin) => (0, index_js_1.isPluginInstalled)(client, { address: accountAddress, plugin }))); pluginCache.pendingPlugins = pluginCache.pendingPlugins.filter((_, index) => !installationResults[index]); pluginCache.allInstalled = pluginCache.pendingPlugins.length === 0; }; const signAuthorization = async () => { const code = await (0, actions_1.getCode)(client, { address: accountAddress }); if (!code || code.length === 0 || !code .toLowerCase() .startsWith(`0xef0100${accountImplementationAddress.slice(2).toLowerCase()}`)) { if (eip7702Auth && !(0, viem_1.isAddressEqual)(eip7702Auth.address, accountImplementationAddress)) { throw new Error("EIP-7702 authorization delegate address does not match account implementation address"); } const auth = eip7702Auth ?? (await (0, actions_1.signAuthorization)(client, { account: localAccount, address: accountImplementationAddress, chainId: await getMemoizedChainId() })); const verified = await (0, utils_1.verifyAuthorization)({ authorization: auth, address: accountAddress }); if (!verified) { throw new Error("Authorization verification failed"); } return auth; } return undefined; }; await checkPluginInstallationStatus(); return (0, account_abstraction_1.toSmartAccount)({ authorization: isEip7702 ? { account: localAccount ?? (0, addressToEmptyAccount_js_1.addressToEmptyAccount)(accountAddress), address: accountImplementationAddress } : undefined, kernelVersion, kernelPluginManager, accountImplementationAddress, factoryAddress: (await getFactoryArgs()).factory, generateInitCode, encodeModuleInstallCallData: async () => { return await kernelPluginManager.encodeModuleInstallCallData(accountAddress); }, nonceKeyManager: (0, viem_1.createNonceManager)({ source: { get: () => 0, set: () => { } } }), client, entryPoint: _entryPoint, getFactoryArgs, async getAddress() { if (accountAddress) return accountAddress; const { factory, factoryData } = await getFactoryArgs(); if (!factory || !factoryData) { throw new Error("Missing factory address or factory data"); } accountAddress = await (0, index_js_1.getSenderAddress)(client, { factory, factoryData, entryPointAddress: entryPoint.address }); return accountAddress; }, async encodeDeployCallData(_tx) { if (entryPoint.version === "0.6") { return (0, encodeDeployCallData_js_1.encodeDeployCallData)(_tx); } return (0, encodeDeployCallData_js_2.encodeDeployCallData)(_tx); }, async encodeCalls(calls, callType, execType) { await checkPluginInstallationStatus(); if (pluginCache.pendingPlugins.length > 0 && entryPoint.version === "0.7" && kernelPluginManager.activeValidatorMode === "sudo") { const pluginInstallCalls = []; for (const plugin of pluginCache.pendingPlugins) { pluginInstallCalls.push((0, getPluginInstallCallData_js_1.getPluginInstallCallData)(accountAddress, plugin)); } return (0, encodeCallData_js_2.encodeCallData)([...calls, ...pluginInstallCalls], callType, plugins?.hook ? true : undefined, execType); } if (calls.length === 1 && (!callType || callType === "call") && calls[0].to.toLowerCase() === accountAddress.toLowerCase()) { return calls[0].data ?? "0x"; } if (entryPoint.version === "0.6") { return (0, encodeCallData_js_1.encodeCallData)(calls, callType); } if (plugins?.hook) { return (0, encodeCallData_js_2.encodeCallData)(calls, callType, true, execType); } return (0, encodeCallData_js_2.encodeCallData)(calls, callType, undefined, execType); }, eip7702Authorization: signAuthorization, async sign({ hash }) { return this.signMessage({ message: hash }); }, async signMessage({ message, useReplayableSignature }) { const messageHash = (0, viem_1.hashMessage)(message); const { name, chainId: metadataChainId, version } = await getMemoizedAccountMetadata(); let signature; if (isEip7702) { signature = await kernelPluginManager.signTypedData({ message: { hash: messageHash }, primaryType: "Kernel", types: { Kernel: [{ name: "hash", type: "bytes32" }] }, domain: { name, version, chainId: useReplayableSignature ? 0 : Number(metadataChainId), verifyingContract: accountAddress } }); } else if (entryPoint.version === "0.6") { const wrappedMessageHash = await (0, eip712WrapHash_js_1.eip712WrapHash)(messageHash, { name, chainId: Number(metadataChainId), version, verifyingContract: accountAddress }, useReplayableSignature); signature = await kernelPluginManager.signMessage({ message: { raw: wrappedMessageHash } }); } else { signature = await kernelPluginManager.signTypedData({ message: { hash: messageHash }, primaryType: "Kernel", types: { Kernel: [{ name: "hash", type: "bytes32" }] }, domain: { name, version, chainId: useReplayableSignature ? 0 : Number(metadataChainId), verifyingContract: accountAddress } }); } if (!(0, utils_js_1.hasKernelFeature)(utils_js_1.KERNEL_FEATURES.ERC1271_WITH_VALIDATOR, version)) { return signature; } if (useReplayableSignature && (0, utils_js_1.hasKernelFeature)(utils_js_1.KERNEL_FEATURES.ERC1271_REPLAYABLE, version)) { signature = (0, viem_1.concatHex)([constants_js_1.MAGIC_VALUE_SIG_REPLAYABLE, signature]); } return (0, viem_1.concatHex)([kernelPluginManager.getIdentifier(), signature]); }, async signTypedData(typedData) { const { message, primaryType, types: _types, domain } = typedData; const types = { EIP712Domain: (0, viem_1.getTypesForEIP712Domain)({ domain: domain }), ..._types }; (0, viem_1.validateTypedData)({ domain: domain, message: message, primaryType: primaryType, types: types }); const typedHash = (0, viem_1.hashTypedData)(typedData); const { name, chainId: metadataChainId, version } = await getMemoizedAccountMetadata(); let signature; if (isEip7702) { signature = await kernelPluginManager.signTypedData({ message: { hash: typedHash }, primaryType: "Kernel", types: { Kernel: [{ name: "hash", type: "bytes32" }] }, domain: { name, version, chainId: Number(metadataChainId), verifyingContract: accountAddress } }); } else if (entryPoint.version === "0.6") { const wrappedMessageHash = await (0, eip712WrapHash_js_1.eip712WrapHash)(typedHash, { name, chainId: Number(metadataChainId), version, verifyingContract: accountAddress }); signature = await kernelPluginManager.signMessage({ message: { raw: wrappedMessageHash } }); } else { signature = await kernelPluginManager.signTypedData({ message: { hash: typedHash }, primaryType: "Kernel", types: { Kernel: [{ name: "hash", type: "bytes32" }] }, domain: { name, version, chainId: Number(metadataChainId), verifyingContract: accountAddress } }); } if (!(0, utils_js_1.hasKernelFeature)(utils_js_1.KERNEL_FEATURES.ERC1271_WITH_VALIDATOR, version)) { return signature; } return (0, viem_1.concatHex)([kernelPluginManager.getIdentifier(), signature]); }, async getNonce(_args) { const key = await kernelPluginManager.getNonceKey(accountAddress, _args?.key); return (0, index_js_1.getAccountNonce)(client, { address: accountAddress, entryPointAddress: entryPoint.address, key }); }, async getStubSignature(userOperation) { if (!userOperation) { throw new Error("No user operation provided"); } return kernelPluginManager.getStubSignature(userOperation); }, async signUserOperation(parameters) { const { chainId = await getMemoizedChainId(), ...userOperation } = parameters; return kernelPluginManager.signUserOperation({ ...userOperation, sender: userOperation.sender ?? (await this.getAddress()), chainId }); } }); } exports.createKernelAccount = createKernelAccount; //# sourceMappingURL=createKernelAccount.js.map