blockchainweb3jssolanasolana-web3jssolana-transaction-instruction

How can I fix this error while transferring SPL token on Solana mainnet?


I developed this script to transfer SPL token on Solana mainnet.

This is the script:

import dotenv from "dotenv";
import bs58 from "bs58";
import {
  LAMPORTS_PER_SOL,
  Transaction,
  sendAndConfirmTransaction,
  Keypair,
  Connection,
  PublicKey,
} from "@solana/web3.js";
import {
  getOrCreateAssociatedTokenAccount,
  createTransferInstruction,
  getMint,
 TOKEN_PROGRAM_ID
} from "@solana/spl-token";

dotenv.config();

// Keys from .env
const fromWalletPrivateKeyString = process.env.SENDER_WALLET_PRIVATE_KEY as string;
const receiverPublicKeyString = process.env.RECEIVER_WALLET_PUBLIC_KEY as string;

const fromWallet = Keypair.fromSecretKey(bs58.decode(fromWalletPrivateKeyString));
const toWalletPublicKey = new PublicKey(receiverPublicKeyString);

// Token Mint Account Address
const mint = new PublicKey("7WphEnjwKtWWMbb7eEVYeLDNN2jodCo871tVt8jHpump"); // Mainnet

(async () => {
  const connection = new Connection("https://api.mainnet-beta.solana.com");

  // Check fromWallet balance
  const fromWalletBalance = await connection.getBalance(fromWallet.publicKey);
  console.log("From Wallet Balance:", fromWalletBalance / LAMPORTS_PER_SOL, "SOL");

  if (fromWalletBalance < 0.01 * LAMPORTS_PER_SOL) {
    throw new Error("From wallet does not have enough SOL to pay for transaction fees.");
  }

  // Get token mint info (including decimals)
  const mintInfo = await getMint(
    connection,
    mint,
    "confirmed",
    TOKEN_PROGRAM_ID,
  );
  console.log("Token Decimals:", mintInfo.decimals);

  // Get or create the fromTokenAccount
  const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    fromWallet,
    mint,
    fromWallet.publicKey
  );

  // Get or create the toTokenAccount
  const toTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    fromWallet,
    mint,
    toWalletPublicKey
  );

  console.log("From Token Account:", fromTokenAccount.address.toString());
  console.log("To Token Account:", toTokenAccount.address.toString());

  // Check the balance of the fromTokenAccount
  const fromTokenAccountBalance = await connection.getTokenAccountBalance(fromTokenAccount.address);
  console.log("From Token Account Balance (UI):", fromTokenAccountBalance.value.uiAmount, "tokens");
  console.log("From Token Account Balance (Lamports):", fromTokenAccountBalance.value.amount, "lamports");

  // Calculate the transfer amount in the smallest units (lamports)
  const transferAmountUI = 100; // Amount in UI units (e.g., 100 tokens)
  const transferAmount = transferAmountUI * Math.pow(10, mintInfo.decimals); // Convert to lamports

  // Ensure the fromTokenAccount has enough tokens for the transfer
  if (BigInt(fromTokenAccountBalance.value.amount) < BigInt(transferAmount)) {
    throw new Error("Insufficient funds in the fromTokenAccount.");
  }

  // Add token transfer instructions to transaction
  const transaction = new Transaction().add(
    createTransferInstruction(
      fromTokenAccount.address,
      toTokenAccount.address,
      fromWallet.publicKey,
      transferAmount // Amount in lamports
    )
  );

  // Sign transaction, broadcast, and confirm
  const transactionSignature = await sendAndConfirmTransaction(
    connection,
    transaction,
    [fromWallet]
  );

  console.log(
    "Transaction Signature: ",
    `https://solscan.io/tx/${transactionSignature}`
  );
})();

But unfortunately, I got this error.

E:\2025\sol\sol-drop\node_modules@solana\web3.js\src\connection.ts:4047 throw new TransactionExpiredBlockheightExceededError(signature); ^ TransactionExpiredBlockheightExceededError: Signature 2tHyzSufmuesDVG5jqMKEJkgVPknipktsg74rmHkp5gZh8R8EwCsE6YRtGu4kykxTVjaEnEsBwiXEPjupQ1e52jp has expired: block height exceeded. at Connection.confirmTransactionUsingBlockHeightExceedanceStrategy (E:\2025\sol\sol-drop\node_modules@solana\web3.js\src\connection.ts:4047:15) at processTicksAndRejections (node:internal/process/task_queues:95:5) at async Connection.confirmTransaction (E:\2025\sol\sol-drop\node_modules@solana\web3.js\src\connection.ts:3858:14) at async sendAndConfirmTransaction (E:\2025\sol\sol-drop\node_modules@solana\web3.js\src\utils\send-and-confirm-transaction.ts:48:7) { signature: '2tHyzSufmuesDVG5jqMKEJkgVPknipktsg74rmHkp5gZh8R8EwCsE6YRtGu4kykxTVjaEnEsBwiXEPjupQ1e52jp'

How can I solve this issue?


Solution

  • This issue is related to TransactionExpiredBlockheightExceededError.

    The error TransactionExpiredBlockheightExceededError indicates that the transaction has expired because it was not confirmed within the allowed block height range. On Solana, transactions have a recent blockhash that is only valid for a limited number of blocks (approximately 150 blocks, or ~1 minute). If the transaction is not confirmed within this time frame, it expires and cannot be processed.

    To transfer SPL tokens in TypeScript using the Solana Web3.js library, you need to include the latestBlockhash and potentially increase the priority fees to ensure your transaction is processed promptly.

    You can check this link: https://docs.chainstack.com/docs/transferring-spl-tokens-on-solana-typescript

    Good luck!