使用@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已正确导入。
疑问
getAssociatedTokenAddress是否会在某些条件下返回undefined?- 获取账户时是否需要显式指定程序ID?
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");
替换后重新测试,即可解决该错误。
针对你的疑问解答
getAssociatedTokenAddress是否会返回undefined?
不会。该函数只要参数合法(即使是无效的Mint地址),都会返回一个PublicKey实例。只有当参数类型错误时才会抛出异常,不会返回undefined。你代码中的判断if (!senderTokenAccount || !recipientTokenAccount)永远不会触发。获取账户时是否需要显式指定程序ID?
getAccount函数默认使用TOKEN_PROGRAM_ID,对于标准SPL代币(如USDC)无需显式指定。但如果是自定义代币程序,才需要传入第三个参数指定程序ID。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
相关产品推荐
相关产品推荐

