This guide covers how to send EVM and Solana transactions with Wallet APIs.
- API key from your dashboard
@alchemy/wallet-apisinstalled in your project- A signer with funds to cover gas (or a sponsorship policy — see Sponsor gas for EVM and Solana sponsorship for Solana)
The EVM client defaults to using EIP-7702, so your EOA will be delegated to a smart wallet to enable gas sponsorship, batching, and more. The SDK handles delegation automatically on the first transaction.
You can send transactions using the smart wallet client sendCalls action.
import { client } from "./client.ts";
// Send the transaction
const { id } = await client.sendCalls({
calls: [
{
to: "0x0000000000000000000000000000000000000000",
value: BigInt(0),
data: "0x",
},
],
});
console.log({ id }); // the Call ID
// Wait for the transaction to be confirmed
const result = await client.waitForCallsStatus({ id });
console.log(result);Using @account-kit/wallet-client (v4)?
The examples on this page use @alchemy/wallet-apis (v5). If you're using @account-kit/wallet-client (v4), 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 differences:
- Account address must be specified on the client or per action (
fromoraccount). In v5, the client automatically uses the owner'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, the paymaster capability on
prepareCallsorsendCallsis calledpaymasterServiceinstead ofpaymaster, or you can set thepolicyIddirectly on the client. - Owners use
LocalAccountSigner/WalletClientSignerfrom@aa-sdk/core. In v5, a viemLocalAccountorWalletClientis used directly.
See the full migration guide for a complete cheat sheet.
Encoding function data
If you need to encode function data (instead of sending value), do so using Viem or Foundry.
In JavaScript, you can use Viem to encode function call data.
import { encodeFunctionData } from "viem";
import { client } from "./client.ts";
import { exampleAbi } from "./abi.ts";
await client.sendCalls({
calls: [
{
to: "0x0000000000000000000000000000000000000000",
data: encodeFunctionData({
abi: exampleAbi,
functionName: "mintTo",
args: ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"],
}),
},
],
});Usage with prepare calls
Instead of using the sendCalls abstraction, you can prepare and send EVM calls using underlying methods. Usage of the capability will be the same as when using send calls. It is recommended to use prepareCalls if you want to inspect the prepared call prior to prompting the user for signature.
You can use smart wallet client actions to prepare, sign, and send transactions.
import { client } from "./client.ts";
// Prepare the calls
const preparedCalls = await client.prepareCalls({
calls: [
{
to: "0x0000000000000000000000000000000000000000",
value: BigInt(0),
data: "0x",
},
],
});
// Inspect the prepared calls before signing
console.log({ preparedCalls });
// Sign the prepared calls
const signedCalls = await client.signPreparedCalls(preparedCalls);
// Send the signed calls
const sentCalls = await client.sendPreparedCalls(signedCalls);
console.log({ sentCalls });See the prepareCalls, signPreparedCalls, and sendPreparedCalls SDK references for full parameter descriptions.
Solana transactions use the same client actions as EVM, but calls contain Solana instructions: programId, hex-encoded data, and account metadata. For signer setup, see Solana signer adapters.
By default, the client uses the signer's address.
You can send Solana instructions using the smart wallet client sendCalls action.
import { client } from "./client.ts";
import { transferSolCall } from "./utils.ts";
const { id } = await client.sendCalls({
calls: [
transferSolCall({
from: client.solanaAccount,
to: client.solanaAccount,
lamports: 0n,
}),
],
});
console.log({ id });
const result = await client.waitForCallsStatus({ id });
console.log(result);This example loads a raw Ed25519 keypair from an environment variable for simplicity. For app wallets like Privy, Phantom, @solana/wallet-adapter-react, or Wallet Standard, see Solana signer adapters.
Usage with prepare calls
Use the prepared call flow when you need to inspect the compiled Solana transaction before signing.
You can use smart wallet client actions to prepare, sign, and send Solana transactions.
import { client } from "./client.ts";
import { transferSolCall } from "./utils.ts";
const preparedCalls = await client.prepareCalls({
calls: [
transferSolCall({
from: client.solanaAccount,
to: client.solanaAccount,
lamports: 0n,
}),
],
});
console.log(preparedCalls.type); // "solana-transaction-v0"
console.log(preparedCalls.signatureRequest.type); // "solana_signTransaction"
const signedCalls = await client.signPreparedCalls(preparedCalls);
const sentCalls = await client.sendPreparedCalls(signedCalls);
console.log(sentCalls);See the prepareCalls, signPreparedCalls, and sendPreparedCalls SDK references for full parameter descriptions.
Build more:
Troubleshooting: