You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@solana/wallet-adapter-react转移USDC失败求助

交易失败原因排查与代码修正

从你提供的交易ID和代码来看,交易失败的核心原因是重复尝试创建已存在的关联代币账户(ATA),同时存在几处逻辑问题需要修正:

核心问题分析

  • 强制创建ATA触发错误:代码中无条件添加createAssociatedTokenAccountInstruction指令,若发送者/接收者的USDC ATA已存在(比如发送者曾持有过USDC),该指令会触发AccountAlreadyInitialized错误,直接导致整个交易失败。
  • 冗余的接收方ATA创建:接收方的ATA无需每次转账都尝试创建,既浪费Gas也容易引发错误,应仅在确认账户不存在时再执行创建操作。
  • 缺乏预检查机制:未提前验证账户状态,导致无效指令上链失败。

修正后的代码

const handleTxn = async (publicKey: PublicKey, sendTransaction: WalletAdapterProps["sendTransaction"], amount: number) => {
  if (!publicKey) {
    console.log("钱包未连接");
    return;
  }

  const connStr = `https://stylish-capable-fire.solana-mainnet.quiknode.pro/${process.env.NEXT_PUBLIC_CUSTOM_RPC_HOST_KEY}`;
  const connection = new Connection(connStr);

  // USDC主网铸币地址
  const USDC_MINT_ADDRESS = new PublicKey(process.env.NEXT_PUBLIC_USDC_TOKEN_ADDRESS!);
  const toWalletPublicKey = new PublicKey(process.env.NEXT_PUBLIC_PRESALE_WALLET!);
  const fromWallet = publicKey;

  // 获取发送者/接收者的ATA地址
  const [fromTokenAccount] = await PublicKey.findProgramAddressSync(
    [fromWallet.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), USDC_MINT_ADDRESS.toBuffer()],
    TOKEN_PROGRAM_ID
  );
  const [toTokenAccount] = await PublicKey.findProgramAddressSync(
    [toWalletPublicKey.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), USDC_MINT_ADDRESS.toBuffer()],
    TOKEN_PROGRAM_ID
  );

  const transaction = new Transaction();

  // 检查发送者ATA是否存在,不存在则创建
  const fromAccountInfo = await connection.getAccountInfo(fromTokenAccount);
  if (!fromAccountInfo) {
    transaction.add(createAssociatedTokenAccountInstruction(
      fromWallet, // 付费账户
      fromTokenAccount, // 目标ATA地址
      fromWallet, // 账户所有者
      USDC_MINT_ADDRESS // 铸币地址
    ));
  }

  // 检查接收者ATA是否存在,不存在则创建(可选:若接收方未创建,可跳过让其自行处理)
  const toAccountInfo = await connection.getAccountInfo(toTokenAccount);
  if (!toAccountInfo) {
    transaction.add(createAssociatedTokenAccountInstruction(
      fromWallet, // 发送者代付创建费用
      toTokenAccount,
      toWalletPublicKey,
      USDC_MINT_ADDRESS
    ));
  }

  // 处理USDC小数精度(6位小数),避免浮点数误差
  const txnAmt = Math.floor(amount * 10 ** 6);
  console.log("amount", amount, "txnAmt", txnAmt);

  // 添加转账指令
  transaction.add(createTransferInstruction(
    fromTokenAccount, // 源ATA
    toTokenAccount, // 目标ATA
    fromWallet, // 授权者(发送者钱包)
    txnAmt,
    [],
    TOKEN_PROGRAM_ID
  ));

  try {
    const txid = await sendTransaction(transaction, connection, {
      skipPreflight: false, // 开启预检查,提前发现错误
      preflightCommitment: "confirmed"
    });
    await connection.confirmTransaction(txid, "confirmed");
    console.log("交易签名(ID):", txid);
    return { txid };
  } catch (error) {
    console.error("交易失败", error);
    return { txid: null };
  }
};

额外注意事项

  • 开启预检查:sendTransaction中设置skipPreflight: false,可让钱包提前验证交易合法性,避免无效交易上链。
  • 精度处理:使用Math.floor确保转账金额为整数,避免浮点数精度问题导致金额错误。
  • 余额验证:确保发送者的USDC ATA有足够余额,且钱包持有足够SOL支付交易手续费。

内容的提问来源于stack exchange,提问作者A.Codera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 15:30:17