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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 17:36:02