Wallets API Quickstart (SDK)

Learn to interact with Wallet APIs using the Wallet Client SDK

1. Install Prerequisities

You’re going to need @account-kit/wallet-client, @account-kit/infra, optionally @aa-sdk/core if you use a LocalAccountSigner, and optionally viem if you want to verify a signed message.

$npm install @account-kit/wallet-client @account-kit/infra @aa-sdk/core

2. Create A Smart Account Client

Given a signer (e.g. a LocalAccountSigner imported from @aa-sdk/core or an Alchemy Signer), all you need to do is follow a few simple steps to start sending user ops with Wallet APIs!

1import { createSmartWalletClient } from "@account-kit/wallet-client";
2import { alchemy, arbitrumSepolia } from "@account-kit/infra";
3import { LocalAccountSigner } from "@aa-sdk/core";
4
5const signer = LocalAccountSigner.privateKeyToAccountSigner(PRIVATE_KEY); // we use a private key signer as an example here
6
7const transport = alchemy({
8 apiKey: ALCHEMY_API_KEY, // use your Alchemy app api key here!
9});
10
11const client = createSmartWalletClient({
12 transport,
13 chain: arbitrumSepolia, // use any chain imported from @account-kit/infra here!
14 signer,
15});

3. Request The Account

A counterfactual address is the account address associated with the given signer— but the account contract hasn’t been deployed yet.

1const account = await client.requestAccount();
2
3// get the address
4const address = account.address;

4. Sign A Message

1import { createPublicClient } from "viem";
2
3const message = "we are so back";
4
5const signature = await client.signMessage({ message });
6
7const publicClient = createPublicClient({
8 chain: arbitrumSepolia,
9 transport: transport,
10});
11
12const isValid = await publicClient.verifyMessage({
13 address: account.address, // fetched from await client.requestAccount()
14 message,
15 signature,
16});

5. Sign Typed Data

1// assuming you have a typedData variable
2const signature = await client.signTypedData({ typedData });
3
4const isValid = await publicClient.verifyTypedData({
5 address: account.address, // fetched from await client.requestAccount()
6 ...typedData,
7 signature,
8});

6. Send A UserOp

1import { zeroAddress } from "viem";
2
3const account = await client.requestAccount();
4
5const preparedCalls = await client.prepareCalls({
6 calls: [{ to: zeroAddress, value: "0x0" }], // callData is optional in a "data" parameter
7 from: account.address,
8 // "capabilities" is a data structure that hold gas manager data (as seen below) or permission data
9 capabilities: {
10 paymasterService: {
11 policyId: GAS_MANAGER_POLICY_ID, // put your gas manager policy ID here
12 },
13 },
14});
15
16// Sign the calls
17const signedCalls = await client.signPreparedCalls(preparedCalls);
18
19// Send the userOp
20const result = await client.sendPreparedCalls(signedCalls);
21
22// Check calls status.
23const status = await client.getCallsStatus(result.preparedCallIds[0]);