@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.Any signer that provides a viem LocalAccount or WalletClient works with createSmartWalletClient. This guide covers the requirements and how to set up each type.
Your signer must implement:
| Property | Required | Purpose |
|---|---|---|
address | Yes | The signer's Ethereum address |
signMessage | Yes | Signs plaintext and raw messages (EIP-191) |
signTypedData | Yes | Signs structured data (EIP-712) |
signAuthorization | Yes (for EIP-7702) | Signs the EIP-7702 delegation authorization |
signAuthorization is required for EIP-7702, which is the default mode. If your signer doesn't support it, you can use non-7702 mode instead.
Use a LocalAccount when your signer gives you direct access to a private key or a signing function. This is the recommended approach because it provides the signAuthorization interface needed for EIP-7702 delegation.
import { toAccount } from "viem/accounts";
import { arbitrumSepolia } from "viem/chains";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
const account = toAccount({
address: "0xYOUR_SIGNER_ADDRESS",
async signMessage({ message }) {
// delegate to your signer
},
async signTypedData(typedData) {
// delegate to your signer
},
async signTransaction(transaction) {
// unused by the Smart Wallet client
throw new Error("signTransaction is not implemented");
},
async signAuthorization(unsignedAuth) {
// required for EIP-7702 delegation
// delegate to your signer and return { ...unsignedAuth, r, s, yParity }
},
});
const client = createSmartWalletClient({
signer: account,
transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
chain: arbitrumSepolia,
});For a private key signer, you can use viem's built-in helper which implements all methods automatically:
import { privateKeyToAccount } from "viem/accounts";
const client = createSmartWalletClient({
signer: privateKeyToAccount("0x..."),
transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
chain: arbitrumSepolia,
});Use a WalletClient when your signer is a browser wallet or embedded wallet that exposes an EIP-1193 provider (e.g. window.ethereum).
import { createWalletClient, custom } from "viem";
import { arbitrumSepolia } from "viem/chains";
import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
// Create a WalletClient from the browser wallet
const [address] = await window.ethereum.request({ method: "eth_requestAccounts" });
const walletClient = createWalletClient({
account: address,
chain: arbitrumSepolia,
transport: custom(window.ethereum),
});
// Pass the WalletClient as the signer
const client = createSmartWalletClient({
signer: walletClient,
transport: alchemyWalletTransport({ apiKey: "YOUR_ALCHEMY_API_KEY" }),
chain: arbitrumSepolia,
paymaster: { policyId: "YOUR_GAS_POLICY_ID" }, // optional
});EIP-7702 authorization signing requires a LocalAccount with signAuthorization implemented. If your wallet doesn't support this, you may need to use non-7702 mode instead.
Once you have a client, usage is the same regardless of signer type:
const result = await client.sendCalls({
calls: [
{
to: "0x0000000000000000000000000000000000000000",
value: BigInt(0),
data: "0x",
},
],
});
const txStatus = await client.waitForCallsStatus({
id: result.id,
timeout: 60_000,
});
console.log("Transaction confirmed:", txStatus.receipts?.[0]?.transactionHash);See full integration guides for supported providers: