// @ts-expect-error import { beforeAll, describe, expect, test } from "bun:test" import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator" import { toSpendingLimitHook } from "@zerodev/hooks" import { type KernelSmartAccount, createKernelAccount } from "@zerodev/sdk" import { KERNEL_V2_4, KERNEL_V3_1 } from "@zerodev/sdk/constants" import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "permissionless" import type { ENTRYPOINT_ADDRESS_V06_TYPE, ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" import { http, type Address, type Hex, createPublicClient, parseEther, zeroAddress } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { sepolia } from "viem/chains" import { decodeCalldata } from "./decodeCalldata" describe("decodeCalldata", () => { let kernelAccountV2: KernelSmartAccount let kernelAccountV3: KernelSmartAccount let kernelAccountV3WithHook: KernelSmartAccount beforeAll(async () => { const publicClient = createPublicClient({ chain: sepolia, transport: http() }) const accountWallet = privateKeyToAccount(generatePrivateKey()) const ecdsaValidatorV2 = await signerToEcdsaValidator(publicClient, { signer: accountWallet, entryPoint: ENTRYPOINT_ADDRESS_V06, kernelVersion: KERNEL_V2_4 }) const ecdsaValidatorV3 = await signerToEcdsaValidator(publicClient, { signer: accountWallet, entryPoint: ENTRYPOINT_ADDRESS_V07, kernelVersion: KERNEL_V3_1 }) const spendingLimitHook = await toSpendingLimitHook({ limits: [ { token: zeroAddress, allowance: parseEther("0.01") } ] }) kernelAccountV2 = await createKernelAccount(publicClient, { plugins: { sudo: ecdsaValidatorV2 }, entryPoint: ENTRYPOINT_ADDRESS_V06, kernelVersion: KERNEL_V2_4 }) kernelAccountV3 = await createKernelAccount(publicClient, { plugins: { sudo: ecdsaValidatorV3 }, entryPoint: ENTRYPOINT_ADDRESS_V07, kernelVersion: KERNEL_V3_1 }) kernelAccountV3WithHook = await createKernelAccount(publicClient, { plugins: { sudo: ecdsaValidatorV3, hook: spendingLimitHook }, entryPoint: ENTRYPOINT_ADDRESS_V07, kernelVersion: KERNEL_V3_1 }) }) describe("decodeCalldata kernel v2", async () => { test("single call", async () => { const call = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const callData = await kernelAccountV2.encodeCallData(call) const decoded = decodeCalldata({ accountAddress: kernelAccountV2.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V06 }) expect(decoded).toEqual([call]) }) test("batch call", async () => { const calls = [ { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex }, { to: zeroAddress, value: parseEther("0.01"), data: "0x01" as Hex } ] const callData = await kernelAccountV2.encodeCallData(calls) const decoded = decodeCalldata({ accountAddress: kernelAccountV2.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V06 }) expect(decoded).toEqual(calls) }) test("delegate call", async () => { const calls = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const callData = await kernelAccountV2.encodeCallData({ ...calls, callType: "delegatecall" }) expect(() => { decodeCalldata({ accountAddress: kernelAccountV2.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V06 }) }).toThrow("delegate call cannot be batched") }) test("to address is the account address", async () => { const selfCall = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const calls = { to: kernelAccountV2.address, value: parseEther("0.01"), data: await kernelAccountV2.encodeCallData(selfCall) } const callData = await kernelAccountV2.encodeCallData(calls) const decoded = decodeCalldata({ accountAddress: kernelAccountV2.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V06 }) expect(decoded).toEqual([selfCall]) }) }) describe("decodeCalldata kernel v3", async () => { test("single call", async () => { const call = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const callData = await kernelAccountV3.encodeCallData(call) const decoded = decodeCalldata({ accountAddress: kernelAccountV3.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(decoded).toEqual([call]) }) test("batch call", async () => { const calls = [ { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex }, { to: zeroAddress, value: parseEther("0.01"), data: "0x01" as Hex } ] const callData = await kernelAccountV3.encodeCallData(calls) const decoded = decodeCalldata({ accountAddress: kernelAccountV3.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(decoded).toEqual(calls) }) test("delegate call", async () => { const calls = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const callData = await kernelAccountV3.encodeCallData({ ...calls, callType: "delegatecall" }) expect(() => { decodeCalldata({ accountAddress: kernelAccountV3.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) }).toThrow("delegate call cannot be batched") }) test("to address is the account address", async () => { const selfCall = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const calls = { to: kernelAccountV3.address, value: parseEther("0.01"), data: await kernelAccountV3.encodeCallData(selfCall) } const callData = await kernelAccountV3.encodeCallData(calls) const decoded = decodeCalldata({ accountAddress: kernelAccountV3.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(decoded).toEqual([selfCall]) }) }) describe("decodeCalldata kernel v3 with hook", async () => { test("single call", async () => { const call = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const callData = await kernelAccountV3WithHook.encodeCallData(call) const decoded = decodeCalldata({ accountAddress: kernelAccountV3WithHook.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(decoded).toEqual([call]) }) test("batch call", async () => { const calls = [ { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex }, { to: zeroAddress, value: parseEther("0.01"), data: "0x01" as Hex } ] const callData = await kernelAccountV3WithHook.encodeCallData(calls) const decoded = decodeCalldata({ accountAddress: kernelAccountV3WithHook.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(decoded).toEqual(calls) }) test("delegate call", async () => { const calls = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const callData = await kernelAccountV3WithHook.encodeCallData({ ...calls, callType: "delegatecall" }) expect(() => { decodeCalldata({ accountAddress: kernelAccountV3WithHook.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) }).toThrow("delegate call cannot be batched") }) test("to address is the account address", async () => { const selfCall = { to: zeroAddress, value: parseEther("0.01"), data: "0x" as Hex } const calls = { to: kernelAccountV3WithHook.address, value: parseEther("0.01"), data: await kernelAccountV3WithHook.encodeCallData(selfCall) } const callData = await kernelAccountV3WithHook.encodeCallData(calls) const decoded = decodeCalldata({ accountAddress: kernelAccountV3WithHook.address, callData, entryPoint: ENTRYPOINT_ADDRESS_V07 }) expect(decoded).toEqual([selfCall]) }) }) })