Solana调用Magic Eden购买NFT报Signature verification error
问题原因
Signature Verification failed错误本质是链上/节点预校验时,交易携带的签名和交易内容、要求的签名公钥不匹配,结合给出的代码,具体诱因按出现概率从高到低排序:
- 签名身份不匹配:代码里传入接口的
buyer是this.WalletAddress,但实际签名用的Keypair是从Array_key生成的,只要这两个地址不是完全一致,交易要求的买家签名和实际提供的签名公钥对不上,直接报错。 - 交易还原逻辑缺失:Magic Eden返回的
tx.data是base64编码的序列化交易消息,直接反序列化populate之后,没有设置正确的feePayer,也没有替换最新的链上区块哈希。一方面旧区块哈希可能已经过期,另一方面交易的签名内容是包含recentBlockhash和feePayer的,这两个值不对,本地签出来的签名和节点要校验的内容哈希完全对不上。 - 签名顺序不匹配:Solana交易验签严格按照
accountKeys数组的顺序匹配签名,直接把signers数组传入发送方法,没有让交易对象自身完成签名对齐的话,很容易出现签名位置错位。 - 私钥格式错误:如果
Array_key不是标准64位Solana私钥字节数组(比如只传了32位seed、字节顺序颠倒、数组缺项),生成的Keypair本身身份错误,签名自然无效。
修复步骤
按顺序做以下调整即可解决:
- 加身份强校验,从根源避免地址不匹配问题
// 校验签名私钥对应的地址和传入的买家地址完全一致 const signerAddress = signers.publicKey.toBase58(); if (signerAddress !== this.WalletAddress) { throw new Error(`签名地址不匹配,私钥对应地址:${signerAddress},传入买家地址:${this.WalletAddress}`); }
- 修正交易还原逻辑,补全交易必要字段
注意反序列化的时候要把返回的data按base64转成Buffer,不要直接传字符串:
// 正确反序列化交易 const tx = Transaction.populate( Message.from(Buffer.from(parsed_buy_response.tx.data, 'base64')) ); // 设置手续费支付方为当前签名者 tx.feePayer = signers.publicKey; // 拉取最新区块信息,替换交易内可能过期的旧值 const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed'); tx.recentBlockhash = blockhash; tx.lastValidBlockHeight = lastValidBlockHeight;
- 对齐签名顺序后再发送交易
不要跳过交易对象的签名步骤直接发送,让交易自身完成签名位置匹配:
// 完成签名,自动匹配签名位置 tx.sign(signers); // 发送并确认交易,加明确的commitment参数 const txSignature = await sendAndConfirmTransaction( connection, tx, [signers], { commitment: 'confirmed', preflightCommitment: 'confirmed' } ); console.log('交易发送成功,链上交易签名:', txSignature);
- 私钥格式校验
确认Array_key是长度为64的数字数组,对应Solana完整私钥格式,打印生成的signer地址和自己的钱包地址做比对,完全一致再执行后续逻辑。
注意:反序列化后的交易不要随意增删、修改指令内容,Magic Eden返回的交易已经包含了拍卖屋合约、卖家相关的预设签名,改动指令会破坏已有签名,同样会触发验签失败。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

