Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: kernelv3.2 #200

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 44 additions & 16 deletions packages/core/accounts/kernel/createKernelAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -73,6 +76,7 @@ export type KernelSmartAccountImplementation<
) => Promise<Hex>
kernelVersion: GetKernelVersion<entryPointVersion>
kernelPluginManager: KernelPluginManager<entryPointVersion>
factoryAddress: Address
generateInitCode: () => Promise<Hex>
encodeModuleInstallCallData: () => Promise<Hex>
encodeDeployCallData: ({
Expand Down Expand Up @@ -106,6 +110,7 @@ export type CreateKernelAccountParameters<
kernelVersion: GetKernelVersion<entryPointVersion>
initConfig?: KernelVerion extends "0.3.1" ? Hex[] : never
useMetaFactory?: boolean
useReplayableSignature?: boolean
}

/**
Expand Down Expand Up @@ -344,7 +349,8 @@ export async function createKernelAccount<
address,
kernelVersion,
initConfig,
useMetaFactory = true
useMetaFactory = true,
useReplayableSignature = false
}: CreateKernelAccountParameters<entryPointVersion, KernelVersion>
): Promise<CreateKernelAccountReturnType<entryPointVersion>> {
const { accountImplementationAddress, factoryAddress, metaFactoryAddress } =
Expand Down Expand Up @@ -441,6 +447,7 @@ export async function createKernelAccount<
return toSmartAccount<KernelSmartAccountImplementation<entryPointVersion>>({
kernelVersion,
kernelPluginManager,
factoryAddress: (await getFactoryArgs()).factory,
generateInitCode,
encodeModuleInstallCallData: async () => {
return await kernelPluginManager.encodeModuleInstallCallData(
Expand Down Expand Up @@ -506,13 +513,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 }
})

Expand All @@ -525,6 +536,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) {
Expand Down Expand Up @@ -562,13 +580,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 (
Expand All @@ -579,6 +601,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
Expand Down
11 changes: 9 additions & 2 deletions packages/core/accounts/kernel/utils/common/eip712WrapHash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,26 @@ export const eip712WrapHash = async (
domain: WithRequired<
TypedDataDomain,
"name" | "chainId" | "verifyingContract" | "version"
>
>,
useReplayableSignature?: boolean
): Promise<Hex> => {
const { name, version, chainId, verifyingContract } = domain

if (!hasKernelFeature(KERNEL_FEATURES.ERC1271_SIG_WRAPPER, version)) {
return messageHash
}

const _chainId =
hasKernelFeature(KERNEL_FEATURES.ERC1271_REPLAYABLE, version) &&
useReplayableSignature
? 0
: chainId

const _domainSeparator = domainSeparator({
domain: {
name,
version,
chainId,
chainId: _chainId,
verifyingContract
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ export async function createKernelAccountV0_2(
client: client,
entryPoint: _entryPoint,
kernelPluginManager,
factoryAddress,
generateInitCode,
encodeModuleInstallCallData: async () => {
return await kernelPluginManager.encodeModuleInstallCallData(
Expand Down
12 changes: 12 additions & 0 deletions packages/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -74,6 +77,14 @@ export const KernelVersionToAddressesMap: {
metaFactoryAddress: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5",
initCodeHash:
"0x85d96aa1c9a65886d094915d76ccae85f14027a02c1647dde659f869460f03e6"
},
"0.3.2": {
accountImplementationAddress:
"0xD830D15D3dc0C269F3dBAa0F3e8626d33CFdaBe1",
factoryAddress: "0x7a1dBAB750f12a90EB1B60D2Ae3aD17D4D81EfFe",
metaFactoryAddress: "0xd703aaE79538628d27099B8c4f621bE4CCd142d5",
initCodeHash:
"0xc7c48c9dd12de68b8a4689b6f8c8c07b61d4d6fa4ddecdd86a6980d045fa67eb"
}
}

Expand All @@ -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 =
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zerodev/sdk",
"version": "5.4.3",
"version": "5.4.4-alpha.2",
"author": "ZeroDev",
"main": "./_cjs/index.js",
"module": "./_esm/index.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/types/kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions packages/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, string> = {
[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 = (
Expand Down
74 changes: 70 additions & 4 deletions packages/test/v0.7/ecdsaKernelAccount.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -49,7 +48,6 @@ import {
findUserOperationEvent,
getEntryPoint,
getPublicClient,
getUserOperationEvent,
getZeroDevPaymasterClient,
index,
kernelVersion,
Expand Down Expand Up @@ -146,7 +144,7 @@ describe("ECDSA kernel Account", () => {
index: index,
initCodeHash:
constants.KernelVersionToAddressesMap[kernelVersion]
.initCodeHash ?? "0x"
.initCodeHash ?? "0x",
})
console.log(
"Generate accountAddress using getKernelAddressFromECDSA: ",
Expand Down Expand Up @@ -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 () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/test/v0.7/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 9 additions & 5 deletions packages/test/v0.7/utils/ecdsaUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<SmartAccount<KernelSmartAccountImplementation<"0.7">>> => {
if (!privateKey) {
throw new Error("privateKey cannot be empty")
Expand All @@ -59,7 +62,8 @@ const getEcdsaKernelAccountWithPrivateKey = async (
},
index,
kernelVersion,
initConfig
initConfig,
useReplayableSignature,
})
}

Expand Down Expand Up @@ -107,7 +111,7 @@ export const getKernelAccountClient = async ({
bundlerTransport: http(getBundlerRpc(), { timeout: 100_000 }),
paymaster,
userOperation: {
estimateFeesPerGas: async () => {
estimateFeesPerGas: async ({bundlerClient}) => {
return getUserOperationGasPrice(bundlerClient)
}
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/ecdsa/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Loading