Basic Payment

Solana enables instant, global token transfers with fees under $0.001. Whether you're building cross-border remittances, payroll disbursements, or treasury operations, a basic stablecoin payment settles in under a second and costs a fraction of a cent.

How It Works

A payment moves stablecoins from the sender's token account to the recipient's token account. If the recipient is receiving this token for the first time, their token account can be created as part of the same transaction.

See How Payments Work on Solana for core payment concepts.

The token2022Program() plugin from @solana-program/token-2022 extends your @solana/kit client with a client.token2022 helper. Its transferToATA method handles ATA derivation and transaction building automatically, which is ideal for single payment transfers.

The steps below show the core flow. See the Demo for complete runnable code.

Create the Token Helper

Add the token2022Program() plugin to your client with .use(token2022Program()). This exposes client.token2022, whose instructions provide methods for common token operations.

Use token2022Program() for mints owned by the Token-2022 program, or tokenProgram() from @solana-program/token for mints owned by the original Token program.

Basic Payment
const client = createClient()
.use(signer(sender))
.use(solanaLocalRpc())
.use(token2022Program());

Send the Payment

Use transferToATA() to transfer tokens between wallets. The method handles:

  • ATA Resolution: Automatically derives Associated Token Accounts (ATAs) for the sender and recipient. If the recipient's ATA doesn't exist, the instruction to create the account is automatically added to the same transaction.
  • Checked Amounts: Pass amount in base units along with the mint's decimals. The transfer is checked against the mint's decimals on-chain (e.g. 250000 base units -> 0.25 tokens, if the mint has 6 decimals)
  • Transaction Building: sendTransaction() builds, signs, and sends the transaction, resolving to a result whose context.signature holds the transaction signature
Basic Payment
const client = createClient()
.use(signer(sender))
.use(solanaLocalRpc())
.use(token2022Program());
const result = await client.token2022.instructions
.transferToATA({
mint: mint.address,
authority: sender,
recipient: recipient.address,
amount: 250_000n,
decimals: 6
})
.sendTransaction();

Verify Balances

After the transfer completes, read the token balances from the RPC. Derive each wallet's ATA with findAssociatedTokenPda(), then call getTokenAccountBalance() to fetch the balance for that account.

Basic Payment
const client = createClient()
.use(signer(sender))
.use(solanaLocalRpc())
.use(token2022Program());
const result = await client.token2022.instructions
.transferToATA({
mint: mint.address,
authority: sender,
recipient: recipient.address,
amount: 250_000n,
decimals: 6
})
.sendTransaction();
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipientAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const senderBalance = await client.rpc.getTokenAccountBalance(senderAta).send();
const recipientBalance = await client.rpc
.getTokenAccountBalance(recipientAta)
.send();

Create the Token Helper

Add the token2022Program() plugin to your client with .use(token2022Program()). This exposes client.token2022, whose instructions provide methods for common token operations.

Use token2022Program() for mints owned by the Token-2022 program, or tokenProgram() from @solana-program/token for mints owned by the original Token program.

Send the Payment

Use transferToATA() to transfer tokens between wallets. The method handles:

  • ATA Resolution: Automatically derives Associated Token Accounts (ATAs) for the sender and recipient. If the recipient's ATA doesn't exist, the instruction to create the account is automatically added to the same transaction.
  • Checked Amounts: Pass amount in base units along with the mint's decimals. The transfer is checked against the mint's decimals on-chain (e.g. 250000 base units -> 0.25 tokens, if the mint has 6 decimals)
  • Transaction Building: sendTransaction() builds, signs, and sends the transaction, resolving to a result whose context.signature holds the transaction signature

Verify Balances

After the transfer completes, read the token balances from the RPC. Derive each wallet's ATA with findAssociatedTokenPda(), then call getTokenAccountBalance() to fetch the balance for that account.

Basic Payment
const client = createClient()
.use(signer(sender))
.use(solanaLocalRpc())
.use(token2022Program());

Demo

Demo
// Generate signers for sender and recipient
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
console.log("Sender Address:", sender.address);
console.log("Recipient Address:", recipient.address);
// Demo Setup: Create client, mint account, and fund the sender with initial tokens
const { client, mint } = await demoSetup(sender);
console.log("\nMint Address:", mint.address);
// =============================================================================
// Basic Token Payment Demo
// =============================================================================
// Transfer tokens from sender to recipient. The source and destination ATAs are
// derived automatically, and the recipient's ATA is created if it does not exist.
const result = await client.token2022.instructions
.transferToATA({
mint: mint.address,
authority: sender,
recipient: recipient.address,
amount: 250_000n, // 0.25 tokens (base units for a mint with 6 decimals)
decimals: 6
})
.sendTransaction();
console.log("\n=== Token Payment Complete ===");
console.log("Transaction Signature:", result.context.signature);
// Derive the sender and recipient ATAs to read their balances
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipientAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
// Fetch final token account balances via RPC
const senderBalance = await client.rpc.getTokenAccountBalance(senderAta).send();
const recipientBalance = await client.rpc
.getTokenAccountBalance(recipientAta)
.send();
console.log(
"\nSender Token Account Balance:",
senderBalance.value.uiAmountString
);
console.log(
"Recipient Token Account Balance:",
recipientBalance.value.uiAmountString
);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

Is this page helpful?

Table of Contents

Edit Page
© 2026 Solana Foundation. All rights reserved.