Configure client

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.

How It Works

The SmartWalletClient is a EIP-1193 compatible extension of viem’s Client which allows you to interact with smart wallets.

Prerequisites

Implementation

Use the createSmartWalletClient function to create a smart wallet client.

  1. Replace the placeholders a. API key from your Alchemy dashboard b. Policy ID from your gas policy c. Signer from authentication or your own signer
  2. Create the initial client using createSmartWalletClient
  3. Generate your smart account by calling requestAccount()
  4. Create the final client with your account attached
import { 
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>

Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.

LocalAccountSigner
} from "@aa-sdk/core";
import {
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
,
const sepolia: Chain
sepolia
} from "@account-kit/infra";
import {
function createSmartWalletClient<TAccount extends Address | undefined = undefined>(params: SmartWalletClientParams<TAccount>): SmartWalletClient<TAccount>

Creates a smart wallet client that can be used to interact with a smart account.

createSmartWalletClient
,
type
type SmartWalletClientParams<TAccount extends Address | undefined = `0x${string}` | undefined> = { transport: AlchemyTransport; chain: Chain; signer: SmartWalletSigner; account?: `0x${string}` | TAccount | undefined; policyId?: string | undefined; policyIds?: never | undefined; } | { transport: AlchemyTransport; chain: Chain; signer: SmartWalletSigner; account?: `0x${string}` | TAccount | undefined; policyIds?: string[] | undefined; policyId?: never | undefined; }
SmartWalletClientParams
,
} from "@account-kit/wallet-client"; const
const clientParams: SmartWalletClientParams
clientParams
:
type SmartWalletClientParams<TAccount extends Address | undefined = `0x${string}` | undefined> = { transport: AlchemyTransport; chain: Chain; signer: SmartWalletSigner; account?: `0x${string}` | TAccount | undefined; policyId?: string | undefined; policyIds?: never | undefined; } | { transport: AlchemyTransport; chain: Chain; signer: SmartWalletSigner; account?: `0x${string}` | TAccount | undefined; policyIds?: string[] | undefined; policyId?: never | undefined; }
SmartWalletClientParams
= {
transport: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
({
apiKey: string
apiKey
: "your-alchemy-api-key"}),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
signer: SmartWalletSigner
signer
:
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>

Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.

LocalAccountSigner
.
LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.privateKeyToAccountSigner(key: Hex): LocalAccountSigner<PrivateKeyAccount>

Creates a LocalAccountSigner instance using the provided private key.

privateKeyToAccountSigner
("0x-your-wallet-private-key"),
policyId?: string | undefined
policyId
: "your-policy-id",
}; const
const clientWithoutAccount: SmartWalletClient<`0x${string}` | undefined>
clientWithoutAccount
=
createSmartWalletClient<`0x${string}` | undefined>(params: SmartWalletClientParams<`0x${string}` | undefined>): SmartWalletClient<`0x${string}` | undefined>

Creates a smart wallet client that can be used to interact with a smart account.

createSmartWalletClient
(
const clientParams: { transport: AlchemyTransport; chain: Chain; signer: SmartWalletSigner; account?: `0x${string}` | undefined; policyId?: string | undefined; policyIds?: never | undefined; }
clientParams
);
const
const account: RequestAccountResult
account
= await
const clientWithoutAccount: SmartWalletClient<`0x${string}` | undefined>
clientWithoutAccount
.
requestAccount: (params?: RequestAccountParams) => Promise<RequestAccountResult>
requestAccount
();
export const
const client: SmartWalletClient<`0x${string}`>
client
=
createSmartWalletClient<`0x${string}`>(params: SmartWalletClientParams<`0x${string}`>): SmartWalletClient<`0x${string}`>

Creates a smart wallet client that can be used to interact with a smart account.

createSmartWalletClient
({
...
const clientParams: { transport: AlchemyTransport; chain: Chain; signer: SmartWalletSigner; account?: `0x${string}` | undefined; policyId?: string | undefined; policyIds?: never | undefined; }
clientParams
,
account: `0x${string}`
account
:
const account: RequestAccountResult
account
.
address: `0x${string}`
address
,
});

Advanced

By default, the Smart Wallet Client will use ModularAccountV2(MAv2). This is the cheapest and most advanced Smart Account, but you can specify other smart contract account types as needed. Learn more about the different smart accounts here.

Changing the account type will deploy a different account. If you’ve already deployed an account for a user and want to change the underlying account type, you’ll need to upgrade it. Learn how to upgrade here.

Javascript

Specify the account type when calling requestAccount using the creationHint parameter. See all parameter options.

1const account = await clientWithoutAccount.requestAccount(
2 creationHint: {
3 accountType: "sma-b"
4 },
5);
6
7export const client = createSmartWalletClient({
8 ...clientParams,
9 account: account.address,
10});

API

Pass an accountType to creationHint when calling wallet_requestAccount.

Using 7702

To use EIP-7702, please see this guide. You’ll need to set additional parameters on the client.

By default, account addresses are deterministically generated from the signer address. To connect to an existing account that doesn’t match the deterministic address of your signer, specify the account address when creating the client.

Javascript

Pass the address to the createSmartWalletClient directly rather than calling requestAccount.

1export const client = createSmartWalletClient({
2 ...clientParams,
3 account: "0xYOUR_SMART_ACCOUNT_ADDR",
4});

API

Pass the account address directly when preparing calls instead of calling wallet_requestAccount. See this guide and skip step 2.

Because the Smart Wallet Clients are extensions of viem’s clients, they support extensions via the .extend method. The base client already includes a number of actions by default. You can find additional details about these actions in the @aa-sdk/core documentation.

Typically, the smart account client uses the default account or the account passed into the client constructor for all of the actions you perform with the client - also known as account hositing.

If you want to manage multiple instances of an account but want to use one client for all of them, you can pass an account to the client on every action.

1import {
2 createAlchemySmartAccountClient,
3 sepolia,
4 alchemy,
5} from "@account-kit/infra";
6import { createLightAccount } from "@account-kit/smart-contracts";
7import { LocalAccountSigner } from "@aa-sdk/core";
8import { http } from "viem";
9import { generatePrivateKey } from "viem/accounts";
10
11// with account hoisting
12const transport = alchemy({ apiKey: "your-api-key" });
13const hoistedClient = createAlchemySmartAccountClient({
14 transport,
15 chain: sepolia,
16 account: await createLightAccount({
17 signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()),
18 chain: sepolia,
19 transport,
20 }),
21});
22
23const signature = await hoistedClient.signMessage({ message: "Hello world! " });
24
25// without account hoisting
26const nonHoistedClient = createAlchemySmartAccountClient({
27 transport,
28 chain: sepolia,
29});
30
31const lightAccount = await createLightAccount({
32 signer: LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey()),
33 chain: sepolia,
34 transport,
35});
36
37const signature2 = await nonHoistedClient.signMessage({
38 message: "Hello world! ",
39 account: lightAccount,
40});

Next Steps