@zerodev/sdk
Version:
A utility library for working with ERC-4337
529 lines • 23.2 kB
JavaScript
"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