@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.A smart wallet client is the main interface used to interact with smart wallets and take actions like sending transactions, batching transactions, swapping, sponsoring gas, and more.
The SmartWalletClient extends viem's Client. By default, it uses EIP-7702 to delegate the signer's EOA to a smart account, so the account address is the same as the signer address. No separate account deployment or address mapping is needed.
- API key
- (Optional) A gas policyID
@alchemy/wallet-apisandvieminstalled (see the quickstart)
Use the createSmartWalletClient function to create a smart wallet client.
- Replace the placeholders:
- API key from your Alchemy dashboard
- Policy ID from your gas policy
- Signer from authentication or your own signer
- Create the client using
createSmartWalletClient— the client defaults to EIP-7702 using the signer's address
import { privateKeyToAccount } from "viem/accounts";
import { arbitrumSepolia } from "viem/chains";
import {
createSmartWalletClient,
alchemyWalletTransport,
} from "@alchemy/wallet-apis";
export const client = createSmartWalletClient({
transport: alchemyWalletTransport({ apiKey: "your-alchemy-api-key" }),
chain: arbitrumSepolia,
signer: privateKeyToAccount("0x-your-wallet-private-key"),
paymaster: { policyId: "your-policy-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.
Use a non-7702 smart contract account
By default, the client uses EIP-7702 with the signer's address. If you need to use a standalone smart contract account instead, see the non-7702 mode guide.
Learn more about the different smart account types here.
Connect to an existing non-7702 account
By default, the client uses the signer's address with EIP-7702. If you already know a non-7702 smart contract account address your signer owns (either from calling requestAccount or stored from a previous session), you can pass it when creating the client or on each action.
On the client:
const client = createSmartWalletClient({
// ... your config
account: "0xYOUR_SCA_ADDRESS",
});Per action:
await client.sendCalls({
account: "0xYOUR_SCA_ADDRESS",
calls: [...],
});Extend client with custom actions
The SmartWalletClient is a viem client extension, so it supports the .extend method for adding custom actions. For example, experimental swap actions are added this way:
import { swapActions } from "@alchemy/wallet-apis/experimental";
const swapClient = client.extend(swapActions);Use one client for multiple accounts
If the same signer owns multiple non-7702 smart contract accounts, you can use a single client to interact with any of them by passing account on each action:
// Two SCAs owned by the same signer, created via requestAccount
const treasuryAccount = "0xaaa...111";
const operationsAccount = "0xbbb...222";
await client.sendCalls({
account: treasuryAccount,
calls: [{ to: "0x...", data: "0x", value: BigInt(0) }],
});
await client.sendCalls({
account: operationsAccount,
calls: [{ to: "0x...", data: "0x", value: BigInt(0) }],
});If different signers are involved, use the prepare/sign/send flow with separate clients per signer instead.