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

Solana脚本购买Magic Eden NFT报unknown signer错误排查

问题根因与修复方案

错误1:unknown signer 签名者不匹配

  • 代码存在基础拼写错误:定义密钥变量时写的是secret,调用Keypair.fromSecretKey时传入的是未定义的secrete(多了末尾的e),导致生成的签名者密钥对完全无效,和预期地址不一致。
  • 冗余硬编码费付地址:手动写死publickey变量作为feePayer,一旦硬编码地址和私钥实际派生的地址存在偏差,交易签名校验直接失败,正确做法是从加载好的Keypair对象上直接取publicKey属性,不需要手动定义。
  • 指令程序ID配置错误:构建TransactionInstruction时把programId填成了个人钱包地址,实际上该字段需要填Magic Eden交易程序的链上合约地址,填个人地址会导致指令找不到对应执行程序,节点校验直接抛出签名相关错误。
  • 账户列表生成逻辑错误:自行实现的账户生成逻辑已经过时,Magic Eden V2买币接口返回值中已经携带了完整的、顺序正确的账户元数据,自行生成的账户如果顺序不对、isSigner/isWritable标记错误,都会触发签名者不匹配报错。

错误2:助记词派生后触发verification error 校验失败

  • 助记词派生逻辑不符合Solana标准:直接截取bip39生成的64字节种子前32字节作为Keypair种子是以太坊的派生规则,Solana采用ed25519签名算法,必须使用标准派生路径m/44'/501'/0'/0'从64字节种子中派生出正确的32字节密钥种子,直接截断得到的密钥对和钱包助记词对应的地址完全不匹配,签名自然无效。
  • 交易缺失必要字段:构建交易时没有设置recentBlockhash(最近区块哈希),Solana要求所有交易必须绑定一个近期的区块哈希作为交易有效期标识,缺失该字段的交易直接会被节点拒绝。

修复步骤

  • 修正密钥加载逻辑:删除硬编码的钱包地址,修复拼写错误,从私钥/助记词正确加载Keypair后,直接从Keypair对象获取公钥作为费付地址。
  • 修正助记词派生逻辑:引入ed25519高清密钥派生库,使用Solana标准路径派生密钥对,不要直接截断bip39种子。
  • 修正交易构建逻辑:直接使用Magic Eden接口返回的programId、账户列表、指令数据,不要自行生成账户列表,构建交易时补上最近区块哈希字段。
  • 签名校验:传入sendAndConfirmTransaction的签名者数组,必须和交易指令中所有标记为isSigner=true的账户一一对应,普通买单场景仅需要传入当前买家的Keypair作为签名者。

可直接运行的参考实现

import fs from 'fs';
import { 
  Keypair, 
  Connection, 
  Transaction, 
  TransactionInstruction, 
  sendAndConfirmTransaction, 
  PublicKey 
} from '@solana/web3.js';
import * as bip39 from 'bip39';
import { derivePath } from 'ed25519-hd-key';

// 初始化RPC连接
const connection = new Connection("https://api.mainnet-beta.solana.com", 'confirmed');

/**
 * 从Solana CLI生成的id.json文件加载密钥对
 * @param idJsonPath id.json文件本地路径
 */
function loadKeypairFromFile(idJsonPath: string): Keypair {
  const secretKeyArray = JSON.parse(fs.readFileSync(idJsonPath, 'utf-8'));
  return Keypair.fromSecretKey(Uint8Array.from(secretKeyArray));
}

/**
 * 从助记词派生Solana标准密钥对
 * @param mnemonic 12/24位助记词
 */
function getKeypairFromMnemonic(mnemonic: string): Keypair {
  const seed = bip39.mnemonicToSeedSync(mnemonic);
  // Solana标准HD派生路径
  const derivedSeed = derivePath("m/44'/501'/0'/0'", seed.toString('hex')).key;
  return Keypair.fromSeed(derivedSeed);
}

/**
 * 执行Magic Eden NFT购买交易
 * @param buyResponse Magic Eden buy_now接口返回的原始响应
 * @param signer 买家签名密钥对
 */
async function executeBuyTx(buyResponse: any, signer: Keypair): Promise<string> {
  const tx = new Transaction();
  // 配置交易基础参数:费付者、最近区块哈希
  const latestBlock = await connection.getLatestBlockhash('confirmed');
  tx.feePayer = signer.publicKey;
  tx.recentBlockhash = latestBlock.blockhash;

  // 从接口响应直接解析指令数据
  const instructionData = Buffer.from(buyResponse.tx.data, 'hex');
  // 从接口响应直接解析账户列表,保持接口返回的顺序不要改动
  const accountMetas = buyResponse.tx.accounts.map((acc: any) => ({
    pubkey: new PublicKey(acc.pubkey),
    isSigner: acc.signer,
    isWritable: acc.writable
  }));
  // 从接口响应直接解析程序ID
  const programId = new PublicKey(buyResponse.tx.programId);

  tx.add(new TransactionInstruction({
    keys: accountMetas,
    programId,
    data: instructionData
  }));

  // 发送并确认交易
  const txSignature = await sendAndConfirmTransaction(
    connection, 
    tx, 
    [signer],
    { commitment: 'confirmed' }
  );
  console.log('交易发送成功,链上签名:', txSignature);
  return txSignature;
}

额外注意事项

  • 请求Magic Eden buy_now接口时,传入的buyer参数必须和当前使用的签名者公钥完全一致,否则接口返回的指令中买家地址不匹配,仍会触发签名错误。
  • 接口返回的账户列表顺序不可随意调整,Solana链上程序对指令账户的顺序有严格校验,顺序错误会导致程序执行失败。
  • 不要在主网直接运行未测试的代码,建议先在devnet环境调试通逻辑再切换主网,避免资产损失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 04:15:30