UNPKG

permissionless

Version:

A utility library for working with ERC-4337

985 lines (910 loc) • 32.1 kB
import { type Account, type Address, type Assign, type Chain, type Client, type Hex, type JsonRpcAccount, type LocalAccount, type OneOf, type PrivateKeyAccount, type Transport, type TypedDataDefinition, type WalletClient, concatHex, decodeFunctionData, encodeAbiParameters, encodeFunctionData, keccak256, toHex, zeroAddress } from "viem" import { type SmartAccount, type SmartAccountImplementation, type UserOperation, type WebAuthnAccount, entryPoint06Abi, entryPoint07Abi, entryPoint07Address, getUserOperationHash, toSmartAccount } from "viem/account-abstraction" import { getChainId, readContract } from "viem/actions" import { getAction } from "viem/utils" import { getAccountNonce } from "../../actions/public/getAccountNonce.js" import { getSenderAddress } from "../../actions/public/getSenderAddress.js" import { encode7579Calls } from "../../utils/encode7579Calls.js" import { encodeInstallModule } from "../../utils/encodeInstallModule.js" import { encodeUninstallModule } from "../../utils/encodeUninstallModule.js" import { getOxExports } from "../../utils/ox.js" import { type EthereumProvider, toOwner } from "../../utils/toOwner.js" import { KernelInitAbi } from "./abi/KernelAccountAbi.js" import { KernelV3InitAbi, KernelV3_1AccountAbi } from "./abi/KernelV3AccountAbi.js" import { KernelV3FactoryAbi } from "./abi/KernelV3FactoryAbi.js" import { KernelV3MetaFactoryDeployWithFactoryAbi } from "./abi/KernelV3MetaFactoryAbi.js" import { DUMMY_ECDSA_SIGNATURE, ROOT_MODE_KERNEL_V2, VALIDATOR_TYPE } from "./constants.js" import { decodeCallData } from "./utils/decodeCallData.js" import { encodeCallData } from "./utils/encodeCallData.js" import { getNonceKeyWithEncoding } from "./utils/getNonceKey.js" import { isKernelV2 } from "./utils/isKernelV2.js" import { isWebAuthnAccount } from "./utils/isWebAuthnAccount.js" import { signMessage } from "./utils/signMessage.js" import { signTypedData } from "./utils/signTypedData.js" type EntryPointVersion = "0.6" | "0.7" const migrationHelperAbi = [ { type: "function", name: "migrateWithCall", inputs: [ { name: "validators", type: "address[]", internalType: "contract IValidator[]" }, { name: "permissionIds", type: "bytes4[]", internalType: "bytes4[]" }, { name: "execMode", type: "bytes32", internalType: "ExecMode" }, { name: "execData", type: "bytes", internalType: "bytes" } ], outputs: [], stateMutability: "nonpayable" } ] /** * The account creation ABI for a kernel smart account (from the KernelFactory) */ 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" } ] as const export type KernelVersion<entryPointVersion extends EntryPointVersion> = entryPointVersion extends "0.6" ? "0.2.1" | "0.2.2" | "0.2.3" | "0.2.4" : "0.3.0-beta" | "0.3.1" | "0.3.2" | "0.3.3" export const MIGRATION_HELPER_ADDRESS = "0x03EB97959433D55748839D27C93330Cb85F31A93" /** * Default addresses map for different kernel smart account versions */ export const KERNEL_VERSION_TO_ADDRESSES_MAP: { [key in KernelVersion<EntryPointVersion>]: { ECDSA_VALIDATOR: Address WEB_AUTHN_VALIDATOR?: Address ACCOUNT_LOGIC: Address FACTORY_ADDRESS: Address META_FACTORY_ADDRESS?: Address } } = { "0.2.1": { ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", ACCOUNT_LOGIC: "0xf048AD83CB2dfd6037A43902a2A5Be04e53cd2Eb", FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" }, "0.2.2": { ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", ACCOUNT_LOGIC: "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5", FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" }, "0.2.3": { ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", ACCOUNT_LOGIC: "0xD3F582F6B4814E989Ee8E96bc3175320B5A540ab", FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" }, "0.2.4": { ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", ACCOUNT_LOGIC: "0xd3082872F8B06073A021b4602e022d5A070d7cfC", FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" }, "0.3.0-beta": { ECDSA_VALIDATOR: "0x8104e3Ad430EA6d354d013A6789fDFc71E671c43", ACCOUNT_LOGIC: "0x94F097E1ebEB4ecA3AAE54cabb08905B239A7D27", FACTORY_ADDRESS: "0x6723b44Abeec4E71eBE3232BD5B455805baDD22f", META_FACTORY_ADDRESS: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", WEB_AUTHN_VALIDATOR: "0x7ab16Ff354AcB328452F1D445b3Ddee9a91e9e69" }, "0.3.1": { ECDSA_VALIDATOR: "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57", ACCOUNT_LOGIC: "0xBAC849bB641841b44E965fB01A4Bf5F074f84b4D", FACTORY_ADDRESS: "0xaac5D4240AF87249B3f71BC8E4A2cae074A3E419", META_FACTORY_ADDRESS: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", WEB_AUTHN_VALIDATOR: "0x7ab16Ff354AcB328452F1D445b3Ddee9a91e9e69" }, "0.3.2": { ECDSA_VALIDATOR: "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57", ACCOUNT_LOGIC: "0xD830D15D3dc0C269F3dBAa0F3e8626d33CFdaBe1", FACTORY_ADDRESS: "0x7a1dBAB750f12a90EB1B60D2Ae3aD17D4D81EfFe", META_FACTORY_ADDRESS: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" }, "0.3.3": { ECDSA_VALIDATOR: "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57", ACCOUNT_LOGIC: "0xd6CEDDe84be40893d153Be9d467CD6aD37875b28", FACTORY_ADDRESS: "0x2577507b78c2008Ff367261CB6285d44ba5eF2E9", META_FACTORY_ADDRESS: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5" } } /** * Get supported Kernel Smart Account version based on entryPoint * @param entryPoint */ const getDefaultKernelVersion = <TEntryPointVersion extends EntryPointVersion>( entryPointVersion: TEntryPointVersion, version?: KernelVersion<TEntryPointVersion>, eip7702?: boolean ): KernelVersion<TEntryPointVersion> => { if (eip7702) { return "0.3.3" as KernelVersion<TEntryPointVersion> } if (version) { return version } return ( entryPointVersion === "0.6" ? "0.2.2" : "0.3.0-beta" ) as KernelVersion<TEntryPointVersion> } type KERNEL_ADDRESSES = { validatorAddress?: Address accountLogicAddress: Address factoryAddress: Address metaFactoryAddress: Address } /** * Get default addresses for Kernel Smart Account based on entryPoint or user input * @param entryPointAddress * @param ecdsaValidatorAddress * @param accountLogicAddress * @param factoryAddress * @param metaFactoryAddress */ const getDefaultAddresses = ({ validatorAddress: _validatorAddress, accountLogicAddress: _accountLogicAddress, factoryAddress: _factoryAddress, metaFactoryAddress: _metaFactoryAddress, kernelVersion, isWebAuthn }: Partial<KERNEL_ADDRESSES> & { kernelVersion: KernelVersion<EntryPointVersion> isWebAuthn: boolean }): KERNEL_ADDRESSES => { const addresses = KERNEL_VERSION_TO_ADDRESSES_MAP[kernelVersion] const validatorAddress = _validatorAddress ?? (isWebAuthn ? addresses.WEB_AUTHN_VALIDATOR : addresses.ECDSA_VALIDATOR) const accountLogicAddress = _accountLogicAddress ?? addresses.ACCOUNT_LOGIC const factoryAddress = _factoryAddress ?? addresses.FACTORY_ADDRESS const metaFactoryAddress = _metaFactoryAddress ?? addresses?.META_FACTORY_ADDRESS ?? zeroAddress // Meta Factory doesn't exists for Kernel v2.2 return { validatorAddress, accountLogicAddress, factoryAddress, metaFactoryAddress } } export const getEcdsaRootIdentifierForKernelV3 = ( validatorAddress: Address, eip7702 = false ) => { return concatHex([ eip7702 ? VALIDATOR_TYPE.EIP7702 : VALIDATOR_TYPE.VALIDATOR, eip7702 ? "0x" : validatorAddress ]) } /** * Get the initialization data for a kernel smart account * @param entryPoint * @param owner * @param ecdsaValidatorAddress */ const getInitializationData = <entryPointVersion extends EntryPointVersion>({ entryPoint: { version: entryPointVersion }, kernelVersion, validatorData, validatorAddress }: { kernelVersion: KernelVersion<entryPointVersion> entryPoint: { version: entryPointVersion } validatorData: Hex validatorAddress: Address }) => { if (entryPointVersion === "0.6") { return encodeFunctionData({ abi: KernelInitAbi, functionName: "initialize", args: [validatorAddress, validatorData] }) } if (kernelVersion === "0.3.0-beta") { return encodeFunctionData({ abi: KernelV3InitAbi, functionName: "initialize", args: [ getEcdsaRootIdentifierForKernelV3(validatorAddress), zeroAddress, validatorData, "0x" ] }) } return encodeFunctionData({ abi: KernelV3_1AccountAbi, functionName: "initialize", args: [ getEcdsaRootIdentifierForKernelV3(validatorAddress), zeroAddress, validatorData, "0x", [] ] }) } const getValidatorData = async (owner: WebAuthnAccount | LocalAccount) => { if (owner.type === "local") { return owner.address } if (isWebAuthnAccount(owner)) { const { PublicKey, Hex, Base64 } = await getOxExports() const parsedPublicKey = PublicKey.fromHex(owner.publicKey) const authenticatorIdHash = keccak256( Hex.fromBytes(Base64.toBytes(owner.id)) ) return encodeAbiParameters( [ { components: [ { name: "x", type: "uint256" }, { name: "y", type: "uint256" } ], name: "webAuthnData", type: "tuple" }, { name: "authenticatorIdHash", type: "bytes32" } ], [ { x: parsedPublicKey.x, y: parsedPublicKey.y }, authenticatorIdHash ] ) } throw new Error("Invalid owner type") } /** * Get the account initialization code for a kernel smart account * @param entryPoint * @param owner * @param index * @param factoryAddress * @param accountLogicAddress * @param ecdsaValidatorAddress */ const getAccountInitCode = async <entryPointVersion extends EntryPointVersion>({ entryPointVersion, kernelVersion, validatorData, index, factoryAddress, accountLogicAddress, validatorAddress, useMetaFactory }: { kernelVersion: KernelVersion<entryPointVersion> entryPointVersion: entryPointVersion validatorData: Hex index: bigint factoryAddress: Address accountLogicAddress: Address validatorAddress: Address useMetaFactory: boolean }): Promise<Hex> => { // Build the account initialization data const initializationData = getInitializationData({ entryPoint: { version: entryPointVersion }, kernelVersion, validatorAddress, validatorData }) // Build the account init code if (entryPointVersion === "0.6") { return encodeFunctionData({ abi: createAccountAbi, functionName: "createAccount", args: [accountLogicAddress, initializationData, index] }) } if (!useMetaFactory) { return encodeFunctionData({ abi: KernelV3FactoryAbi, functionName: "createAccount", args: [initializationData, toHex(index, { size: 32 })] }) } return encodeFunctionData({ abi: KernelV3MetaFactoryDeployWithFactoryAbi, functionName: "deployWithFactory", args: [factoryAddress, initializationData, toHex(index, { size: 32 })] }) } export type ToKernelSmartAccountParameters< entryPointVersion extends EntryPointVersion, kernelVersion extends KernelVersion<entryPointVersion>, owner extends OneOf< | EthereumProvider | WalletClient<Transport, Chain | undefined, Account> | LocalAccount | WebAuthnAccount >, eip7702 extends boolean = false > = { client: Client< Transport, Chain | undefined, JsonRpcAccount | LocalAccount | undefined > version?: kernelVersion eip7702?: eip7702 } & (eip7702 extends true ? { owner: OneOf< | EthereumProvider | WalletClient<Transport, Chain | undefined, Account> | LocalAccount > entryPoint?: { address: Address version: "0.7" } address?: never index?: never factoryAddress?: never metaFactoryAddress?: never accountLogicAddress?: Address validatorAddress?: never nonceKey?: never useMetaFactory?: never } : { entryPoint?: { address: Address version: entryPointVersion } owners: [owner] address?: Address index?: bigint factoryAddress?: Address metaFactoryAddress?: Address accountLogicAddress?: Address validatorAddress?: Address nonceKey?: bigint useMetaFactory?: boolean | "optional" }) export type KernelSmartAccountImplementation< entryPointVersion extends EntryPointVersion = "0.7", eip7702 extends boolean = false > = Assign< SmartAccountImplementation< entryPointVersion extends "0.6" ? typeof entryPoint06Abi : typeof entryPoint07Abi, entryPointVersion, eip7702 extends true ? { implementation: Address } : object, eip7702 // { // // entryPoint === ENTRYPOINT_ADDRESS_V06 ? "0.2.2" : "0.3.0-beta" // abi: entryPointVersion extends "0.6" ? typeof BiconomyAbi // factory: { abi: typeof FactoryAbi; address: Address } // } >, { sign: NonNullable<SmartAccountImplementation["sign"]> } > export type ToKernelSmartAccountReturnType< entryPointVersion extends EntryPointVersion = "0.7", eip7702 extends boolean = false > = eip7702 extends true ? SmartAccount<KernelSmartAccountImplementation<entryPointVersion, true>> : SmartAccount<KernelSmartAccountImplementation<entryPointVersion, false>> /** * Build a kernel smart account from a private key, that use the ECDSA or passkeys signer behind the scene * @param client * @param privateKey * @param entryPoint * @param index * @param factoryAddress * @param accountLogicAddress * @param validatorAddress */ export async function toKernelSmartAccount< entryPointVersion extends EntryPointVersion, kernelVersion extends KernelVersion<entryPointVersion>, owner extends OneOf< | EthereumProvider | WalletClient<Transport, Chain | undefined, Account> | LocalAccount | WebAuthnAccount >, eip7702 extends boolean = false >( parameters: ToKernelSmartAccountParameters< entryPointVersion, kernelVersion, owner, eip7702 > ): Promise<ToKernelSmartAccountReturnType<entryPointVersion, eip7702>> { const { client, address, index = 0n, version, validatorAddress: _validatorAddress, factoryAddress: _factoryAddress, metaFactoryAddress: _metaFactoryAddress, accountLogicAddress: _accountLogicAddress, useMetaFactory = true, eip7702 = false } = parameters const owners = (() => { if (eip7702 && "owner" in parameters) { return [parameters.owner] } if ("owners" in parameters) { return parameters.owners } throw new Error("Invalid parameters") })() const isWebAuthn = owners[0].type === "webAuthn" const owner = await (() => { if (isWebAuthn) { return owners[0] as WebAuthnAccount } return toOwner({ owner: owners[0] as OneOf< | EthereumProvider | WalletClient<Transport, Chain | undefined, Account> | LocalAccount > }) })() const entryPoint = (() => { const address = parameters.entryPoint?.address ?? entryPoint07Address const version = parameters.entryPoint?.version ?? "0.7" let abi: typeof entryPoint06Abi | typeof entryPoint07Abi = entryPoint07Abi if (version === "0.6") { abi = entryPoint06Abi } return { address, abi, version } as const })() const kernelVersion = getDefaultKernelVersion( entryPoint.version, version, eip7702 ) const { accountLogicAddress, validatorAddress, factoryAddress, metaFactoryAddress } = getDefaultAddresses({ validatorAddress: _validatorAddress, accountLogicAddress: _accountLogicAddress, factoryAddress: _factoryAddress, metaFactoryAddress: _metaFactoryAddress, kernelVersion, isWebAuthn }) if (!validatorAddress) { throw new Error("Validator address is required") } // Helper to generate the init code for the smart account const generateInitCode = async (_useMetaFactory: boolean) => getAccountInitCode({ entryPointVersion: entryPoint.version, kernelVersion, validatorData: await getValidatorData(owner), index, factoryAddress, accountLogicAddress, validatorAddress, useMetaFactory: _useMetaFactory }) let chainId: number const getMemoizedChainId = async () => { if (chainId) return chainId chainId = client.chain ? client.chain.id : await getAction(client, getChainId, "getChainId")({}) return chainId } const getFactoryArgsFunc = (_useMetaFactory: boolean) => async () => { return { factory: entryPoint.version === "0.6" || _useMetaFactory === false ? factoryAddress : metaFactoryAddress, factoryData: (await generateInitCode(_useMetaFactory)) as Hex } } const { accountAddress, getFactoryArgs } = await (async () => { if (eip7702) { return { accountAddress: (owner as LocalAccount).address, getFactoryArgs: async () => { return { factory: undefined, factoryData: undefined } } } } let getFactoryArgs = getFactoryArgsFunc( useMetaFactory === "optional" ? true : useMetaFactory ) if (address && useMetaFactory !== "optional") { return { accountAddress: address, getFactoryArgs } } const { factory, factoryData } = await getFactoryArgs() let accountAddress = await getSenderAddress(client, { factory, factoryData, entryPointAddress: entryPoint.address }) if (address === accountAddress) { return { accountAddress, getFactoryArgs } } if (useMetaFactory === "optional" && accountAddress === zeroAddress) { getFactoryArgs = getFactoryArgsFunc(false) const { factory, factoryData } = await getFactoryArgs() accountAddress = await getSenderAddress(client, { factory, factoryData, entryPointAddress: entryPoint.address }) } return { accountAddress, getFactoryArgs } })() const getKernelAccountPatchedStatus = async () => { const rootValidator = await getAction( client, readContract, "readContract" )({ address: accountAddress, abi: [ { type: "function", name: "rootValidator", inputs: [], outputs: [ { name: "", type: "bytes21", internalType: "ValidationId" } ], stateMutability: "view" } ], functionName: "rootValidator", args: [] }) const patchedRootValidator = "0x017ab16ff354acb328452f1d445b3ddee9a91e9e69" return rootValidator.toLowerCase() === patchedRootValidator } let isKernelAccountPatched = validatorAddress !== "0xbA45a2BFb8De3D24cA9D7F1B551E14dFF5d690Fd" return toSmartAccount({ client, entryPoint, getFactoryArgs, extend: eip7702 ? { implementation: accountLogicAddress } : undefined, authorization: eip7702 ? { address: accountLogicAddress, account: owner as PrivateKeyAccount } : undefined, async getAddress() { return accountAddress }, async encodeCalls(calls) { if (!isKernelAccountPatched) { const isDeployed = "isDeployed" in this && (await (this as any).isDeployed()) isKernelAccountPatched = isDeployed && (await getKernelAccountPatchedStatus()) } if (!isKernelAccountPatched) { const [installFallbackCall] = encodeInstallModule({ account: this as any, modules: [ { type: "fallback", address: MIGRATION_HELPER_ADDRESS, context: "0x36f541c10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000" } ] }) const [uninstallFallbackCall] = encodeUninstallModule({ account: this as any, modules: [ { type: "fallback", address: MIGRATION_HELPER_ADDRESS, context: "0x36f541c1" } ] }) const executeCallData = encodeCallData({ calls, kernelVersion }) const { args } = decodeFunctionData({ abi: [ { type: "function", name: "execute", inputs: [ { name: "execMode", type: "bytes32", internalType: "ExecMode" }, { name: "executionCalldata", type: "bytes", internalType: "bytes" } ], outputs: [], stateMutability: "payable" } ], data: executeCallData }) const migrationCallData = encodeFunctionData({ abi: migrationHelperAbi, functionName: "migrateWithCall", args: [[], [], ...args] as readonly any[] }) if (kernelVersion !== "0.3.0-beta") { return encode7579Calls({ mode: { type: "delegatecall", revertOnError: false, selector: "0x", context: "0x" }, callData: [ { to: MIGRATION_HELPER_ADDRESS, data: migrationCallData, value: 0n } ] }) } return encodeCallData({ calls: [ installFallbackCall, { to: accountAddress, data: migrationCallData, value: 0n }, uninstallFallbackCall ], kernelVersion }) } return encodeCallData({ calls, kernelVersion }) }, async decodeCalls(callData) { return decodeCallData({ callData, kernelVersion }) }, async getNonce(_args) { return getAccountNonce(client, { address: await this.getAddress(), entryPointAddress: entryPoint.address, key: getNonceKeyWithEncoding( kernelVersion, validatorAddress, /*args?.key ?? */ parameters.nonceKey ?? 0n ) }) }, async getStubSignature() { if (isKernelV2(kernelVersion)) { return concatHex([ROOT_MODE_KERNEL_V2, DUMMY_ECDSA_SIGNATURE]) } if (isWebAuthnAccount(owner)) { return encodeAbiParameters( [ { name: "authenticatorData", type: "bytes" }, { name: "clientDataJSON", type: "string" }, { name: "responseTypeLocation", type: "uint256" }, { name: "r", type: "uint256" }, { name: "s", type: "uint256" }, { name: "usePrecompiled", type: "bool" } ], [ "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97631d00000000", '{"type":"webauthn.get","challenge":"tbxXNFS9X_4Byr1cMwqKrIGB-_30a0QhZ6y7ucM0BOE","origin":"http://localhost:3000","crossOrigin":false, "other_keys_can_be_added_here":"do not compare clientDataJSON against a template. See https://goo.gl/yabPex"}', 1n, 44941127272049826721201904734628716258498742255959991581049806490182030242267n, 9910254599581058084911561569808925251374718953855182016200087235935345969636n, false ] ) } return DUMMY_ECDSA_SIGNATURE }, async sign({ hash }) { return this.signMessage({ message: hash }) }, async signMessage({ message }) { if ( "isDeployed" in this && !(await (this as any).isDeployed()) && eip7702 ) { throw new Error( "Kernel with EIP-7702 isn't 1271 compliant before delegation." ) } const signature = await signMessage({ owner, message, accountAddress: await this.getAddress(), kernelVersion: kernelVersion, chainId: await getMemoizedChainId(), eip7702: eip7702 }) if (isKernelV2(kernelVersion)) { return signature } return concatHex([ getEcdsaRootIdentifierForKernelV3(validatorAddress, eip7702), signature ]) }, async signTypedData(typedData) { if ( "isDeployed" in this && !(await (this as any).isDeployed()) && eip7702 ) { throw new Error( "Kernel with EIP-7702 isn't 1271 compliant before delegation." ) } const signature = await signTypedData({ owner: owner, chainId: await getMemoizedChainId(), ...(typedData as TypedDataDefinition), accountAddress: await this.getAddress(), kernelVersion: kernelVersion, eip7702 }) if (isKernelV2(kernelVersion)) { return signature } return concatHex([ getEcdsaRootIdentifierForKernelV3(validatorAddress, eip7702), signature ]) }, // Sign a user operation async signUserOperation(parameters) { const { chainId = await getMemoizedChainId(), ...userOperation } = parameters const hash = getUserOperationHash({ userOperation: { ...userOperation, sender: userOperation.sender ?? (await this.getAddress()), signature: "0x" } as UserOperation<entryPointVersion>, entryPointAddress: entryPoint.address, entryPointVersion: entryPoint.version, chainId: chainId }) const signature = isWebAuthnAccount(owner) ? await signMessage({ owner, message: { raw: hash }, chainId, accountAddress: await this.getAddress(), kernelVersion, eip7702: false }) : await owner.signMessage({ message: { raw: hash } }) // Always use the sudo mode, since we will use external paymaster if (isKernelV2(kernelVersion)) { return concatHex(["0x00000000", signature]) } return signature } }) as Promise<ToKernelSmartAccountReturnType<entryPointVersion, eip7702>> }