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

如何获取Solana Candy Machine铸造的SPL Token并为元数据签名

功能实现完整方案

前置依赖

确保你已经安装了以下依赖包:

  • @solana/web3.js
  • @metaplex-foundation/mpl-token-metadata
  • bs58(可选,用于私钥解码)

代码修正与补全说明

你原有代码的问题是查询对象错误:你当前调用了Candy Machine程序的getProgramAccounts接口,实际需要查询Metaplex Token元数据程序的账户,过滤条件为「第一个创作者地址为你的Candy Machine地址」,对应就是所有该CM铸造的NFT元数据。

完整可运行代码如下:

import { Connection, Keypair, PublicKey, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
import { createSignMetadataInstruction, Metadata, PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
import bs58 from "bs58";

// --------------- 替换为你自己的配置 ---------------
const RPC_URL = "你的RPC节点地址";
const CANDY_MACHINE_ADDRESS = new PublicKey("你的Candy Machine地址");
const CREATOR_PRIVATE_KEY = bs58.decode("你的创作者账户私钥base58字符串");
const creatorKeypair = Keypair.fromSecretKey(CREATOR_PRIVATE_KEY);
const BATCH_SIZE = 15; // 每批处理的NFT数量,避免交易过大/超时
// -------------------------------------------------

const connection = new Connection(RPC_URL, "confirmed");

async function getCMNFTMetadataList(): Promise<PublicKey[]> {
  // 元数据账户中第一个creator地址的偏移量:固定为249
  const creatorOffset = 249;
  const filters = [
    {
      memcmp: {
        offset: creatorOffset,
        bytes: CANDY_MACHINE_ADDRESS.toBase58(),
      },
    },
    // 可选过滤:只返回数据长度符合标准NFT元数据的账户,减少无效数据
    { dataSize: 679 },
  ];

  const accounts = await connection.getProgramAccounts(TOKEN_METADATA_PROGRAM_ID, {
    commitment: "confirmed",
    filters,
  });

  // 提取所有元数据地址
  return accounts.map(acc => acc.pubkey);
}

async function batchSignMetadata(metadataList: PublicKey[]) {
  const total = metadataList.length;
  console.log(`共找到${total}个该Candy Machine铸造的NFT,开始分批签名`);

  for (let i = 0; i < total; i += BATCH_SIZE) {
    const batch = metadataList.slice(i, i + BATCH_SIZE);
    const tx = new Transaction();

    for (const metadataAddr of batch) {
      // 先查询元数据,确认你是未签名的创作者,避免重复签名
      const metadata = await Metadata.fromAccountAddress(connection, metadataAddr);
      const selfCreator = metadata.data.creators?.find(c => c.address.equals(creatorKeypair.publicKey));
      
      // 已经签名过的跳过
      if (!selfCreator || selfCreator.verified) continue;

      // 添加签名指令
      tx.add(
        createSignMetadataInstruction({
          metadata: metadataAddr,
          creator: creatorKeypair.publicKey,
        })
      );
    }

    // 空批次跳过
    if (tx.instructions.length === 0) {
      console.log(`批次${Math.ceil(i/BATCH_SIZE)+1}无待签名NFT,跳过`);
      continue;
    }

    // 发送交易
    const txSig = await sendAndConfirmTransaction(connection, tx, [creatorKeypair]);
    console.log(`批次${Math.ceil(i/BATCH_SIZE)+1}签名完成,交易哈希:${txSig}`);
    
    // 加延迟避免RPC限流
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
  console.log("所有NFT签名处理完成");
}

// 执行逻辑
async function main() {
  const metadataList = await getCMNFTMetadataList();
  await batchSignMetadata(metadataList);
}

main().catch(console.error);

注意事项

  • 建议先注释掉交易发送逻辑,先打印待签名的元数据地址,确认数量和地址正确后再实际执行签名,避免误操作
  • 如果NFT数量超过1000个,建议使用带索引的RPC节点,否则getProgramAccounts可能会超时
  • 不要使用公共RPC节点处理大批量任务,容易被限流导致执行失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 07:18:04