From 706767e5cb8e0671f26dd1d35fadf55f65ec340b Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Thu, 18 Sep 2025 00:57:52 -0400 Subject: [PATCH] ideation: aa in viem client --- packages/viem/README.md | 1 + packages/viem/package.json | 4 +- packages/viem/src/index.ts | 96 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/packages/viem/README.md b/packages/viem/README.md index efb4a0204..ed20e6142 100644 --- a/packages/viem/README.md +++ b/packages/viem/README.md @@ -77,6 +77,7 @@ main().catch((error) => { ``` 2. Start the Anvil node in one shell: + - Install [Foundry](https://book.getfoundry.sh/getting-started/installation) & Anvil if you haven't done so already - Add Foundry to your `$PATH` ```bash diff --git a/packages/viem/package.json b/packages/viem/package.json index 2212d6f2a..026df7197 100644 --- a/packages/viem/package.json +++ b/packages/viem/package.json @@ -63,7 +63,9 @@ "@turnkey/sdk-browser": "workspace:*", "@turnkey/sdk-server": "workspace:*", "@turnkey/core": "workspace:*", - "cross-fetch": "^4.0.0" + "cross-fetch": "^4.0.0", + "@zerodev/ecdsa-validator": "^5.4.8", + "@zerodev/sdk": "^5.4.32" }, "devDependencies": { "@types/jest": "^29.5.3", diff --git a/packages/viem/src/index.ts b/packages/viem/src/index.ts index 801545b0f..d3359c8bf 100644 --- a/packages/viem/src/index.ts +++ b/packages/viem/src/index.ts @@ -7,6 +7,9 @@ import { hexToBytes, parseTransaction, serializeTypedData, + createPublicClient, + http, + Chain, } from "viem"; import { SignAuthorizationReturnType, @@ -23,6 +26,16 @@ import type { TypedData, } from "viem"; import { secp256k1 } from "@noble/curves/secp256k1"; +import { getEntryPoint, KERNEL_V3_3 } from "@zerodev/sdk/constants"; +import { + create7702KernelAccount, + create7702KernelAccountClient, +} from "@zerodev/ecdsa-validator"; +import { + createZeroDevPaymasterClient, + getUserOperationGasPrice, + KernelAccountClient, +} from "@zerodev/sdk"; import { assertNonNull, @@ -718,3 +731,86 @@ export function isTurnkeyActivityError(error: any) { }) ); } + +export async function initSmartAccount( + client: + | TurnkeyClient + | TurnkeyBrowserClient + | TurnkeyServerClient + | TurnkeySDKClientBase, + organizationId: string, + signWith: string, // your Ethereum EOA + smartAccountParams: { + chain: Chain; + paymasterUrl: string; + sponsor?: boolean; + }, +): Promise { + const { paymasterUrl, sponsor, chain } = smartAccountParams; + const entryPoint = getEntryPoint("0.7"); + const kernelVersion = KERNEL_V3_3; + + const publicClient = createPublicClient({ + transport: http(), + chain, + }); + + const turnkeyAccount = await createAccount({ + client, + organizationId, + signWith, + }); + + const account = await create7702KernelAccount(publicClient, { + signer: turnkeyAccount, + entryPoint, + kernelVersion, + }); + + const paymasterClient = createZeroDevPaymasterClient({ + chain, + transport: http(paymasterUrl), + }); + + const kernelClient = create7702KernelAccountClient({ + account, + chain, + bundlerTransport: http(paymasterUrl), + userOperation: { + estimateFeesPerGas: async ({ bundlerClient }) => { + return getUserOperationGasPrice(bundlerClient); + }, + }, + paymaster: sponsor + ? { + getPaymasterData: (userOperation) => { + return paymasterClient.sponsorUserOperation({ + userOperation, + }); + }, + } + : {}, + client: publicClient, + }); + + return kernelClient; +} + +export async function signWithSmartAccount( + kernelClient: KernelAccountClient, + calls: readonly { + to: `0x${string}`; + data?: `0x${string}` | undefined; + value?: bigint | undefined; + }[], +): Promise { + const userOpHash = await kernelClient.sendUserOperation({ + callData: await kernelClient.account.encodeCalls(calls), + }); + + const { receipt } = await kernelClient.waitForUserOperationReceipt({ + hash: userOpHash, + }); + + return receipt; +}