Sending SPL tokens is a common transaction on the Solana blockchain. This recipe walks you through creating and sending SPL token transfer transactions using @solana/spl-token and @solana/web3.js with Privy wallets. In this example, we’ll use USDC as the SPL token, but you can adapt it for any SPL token by changing the mint address and decimals.
Before following this recipe, make sure you have configured Privy for Solana in your app.

Overview

This recipe demonstrates how to:
  • Create an SPL token transfer transaction using @solana/spl-token
  • Handle token accounts and decimals properly
  • Sign and send the transaction using Privy wallets

Prerequisites

Install the required dependencies:
bash npm install @solana/web3.js @solana/spl-token

1. Create the SPL token transfer transaction

Create an SPL token transfer transaction using your preferred language:
import {Connection, PublicKey, Transaction} from '@solana/web3.js';
import {getAssociatedTokenAddress, createTransferInstruction} from '@solana/spl-token';

const createSPLTransferTransaction = async (
  fromAddress: string,
  toAddress: string,
  tokenMintAddress: string,
  amount: number,
  decimals: number = 6 // Default for USDC, adjust for your token
) => {
  // Set up connection to Solana network
  const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');

  // Create public key objects
  const fromPubkey = new PublicKey(fromAddress);
  const toPubkey = new PublicKey(toAddress);
  const mintPubkey = new PublicKey(tokenMintAddress);

  // Get associated token accounts
  const fromTokenAccount = await getAssociatedTokenAddress(mintPubkey, fromPubkey);

  const toTokenAccount = await getAssociatedTokenAddress(mintPubkey, toPubkey);

  // Convert amount to token units (considering decimals)
  const tokenAmount = amount * Math.pow(10, decimals);

  // Create transfer instruction
  const transferInstruction = createTransferInstruction(
    fromTokenAccount,
    toTokenAccount,
    fromPubkey,
    tokenAmount
  );

  // Create transaction and add instruction
  const transaction = new Transaction().add(transferInstruction);

  // Get recent blockhash
  const {blockhash} = await connection.getLatestBlockhash();
  transaction.recentBlockhash = blockhash;
  transaction.feePayer = fromPubkey;

  return {transaction, connection};
};

2. Send the transaction

You can send the transaction using Privy’s different SDKs. Below are examples for React, React Native, NodeJS, and Python:
import {useSendTransaction, useSolanaWallets} from '@privy-io/react-auth/solana';

const {wallets} = useSolanaWallets();
const {sendTransaction} = useSendTransaction();

const {transaction, connection} = await createSPLTransferTransaction(
  wallets[0].address,
  'recipient-wallet-address', // Replace with recipient's token account address
  'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC mint address
  10 // Amount to send
);

// Assuming you have a transaction created from the previous step
const signature = await sendTransaction({
  transaction, // from createSPLTransferTransaction
  address: wallets[0].address,
  connection // from createSPLTransferTransaction
});
You’ve successfully sent SPL tokens!

Token account considerations

Before sending SPL tokens, ensure that the recipient has a token account for the specific token mint.

Getting token account information

You can check if token accounts exist and get their addresses:
import {getAssociatedTokenAddress} from '@solana/spl-token';

// Check if token account exists
const tokenAccountAddress = await getAssociatedTokenAddress(
  new PublicKey(tokenMintAddress),
  new PublicKey(walletAddress)
);

const accountInfo = await connection.getAccountInfo(tokenAccountAddress);
const accountExists = accountInfo !== null;
Token mint addresses are different on each network, so make sure you’re using the correct addresses for your target environment.

Next steps

Now that you can send SPL tokens, you might want to explore: