From 8e1764d16935ff32bdcf9741605ecf77670fc782 Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 19:08:56 +0900 Subject: [PATCH 01/10] feat: add a draft code for kernel v1 support --- .../accounts/kernel/createKernelAccount.ts | 9 +- .../accounts/kernel/createKernelV1Account.ts | 205 ++++++++++++++++++ packages/core/accounts/utils/index.ts | 9 + 3 files changed, 215 insertions(+), 8 deletions(-) create mode 100644 packages/core/accounts/kernel/createKernelV1Account.ts diff --git a/packages/core/accounts/kernel/createKernelAccount.ts b/packages/core/accounts/kernel/createKernelAccount.ts index 1bedc779..c0c8b0ff 100644 --- a/packages/core/accounts/kernel/createKernelAccount.ts +++ b/packages/core/accounts/kernel/createKernelAccount.ts @@ -36,6 +36,7 @@ import type { } from "../../types/kernel.js" import { getKernelVersion } from "../../utils.js" import { wrapSignatureWith6492 } from "../utils/6492.js" +import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../utils/index.js" import { isKernelPluginManager, toKernelPluginManager @@ -207,14 +208,6 @@ const getAccountAddress = async < }) } -const parseFactoryAddressAndCallDataFromAccountInitCode = ( - initCode: Hex -): [Address, Hex] => { - const factoryAddress = `0x${initCode.substring(2, 42)}` as Address - const factoryCalldata = `0x${initCode.substring(42)}` as Hex - return [factoryAddress, factoryCalldata] -} - /** * Build a kernel smart account from a private key, that use the ECDSA signer behind the scene * @param client diff --git a/packages/core/accounts/kernel/createKernelV1Account.ts b/packages/core/accounts/kernel/createKernelV1Account.ts new file mode 100644 index 00000000..715c79a3 --- /dev/null +++ b/packages/core/accounts/kernel/createKernelV1Account.ts @@ -0,0 +1,205 @@ +import { + getAccountNonce, + getSenderAddress, + getUserOperationHash +} from "permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + SmartAccountSigner +} from "permissionless/accounts" +import { + Address, + Chain, + Client, + Hash, + Hex, + Transport, + TypedDataDefinition, + concatHex, + encodeFunctionData, + getTypesForEIP712Domain, + hashMessage, + hashTypedData, + validateTypedData +} from "viem" +import { toAccount } from "viem/accounts" +import { getBytecode, getChainId } from "viem/actions" +import { wrapSignatureWith6492 } from "../utils/6492.js" +import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../utils/index.js" +import { KernelSmartAccount } from "./createKernelAccount" + +const createAccountAbi = [ + { + inputs: [ + { internalType: "address", name: "_owner", type: "address" }, + { internalType: "uint256", name: "_index", type: "uint256" } + ], + name: "createAccount", + outputs: [ + { + internalType: "contract EIP1967Proxy", + name: "proxy", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + } +] + +const KERNEL_V1_ADDRESSES: { + FACTORY_ADDRESS: Address + ENTRYPOINT_V0_6: Address +} = { + FACTORY_ADDRESS: "0x4E4946298614FC299B50c947289F4aD0572CB9ce", + ENTRYPOINT_V0_6: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" +} + +export async function createKernelV1Account< + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TSource extends string = string, + TAddress extends Address = Address +>( + client: Client, + { + signer, + entrypoint = KERNEL_V1_ADDRESSES.ENTRYPOINT_V0_6, + index = 0n, + factoryAddress = KERNEL_V1_ADDRESSES.FACTORY_ADDRESS, + deployedAccountAddress + }: { + signer: SmartAccountSigner + entrypoint?: Address + index?: bigint + factoryAddress?: Address + deployedAccountAddress?: Address + } +): Promise> { + if (entrypoint !== KERNEL_V1_ADDRESSES.ENTRYPOINT_V0_6) { + throw new Error("Only EntryPoint 0.6 is supported") + } + + // Fetch chain id + const chainId = await getChainId(client) + + const getAccountInitCode = async (): Promise => { + return concatHex([ + KERNEL_V1_ADDRESSES.FACTORY_ADDRESS, + encodeFunctionData({ + abi: createAccountAbi, + functionName: "createAccount", + args: [signer.address, index] + }) + ]) as Hex + } + + const initCode = await getAccountInitCode() + const accountAddress = await getSenderAddress(client, { + initCode, + entryPoint: entrypoint + }) + + if (!accountAddress) throw new Error("Account address not found") + + const account = toAccount({ + address: accountAddress, + async signMessage({ message }) { + const hash = hashMessage(message) + const [isDeployed, signature] = await Promise.all([ + isAccountDeployed(), + signer.signMessage({ message: hash }) + ]) + return create6492Signature(isDeployed, signature) + }, + async signTransaction(_, __) { + throw new SignTransactionNotSupportedBySmartAccount() + }, + async signTypedData(typedData) { + const types = { + EIP712Domain: getTypesForEIP712Domain({ + domain: typedData.domain + }), + ...typedData.types + } + + // Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc + // as we can't statically check this with TypeScript. + validateTypedData({ + domain: typedData.domain, + message: typedData.message, + primaryType: typedData.primaryType, + types: types + } as TypedDataDefinition) + + const typedHash = hashTypedData(typedData) + const [isDeployed, signature] = await Promise.all([ + isAccountDeployed(), + signer.signMessage({ message: typedHash }) + ]) + return create6492Signature(isDeployed, signature) + } + }) + + const isAccountDeployed = async (): Promise => { + const contractCode = await getBytecode(client, { + address: accountAddress + }) + + return (contractCode?.length ?? 0) > 2 + } + + const create6492Signature = async ( + isDeployed: boolean, + signature: Hash + ): Promise => { + if (isDeployed) { + return signature + } + + const [factoryAddress, factoryCalldata] = + parseFactoryAddressAndCallDataFromAccountInitCode( + await getAccountInitCode() + ) + + return wrapSignatureWith6492({ + factoryAddress, + factoryCalldata, + signature + }) + } + + return { + ...account, + async getNonce() { + return getAccountNonce(client, { + sender: accountAddress, + entryPoint: entrypoint + }) + }, + async signUserOperation(userOperation) { + const hash = getUserOperationHash({ + userOperation: { + ...userOperation, + signature: "0x" + }, + entryPoint: entrypoint, + chainId: chainId + }) + const signature = await account.signMessage({ message: hash }) + return signature + }, + async getInitCode() { + if (await isAccountDeployed()) { + return "0x" + } else { + return getAccountInitCode() + } + }, + async encodeCallData(_tx) {}, + async getDummySignature() { + return "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" + }, + async encodeDeployCallData() {} + } +} diff --git a/packages/core/accounts/utils/index.ts b/packages/core/accounts/utils/index.ts index 33ab4e61..a96846d6 100644 --- a/packages/core/accounts/utils/index.ts +++ b/packages/core/accounts/utils/index.ts @@ -1,5 +1,14 @@ import { toKernelPluginManager } from "./toKernelPluginManager.js" export { toKernelPluginManager } +import { Address, Hex } from "viem" import { verifyEIP6492Signature } from "./6492.js" export { verifyEIP6492Signature } + +export const parseFactoryAddressAndCallDataFromAccountInitCode = ( + initCode: Hex +): [Address, Hex] => { + const factoryAddress = `0x${initCode.substring(2, 42)}` as Address + const factoryCalldata = `0x${initCode.substring(42)}` as Hex + return [factoryAddress, factoryCalldata] +} From ccabf065ec94386b850382cf5fed0d42cf8855bc Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 21:23:53 +0900 Subject: [PATCH 02/10] feat: implement createKernelV1Account function --- .../accounts/kernel/createKernelV1Account.ts | 89 +++++++++++++++++-- packages/core/accounts/kernel/v1/multisend.ts | 40 +++++++++ 2 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 packages/core/accounts/kernel/v1/multisend.ts diff --git a/packages/core/accounts/kernel/createKernelV1Account.ts b/packages/core/accounts/kernel/createKernelV1Account.ts index 715c79a3..f7fe4802 100644 --- a/packages/core/accounts/kernel/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/createKernelV1Account.ts @@ -27,6 +27,17 @@ import { getBytecode, getChainId } from "viem/actions" import { wrapSignatureWith6492 } from "../utils/6492.js" import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../utils/index.js" import { KernelSmartAccount } from "./createKernelAccount" +import { KernelEncodeCallDataArgs } from "../../types/kernel.js" +import { + MULTISEND_ADDRESS, + encodeMultiSend, + multiSendAbi +} from "./v1/multisend.js" + +export type KernelV1SmartAccount< + transport extends Transport = Transport, + chain extends Chain | undefined = Chain | undefined +> = Omit, "kernelPluginManager"> const createAccountAbi = [ { @@ -47,6 +58,21 @@ const createAccountAbi = [ } ] +const executeAndRevertAbi = [ + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + { internalType: "enum Operation", name: "operation", type: "uint8" } + ], + name: "executeAndRevert", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] + const KERNEL_V1_ADDRESSES: { FACTORY_ADDRESS: Address ENTRYPOINT_V0_6: Address @@ -75,7 +101,7 @@ export async function createKernelV1Account< factoryAddress?: Address deployedAccountAddress?: Address } -): Promise> { +): Promise> { if (entrypoint !== KERNEL_V1_ADDRESSES.ENTRYPOINT_V0_6) { throw new Error("Only EntryPoint 0.6 is supported") } @@ -83,7 +109,7 @@ export async function createKernelV1Account< // Fetch chain id const chainId = await getChainId(client) - const getAccountInitCode = async (): Promise => { + const generateInitCode = async (): Promise => { return concatHex([ KERNEL_V1_ADDRESSES.FACTORY_ADDRESS, encodeFunctionData({ @@ -94,7 +120,7 @@ export async function createKernelV1Account< ]) as Hex } - const initCode = await getAccountInitCode() + const initCode = await generateInitCode() const accountAddress = await getSenderAddress(client, { initCode, entryPoint: entrypoint @@ -159,7 +185,7 @@ export async function createKernelV1Account< const [factoryAddress, factoryCalldata] = parseFactoryAddressAndCallDataFromAccountInitCode( - await getAccountInitCode() + await generateInitCode() ) return wrapSignatureWith6492({ @@ -171,6 +197,11 @@ export async function createKernelV1Account< return { ...account, + client: client, + publicKey: accountAddress, + entryPoint: entrypoint, + source: "kernelSmartAccount", + generateInitCode, async getNonce() { return getAccountNonce(client, { sender: accountAddress, @@ -193,13 +224,55 @@ export async function createKernelV1Account< if (await isAccountDeployed()) { return "0x" } else { - return getAccountInitCode() + return generateInitCode() } }, - async encodeCallData(_tx) {}, + async encodeCallData(_tx) { + const tx = _tx as KernelEncodeCallDataArgs + + if (Array.isArray(tx)) { + // Encode a batched call using multiSend + const multiSendCallData = encodeFunctionData({ + abi: multiSendAbi, + functionName: "multiSend", + args: [encodeMultiSend(tx)] + }) + + return encodeFunctionData({ + abi: executeAndRevertAbi, + functionName: "executeAndRevert", + args: [MULTISEND_ADDRESS, 0n, multiSendCallData, 1n] + }) + } + + // Default to `call` + if (!tx.callType || tx.callType === "call") { + if (tx.to.toLowerCase() === accountAddress.toLowerCase()) { + return tx.data + } + + return encodeFunctionData({ + abi: executeAndRevertAbi, + functionName: "executeAndRevert", + args: [tx.to, tx.value || 0n, tx.data, 0n] + }) + } + + if (tx.callType === "delegatecall") { + return encodeFunctionData({ + abi: executeAndRevertAbi, + functionName: "executeAndRevert", + args: [tx.to, tx.value || 0n, tx.data, 1n] + }) + } + + throw new Error("Invalid call type") + }, + async encodeDeployCallData() { + return "0x" + }, async getDummySignature() { return "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" - }, - async encodeDeployCallData() {} + } } } diff --git a/packages/core/accounts/kernel/v1/multisend.ts b/packages/core/accounts/kernel/v1/multisend.ts new file mode 100644 index 00000000..5fbe0d0e --- /dev/null +++ b/packages/core/accounts/kernel/v1/multisend.ts @@ -0,0 +1,40 @@ +import { Address, Hex, encodePacked, toBytes } from "viem" +import { CallType, KernelEncodeCallDataArgs } from "../../../types" + +export const MULTISEND_ADDRESS = "0x8ae01fcf7c655655ff2c6ef907b8b4718ab4e17c" + +export const multiSendAbi = [ + { + type: "function", + name: "multiSend", + inputs: [{ type: "bytes", name: "transactions" }] + } +] + +const encodeCall = (call: { + to: Address + value: bigint + data: Hex + callType: CallType | undefined +}): string => { + const data = toBytes(call.data) + const encoded = encodePacked( + ["uint8", "address", "uint256", "uint256", "bytes"], + [ + call.callType === "delegatecall" ? 1 : 0, + call.to, + call.value || 0n, + BigInt(data.length), + call.data + ] + ) + return encoded.slice(2) +} + +export const encodeMultiSend = (calls: KernelEncodeCallDataArgs): Hex => { + if (!Array.isArray(calls)) { + throw new Error("Invalid multiSend calls, should use an array of calls") + } + + return `0x${calls.map((call) => encodeCall(call)).join("")}` +} From 4f0f2cbd1ef841f24333e435e7336d91a6083a82 Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 21:24:01 +0900 Subject: [PATCH 03/10] chore: format --- packages/core/accounts/kernel/createKernelV1Account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/accounts/kernel/createKernelV1Account.ts b/packages/core/accounts/kernel/createKernelV1Account.ts index f7fe4802..15cb363d 100644 --- a/packages/core/accounts/kernel/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/createKernelV1Account.ts @@ -24,10 +24,10 @@ import { } from "viem" import { toAccount } from "viem/accounts" import { getBytecode, getChainId } from "viem/actions" +import { KernelEncodeCallDataArgs } from "../../types/kernel.js" import { wrapSignatureWith6492 } from "../utils/6492.js" import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../utils/index.js" import { KernelSmartAccount } from "./createKernelAccount" -import { KernelEncodeCallDataArgs } from "../../types/kernel.js" import { MULTISEND_ADDRESS, encodeMultiSend, From 9a581bc53246b1e000d8fc39abecaa41464ef2c8 Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 22:59:30 +0900 Subject: [PATCH 04/10] feat: update path --- bun.lockb | Bin 208528 -> 208936 bytes packages/core/accounts/index.ts | 1 + .../kernel/{ => v1}/createKernelV1Account.ts | 35 ++++++++---------- packages/core/accounts/kernel/v1/multisend.ts | 4 +- packages/core/accounts/utils/index.ts | 2 +- packages/core/index.ts | 6 +-- 6 files changed, 21 insertions(+), 27 deletions(-) rename packages/core/accounts/kernel/{ => v1}/createKernelV1Account.ts (92%) diff --git a/bun.lockb b/bun.lockb index c456069205221442398be90f1095af0063d4a2f4..43f9d73143795b10043eb0d7d787cfe99584bb46 100755 GIT binary patch delta 29345 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 delta 29313 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 C?IhX& diff --git a/packages/core/accounts/index.ts b/packages/core/accounts/index.ts index 92f1392c..fc687b0f 100644 --- a/packages/core/accounts/index.ts +++ b/packages/core/accounts/index.ts @@ -4,5 +4,6 @@ export { KERNEL_ADDRESSES, EIP1271ABI } from "./kernel/createKernelAccount.js" +export { createKernelV1Account } from "./kernel/v1/createKernelV1Account.js" export { addressToEmptyAccount } from "./addressToEmptyAccount.js" export * from "./utils/index.js" diff --git a/packages/core/accounts/kernel/createKernelV1Account.ts b/packages/core/accounts/kernel/v1/createKernelV1Account.ts similarity index 92% rename from packages/core/accounts/kernel/createKernelV1Account.ts rename to packages/core/accounts/kernel/v1/createKernelV1Account.ts index 15cb363d..3d4ddcb2 100644 --- a/packages/core/accounts/kernel/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/v1/createKernelV1Account.ts @@ -5,16 +5,16 @@ import { } from "permissionless" import { SignTransactionNotSupportedBySmartAccount, - SmartAccountSigner + type SmartAccountSigner } from "permissionless/accounts" import { - Address, - Chain, - Client, - Hash, - Hex, - Transport, - TypedDataDefinition, + type Address, + type Chain, + type Client, + type Hash, + type Hex, + type Transport, + type TypedDataDefinition, concatHex, encodeFunctionData, getTypesForEIP712Domain, @@ -24,15 +24,15 @@ import { } from "viem" import { toAccount } from "viem/accounts" import { getBytecode, getChainId } from "viem/actions" -import { KernelEncodeCallDataArgs } from "../../types/kernel.js" -import { wrapSignatureWith6492 } from "../utils/6492.js" -import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../utils/index.js" -import { KernelSmartAccount } from "./createKernelAccount" +import { type KernelEncodeCallDataArgs } from "../../../types/kernel.js" +import { wrapSignatureWith6492 } from "../../utils/6492.js" +import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../../utils/index.js" +import { type KernelSmartAccount } from "../createKernelAccount.js" import { MULTISEND_ADDRESS, encodeMultiSend, multiSendAbi -} from "./v1/multisend.js" +} from "./multisend.js" export type KernelV1SmartAccount< transport extends Transport = Transport, @@ -91,15 +91,11 @@ export async function createKernelV1Account< { signer, entrypoint = KERNEL_V1_ADDRESSES.ENTRYPOINT_V0_6, - index = 0n, - factoryAddress = KERNEL_V1_ADDRESSES.FACTORY_ADDRESS, - deployedAccountAddress + index = 0n }: { signer: SmartAccountSigner entrypoint?: Address index?: bigint - factoryAddress?: Address - deployedAccountAddress?: Address } ): Promise> { if (entrypoint !== KERNEL_V1_ADDRESSES.ENTRYPOINT_V0_6) { @@ -131,10 +127,9 @@ export async function createKernelV1Account< const account = toAccount({ address: accountAddress, async signMessage({ message }) { - const hash = hashMessage(message) const [isDeployed, signature] = await Promise.all([ isAccountDeployed(), - signer.signMessage({ message: hash }) + signer.signMessage({ message }) ]) return create6492Signature(isDeployed, signature) }, diff --git a/packages/core/accounts/kernel/v1/multisend.ts b/packages/core/accounts/kernel/v1/multisend.ts index 5fbe0d0e..68f78571 100644 --- a/packages/core/accounts/kernel/v1/multisend.ts +++ b/packages/core/accounts/kernel/v1/multisend.ts @@ -1,5 +1,5 @@ -import { Address, Hex, encodePacked, toBytes } from "viem" -import { CallType, KernelEncodeCallDataArgs } from "../../../types" +import { type Address, type Hex, encodePacked, toBytes } from "viem" +import { type CallType, type KernelEncodeCallDataArgs } from "../../../types" export const MULTISEND_ADDRESS = "0x8ae01fcf7c655655ff2c6ef907b8b4718ab4e17c" diff --git a/packages/core/accounts/utils/index.ts b/packages/core/accounts/utils/index.ts index a96846d6..74a76df6 100644 --- a/packages/core/accounts/utils/index.ts +++ b/packages/core/accounts/utils/index.ts @@ -1,7 +1,7 @@ import { toKernelPluginManager } from "./toKernelPluginManager.js" export { toKernelPluginManager } -import { Address, Hex } from "viem" +import type { Address, Hex } from "viem" import { verifyEIP6492Signature } from "./6492.js" export { verifyEIP6492Signature } diff --git a/packages/core/index.ts b/packages/core/index.ts index 848ed8c1..64b50385 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -1,5 +1,6 @@ export { createKernelAccount, + createKernelV1Account, type KernelSmartAccount, KERNEL_ADDRESSES, addressToEmptyAccount, @@ -34,8 +35,5 @@ export { KernelFactoryAbi } from "./accounts/kernel/abi/KernelFactoryAbi.js" export { TokenActionsAbi } from "./accounts/kernel/abi/TokenActionsAbi.js" export * as constants from "./constants.js" export * from "./utils.js" -export { - gasTokenAddresses, - type TokenSymbolsMap -} from "./gasTokenAddresses.js" +export { gasTokenAddresses, type TokenSymbolsMap } from "./gasTokenAddresses.js" export { verifyEIP6492Signature } from "./accounts/utils/index.js" From 9e2502777cb12e9aaff02ffe6819029c9e2d4cd6 Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 23:15:45 +0900 Subject: [PATCH 05/10] feat: sign user operation with viem signer --- .../kernel/v1/createKernelV1Account.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/core/accounts/kernel/v1/createKernelV1Account.ts b/packages/core/accounts/kernel/v1/createKernelV1Account.ts index 3d4ddcb2..8a0b1b6d 100644 --- a/packages/core/accounts/kernel/v1/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/v1/createKernelV1Account.ts @@ -18,12 +18,12 @@ import { concatHex, encodeFunctionData, getTypesForEIP712Domain, - hashMessage, hashTypedData, - validateTypedData + validateTypedData, + type LocalAccount } from "viem" import { toAccount } from "viem/accounts" -import { getBytecode, getChainId } from "viem/actions" +import { getBytecode, getChainId, signMessage } from "viem/actions" import { type KernelEncodeCallDataArgs } from "../../../types/kernel.js" import { wrapSignatureWith6492 } from "../../utils/6492.js" import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../../utils/index.js" @@ -102,6 +102,13 @@ export async function createKernelV1Account< throw new Error("Only EntryPoint 0.6 is supported") } + const viemSigner: LocalAccount = { + ...signer, + signTransaction: (_, __) => { + throw new SignTransactionNotSupportedBySmartAccount() + } + } as LocalAccount + // Fetch chain id const chainId = await getChainId(client) @@ -212,7 +219,10 @@ export async function createKernelV1Account< entryPoint: entrypoint, chainId: chainId }) - const signature = await account.signMessage({ message: hash }) + const signature = await signMessage(client, { + account: viemSigner, + message: { raw: hash } + }) return signature }, async getInitCode() { From 09d7b412b8510f42629c0a7578c9fb12b0ff595f Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 14:16:15 +0000 Subject: [PATCH 06/10] chore: format --- packages/core/accounts/kernel/v1/createKernelV1Account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/accounts/kernel/v1/createKernelV1Account.ts b/packages/core/accounts/kernel/v1/createKernelV1Account.ts index 8a0b1b6d..92361a5c 100644 --- a/packages/core/accounts/kernel/v1/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/v1/createKernelV1Account.ts @@ -13,14 +13,14 @@ import { type Client, type Hash, type Hex, + type LocalAccount, type Transport, type TypedDataDefinition, concatHex, encodeFunctionData, getTypesForEIP712Domain, hashTypedData, - validateTypedData, - type LocalAccount + validateTypedData } from "viem" import { toAccount } from "viem/accounts" import { getBytecode, getChainId, signMessage } from "viem/actions" From 6239bcada784d16dea363105753f774e9470d3fb Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 23:54:19 +0900 Subject: [PATCH 07/10] test: add test cases for kernel v1 --- .../kernel/v1/createKernelV1Account.ts | 49 +- packages/test/KernelV1Account.test.ts | 478 ++++++++++++++++++ packages/test/utils.ts | 17 +- 3 files changed, 515 insertions(+), 29 deletions(-) create mode 100644 packages/test/KernelV1Account.test.ts diff --git a/packages/core/accounts/kernel/v1/createKernelV1Account.ts b/packages/core/accounts/kernel/v1/createKernelV1Account.ts index 8a0b1b6d..3e55c837 100644 --- a/packages/core/accounts/kernel/v1/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/v1/createKernelV1Account.ts @@ -13,17 +13,20 @@ import { type Client, type Hash, type Hex, + type LocalAccount, type Transport, type TypedDataDefinition, concatHex, encodeFunctionData, - getTypesForEIP712Domain, - hashTypedData, - validateTypedData, - type LocalAccount + type TypedData } from "viem" import { toAccount } from "viem/accounts" -import { getBytecode, getChainId, signMessage } from "viem/actions" +import { + getBytecode, + getChainId, + signMessage, + signTypedData +} from "viem/actions" import { type KernelEncodeCallDataArgs } from "../../../types/kernel.js" import { wrapSignatureWith6492 } from "../../utils/6492.js" import { parseFactoryAddressAndCallDataFromAccountInitCode } from "../../utils/index.js" @@ -143,29 +146,19 @@ export async function createKernelV1Account< async signTransaction(_, __) { throw new SignTransactionNotSupportedBySmartAccount() }, - async signTypedData(typedData) { - const types = { - EIP712Domain: getTypesForEIP712Domain({ - domain: typedData.domain - }), - ...typedData.types - } - - // Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc - // as we can't statically check this with TypeScript. - validateTypedData({ - domain: typedData.domain, - message: typedData.message, - primaryType: typedData.primaryType, - types: types - } as TypedDataDefinition) - - const typedHash = hashTypedData(typedData) - const [isDeployed, signature] = await Promise.all([ - isAccountDeployed(), - signer.signMessage({ message: typedHash }) - ]) - return create6492Signature(isDeployed, signature) + async signTypedData< + const TTypedData extends TypedData | Record, + TPrimaryType extends + | keyof TTypedData + | "EIP712Domain" = keyof TTypedData + >(typedData: TypedDataDefinition) { + return signTypedData( + client, + { + account: viemSigner, + ...typedData + } + ) } }) diff --git a/packages/test/KernelV1Account.test.ts b/packages/test/KernelV1Account.test.ts new file mode 100644 index 00000000..29811fbf --- /dev/null +++ b/packages/test/KernelV1Account.test.ts @@ -0,0 +1,478 @@ +import { beforeAll, describe, expect, test } from "bun:test" +import { verifyMessage } from "@ambire/signature-validator" +import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator" +import { + EIP1271ABI, + KERNEL_ADDRESSES, + KernelAccountClient, + KernelSmartAccount, + createKernelAccount, + getERC20PaymasterApproveCall, + verifyEIP6492Signature +} from "@zerodev/sdk" +import { gasTokenAddresses } from "@zerodev/sdk" +import dotenv from "dotenv" +import { ethers } from "ethers" +import { BundlerClient, bundlerActions } from "permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + SmartAccount +} from "permissionless/accounts" +import type { UserOperation } from "permissionless/types/userOperation.js" +import { + Address, + Chain, + Hex, + type PublicClient, + Transport, + decodeEventLog, + encodeFunctionData, + erc20Abi, + getContract, + hashMessage, + hashTypedData, + zeroAddress +} from "viem" +import { privateKeyToAccount, sign } from "viem/accounts" +import { goerli } from "viem/chains" +import { EntryPointAbi } from "./abis/EntryPoint.js" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter.js" +import { TEST_ERC20Abi } from "./abis/Test_ERC20Abi.js" +import { + findUserOperationEvent, + getEcdsaKernelAccountWithRandomSigner, + getEntryPoint, + getKernelAccountClient, + getKernelBundlerClient, + getKernelV1Account, + getPublicClient, + getSignerToEcdsaKernelAccount, + getZeroDevERC20PaymasterClient, + getZeroDevPaymasterClient, + index, + waitForNonceUpdate +} 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 SIGNATURE_LENGTH = 132 +const SIGNATURE_REGEX = /^0x[0-9a-fA-F]{130}$/ +const TX_HASH_LENGTH = 66 +const TX_HASH_REGEX = /^0x[0-9a-fA-F]{64}$/ +const TEST_TIMEOUT = 1000000 + +describe("ECDSA kernel Account", () => { + let account: SmartAccount + let publicClient: PublicClient + let bundlerClient: BundlerClient + let kernelClient: KernelAccountClient + + beforeAll(async () => { + account = await getKernelV1Account() + publicClient = await getPublicClient() + bundlerClient = getKernelBundlerClient() + kernelClient = await getKernelAccountClient({ + account, + sponsorUserOperation: async ({ userOperation }) => { + const zerodevPaymaster = getZeroDevPaymasterClient() + const entryPoint = getEntryPoint() + return zerodevPaymaster.sponsorUserOperation({ + userOperation, + entryPoint + }) + } + }) + }) + + test("Account address should be a valid Ethereum address", async () => { + expect(account.address).toBeString() + expect(account.address).toHaveLength(ETHEREUM_ADDRESS_LENGTH) + expect(account.address).toMatch(ETHEREUM_ADDRESS_REGEX) + }) + + test("Account should throw when trying to sign a transaction", async () => { + await expect(async () => { + await account.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + }).toThrow(new SignTransactionNotSupportedBySmartAccount()) + }) + + test( + "Client signMessage should return a valid signature", + async () => { + // to make sure kernel is deployed + await kernelClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + const message = "hello world" + const response = await kernelClient.signMessage({ + message + }) + + const ambireResult = await verifyMessage({ + signer: account.address, + message, + signature: response, + provider: new ethers.providers.JsonRpcProvider( + process.env.RPC_URL as string + ) + }) + expect(ambireResult).toBeTrue() + + const eip1271response = await publicClient.readContract({ + address: account.address, + abi: EIP1271ABI, + functionName: "isValidSignature", + args: [hashMessage(message), response] + }) + expect(eip1271response).toEqual("0x1626ba7e") + expect(response).toBeString() + expect(response).toHaveLength(SIGNATURE_LENGTH) + expect(response).toMatch(SIGNATURE_REGEX) + }, + TEST_TIMEOUT + ) + + test( + "Smart account client signTypedData", + async () => { + const domain = { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + } + + const primaryType = "Test" + + const types = { + Test: [ + { + name: "test", + type: "string" + } + ] + } + + const message = { + test: "hello world" + } + const typedHash = hashTypedData({ + domain, + primaryType, + types, + message + }) + + const response = await kernelClient.signTypedData({ + domain, + primaryType, + types, + message + }) + + const eip1271response = await publicClient.readContract({ + address: account.address, + abi: EIP1271ABI, + functionName: "isValidSignature", + args: [typedHash, response] + }) + expect(eip1271response).toEqual("0x1626ba7e") + expect(response).toBeString() + expect(response).toHaveLength(SIGNATURE_LENGTH) + expect(response).toMatch(SIGNATURE_REGEX) + }, + TEST_TIMEOUT + ) + + test( + "Client deploy contract", + async () => { + const response = await kernelClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + + expect(response).toBeString() + expect(response).toHaveLength(TX_HASH_LENGTH) + expect(response).toMatch(TX_HASH_REGEX) + + const transactionReceipt = + await publicClient.waitForTransactionReceipt({ + hash: response + }) + + expect(findUserOperationEvent(transactionReceipt.logs)).toBeTrue() + }, + TEST_TIMEOUT + ) + + test( + "Smart account client send multiple transactions", + async () => { + const response = await kernelClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expect(response).toBeString() + expect(response).toHaveLength(TX_HASH_LENGTH) + expect(response).toMatch(TX_HASH_REGEX) + }, + TEST_TIMEOUT + ) + + test( + "Write contract", + async () => { + const greeterContract = getContract({ + abi: GreeterAbi, + address: process.env.GREETER_ADDRESS as Address, + client: kernelClient + }) + + const oldGreet = await greeterContract.read.greet() + + expect(oldGreet).toBeString() + + const txHash = await greeterContract.write.setGreeting([ + "hello world" + ]) + + expect(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newGreet = await greeterContract.read.greet() + + expect(newGreet).toBeString() + expect(newGreet).toEqual("hello world") + }, + TEST_TIMEOUT + ) + + test( + "Client signs and then sends UserOp with paymaster", + async () => { + const userOp = await kernelClient.signUserOperation({ + userOperation: { + callData: await kernelClient.account.encodeCallData({ + to: process.env.GREETER_ADDRESS as Address, + value: 0n, + data: encodeFunctionData({ + abi: GreeterAbi, + functionName: "setGreeting", + args: ["hello world"] + }) + }) + } + }) + + expect(userOp.signature).not.toBe("0x") + + const userOpHash = await bundlerClient.sendUserOperation({ + userOperation: userOp, + entryPoint: KERNEL_ADDRESSES.ENTRYPOINT_V0_6 + }) + expect(userOpHash).toHaveLength(66) + + await waitForNonceUpdate() + }, + TEST_TIMEOUT + ) + + test( + "Client send UserOp with delegatecall", + async () => { + const userOpHash = await kernelClient.sendUserOperation({ + userOperation: { + callData: await kernelClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x", + callType: "delegatecall" + }) + } + }) + + expect(userOpHash).toHaveLength(66) + + await waitForNonceUpdate() + }, + TEST_TIMEOUT + ) + + test( + "Client send Transaction with paymaster", + async () => { + const response = await kernelClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expect(response).toBeString() + expect(response).toHaveLength(TX_HASH_LENGTH) + expect(response).toMatch(TX_HASH_REGEX) + + const transactionReceipt = + await publicClient.waitForTransactionReceipt({ + hash: response + }) + + expect(findUserOperationEvent(transactionReceipt.logs)).toBeTrue() + }, + TEST_TIMEOUT + ) + + test( + "Client send transaction with ERC20 paymaster", + async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getKernelBundlerClient() + + const kernelClient = await getKernelAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }): Promise => { + const zerodevPaymaster = getZeroDevERC20PaymasterClient() + return zerodevPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint(), + gasToken: gasTokenAddresses[goerli.id]["6TEST"] + }) + } + }) + + const pmClient = await getZeroDevERC20PaymasterClient() + const response = await kernelClient.sendTransactions({ + transactions: [ + { + to: gasTokenAddresses[goerli.id]["6TEST"], + data: encodeFunctionData({ + abi: TEST_ERC20Abi, + functionName: "mint", + args: [account.address, 100000n] + }), + value: 0n + }, + await getERC20PaymasterApproveCall(pmClient, { + gasToken: gasTokenAddresses[goerli.id]["6TEST"], + approveAmount: 100000n + }), + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + console.log( + "erc20PMTransaction:", + `https://mumbai.polygonscan.com/tx/${response}` + ) + + expect(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = + await publicClient.waitForTransactionReceipt({ + hash: response + }) + + let transferEventFound = false + for (const log of transactionReceipt.logs) { + try { + const event = decodeEventLog({ + abi: erc20Abi, + ...log + }) + if ( + event.eventName === "Transfer" && + event.args.from === account.address + ) { + transferEventFound = true + } + } catch (error) {} + } + let userOpEventFound = false + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + userOpEventFound = true + console.log( + "jiffyScanLink:", + `https://jiffyscan.xyz/userOpHash/${event.args.userOpHash}?network=mumbai/` + ) + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(transferEventFound).toBeTrue() + expect(userOpEventFound).toBeTrue() + }, + TEST_TIMEOUT + ) +}) diff --git a/packages/test/utils.ts b/packages/test/utils.ts index d0447cbd..efe3eaec 100644 --- a/packages/test/utils.ts +++ b/packages/test/utils.ts @@ -6,7 +6,7 @@ import { createKernelAccountClient, createZeroDevPaymasterClient } from "@zerodev/sdk" -import { KernelValidator } from "@zerodev/sdk" +import { KernelValidator, createKernelV1Account } from "@zerodev/sdk" import { addressToEmptyAccount, createKernelAccount @@ -136,6 +136,21 @@ const getEcdsaKernelAccountWithPrivateKey = async ( }) } +export const getKernelV1Account = async (): Promise => { + const privateKey = process.env.TEST_PRIVATE_KEY as Hex + if (!privateKey) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + + const publicClient = await getPublicClient() + const signer = privateKeyToAccount(privateKey) + + return createKernelV1Account(publicClient, { + signer, + index + }) +} + // we only use two signers for testing export const getSignersToWeightedEcdsaKernelAccount = async ( plugin?: KernelValidator From 610a0d84577ab4bffbaaf10666580c4aaa883b47 Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 23:54:31 +0900 Subject: [PATCH 08/10] chore: format --- packages/core/accounts/kernel/v1/createKernelV1Account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/accounts/kernel/v1/createKernelV1Account.ts b/packages/core/accounts/kernel/v1/createKernelV1Account.ts index 3e55c837..3331a11a 100644 --- a/packages/core/accounts/kernel/v1/createKernelV1Account.ts +++ b/packages/core/accounts/kernel/v1/createKernelV1Account.ts @@ -15,10 +15,10 @@ import { type Hex, type LocalAccount, type Transport, + type TypedData, type TypedDataDefinition, concatHex, - encodeFunctionData, - type TypedData + encodeFunctionData } from "viem" import { toAccount } from "viem/accounts" import { From 3de4339fc4581f078600052fa72360980df582c4 Mon Sep 17 00:00:00 2001 From: adnpark Date: Wed, 6 Mar 2024 23:59:55 +0900 Subject: [PATCH 09/10] chore: format --- packages/core/accounts/kernel/v1/multisend.ts | 5 ++++- packages/test/KernelV1Account.test.ts | 10 ++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/core/accounts/kernel/v1/multisend.ts b/packages/core/accounts/kernel/v1/multisend.ts index 68f78571..e9e2d972 100644 --- a/packages/core/accounts/kernel/v1/multisend.ts +++ b/packages/core/accounts/kernel/v1/multisend.ts @@ -1,5 +1,8 @@ import { type Address, type Hex, encodePacked, toBytes } from "viem" -import { type CallType, type KernelEncodeCallDataArgs } from "../../../types" +import { + type CallType, + type KernelEncodeCallDataArgs +} from "../../../types/index.js" export const MULTISEND_ADDRESS = "0x8ae01fcf7c655655ff2c6ef907b8b4718ab4e17c" diff --git a/packages/test/KernelV1Account.test.ts b/packages/test/KernelV1Account.test.ts index 29811fbf..4d542ab4 100644 --- a/packages/test/KernelV1Account.test.ts +++ b/packages/test/KernelV1Account.test.ts @@ -1,19 +1,16 @@ import { beforeAll, describe, expect, test } from "bun:test" import { verifyMessage } from "@ambire/signature-validator" -import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator" import { EIP1271ABI, KERNEL_ADDRESSES, KernelAccountClient, KernelSmartAccount, - createKernelAccount, - getERC20PaymasterApproveCall, - verifyEIP6492Signature + getERC20PaymasterApproveCall } from "@zerodev/sdk" import { gasTokenAddresses } from "@zerodev/sdk" import dotenv from "dotenv" import { ethers } from "ethers" -import { BundlerClient, bundlerActions } from "permissionless" +import { BundlerClient } from "permissionless" import { SignTransactionNotSupportedBySmartAccount, SmartAccount @@ -33,14 +30,12 @@ import { hashTypedData, zeroAddress } from "viem" -import { privateKeyToAccount, sign } from "viem/accounts" import { goerli } from "viem/chains" import { EntryPointAbi } from "./abis/EntryPoint.js" import { GreeterAbi, GreeterBytecode } from "./abis/Greeter.js" import { TEST_ERC20Abi } from "./abis/Test_ERC20Abi.js" import { findUserOperationEvent, - getEcdsaKernelAccountWithRandomSigner, getEntryPoint, getKernelAccountClient, getKernelBundlerClient, @@ -49,7 +44,6 @@ import { getSignerToEcdsaKernelAccount, getZeroDevERC20PaymasterClient, getZeroDevPaymasterClient, - index, waitForNonceUpdate } from "./utils.js" From 4314bf3411f99659ec334a06037374d177c6785a Mon Sep 17 00:00:00 2001 From: adnpark Date: Thu, 7 Mar 2024 00:18:12 +0900 Subject: [PATCH 10/10] bump version --- packages/core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/package.json b/packages/core/package.json index faf23935..189ef1a7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@zerodev/sdk", - "version": "5.1.8", + "version": "5.1.9", "author": "ZeroDev", "main": "./_cjs/index.js", "module": "./_esm/index.js",