From 54490ef4c993ba4226f4d540c6a54e7b67c168b9 Mon Sep 17 00:00:00 2001 From: Sahil Vasava Date: Thu, 12 Dec 2024 20:12:16 +0400 Subject: [PATCH 1/3] feat: integrated kernelv3.2 and released alpha vers of core and ecdsa --- .../accounts/kernel/createKernelAccount.ts | 58 ++++++++++++++----- .../kernel/utils/common/eip712WrapHash.ts | 11 +++- packages/core/constants.ts | 12 ++++ packages/core/package.json | 2 +- packages/core/types/kernel.ts | 2 +- packages/core/utils.ts | 6 +- 6 files changed, 69 insertions(+), 22 deletions(-) diff --git a/packages/core/accounts/kernel/createKernelAccount.ts b/packages/core/accounts/kernel/createKernelAccount.ts index 9a09e14b..20b1771d 100644 --- a/packages/core/accounts/kernel/createKernelAccount.ts +++ b/packages/core/accounts/kernel/createKernelAccount.ts @@ -31,7 +31,10 @@ import { getAccountNonce, getSenderAddress } from "../../actions/public/index.js" -import { KernelVersionToAddressesMap } from "../../constants.js" +import { + KernelVersionToAddressesMap, + MAGIC_VALUE_SIG_REPLAYABLE +} from "../../constants.js" import type { CallType, EntryPointType, @@ -106,6 +109,7 @@ export type CreateKernelAccountParameters< kernelVersion: GetKernelVersion initConfig?: KernelVerion extends "0.3.1" ? Hex[] : never useMetaFactory?: boolean + useReplayableSignature?: boolean } /** @@ -344,7 +348,8 @@ export async function createKernelAccount< address, kernelVersion, initConfig, - useMetaFactory = true + useMetaFactory = true, + useReplayableSignature = false }: CreateKernelAccountParameters ): Promise> { const { accountImplementationAddress, factoryAddress, metaFactoryAddress } = @@ -506,13 +511,17 @@ export async function createKernelAccount< kernelVersion, chainId ) - const wrappedMessageHash = await eip712WrapHash(messageHash, { - name, - chainId: Number(metadataChainId), - version, - verifyingContract: accountAddress - }) - const signature = await kernelPluginManager.signMessage({ + const wrappedMessageHash = await eip712WrapHash( + messageHash, + { + name, + chainId: Number(metadataChainId), + version, + verifyingContract: accountAddress + }, + useReplayableSignature + ) + let signature = await kernelPluginManager.signMessage({ message: { raw: wrappedMessageHash } }) @@ -525,6 +534,13 @@ export async function createKernelAccount< return signature } + if ( + useReplayableSignature && + hasKernelFeature(KERNEL_FEATURES.ERC1271_REPLAYABLE, version) + ) { + signature = concatHex([MAGIC_VALUE_SIG_REPLAYABLE, signature]) + } + return concatHex([kernelPluginManager.getIdentifier(), signature]) }, async signTypedData(typedData) { @@ -562,13 +578,17 @@ export async function createKernelAccount< kernelVersion, chainId ) - const wrappedMessageHash = await eip712WrapHash(typedHash, { - name, - chainId: Number(metadataChainId), - version, - verifyingContract: accountAddress - }) - const signature = await kernelPluginManager.signMessage({ + const wrappedMessageHash = await eip712WrapHash( + typedHash, + { + name, + chainId: Number(metadataChainId), + version, + verifyingContract: accountAddress + }, + useReplayableSignature + ) + let signature = await kernelPluginManager.signMessage({ message: { raw: wrappedMessageHash } }) if ( @@ -579,6 +599,12 @@ export async function createKernelAccount< ) { return signature } + if ( + useReplayableSignature && + hasKernelFeature(KERNEL_FEATURES.ERC1271_REPLAYABLE, version) + ) { + signature = concatHex([MAGIC_VALUE_SIG_REPLAYABLE, signature]) + } return concatHex([kernelPluginManager.getIdentifier(), signature]) }, // Get the nonce of the smart account diff --git a/packages/core/accounts/kernel/utils/common/eip712WrapHash.ts b/packages/core/accounts/kernel/utils/common/eip712WrapHash.ts index b1d6456c..8e2f42cd 100644 --- a/packages/core/accounts/kernel/utils/common/eip712WrapHash.ts +++ b/packages/core/accounts/kernel/utils/common/eip712WrapHash.ts @@ -14,7 +14,8 @@ export const eip712WrapHash = async ( domain: WithRequired< TypedDataDomain, "name" | "chainId" | "verifyingContract" | "version" - > + >, + useReplayableSignature?: boolean ): Promise => { const { name, version, chainId, verifyingContract } = domain @@ -22,11 +23,17 @@ export const eip712WrapHash = async ( return messageHash } + const _chainId = + hasKernelFeature(KERNEL_FEATURES.ERC1271_REPLAYABLE, version) && + useReplayableSignature + ? 0 + : chainId + const _domainSeparator = domainSeparator({ domain: { name, version, - chainId, + chainId: _chainId, verifyingContract } }) diff --git a/packages/core/constants.ts b/packages/core/constants.ts index 52019892..d4fb164d 100644 --- a/packages/core/constants.ts +++ b/packages/core/constants.ts @@ -14,6 +14,9 @@ import type { export const DUMMY_ECDSA_SIG = "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" +export const MAGIC_VALUE_SIG_REPLAYABLE = + "0x0555ad2729e8da1777a4e5020806f8bf7601c3db6bfe402f410a34958363a95a" + // export const KernelImplToVersionMap: { [key: Address]: string } = { // "0x8dD4DBB54d8A8Cf0DE6F9CCC4609470A30EfF18C": "0.2.2", // "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5": "0.2.2", @@ -74,6 +77,14 @@ export const KernelVersionToAddressesMap: { metaFactoryAddress: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", initCodeHash: "0x85d96aa1c9a65886d094915d76ccae85f14027a02c1647dde659f869460f03e6" + }, + "0.3.2": { + accountImplementationAddress: + "0xD830D15D3dc0C269F3dBAa0F3e8626d33CFdaBe1", + factoryAddress: "0x7a1dBAB750f12a90EB1B60D2Ae3aD17D4D81EfFe", + metaFactoryAddress: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", + initCodeHash: + "0xc7c48c9dd12de68b8a4689b6f8c8c07b61d4d6fa4ddecdd86a6980d045fa67eb" } } @@ -83,6 +94,7 @@ export const KERNEL_V2_3: KERNEL_V2_VERSION_TYPE = "0.2.3" export const KERNEL_V2_4: KERNEL_V2_VERSION_TYPE = "0.2.4" export const KERNEL_V3_0: KERNEL_V3_VERSION_TYPE = "0.3.0" export const KERNEL_V3_1: KERNEL_V3_VERSION_TYPE = "0.3.1" +export const KERNEL_V3_2: KERNEL_V3_VERSION_TYPE = "0.3.2" export const TOKEN_ACTION = "0x2087C7FfD0d0DAE80a00EE74325aBF3449e0eaf1" export const ONLY_ENTRYPOINT_HOOK_ADDRESS = diff --git a/packages/core/package.json b/packages/core/package.json index 86e7e4f8..af0e5bc9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@zerodev/sdk", - "version": "5.4.3", + "version": "5.4.4-alpha.1", "author": "ZeroDev", "main": "./_cjs/index.js", "module": "./_esm/index.js", diff --git a/packages/core/types/kernel.ts b/packages/core/types/kernel.ts index 48112b60..06b2f28f 100644 --- a/packages/core/types/kernel.ts +++ b/packages/core/types/kernel.ts @@ -243,7 +243,7 @@ export type Execution = { export type KERNEL_V2_VERSION_TYPE = "0.0.2" | "0.2.2" | "0.2.3" | "0.2.4" -export type KERNEL_V3_VERSION_TYPE = "0.3.0" | "0.3.1" +export type KERNEL_V3_VERSION_TYPE = "0.3.0" | "0.3.1" | "0.3.2" export type KERNEL_VERSION_TYPE = | KERNEL_V2_VERSION_TYPE diff --git a/packages/core/utils.ts b/packages/core/utils.ts index db006348..b30ac38f 100644 --- a/packages/core/utils.ts +++ b/packages/core/utils.ts @@ -19,13 +19,15 @@ import type { EntryPointType, GetKernelVersion } from "./types/kernel.js" export enum KERNEL_FEATURES { ERC1271_SIG_WRAPPER = "ERC1271_SIG_WRAPPER", ERC1271_WITH_VALIDATOR = "ERC1271_WITH_VALIDATOR", - ERC1271_SIG_WRAPPER_WITH_WRAPPED_HASH = "ERC1271_SIG_WRAPPER_WITH_WRAPPED_HASH" + ERC1271_SIG_WRAPPER_WITH_WRAPPED_HASH = "ERC1271_SIG_WRAPPER_WITH_WRAPPED_HASH", + ERC1271_REPLAYABLE = "ERC1271_REPLAYABLE" } export const KERNEL_FEATURES_BY_VERSION: Record = { [KERNEL_FEATURES.ERC1271_SIG_WRAPPER]: ">=0.2.3 || >=0.3.0-beta", [KERNEL_FEATURES.ERC1271_WITH_VALIDATOR]: ">=0.3.0-beta", - [KERNEL_FEATURES.ERC1271_SIG_WRAPPER_WITH_WRAPPED_HASH]: ">=0.3.0-beta" + [KERNEL_FEATURES.ERC1271_SIG_WRAPPER_WITH_WRAPPED_HASH]: ">=0.3.0-beta", + [KERNEL_FEATURES.ERC1271_REPLAYABLE]: ">=0.3.2" } export const hasKernelFeature = ( From 0dbb5a8b71c4ba3dd290a8d08d15b19efd9ad99a Mon Sep 17 00:00:00 2001 From: Sahil Vasava Date: Thu, 12 Dec 2024 20:12:22 +0400 Subject: [PATCH 2/3] feat: integrated kernelv3.2 and released alpha vers of core and ecdsa --- packages/test/v0.7/ecdsaKernelAccount.test.ts | 74 ++++++++++++++++++- packages/test/v0.7/utils/common.ts | 2 +- packages/test/v0.7/utils/ecdsaUtils.ts | 14 ++-- plugins/ecdsa/constants.ts | 2 +- plugins/ecdsa/package.json | 2 +- 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/packages/test/v0.7/ecdsaKernelAccount.test.ts b/packages/test/v0.7/ecdsaKernelAccount.test.ts index 3210e506..038456e8 100644 --- a/packages/test/v0.7/ecdsaKernelAccount.test.ts +++ b/packages/test/v0.7/ecdsaKernelAccount.test.ts @@ -33,14 +33,13 @@ import { zeroAddress } from "viem" import { privateKeyToAccount } from "viem/accounts" -import { sepolia } from "viem/chains" +import { baseSepolia, sepolia } from "viem/chains" import { EntryPointAbi } from "../abis/EntryPoint.js" import { GreeterAbi, GreeterBytecode } from "../abis/Greeter.js" import { TokenActionsAbi } from "../abis/TokenActionsAbi.js" import { TOKEN_ACTION_ADDRESS, config } from "../config.js" import { - type BundlerClient, type SmartAccount, entryPoint07Address } from "viem/account-abstraction" @@ -49,7 +48,6 @@ import { findUserOperationEvent, getEntryPoint, getPublicClient, - getUserOperationEvent, getZeroDevPaymasterClient, index, kernelVersion, @@ -146,7 +144,7 @@ describe("ECDSA kernel Account", () => { index: index, initCodeHash: constants.KernelVersionToAddressesMap[kernelVersion] - .initCodeHash ?? "0x" + .initCodeHash ?? "0x", }) console.log( "Generate accountAddress using getKernelAddressFromECDSA: ", @@ -309,6 +307,74 @@ describe("ECDSA kernel Account", () => { TEST_TIMEOUT ) + test( + "Client signMessage should return a valid replayable signature", + async () => { + const sepoliaAccount = await getEcdsaKernelAccountWithRandomSigner( + [], + sepolia.id, + true + ) + const baseSepoliaAccount = + await getEcdsaKernelAccountWithRandomSigner( + [], + baseSepolia.id, + true + ) + const sepoliaPublicClient = await getPublicClient(sepolia.id) + const baseSepoliaPublicClient = await getPublicClient( + baseSepolia.id + ) + + const message = "0x51ec26f01af586507f7a8198bc8fba82754567b5cca1bff07f9765ebfe69ed66" + const replayableSignature = await sepoliaAccount.signMessage({ + message + }) + + const sepoliaAmbireResult = await verifyMessage({ + signer: sepoliaAccount.address, + // message, + finalDigest: hashMessage(message), + signature: replayableSignature, + provider: new ethers.providers.JsonRpcProvider( + config["0.7"][sepolia.id].rpcUrl + ) + }) + expect(sepoliaAmbireResult).toBeTrue() + + expect( + await verifyEIP6492Signature({ + signer: sepoliaAccount.address, + hash: hashMessage(message), + signature: replayableSignature, + client: sepoliaPublicClient + }) + ).toBeTrue() + + const baseSepoliaAmbireResult = await verifyMessage({ + signer: baseSepoliaAccount.address, + message, + signature: replayableSignature, + provider: new ethers.providers.JsonRpcProvider( + config["0.7"][baseSepolia.id].rpcUrl + ) + }) + expect(baseSepoliaAmbireResult).toBeTrue() + + expect( + await verifyEIP6492Signature({ + signer: baseSepoliaAccount.address, + hash: hashMessage(message), + signature: replayableSignature, + client: baseSepoliaPublicClient + }) + ).toBeTrue() + + expect(replayableSignature).toBeString() + }, + TEST_TIMEOUT + ) + test( "Smart account client signTypedData", async () => { diff --git a/packages/test/v0.7/utils/common.ts b/packages/test/v0.7/utils/common.ts index 4b12366b..191929f8 100644 --- a/packages/test/v0.7/utils/common.ts +++ b/packages/test/v0.7/utils/common.ts @@ -25,7 +25,7 @@ import { config } from "../../config" export const Test_ERC20Address = "0x3870419Ba2BBf0127060bCB37f69A1b1C090992B" const testingChain = allChains.sepolia.id -export const kernelVersion = "0.3.1" +export const kernelVersion = "0.3.2" export const index = 11111111111111111n // 432334375434333332434365532464445487823332432423423n const DEFAULT_PROVIDER = "PIMLICO" const projectId = config["0.7"][testingChain].projectId diff --git a/packages/test/v0.7/utils/ecdsaUtils.ts b/packages/test/v0.7/utils/ecdsaUtils.ts index 87ba18be..909f31c6 100644 --- a/packages/test/v0.7/utils/ecdsaUtils.ts +++ b/packages/test/v0.7/utils/ecdsaUtils.ts @@ -24,21 +24,24 @@ import { export const getEcdsaKernelAccountWithRandomSigner = async ( initConfig?: Hex[], - chain?: number + chain?: number, + useReplayableSignature = false ) => { return getEcdsaKernelAccountWithPrivateKey( "0xdfbb0d855aafff58aa0ae92aa9d03e88562bad9befe209f5693db89b65cc4a9a" ?? "0x3688628d97b817ee5e25dfce254ba4d87b5fd894449fce6c2acc60fdf98906de" ?? generatePrivateKey(), initConfig, - chain + chain, + useReplayableSignature ) } const getEcdsaKernelAccountWithPrivateKey = async ( privateKey: Hex, initConfig?: Hex[], - chain?: number + chain?: number, + useReplayableSignature = false ): Promise>> => { if (!privateKey) { throw new Error("privateKey cannot be empty") @@ -59,7 +62,8 @@ const getEcdsaKernelAccountWithPrivateKey = async ( }, index, kernelVersion, - initConfig + initConfig, + useReplayableSignature, }) } @@ -107,7 +111,7 @@ export const getKernelAccountClient = async ({ bundlerTransport: http(getBundlerRpc(), { timeout: 100_000 }), paymaster, userOperation: { - estimateFeesPerGas: async () => { + estimateFeesPerGas: async ({bundlerClient}) => { return getUserOperationGasPrice(bundlerClient) } } diff --git a/plugins/ecdsa/constants.ts b/plugins/ecdsa/constants.ts index 5cfb78b2..ccdd0839 100644 --- a/plugins/ecdsa/constants.ts +++ b/plugins/ecdsa/constants.ts @@ -5,5 +5,5 @@ export const kernelVersionRangeToValidator: { } = { "0.0.2 - 0.2.4": "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", "0.3.0": "0x8104e3Ad430EA6d354d013A6789fDFc71E671c43", - "0.3.1": "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57" + "0.3.1 - 0.3.2": "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57" } diff --git a/plugins/ecdsa/package.json b/plugins/ecdsa/package.json index 3ed35541..a600d1f2 100644 --- a/plugins/ecdsa/package.json +++ b/plugins/ecdsa/package.json @@ -1,6 +1,6 @@ { "name": "@zerodev/ecdsa-validator", - "version": "5.4.0", + "version": "5.4.1-alpha.0", "author": "ZeroDev", "main": "./_cjs/index.js", "module": "./_esm/index.js", From a0aaf55ea294b811050ba3e98b469ea87919006d Mon Sep 17 00:00:00 2001 From: Sahil Vasava Date: Tue, 17 Dec 2024 11:14:51 +0400 Subject: [PATCH 3/3] feat: expose factoryAddress from kernelAccount --- packages/core/accounts/kernel/createKernelAccount.ts | 2 ++ packages/core/accounts/kernel/v2/createKernelAccountV0_2.ts | 1 + packages/core/package.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/accounts/kernel/createKernelAccount.ts b/packages/core/accounts/kernel/createKernelAccount.ts index 20b1771d..131eacb4 100644 --- a/packages/core/accounts/kernel/createKernelAccount.ts +++ b/packages/core/accounts/kernel/createKernelAccount.ts @@ -76,6 +76,7 @@ export type KernelSmartAccountImplementation< ) => Promise kernelVersion: GetKernelVersion kernelPluginManager: KernelPluginManager + factoryAddress: Address generateInitCode: () => Promise encodeModuleInstallCallData: () => Promise encodeDeployCallData: ({ @@ -446,6 +447,7 @@ export async function createKernelAccount< return toSmartAccount>({ kernelVersion, kernelPluginManager, + factoryAddress: (await getFactoryArgs()).factory, generateInitCode, encodeModuleInstallCallData: async () => { return await kernelPluginManager.encodeModuleInstallCallData( diff --git a/packages/core/accounts/kernel/v2/createKernelAccountV0_2.ts b/packages/core/accounts/kernel/v2/createKernelAccountV0_2.ts index 0df963c2..dad9bf16 100644 --- a/packages/core/accounts/kernel/v2/createKernelAccountV0_2.ts +++ b/packages/core/accounts/kernel/v2/createKernelAccountV0_2.ts @@ -232,6 +232,7 @@ export async function createKernelAccountV0_2( client: client, entryPoint: _entryPoint, kernelPluginManager, + factoryAddress, generateInitCode, encodeModuleInstallCallData: async () => { return await kernelPluginManager.encodeModuleInstallCallData( diff --git a/packages/core/package.json b/packages/core/package.json index af0e5bc9..3848ccb3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@zerodev/sdk", - "version": "5.4.4-alpha.1", + "version": "5.4.4-alpha.2", "author": "ZeroDev", "main": "./_cjs/index.js", "module": "./_esm/index.js",