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/coreGiven 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!
import { createSmartWalletClient } from "@account-kit/wallet-client";
import { alchemy, arbitrumSepolia } from "@account-kit/infra";
import { LocalAccountSigner } from "@aa-sdk/core";
const signer = LocalAccountSigner.privateKeyToAccountSigner(PRIVATE_KEY); // we use a private key signer as an example here
const transport = alchemy({
apiKey: ALCHEMY_API_KEY, // use your Alchemy app api key here!
});
const client = createSmartWalletClient({
transport,
chain: arbitrumSepolia, // use any chain imported from @account-kit/infra here!
signer,
});Use your signer address directly as the from field to enable EIP-7702 by default. This first transaction will delegate your account.
import { zeroAddress } from "viem";
const signerAddress = await signer.getAddress();
const preparedCalls = await client.prepareCalls({
calls: [{ to: zeroAddress, value: "0x0" }], // callData is optional in a "data" parameter
from: signerAddress,
// "capabilities" is a data structure that hold gas manager data (as seen below) or permission data
capabilities: {
paymasterService: {
policyId: GAS_MANAGER_POLICY_ID, // put your gas manager policy ID here
},
},
});
// Sign the calls (handles both authorization and user operation if account isn't delegated yet)
const signedCalls = await client.signPreparedCalls(preparedCalls);
// Send the userOp
const result = await client.sendPreparedCalls(signedCalls);
// Check calls status.
const status = await client.getCallsStatus(result.id);Once your account is delegated, you can sign messages.
import { createPublicClient } from "viem";
const signerAddress = await signer.getAddress();
const message = "we are so back";
const signature = await client.signMessage({ message, account: signerAddress });
const publicClient = createPublicClient({
chain: arbitrumSepolia,
transport: transport,
});
const isValid = await publicClient.verifyMessage({
address: signerAddress,
message,
signature,
});// assuming you have a typedData variable
const signature = await client.signTypedData({ typedData, account: signerAddress });
const isValid = await publicClient.verifyTypedData({
address: signerAddress,
...typedData,
signature,
});