diff --git a/bun.lockb b/bun.lockb index 3de78ceb..005bec5d 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/core/accounts/kernel/createKernelAccount.ts b/packages/core/accounts/kernel/createKernelAccount.ts index 79914093..5e5bc90c 100644 --- a/packages/core/accounts/kernel/createKernelAccount.ts +++ b/packages/core/accounts/kernel/createKernelAccount.ts @@ -60,6 +60,7 @@ export type KernelSmartAccount< getNonce: (customNonceKey?: bigint) => Promise generateInitCode: () => Promise encodeCallData: (args: KernelEncodeCallDataArgs) => Promise + encodeModuleInstallCallData: () => Promise } export type CreateKernelAccountParameters = { @@ -267,21 +268,23 @@ export async function createKernelAccount< plugins, entryPoint: entryPointAddress, index = 0n, - factoryAddress = KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_6, - accountLogicAddress = KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_6, + factoryAddress, + accountLogicAddress, factoryStakerAddress = KERNEL_ADDRESSES.FACTORY_STAKER, deployedAccountAddress }: CreateKernelAccountParameters ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) accountLogicAddress = - entryPointVersion === "v0.6" + accountLogicAddress ?? + (entryPointVersion === "v0.6" ? KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_6 - : KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_7 + : KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_7) factoryAddress = - entryPointVersion === "v0.6" + factoryAddress ?? + (entryPointVersion === "v0.6" ? KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_6 - : KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_7 + : KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_7) const kernelPluginManager = isKernelPluginManager(plugins) ? plugins @@ -294,6 +297,8 @@ export async function createKernelAccount< }) // Helper to generate the init code for the smart account const generateInitCode = async () => { + if (!accountLogicAddress || !factoryAddress) + throw new Error("Missing account logic address or factory address") return getAccountInitCode({ index, factoryAddress, @@ -323,6 +328,11 @@ export async function createKernelAccount< return { kernelPluginManager, generateInitCode, + encodeModuleInstallCallData: async () => { + return await kernelPluginManager.encodeModuleInstallCallData( + accountAddress + ) + }, ...toSmartAccount({ address: accountAddress, publicKey: accountAddress, diff --git a/packages/core/accounts/kernel/utils/account/ep0_6/encodeModuleInstallCallData.ts b/packages/core/accounts/kernel/utils/account/ep0_6/encodeModuleInstallCallData.ts new file mode 100644 index 00000000..74d5b130 --- /dev/null +++ b/packages/core/accounts/kernel/utils/account/ep0_6/encodeModuleInstallCallData.ts @@ -0,0 +1,35 @@ +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types/entrypoint" +import { type Address, type Hex, encodeFunctionData } from "viem" +import type { PluginInstallData } from "../../../../../types/kernel.js" +import { KernelAccountAbi } from "../../../abi/KernelAccountAbi.js" +import { encodeCallData } from "./encodeCallData.js" + +export const encodeModuleInstallCallData = async ({ + accountAddress, + enableData, + executor, + selector, + validAfter, + validUntil, + validator +}: { + accountAddress: Address +} & PluginInstallData): Promise => { + return encodeCallData({ + to: accountAddress, + value: 0n, + data: encodeFunctionData({ + abi: KernelAccountAbi, + functionName: "setExecution", + args: [ + selector, + executor, + validator, + validUntil, + validAfter, + enableData + ] + }), + callType: "call" + }) +} diff --git a/packages/core/accounts/kernel/utils/account/ep0_7/getKernelV3Nonce.ts b/packages/core/accounts/kernel/utils/account/ep0_7/getKernelV3Nonce.ts index 9690cde6..14446e48 100644 --- a/packages/core/accounts/kernel/utils/account/ep0_7/getKernelV3Nonce.ts +++ b/packages/core/accounts/kernel/utils/account/ep0_7/getKernelV3Nonce.ts @@ -1,6 +1,6 @@ -import { getAction } from "permissionless" import type { Address, Client } from "viem" import { readContract } from "viem/actions" +import { getAction } from "viem/utils" import { KernelV3AccountAbi } from "../../../abi/kernel_v_3_0_0/KernelAccountAbi.js" export const getKernelV3Nonce = async ( @@ -10,7 +10,8 @@ export const getKernelV3Nonce = async ( try { const nonce = await getAction( client, - readContract + readContract, + "sendTransaction" )({ abi: KernelV3AccountAbi, address: accountAddress, diff --git a/packages/core/accounts/kernel/utils/plugins/ep0_6/getPluginsEnableTypedData.ts b/packages/core/accounts/kernel/utils/plugins/ep0_6/getPluginsEnableTypedData.ts index 2366e46f..84adf872 100644 --- a/packages/core/accounts/kernel/utils/plugins/ep0_6/getPluginsEnableTypedData.ts +++ b/packages/core/accounts/kernel/utils/plugins/ep0_6/getPluginsEnableTypedData.ts @@ -34,7 +34,6 @@ export const getPluginsEnableTypedData = async < accountAddress: Address chainId: number kernelVersion: string - // { action, validator }: Kernel2_0_plugins } & Kernel2_0_plugins & PluginValidityData): Promise< Parameters[0] diff --git a/packages/core/accounts/kernel/utils/plugins/ep0_7/isPluginInitialized.ts b/packages/core/accounts/kernel/utils/plugins/ep0_7/isPluginInitialized.ts index cddecff5..cbeb75a1 100644 --- a/packages/core/accounts/kernel/utils/plugins/ep0_7/isPluginInitialized.ts +++ b/packages/core/accounts/kernel/utils/plugins/ep0_7/isPluginInitialized.ts @@ -1,6 +1,6 @@ -import { getAction } from "permissionless" import type { Address, Client } from "viem" import { readContract } from "viem/actions" +import { getAction } from "viem/utils" import { KernelModuleIsInitializedAbi } from "../../../abi/kernel_v_3_0_0/KernelModuleAbi.js" export const isPluginInitialized = async ( @@ -11,7 +11,8 @@ export const isPluginInitialized = async ( try { return await getAction( client, - readContract + readContract, + "readContract" )({ abi: KernelModuleIsInitializedAbi, address: pluginAddress, diff --git a/packages/core/accounts/kernel/v1/createKernelV1Account.ts b/packages/core/accounts/kernel/v1/createKernelV1Account.ts index ec979929..1ffa09bf 100644 --- a/packages/core/accounts/kernel/v1/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/v1/createKernelV1Account.ts @@ -213,6 +213,9 @@ export async function createKernelV1Account< return { ...account, generateInitCode, + encodeModuleInstallCallData: async () => { + throw new Error("Not implemented") + }, client: client, publicKey: accountAddress, entryPoint: entryPointAddress, diff --git a/packages/core/accounts/kernel/v2/createKernelV2Account.ts b/packages/core/accounts/kernel/v2/createKernelV2Account.ts index c665e6e9..c0134e5a 100644 --- a/packages/core/accounts/kernel/v2/createKernelV2Account.ts +++ b/packages/core/accounts/kernel/v2/createKernelV2Account.ts @@ -4,10 +4,7 @@ import { getSenderAddress, isSmartAccountDeployed } from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - type SmartAccount -} from "permissionless/accounts" +import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint @@ -47,20 +44,10 @@ import { isKernelPluginManager, toKernelPluginManager } from "../../utils/toKernelPluginManager.js" +import { type KernelSmartAccount } from "../createKernelAccount.js" import { KernelAccountV2Abi } from "./abi/KernelAccountV2Abi.js" import { KernelFactoryV2Abi } from "./abi/KernelFactoryV2Abi.js" -export type KernelSmartAccount< - entryPoint extends EntryPoint, - transport extends Transport = Transport, - chain extends Chain | undefined = Chain | undefined -> = SmartAccount & { - kernelPluginManager: KernelPluginManager - getNonce: (customNonceKey?: bigint) => Promise - generateInitCode: () => Promise - encodeCallData: (args: KernelEncodeCallDataArgs) => Promise -} - // Safe's library for create and create2: https://github.com/safe-global/safe-contracts/blob/0acdd35a203299585438f53885df630f9d486a86/contracts/libraries/CreateCall.sol // Address was found here: https://github.com/safe-global/safe-deployments/blob/926ec6bbe2ebcac3aa2c2c6c0aff74aa590cbc6a/src/assets/v1.4.1/create_call.json const createCallAddress = "0x9b35Af71d77eaf8d7e40252370304687390A1A52" @@ -289,6 +276,11 @@ export async function createKernelV2Account< source: "kernelSmartAccount", kernelPluginManager, generateInitCode, + encodeModuleInstallCallData: async () => { + return await kernelPluginManager.encodeModuleInstallCallData( + accountAddress + ) + }, async getFactory() { if (smartAccountDeployed) return undefined diff --git a/packages/core/accounts/utils/6492.ts b/packages/core/accounts/utils/6492.ts index 4d9fcb6f..f970a668 100644 --- a/packages/core/accounts/utils/6492.ts +++ b/packages/core/accounts/utils/6492.ts @@ -1,6 +1,5 @@ // copied from: https://github.com/alchemyplatform/aa-sdk/blob/266c9757cd721ef0bd97d04c0b592a329f8a9da5/packages/core/src/signer/utils.ts -import { getAction } from "permissionless" import { type Address, type Chain, @@ -14,6 +13,7 @@ import { parseAbiParameters } from "viem" import { getStorageAt } from "viem/actions" +import { getAction } from "viem/utils" export type SignWith6492Params = { factoryAddress: Address @@ -85,7 +85,8 @@ export const getKernelImplementationAddress = async < try { const strgAddr = await getAction( client, - getStorageAt + getStorageAt, + "getStorageAt" )({ address: accountAddress, slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" diff --git a/packages/core/accounts/utils/toKernelPluginManager.ts b/packages/core/accounts/utils/toKernelPluginManager.ts index 3b11bc47..2d8a43c7 100644 --- a/packages/core/accounts/utils/toKernelPluginManager.ts +++ b/packages/core/accounts/utils/toKernelPluginManager.ts @@ -15,6 +15,7 @@ import { zeroAddress } from "viem" import { getChainId } from "viem/actions" +import { encodeModuleInstallCallData as encodeModuleInstallCallDataEpV06 } from "../../accounts/kernel/utils/account/ep0_6/encodeModuleInstallCallData.js" import { VALIDATOR_MODE, VALIDATOR_TYPE } from "../../constants.js" import { type KernelPluginManager, @@ -193,6 +194,24 @@ export async function toKernelPluginManager< return { ...activeValidator, getIdentifier, + encodeModuleInstallCallData: async (accountAddress: Address) => { + if (!action) { + throw new Error("Action data must be set") + } + if (!regular) throw new Error("regular validator not set") + if (entryPointVersion === "v0.6") { + return await encodeModuleInstallCallDataEpV06({ + accountAddress, + selector: action.selector, + executor: action.address, + validator: regular?.address, + validUntil, + validAfter, + enableData: await regular.getEnableData(accountAddress) + }) + } + throw new Error("EntryPoint v0.7 not supported yet") + }, signUserOperation: async (userOperation) => { const userOpSig = await activeValidator.signUserOperation(userOperation) diff --git a/packages/core/actions/account-client/signUserOperation.ts b/packages/core/actions/account-client/signUserOperation.ts index 74019ee8..f9a80e01 100644 --- a/packages/core/actions/account-client/signUserOperation.ts +++ b/packages/core/actions/account-client/signUserOperation.ts @@ -13,10 +13,10 @@ import type { } from "permissionless/types" import { AccountOrClientNotFoundError, - getAction, parseAccount } from "permissionless/utils" import type { Chain, Client, Transport } from "viem" +import { getAction } from "viem/utils" export type SignUserOperationParameters< entryPoint extends EntryPoint, @@ -60,7 +60,8 @@ export async function signUserOperation< const userOperation = await getAction( client, - prepareUserOperationRequest + prepareUserOperationRequest, + "prepareUserOperationRequest" )(args) userOperation.signature = await account.signUserOperation( diff --git a/packages/core/package.json b/packages/core/package.json index 03cb1401..a1ff6f1d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -90,8 +90,8 @@ } }, "peerDependencies": { - "viem": "^2.0.0", - "permissionless": "^0.1.16" + "viem": "^2.9.17", + "permissionless": "^0.1.17" }, "dependencies": { "semver": "^7.6.0" diff --git a/packages/core/types/kernel.ts b/packages/core/types/kernel.ts index 40e889dc..3eef4db1 100644 --- a/packages/core/types/kernel.ts +++ b/packages/core/types/kernel.ts @@ -1,4 +1,7 @@ -import type { EntryPoint } from "permissionless/types" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + EntryPoint +} from "permissionless/types" import type { GetEntryPointVersion } from "permissionless/types/entrypoint" import type { UserOperation, @@ -151,8 +154,22 @@ export type KernelPluginManager = getAction(): Action getValidityData(): PluginValidityData getIdentifier(isSudo?: boolean): Hex + encodeModuleInstallCallData: (accountAddress: Address) => Promise } +export type PluginInstallData = + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE + ? { + selector: Hex + executor: Address + validator: Address + validUntil: number + validAfter: number + enableData: Hex + } + : // TODO: Add support for EP v0.7 + never + export type KernelPluginManagerParams = { sudo?: KernelValidator regular?: KernelValidator diff --git a/packages/core/utils.ts b/packages/core/utils.ts index 561d37ea..395b44cd 100644 --- a/packages/core/utils.ts +++ b/packages/core/utils.ts @@ -98,7 +98,8 @@ export const fixSignedData = (sig: Hex): Hex => { let { r, s, v } = hexToSignature(signature) if (v === 0n || v === 1n) v += 27n - const joined = signatureToHex({ r, s, v }) + // biome-ignore lint/style/noNonNullAssertion: + const joined = signatureToHex({ r, s, v: v! }) return joined } diff --git a/packages/presets/package.json b/packages/presets/package.json index f0e25183..6150a4b7 100644 --- a/packages/presets/package.json +++ b/packages/presets/package.json @@ -52,7 +52,7 @@ "typescript": "^5.0.0", "@zerodev/sdk": "^5.2.0", "@zerodev/ecdsa-validator": "^5.2.0", - "permissionless": "^0.1.16", - "viem": "^2.0.0" + "permissionless": "^0.1.17", + "viem": "^2.9.17" } } diff --git a/packages/test/package.json b/packages/test/package.json index 960e32d9..6a902c23 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -7,11 +7,11 @@ }, "dependencies": { "dotenv": "^16.3.1", - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "workspace:*", "@zerodev/ecdsa-validator": "workspace:*", "@zerodev/session-key": "workspace:*", "@zerodev/modular-permission": "workspace:*", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/packages/test/recoveryKernelAccount.test.ts b/packages/test/recoveryKernelAccount.test.ts new file mode 100644 index 00000000..03532164 --- /dev/null +++ b/packages/test/recoveryKernelAccount.test.ts @@ -0,0 +1,124 @@ +// @ts-expect-error +import { beforeAll, describe, expect, test } from "bun:test" +import { KernelAccountClient, KernelSmartAccount } from "@zerodev/sdk" +import dotenv from "dotenv" +import { BundlerClient, bundlerActions } from "permissionless" +import { EntryPoint } from "permissionless/types/entrypoint.js" +import { Chain, type PublicClient, Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { + getEcdsaKernelAccountWithPrivateKey, + getEntryPoint, + getKernelAccountClient, + getPublicClient, + getRecoveryKernelAccount, + getZeroDevPaymasterClient +} from "./utils.js" + +dotenv.config() + +const requiredEnvVars = [ + "FACTORY_ADDRESS", + "TEST_PRIVATE_KEY", + "RPC_URL", + "ENTRYPOINT_ADDRESS", + "GREETER_ADDRESS", + "ZERODEV_PROJECT_ID", + "ZERODEV_BUNDLER_RPC_HOST", + "ZERODEV_PAYMASTER_RPC_HOST" +] + +const validateEnvironmentVariables = (envVars: string[]): void => { + const unsetEnvVars = envVars.filter((envVar) => !process.env[envVar]) + if (unsetEnvVars.length > 0) { + throw new Error( + `The following environment variables are not set: ${unsetEnvVars.join( + ", " + )}` + ) + } +} + +validateEnvironmentVariables(requiredEnvVars) + +const ETHEREUM_ADDRESS_LENGTH = 42 +const ETHEREUM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/ +const TEST_TIMEOUT = 1000000 + +describe("Recovery kernel Account", () => { + let ownerAccount: KernelSmartAccount + let recoveryAccount: KernelSmartAccount + let publicClient: PublicClient + let bundlerClient: BundlerClient + let ownerKernelClient: KernelAccountClient< + EntryPoint, + Transport, + Chain, + KernelSmartAccount + > + + beforeAll(async () => { + publicClient = await getPublicClient() + const ownerPrivateKey = generatePrivateKey() + ownerAccount = + await getEcdsaKernelAccountWithPrivateKey(ownerPrivateKey) + + recoveryAccount = await getRecoveryKernelAccount(ownerAccount.address) + ownerKernelClient = await getKernelAccountClient({ + account: ownerAccount, + middleware: { + sponsorUserOperation: async ({ userOperation, entryPoint }) => { + const zerodevPaymaster = getZeroDevPaymasterClient() + return zerodevPaymaster.sponsorUserOperation({ + userOperation, + entryPoint + }) + } + } + }) + + bundlerClient = ownerKernelClient.extend( + bundlerActions(getEntryPoint()) + ) + }) + + test("Account address should be a valid Ethereum address", async () => { + expect(ownerAccount.address).toBeString() + expect(ownerAccount.address).toHaveLength(ETHEREUM_ADDRESS_LENGTH) + expect(ownerAccount.address).toMatch(ETHEREUM_ADDRESS_REGEX) + expect(ownerAccount.address).not.toEqual(zeroAddress) + }) + + test( + "enable recovery", + async () => { + console.log("Deploying the Owner Kernel Account") + const txHash = await ownerKernelClient.sendTransaction({ + to: zeroAddress + }) + console.log( + `✅ Owner account Deployed {accountAddress: ${ownerAccount.address}}, txHash:`, + txHash + ) + const userOpHash = await ownerKernelClient.sendUserOperation({ + userOperation: { + callData: + await recoveryAccount.encodeModuleInstallCallData() + } + }) + console.log("userOpHash:", userOpHash) + + expect(userOpHash).toHaveLength(66) + + const transactionReceipt = + await bundlerClient.waitForUserOperationReceipt({ + hash: userOpHash + }) + console.log( + "recoveryTransactionLink", + `https://sepolia.etherscan.io/tx/${transactionReceipt.receipt.transactionHash}` + ) + }, + TEST_TIMEOUT + ) +}) diff --git a/packages/test/utils.ts b/packages/test/utils.ts index 3967f00e..b1f49361 100644 --- a/packages/test/utils.ts +++ b/packages/test/utils.ts @@ -11,7 +11,6 @@ import { createKernelAccount } from "@zerodev/sdk/accounts" import { createKernelV2Account } from "@zerodev/sdk/accounts" -import { KernelV1SmartAccount } from "@zerodev/sdk/accounts/kernel/v1/createKernelV1Account.js" import type { Action } from "@zerodev/sdk/types" import { ParamOperator, @@ -22,6 +21,7 @@ import { signerToSessionKeyValidator } from "@zerodev/session-key" import { createWeightedECDSAValidator } from "@zerodev/weighted-ecdsa-validator" +import { getRecoveryAction } from "@zerodev/weighted-ecdsa-validator/constants.js" import { BundlerClient, ENTRYPOINT_ADDRESS_V06, @@ -52,7 +52,7 @@ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { type Chain, goerli, sepolia } from "viem/chains" +import { type Chain, sepolia } from "viem/chains" import * as allChains from "viem/chains" import { Policy } from "../../plugins/modularPermission/policies/types.js" import { toECDSASigner } from "../../plugins/modularPermission/signers/toECDSASigner.js" @@ -62,7 +62,8 @@ import { TEST_ERC20Abi } from "./abis/Test_ERC20Abi.js" import { config } from "./config.js" export const Test_ERC20Address = "0x3870419Ba2BBf0127060bCB37f69A1b1C090992B" -export const index = 543853232332340n +export const index = 5438533232332340n +const DEFAULT_PROVIDER = "STACKUP" const projectId = config["v0.6"].sepolia.projectId export const getFactoryAddress = (): Address => { const factoryAddress = process.env.FACTORY_ADDRESS @@ -120,12 +121,12 @@ export const getSignerToEcdsaKernelAccount = async < } export const getEcdsaKernelAccountWithRandomSigner = async (): Promise< - SmartAccount + KernelSmartAccount > => { return getEcdsaKernelAccountWithPrivateKey(generatePrivateKey()) } -const getEcdsaKernelAccountWithPrivateKey = async < +export const getEcdsaKernelAccountWithPrivateKey = async < entryPoint extends EntryPoint >( privateKey: Hex @@ -305,6 +306,34 @@ export const getSignersToWeightedEcdsaKernelAccount = async ( } } +export const getRecoveryKernelAccount = async ( + deployedAccountAddress: Address +) => { + const privateKey1 = generatePrivateKey() + const signer1 = privateKeyToAccount(privateKey1) + const recoveryPlugin = await createWeightedECDSAValidator( + await getPublicClient(), + { + entryPoint: getEntryPoint(), + config: { + threshold: 100, + delay: 0, + signers: [{ address: signer1.address, weight: 100 }] + }, + signers: [signer1] + } + ) + return await createKernelAccount(await getPublicClient(), { + entryPoint: getEntryPoint(), + deployedAccountAddress, + plugins: { + regular: recoveryPlugin, + action: getRecoveryAction() + }, + index + }) +} + export const getSignerToSessionKeyKernelAccount = async (): Promise< KernelSmartAccount > => { @@ -428,8 +457,6 @@ export const getSessionKeyToSessionKeyKernelAccount = async ( }) } -const DEFAULT_PROVIDER = "STACKUP" - const getBundlerRpc = (): string => { const zeroDevProjectId = projectId const zeroDevBundlerRpcHost = config["v0.6"].sepolia.bundlerUrl diff --git a/packages/test/v0.7/ecdsaKernelAccount.test.ts b/packages/test/v0.7/ecdsaKernelAccount.test.ts index be006cd6..261d1550 100644 --- a/packages/test/v0.7/ecdsaKernelAccount.test.ts +++ b/packages/test/v0.7/ecdsaKernelAccount.test.ts @@ -13,7 +13,11 @@ import { } from "@zerodev/sdk" import dotenv from "dotenv" import { ethers } from "ethers" -import { BundlerClient, ENTRYPOINT_ADDRESS_V07 } from "permissionless" +import { + BundlerClient, + ENTRYPOINT_ADDRESS_V07, + bundlerActions +} from "permissionless" import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" import { PimlicoBundlerClient } from "permissionless/clients/pimlico.js" import { EntryPoint } from "permissionless/types/entrypoint.js" @@ -109,7 +113,6 @@ describe("ECDSA kernel Account", () => { account = await getSignerToEcdsaKernelAccount() owner = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex).address publicClient = await getPublicClient() - bundlerClient = getKernelBundlerClient() pimlicoBundlerClient = getPimlicoBundlerClient() kernelClient = await getKernelAccountClient({ account, @@ -123,6 +126,7 @@ describe("ECDSA kernel Account", () => { } } }) + bundlerClient = kernelClient.extend(bundlerActions(getEntryPoint())) greeterContract = getContract({ abi: GreeterAbi, address: process.env.GREETER_ADDRESS as Address, diff --git a/plugins/ecdsa/package.json b/plugins/ecdsa/package.json index 1924684b..2194bc75 100644 --- a/plugins/ecdsa/package.json +++ b/plugins/ecdsa/package.json @@ -35,8 +35,8 @@ "lint:fix": "bun run lint --apply" }, "peerDependencies": { - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "^5.2.0", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/plugins/modularPermission/package.json b/plugins/modularPermission/package.json index a4dcf1b3..85f45d89 100644 --- a/plugins/modularPermission/package.json +++ b/plugins/modularPermission/package.json @@ -56,8 +56,8 @@ "@simplewebauthn/browser": "^9.0.1" }, "peerDependencies": { - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "^5.2.0", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/plugins/modularPermission/toModularPermissionValidatorPlugin.ts b/plugins/modularPermission/toModularPermissionValidatorPlugin.ts index 052b70f9..c8e485b5 100644 --- a/plugins/modularPermission/toModularPermissionValidatorPlugin.ts +++ b/plugins/modularPermission/toModularPermissionValidatorPlugin.ts @@ -1,9 +1,5 @@ import { KernelAccountAbi } from "@zerodev/sdk" -import { - getAction, - getEntryPointVersion, - getUserOperationHash -} from "permissionless" +import { getEntryPointVersion, getUserOperationHash } from "permissionless" import type { EntryPoint } from "permissionless/types/entrypoint" import { type Address, @@ -18,6 +14,7 @@ import { toHex } from "viem" import { getChainId, readContract } from "viem/actions" +import { getAction } from "viem/utils" import { ModularPermissionValidatorAbi } from "./abi/ModularPermissionValidatorAbi.js" import { MAX_FLAG, MODULAR_PERMISSION_VALIDATOR_ADDRESS } from "./constants.js" import type { Policy } from "./policies/types.js" @@ -62,7 +59,8 @@ export async function createPermissionValidator< ): Promise => { const nonce = await getAction( client, - readContract + readContract, + "readContract" )({ abi: ModularPermissionValidatorAbi, address: validatorAddress, @@ -197,7 +195,8 @@ export async function createPermissionValidator< try { const execDetail = await getAction( client, - readContract + readContract, + "readContract" )({ abi: KernelAccountAbi, address: kernelAccountAddress, @@ -206,7 +205,8 @@ export async function createPermissionValidator< }) const permission = await getAction( client, - readContract + readContract, + "readContract" )({ abi: ModularPermissionValidatorAbi, address: validatorAddress, diff --git a/plugins/passkey/package.json b/plugins/passkey/package.json index c94074a7..7a8d5ce8 100644 --- a/plugins/passkey/package.json +++ b/plugins/passkey/package.json @@ -39,8 +39,8 @@ "@simplewebauthn/browser": "^8.3.4" }, "peerDependencies": { - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "^5.2.0", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/plugins/permission/package.json b/plugins/permission/package.json index 08aeba2d..2f705af3 100644 --- a/plugins/permission/package.json +++ b/plugins/permission/package.json @@ -56,8 +56,8 @@ "@simplewebauthn/browser": "^9.0.1" }, "peerDependencies": { - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "^5.2.0", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/plugins/permission/toPermissionValidator.ts b/plugins/permission/toPermissionValidator.ts index e8bb4653..98fb6ba1 100644 --- a/plugins/permission/toPermissionValidator.ts +++ b/plugins/permission/toPermissionValidator.ts @@ -1,9 +1,5 @@ import { KernelV3AccountAbi } from "@zerodev/sdk" -import { - getAction, - getEntryPointVersion, - getUserOperationHash -} from "permissionless" +import { getEntryPointVersion, getUserOperationHash } from "permissionless" import type { EntryPoint } from "permissionless/types/entrypoint" import { type Address, @@ -18,6 +14,7 @@ import { zeroAddress } from "viem" import { getChainId, readContract } from "viem/actions" +import { getAction } from "viem/utils" import { PolicyFlags } from "./constants.js" import { toPolicyId } from "./policies/index.js" import { toSignerId } from "./signers/index.js" @@ -135,7 +132,8 @@ export async function toPermissionValidator< try { const permissionConfig = await getAction( client, - readContract + readContract, + "readContract" )({ abi: KernelV3AccountAbi, address: kernelAccountAddress, diff --git a/plugins/session-key/package.json b/plugins/session-key/package.json index 8c729f27..910ffcc9 100644 --- a/plugins/session-key/package.json +++ b/plugins/session-key/package.json @@ -38,8 +38,8 @@ "merkletreejs": "^0.3.11" }, "peerDependencies": { - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "^5.2.0", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/plugins/session-key/toSessionKeyValidatorPlugin.ts b/plugins/session-key/toSessionKeyValidatorPlugin.ts index f3ddae03..dc50fcae 100644 --- a/plugins/session-key/toSessionKeyValidatorPlugin.ts +++ b/plugins/session-key/toSessionKeyValidatorPlugin.ts @@ -20,17 +20,13 @@ import { signMessage, signTypedData } from "viem/actions" -import { concat, concatHex } from "viem/utils" +import { concat, concatHex, getAction } from "viem/utils" import { SessionKeyValidatorAbi } from "./abi/SessionKeyValidatorAbi.js" import { KernelAccountAbi } from "@zerodev/sdk" import { constants } from "@zerodev/sdk" import { MerkleTree } from "merkletreejs" -import { - getAction, - getEntryPointVersion, - getUserOperationHash -} from "permissionless" +import { getEntryPointVersion, getUserOperationHash } from "permissionless" import { SignTransactionNotSupportedBySmartAccount, type SmartAccountSigner @@ -204,7 +200,8 @@ export async function signerToSessionKeyValidator< ): Promise => { const nonce = await getAction( client, - readContract + readContract, + "readContract" )({ abi: SessionKeyValidatorAbi, address: validatorAddress, @@ -304,7 +301,8 @@ export async function signerToSessionKeyValidator< try { const execDetail = await getAction( client, - readContract + readContract, + "readContract" )({ abi: KernelAccountAbi, address: kernelAccountAddress, @@ -313,7 +311,8 @@ export async function signerToSessionKeyValidator< }) const enableData = await getAction( client, - readContract + readContract, + "readContract" )({ abi: SessionKeyValidatorAbi, address: validatorAddress, diff --git a/plugins/session-key/utils.ts b/plugins/session-key/utils.ts index 931239b8..a05f9351 100644 --- a/plugins/session-key/utils.ts +++ b/plugins/session-key/utils.ts @@ -92,7 +92,8 @@ export const fixSignedData = (sig: Hex): Hex => { let { r, s, v } = hexToSignature(signature) if (v === 0n || v === 1n) v += 27n - const joined = signatureToHex({ r, s, v }) + // biome-ignore lint/style/noNonNullAssertion: + const joined = signatureToHex({ r, s, v: v! }) return joined } diff --git a/plugins/weighted-ecdsa/constants.ts b/plugins/weighted-ecdsa/constants.ts new file mode 100644 index 00000000..1903a42f --- /dev/null +++ b/plugins/weighted-ecdsa/constants.ts @@ -0,0 +1,20 @@ +import type { Action } from "@zerodev/sdk/types" +import { toFunctionSelector } from "viem" + +const RECOVERY_ACTION_ADDRESS = "0x2f65dB8039fe5CAEE0a8680D2879deB800F31Ae1" +const RECOVERY_ACTION_SELECTOR = toFunctionSelector( + "doRecovery(address, bytes)" +) + +export const getRecoveryAction = (): Action => { + return { + address: RECOVERY_ACTION_ADDRESS, + selector: RECOVERY_ACTION_SELECTOR + } +} + +export const WEIGHTED_ECDSA_VALIDATOR_ADDRESS_V06 = + "0x8012D9ee59176Cb01a4aa80fCFE6f5E8bA58d4fb" + +export const WEIGHTED_ECDSA_VALIDATOR_ADDRESS_V07 = + "0x750Fe8F6FE28b9F2Bd89B4B195c4a9f5D9F5fAa1" diff --git a/plugins/weighted-ecdsa/index.ts b/plugins/weighted-ecdsa/index.ts index 67af2278..de5e29f4 100644 --- a/plugins/weighted-ecdsa/index.ts +++ b/plugins/weighted-ecdsa/index.ts @@ -11,10 +11,4 @@ export { getCurrentSigners, type KernelValidator } - -/// @dev note that only deployed on polygon-mumbai now -export const WEIGHTED_ECDSA_VALIDATOR_ADDRESS_V06 = - "0x8012D9ee59176Cb01a4aa80fCFE6f5E8bA58d4fb" - -export const WEIGHTED_ECDSA_VALIDATOR_ADDRESS_V07 = - "0x750Fe8F6FE28b9F2Bd89B4B195c4a9f5D9F5fAa1" +export * from "./constants.js" diff --git a/plugins/weighted-ecdsa/package.json b/plugins/weighted-ecdsa/package.json index 30f4d1ae..4432822b 100644 --- a/plugins/weighted-ecdsa/package.json +++ b/plugins/weighted-ecdsa/package.json @@ -35,8 +35,8 @@ "lint:fix": "bun run lint --apply" }, "peerDependencies": { - "viem": "^2.0.0", + "viem": "^2.9.17", "@zerodev/sdk": "^5.2.0", - "permissionless": "^0.1.16" + "permissionless": "^0.1.17" } } diff --git a/plugins/weighted-ecdsa/toWeightedECDSAValidatorPlugin.ts b/plugins/weighted-ecdsa/toWeightedECDSAValidatorPlugin.ts index a854bea7..194cd7ee 100644 --- a/plugins/weighted-ecdsa/toWeightedECDSAValidatorPlugin.ts +++ b/plugins/weighted-ecdsa/toWeightedECDSAValidatorPlugin.ts @@ -3,7 +3,6 @@ import type { KernelValidator } from "@zerodev/sdk/types" import type { TypedData } from "abitype" import { type UserOperation, - getAction, getEntryPointVersion, getUserOperationHash } from "permissionless" @@ -29,6 +28,7 @@ import { } from "viem" import { toAccount } from "viem/accounts" import { getChainId, readContract } from "viem/actions" +import { getAction } from "viem/utils" import { WeightedValidatorAbi } from "./abi.js" import { WEIGHTED_ECDSA_VALIDATOR_ADDRESS_V06, @@ -302,7 +302,8 @@ export async function createWeightedECDSAValidator< try { const execDetail = await getAction( client, - readContract + readContract, + "readContract" )({ abi: KernelAccountAbi, address: kernelAccountAddress, @@ -374,7 +375,8 @@ export async function getCurrentSigners< // Fetch first guardian info from weightedStorage const weightedStorage = await getAction( client, - readContract + readContract, + "readContract" )({ abi: WeightedValidatorAbi, address: validatorAddress, @@ -388,7 +390,8 @@ export async function getCurrentSigners< while (nextGuardian !== "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF") { const guardianStorage = await getAction( client, - readContract + readContract, + "readContract" )({ abi: WeightedValidatorAbi, address: validatorAddress,