Skip to content
Alchemy Logo

Send transactions

This guide covers how to send EVM and Solana transactions with Wallet APIs.

  • API key from your dashboard
  • @alchemy/wallet-apis installed 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.

sendCalls.ts
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:

client.ts (v4)
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 (from or account). In v5, the client automatically uses the owner's address as the account address via EIP-7702.
  • Chain imports come directly from @account-kit/infra instead of viem/chains.
  • Numeric values use hex strings: value: "0x0" instead of value: BigInt(0).
  • In v4, the paymaster capability on prepareCalls or sendCalls is called paymasterService instead of paymaster, or you can set the policyId directly on the client.
  • Owners use LocalAccountSigner / WalletClientSigner from @aa-sdk/core. In v5, a viem LocalAccount or WalletClient is 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.

sendCalls.ts
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.

sendCalls.ts
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.

sendCalls.ts
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.

sendCalls.ts
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:

Was this page helpful?