// @ts-expect-error import { beforeAll, describe, expect, test } from "bun:test" import { toMultiChainECDSAValidator } from "@zerodev/multi-chain-validator" import { createKernelAccount, createKernelAccountClient } from "@zerodev/sdk" import { KERNEL_V3_1 } from "@zerodev/sdk/constants" import { type BundlerClient, ENTRYPOINT_ADDRESS_V07, createBundlerClient } from "permissionless" import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" import { http, type PublicClient, type Transport, createPublicClient, encodeFunctionData, erc20Abi } from "viem" import { optimismSepolia, sepolia } from "viem/chains" import { CAB_V0_1, CAB_V0_2_1, type KernelCABClient, createKernelCABClient, supportedTokensV1, supportedTokensV2_1 } from "../src/index" import { accountWallet, bundlerUrl, cabPaymasterUrl, magicNewton, newtonSepoliaBundlerUrl, opSepoliaBundlerUrl, rpcUrl } from "./utils/constants" import { getGasPrice } from "./utils/gasPrice" const TEST_TIMEOUT = 10000000 describe("SendUserOperationCab", () => { describe("ECDSA V1_0 CAB client", () => { const entryPoint = ENTRYPOINT_ADDRESS_V07 const kernelVersion = KERNEL_V3_1 const sponsorChain = magicNewton const repayChain = optimismSepolia const rpcUrl = magicNewton.rpcUrls.default.http[0] const bundlerUrl = newtonSepoliaBundlerUrl let publicClient: PublicClient let bundlerClient: BundlerClient let cabClient: KernelCABClient< ENTRYPOINT_ADDRESS_V07_TYPE, Transport, typeof sponsorChain > beforeAll(async () => { publicClient = createPublicClient({ chain: sponsorChain, transport: http(rpcUrl) }) bundlerClient = createBundlerClient({ chain: sponsorChain, entryPoint: entryPoint, transport: http(bundlerUrl, { timeout: 60000 }) }) const multiChainValidator = await toMultiChainECDSAValidator( publicClient, { signer: accountWallet, entryPoint: entryPoint, kernelVersion: kernelVersion } ) const kernelAccount = await createKernelAccount(publicClient, { plugins: { sudo: multiChainValidator }, entryPoint: entryPoint, kernelVersion: kernelVersion }) const kernelClient = createKernelAccountClient({ account: kernelAccount, chain: sponsorChain, entryPoint: entryPoint, bundlerTransport: http(bundlerUrl), middleware: { gasPrice: getGasPrice(sponsorChain.id) } }) cabClient = createKernelCABClient(kernelClient, { transport: http(cabPaymasterUrl), entryPoint, cabVersion: CAB_V0_1 }) }) test( "transfer 0.001 USDC on opSepolia, specify repayTokens address", async () => { // transfer 0.001 USDC to EOA const calls = [ { to: supportedTokensV1["6TEST"][sponsorChain.id].token, data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [accountWallet.address, 10n] }), value: 0n } ] // repay on scavenger const repayTokens = [ { address: supportedTokensV1["6TEST"][repayChain.id].token, chainId: repayChain.id } ] const { userOperation, repayTokensInfo, sponsorTokensInfo } = await cabClient.prepareUserOperationRequestCAB({ account: cabClient.account, calls, repayTokens: repayTokens }) expect(userOperation).toBeDefined() expect(Array.isArray(repayTokensInfo)).toBe(true) expect(Array.isArray(sponsorTokensInfo)).toBe(true) expect(repayTokensInfo.length).toBeGreaterThan(0) expect(sponsorTokensInfo.length).toBeGreaterThan(0) const userOpHash = await cabClient.sendUserOperationCAB({ userOperation }) console.log("transfer with cab userOpHash:", userOpHash) const ret = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash, timeout: 100_000_000 }) console.log( "transfer with cab transactionHash:", ret.receipt.transactionHash ) }, TEST_TIMEOUT ) test( "transfer 0.001 USDC on opSepolia, specify repayTokens name", async () => { // transfer 0.001 USDC to EOA const calls = [ { to: supportedTokensV1["6TEST"][repayChain.id].token, data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [accountWallet.address, 1000n] }), value: 0n } ] // repay on optimism Sepolia const repayTokens = ["6TEST"] const { userOperation, repayTokensInfo, sponsorTokensInfo } = await cabClient.prepareUserOperationRequestCAB({ account: cabClient.account, calls, repayTokens: repayTokens }) expect(userOperation).toBeDefined() expect(Array.isArray(repayTokensInfo)).toBe(true) expect(Array.isArray(sponsorTokensInfo)).toBe(true) expect(repayTokensInfo.length).toBeGreaterThan(0) expect(sponsorTokensInfo.length).toBeGreaterThan(0) const userOpHash = await cabClient.sendUserOperationCAB({ userOperation }) console.log("transfer with cab userOpHash:", userOpHash) const ret = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash }) console.log( "transfer with cab transactionHash:", ret.receipt.transactionHash ) }, TEST_TIMEOUT ) }) describe("ECDSA V2_1 CAB client", () => { const entryPoint = ENTRYPOINT_ADDRESS_V07 const kernelVersion = KERNEL_V3_1 let publicClient: PublicClient let bundlerClient: BundlerClient let cabClient: KernelCABClient< ENTRYPOINT_ADDRESS_V07_TYPE, Transport, typeof sepolia > beforeAll(async () => { publicClient = createPublicClient({ chain: sepolia, transport: http(rpcUrl) }) bundlerClient = createBundlerClient({ chain: sepolia, entryPoint: entryPoint, transport: http(bundlerUrl, { timeout: 60000 }) }) const multiChainValidator = await toMultiChainECDSAValidator( publicClient, { signer: accountWallet, entryPoint: entryPoint, kernelVersion: kernelVersion } ) const kernelAccount = await createKernelAccount(publicClient, { plugins: { sudo: multiChainValidator }, entryPoint: entryPoint, kernelVersion: kernelVersion }) const kernelClient = createKernelAccountClient({ account: kernelAccount, chain: sepolia, entryPoint: entryPoint, bundlerTransport: http(bundlerUrl) }) cabClient = createKernelCABClient(kernelClient, { transport: http(cabPaymasterUrl), entryPoint, cabVersion: CAB_V0_2_1 }) }) test( "transfer 0.001 USDC on sepolia, specify repayTokens address", async () => { // transfer 0.001 USDC to EOA const calls = [ { to: supportedTokensV2_1["6TEST"][11155111].token, data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [accountWallet.address, 10n] }), value: 0n } ] // repay on optimismSepolia const repayTokens = [ { address: supportedTokensV2_1["6TEST"][11155420].token, chainId: 11155420 } ] const { userOperation, repayTokensInfo, sponsorTokensInfo } = await cabClient.prepareUserOperationRequestCAB({ account: cabClient.account, calls, repayTokens: repayTokens }) expect(userOperation).toBeDefined() expect(Array.isArray(repayTokensInfo)).toBe(true) expect(Array.isArray(sponsorTokensInfo)).toBe(true) expect(repayTokensInfo.length).toBeGreaterThan(0) expect(sponsorTokensInfo.length).toBeGreaterThan(0) const userOpHash = await cabClient.sendUserOperationCAB({ userOperation }) console.log("transfer with cab userOpHash:", userOpHash) const ret = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash, timeout: 100_000_000 }) console.log( "transfer with cab transactionHash:", ret.receipt.transactionHash ) }, TEST_TIMEOUT ) test( "transfer 0.001 USDC on sepolia, specify repayTokens name", async () => { // transfer 0.001 USDC to EOA const calls = [ { to: supportedTokensV2_1["6TEST"][11155111].token, data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [accountWallet.address, 1000n] }), value: 0n } ] // repay on optimism Sepolia const repayTokens = ["6TEST"] const { userOperation, repayTokensInfo, sponsorTokensInfo } = await cabClient.prepareUserOperationRequestCAB({ account: cabClient.account, calls, repayTokens: repayTokens }) expect(userOperation).toBeDefined() expect(Array.isArray(repayTokensInfo)).toBe(true) expect(Array.isArray(sponsorTokensInfo)).toBe(true) expect(repayTokensInfo.length).toBeGreaterThan(0) expect(sponsorTokensInfo.length).toBeGreaterThan(0) const userOpHash = await cabClient.sendUserOperationCAB({ userOperation }) console.log("transfer with cab userOpHash:", userOpHash) const ret = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash }) console.log( "transfer with cab transactionHash:", ret.receipt.transactionHash ) }, TEST_TIMEOUT ) }) })