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

使用@solana/spl-token转账USDC时出现Cannot Read Properties of Undefined错误

Solana USDC转账报错:Uncaught TypeError: Cannot read properties of undefined (reading 'from')

错误信息

Uncaught TypeError: Cannot read properties of undefined (reading 'from')
    at @solana_spl-token.js?v=0c2b08b7:5387:43

操作流程

  • 使用getAssociatedTokenAddress获取关联代币地址(ATA);
  • 使用getAccount检查发送方的ATA是否存在;
  • 若接收方ATA不存在则创建;
  • 使用createTransferInstruction发起USDC转账;
  • 已确保导入TOKEN_PROGRAM_ID。

已尝试的排查措施

  • ✅ 添加调试日志检查getAssociatedTokenAddress返回值;
  • ✅ 转账前验证发送方代币账户存在;
  • ✅ 将金额转换为BigInt(BigInt(Math.round(amount * 1e6)));
  • ✅ 确认TOKEN_PROGRAM_ID已正确导入。

疑问

  1. getAssociatedTokenAddress是否会在某些条件下返回undefined?
  2. 获取账户时是否需要显式指定程序ID?
  3. createTransferInstruction是否存在已知问题会导致该错误?

完整React/TypeScript代码

import { useState, useEffect } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import {
    Connection,
    PublicKey,
    Transaction,
} from "@solana/web3.js";
import {
    getAssociatedTokenAddress,
    createAssociatedTokenAccountInstruction,
    createTransferInstruction,
    getAccount,
    TOKEN_PROGRAM_ID, // Ensure TOKEN_PROGRAM_ID is imported
} from "@solana/spl-token";
import axios from "axios";

const USDC_MINT_ADDRESS = new PublicKey("11111111111111111111111111111111111111111111");

const USDC = () => {
    const { publicKey, sendTransaction } = useWallet();
    const [recipient, setRecipient] = useState("");
    const [amount, setAmount] = useState<string>(""); // Keep it as a string for input handling
    const connection = new Connection("https://api.devnet.solana.com");

    useEffect(() => {
        fetchRecipientAddress();
    }, []);

    const fetchRecipientAddress = async () => {
        try {
            console.log("Fetching recipient wallet address...");
            const response = await axios.get("http://192.168.29.183:5000/wallet");
            setRecipient(response.data.wallet_address);
            console.log("✅ Recipient Wallet Address:", response.data.wallet_address);
        } catch (error) {
            console.error("❌ Error fetching recipient address:", error);
        }
    };

    const transferUSDC = async (recipientWallet: string, amount: number): Promise<void> => {
        try {
            console.log("🔹 USDC Transfer Initiated...");

            if (!publicKey) {
                console.error("🚨 Wallet not connected. Aborting transaction.");
                alert("⚠️ Wallet not connected!");
                return;
            }

            console.log("✅ Wallet Connected:", publicKey.toBase58());

            const senderPublicKey = publicKey;
            const recipientPublicKey = new PublicKey(recipientWallet);
            console.log("✅ Recipient Public Key:", recipientPublicKey.toBase58());

            // ✅ Log ATA Before Fetching
            console.log("🔍 Fetching Associated Token Addresses...");
            const senderTokenAccount = await getAssociatedTokenAddress(
                USDC_MINT_ADDRESS, senderPublicKey, false, TOKEN_PROGRAM_ID
            );
            const recipientTokenAccount = await getAssociatedTokenAddress(
                USDC_MINT_ADDRESS, recipientPublicKey, false, TOKEN_PROGRAM_ID
            );

            if (!senderTokenAccount || !recipientTokenAccount) {
                console.error("❌ Error fetching token accounts!");
                alert("⚠️ Error retrieving token accounts.");
                return;
            }

            console.log("✅ Sender USDC Token Account:", senderTokenAccount.toBase58());
            console.log("✅ Recipient USDC Token Account:", recipientTokenAccount.toBase58());

            // ✅ Ensure sender has a USDC token account
            try {
                console.log("🔍 Checking sender's USDC token account...");
                await getAccount(connection, senderTokenAccount);
                console.log("✅ Sender USDC token account exists.");
            } catch (error) {
                console.error("❌ Sender does not have a USDC token account!");
                alert("⚠️ Your wallet doesn't have a USDC account. Please receive some USDC first.");
                return;
            }

            // ✅ Check if recipient's ATA exists
            console.log("🔍 Checking recipient's USDC token account...");
            const recipientATAInfo = await connection.getAccountInfo(recipientTokenAccount);
            const transaction = new Transaction();

            if (!recipientATAInfo) {
                console.log("⚠️ Recipient does not have a USDC ATA. Creating one...");
                transaction.add(
                    createAssociatedTokenAccountInstruction(
                        senderPublicKey,
                        recipientTokenAccount,
                        recipientPublicKey,
                        USDC_MINT_ADDRESS,
                        TOKEN_PROGRAM_ID
                    )
                );
                console.log("✅ Recipient USDC ATA Created.");
            } else {
                console.log("✅ Recipient already has a USDC ATA.");
            }

            // ✅ Convert amount to smallest unit & use BigInt
            const amountInSmallestUnit = BigInt(Math.round(amount * 1e6));

            // ✅ Add transfer instruction
            console.log(`🔹 Adding transfer instruction: ${amount} USDC`);
            transaction.add(
                createTransferInstruction(
                    senderTokenAccount,
                    recipientTokenAccount,
                    senderPublicKey,
                    amountInSmallestUnit,
                    [],
                    TOKEN_PROGRAM_ID
                )
            );

            console.log("✅ Transaction built, sending transaction...");

            // ✅ Send transaction
            const signature = await sendTransaction(transaction, connection);
            console.log("✅ USDC Transfer Successful! Signature:", signature);
            alert(`✅ Transfer successful! Transaction: ${signature}`);

        } catch (error) {
            console.error("❌ USDC Transfer Failed:", error);
            alert("❌ Transfer failed. Check console for details.");
        }
    };

    const handleTransfer = async () => {
        if (!publicKey) {
          alert("⚠️ Connect your wallet first!");
          return;
        }
        if (!recipient) {
          alert("⚠️ Recipient address not fetched!");
          return;
        }
      
        // ✅ Convert amount to number
        const numericAmount = parseFloat(amount);
      
        if (isNaN(numericAmount) || numericAmount <= 0) {
          alert("⚠️ Please enter a valid amount.");
          return;
        }
      
        console.log("🔹 Initiating transfer process...");
        try {
          await transferUSDC(recipient, numericAmount); // Pass number, not string
        } catch (error) {
          console.error(error);
        }
      };
      

    return (
        <div>
            <h2>USDC Transfer</h2>
            <p><strong>Recipient Wallet:</strong> {recipient || "Fetching..."}</p>
            <input
                type="number"
                placeholder="Amount (USDC)"
                value={amount}
                onChange={(e) => setAmount(e.target.value)} // Keep as string
            />

            <button onClick={handleTransfer}>Send USDC</button>
        </div>
    );
};

export default USDC;

问题原因与修复方案

核心问题:USDC Mint地址错误

你代码中使用的USDC_MINT_ADDRESS是无效的占位地址(11111111111111111111111111111111111111111111),这会导致所有基于该Mint的代币账户操作出现异常,最终触发Cannot read properties of undefined (reading 'from')错误。

Solana Devnet环境下的USDC官方Mint地址为:

const USDC_MINT_ADDRESS = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");

替换后重新测试,即可解决该错误。

针对你的疑问解答

  1. getAssociatedTokenAddress是否会返回undefined?
    不会。该函数只要参数合法(即使是无效的Mint地址),都会返回一个PublicKey实例。只有当参数类型错误时才会抛出异常,不会返回undefined。你代码中的判断if (!senderTokenAccount || !recipientTokenAccount)永远不会触发。

  2. 获取账户时是否需要显式指定程序ID?
    getAccount函数默认使用TOKEN_PROGRAM_ID,对于标准SPL代币(如USDC)无需显式指定。但如果是自定义代币程序,才需要传入第三个参数指定程序ID。

  3. createTransferInstruction是否存在已知问题?
    该函数本身没有已知问题,错误是由于你传入了基于无效Mint生成的代币账户地址,导致函数内部处理时出现未定义值访问。

额外优化建议

  • 使用useMemo缓存Connection实例,避免组件每次渲染都新建连接:
    const connection = useMemo(() => new Connection("https://api.devnet.solana.com"), []);
    
  • 发送交易时可以添加可选配置,提升可靠性:
    const signature = await sendTransaction(transaction, connection, {
      skipPreflight: false,
      preflightCommitment: "confirmed"
    });
    

内容的提问来源于stack exchange,提问作者Anurag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:22:04