@alchemy/wallet-apis (v5.x.x) is currently in beta but is the recommended replacement for @account-kit/wallet-client (v4.x.x). If you run into any issues, please reach out.You're going to need @alchemy/wallet-apis and viem. We'll use privateKeyToAccount from viem/accounts as the signer for demonstration purposes.
npm install @alchemy/wallet-apis viemCreate a client for a given signer (e.g. using privateKeyToAccount from viem/accounts).
import { privateKeyToAccount } from "viem/accounts";
import { arbitrumSepolia } from "viem/chains";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
const client = createSmartWalletClient({
transport: alchemyWalletTransport({
apiKey: "YOUR_API_KEY",
}),
chain: arbitrumSepolia,
signer: privateKeyToAccount("0xYOUR_PRIVATE_KEY" as const),
});Need to delegate your account first?
EIP-7702 accounts must be delegated onchain before creating a session. If the account has already sent calls, it will already be delegated. If it hasn't sent any calls before creating the session key, you can delegate it by sending an empty call as the owner:
const { id } = await client.sendCalls({
calls: [], // empty array since you just want to delegate
});
await client.waitForCallsStatus({ id });Now you can continue to create the session key as described below.
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
// This is where you would use your session key signer
const sessionKeyPrivateKey = generatePrivateKey();
const sessionKey = privateKeyToAccount(sessionKeyPrivateKey);
const permissions = await client.grantPermissions({
expirySec: Math.floor(Date.now() / 1000) + 60 * 60,
key: {
publicKey: sessionKey.address,
type: "secp256k1",
},
permissions: [{ type: "root" }], // Here we grant root permissions as an example, but this is not advised in production!
});import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
// Create a client with the session key as signer
const sessionKeyClient = createSmartWalletClient({
transport: alchemyWalletTransport({
apiKey: "YOUR_API_KEY",
}),
chain: arbitrumSepolia,
signer: sessionKey, // Use the session key as signer
account: client.account.address, // The original account that granted permissions
});
const { id } = await sessionKeyClient.sendCalls({
calls: [{ to: "0x0000000000000000000000000000000000000000", value: BigInt(0) }],
capabilities: {
permissions,
},
});
await sessionKeyClient.waitForCallsStatus({ id });Using @account-kit/wallet-client (v4.x.x)?
The examples on this page use @alchemy/wallet-apis (v5.x.x). If you're using @account-kit/wallet-client (v4.x.x), the client setup looks like this:
import { LocalAccountSigner } from "@aa-sdk/core";
import { createSmartWalletClient } from "@account-kit/wallet-client";
import { alchemy, sepolia } from "@account-kit/infra";
const signer = LocalAccountSigner.privateKeyToAccountSigner("0xYOUR_PRIVATE_KEY" as const);
export const client = createSmartWalletClient({
transport: alchemy({ apiKey: "YOUR_API_KEY" }),
chain: sepolia,
signer,
account: signer.address, // can also be passed per action as `from` or `account`
// Optional: sponsor gas for your users (see "Sponsor gas" guide)
policyId: "YOUR_POLICY_ID",
});Key v4.x.x differences:
- Account address must be specified on the client or per action (
fromoraccount). In v5.x.x, the client automatically uses the signer's address as the account address via EIP-7702. - Chain imports come directly from
@account-kit/infrainstead ofviem/chains. - Numeric values use hex strings:
value: "0x0"instead ofvalue: BigInt(0). - In v4.x.x, the paymaster capability on
prepareCallsorsendCallsis calledpaymasterServiceinstead ofpaymaster, or you can set thepolicyIddirectly on the client. - Signers use
LocalAccountSigner/WalletClientSignerfrom@aa-sdk/core. In v5.x.x, a viemLocalAccountorWalletClientis used directly.
See the full migration guide for a complete cheat sheet.