Solana如何使用JavaScript通过钱包向其他地址转账NFT(SPL Token)
Solana NFT存入功能完整实现方案
前置依赖检查
确保安装了所有必需的包,很多基础转账报错都是缺包或者版本不兼容导致:
npm install @solana/web3.js @solana/spl-token @solana/wallet-adapter-react @solana/wallet-adapter-wallets @project-serum/anchor
步骤1:钱包连接与用户NFT列表拉取
使用标准钱包适配器实现钱包连接,不要自行手写私钥读取或者钱包唤起逻辑,避免权限问题:
- 先在项目顶层配置WalletProvider,接入Phantom、Solflare等主流钱包
- 钱包连接成功后,调用链上接口拉取用户持有的NFT:
import { TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { Connection, PublicKey } from "@solana/web3.js"; const RPC_URL = "你的RPC节点地址,可对应配置为测试网或者主网地址"; const connection = new Connection(RPC_URL, "confirmed"); // 拉取用户所有SPL代币账户,过滤出NFT const fetchUserNFTs = async (userWalletAddress) => { const userPubkey = new PublicKey(userWalletAddress); const tokenAccounts = await connection.getParsedProgramAccounts( TOKEN_PROGRAM_ID, { filters: [ { dataSize: 165 }, // SPL代币账户固定大小 { memcmp: { offset: 32, // owner字段在账户数据中的偏移量 bytes: userPubkey.toBase58(), }, }, ], } ); // 过滤出符合NFT特征的代币:余额为1,小数位为0 return tokenAccounts.filter(({ account }) => { const parsedInfo = account.data.parsed.info; return parsedInfo.tokenAmount.amount === "1" && parsedInfo.tokenAmount.decimals === 0; }).map(item => ({ mint: item.account.data.parsed.info.mint, tokenAccount: item.pubkey.toBase58(), })); }
步骤2:NFT转账到网站地址核心逻辑
这一步最常见的报错是未提前创建接收方的关联代币账户(ATA),转账前必须先校验:
import { getAssociatedTokenAddress, createTransferInstruction, createAssociatedTokenAccountInstruction } from "@solana/spl-token"; import { Transaction } from "@solana/web3.js"; // 替换为你的网站关联链上账户地址 const RECEIVER_WALLET = new PublicKey("你的网站接收钱包地址"); const transferNFT = async (userWallet, nftMintAddress, userNFTTokenAccount) => { const mintPubkey = new PublicKey(nftMintAddress); const userTokenAccountPubkey = new PublicKey(userNFTTokenAccount); // 1. 查找接收方的ATA地址 const receiverATA = await getAssociatedTokenAddress( mintPubkey, RECEIVER_WALLET, false ); // 2. 检查接收方ATA是否存在,不存在则先创建 const transaction = new Transaction(); const receiverAccount = await connection.getAccountInfo(receiverATA); if (!receiverAccount) { transaction.add( createAssociatedTokenAccountInstruction( userWallet.publicKey, // 支付创建账户的手续费 receiverATA, RECEIVER_WALLET, mintPubkey ) ); } // 3. 添加转账指令 transaction.add( createTransferInstruction( userTokenAccountPubkey, // 发送方的NFT代币账户 receiverATA, // 接收方的NFT代币账户 userWallet.publicKey, // 发送方owner 1, // NFT转账金额固定为1 [] ) ); // 4. 设置交易必要参数 transaction.feePayer = userWallet.publicKey; const latestBlockhash = await connection.getLatestBlockhash(); transaction.recentBlockhash = latestBlockhash.blockhash; // 5. 唤起钱包签名并发送交易 const signedTx = await userWallet.signTransaction(transaction); const txHash = await connection.sendRawTransaction(signedTx.serialize()); await connection.confirmTransaction(txHash, "confirmed"); return txHash; }
步骤3:前端按钮触发逻辑
直接在React组件里绑定点击事件即可:
import { useWallet } from "@solana/wallet-adapter-react"; const NFTDepositButton = () => { const { connected, wallet, publicKey } = useWallet(); const handleDeposit = async () => { if (!connected || !publicKey) return alert("请先连接钱包"); // 1. 拉取用户NFT列表,弹窗让用户选择 const nftList = await fetchUserNFTs(publicKey); if (nftList.length === 0) return alert("你没有可存入的NFT"); // 此处可自行实现选择弹窗,示例默认选第一个NFT const selectedNFT = nftList[0]; // 2. 执行转账 try { const txHash = await transferNFT(wallet.adapter, selectedNFT.mint, selectedNFT.tokenAccount); alert(`存入成功,交易哈希:${txHash}`); } catch (e) { console.error("转账失败:", e); alert("存入失败,请重试"); } } return <button onClick={handleDeposit}>存入NFT</button> }
常见问题排查
- 转账无响应:检查钱包适配器是否正确配置,确保wallet.adapter暴露了
signTransaction方法 - 交易执行失败:检查RPC节点是否正常,接收方地址是否正确,网络(主网/测试网)是否匹配
- 拉取不到NFT:检查过滤器配置是否正确,用户钱包地址是否传对,RPC节点是否开启账户索引服务
内容的提问来源于stack exchange,提问作者Qeest
相关产品推荐
相关产品推荐

