Phantom钱包签名交易后调用web3.sendRawTransaction()报错
报错核心原因
这个报错本质是RPC节点收到广播的交易后签名校验不通过,常见诱发场景有四类:
- 序列化逻辑不兼容:
Transaction.serialize()方法默认强制校验所有签名位都存在有效签名,若交易包含Phantom之外的其他签名方(如PDA签名、服务端签名、多签账户未完成全部签名),无参调用序列化会生成格式非法的交易数据;另外本地@solana/web3.js版本和Phantom内置依赖的web3.js大版本不兼容时,会出现签名字段偏移,序列化后签名和交易内容不匹配。 - 交易基础参数无效:构造交易时未显式指定
feePayer为当前Phantom钱包地址,或签名用的recentBlockhash超过150个区块的有效期(约1分钟),或获取区块哈希的RPC节点和广播交易的RPC节点不属于同一个集群(如拿开发网哈希往主网节点广播)。 - 交易版本不匹配:构造的是V0版本化交易,却用传统Legacy交易的序列化、签名逻辑处理,或反之,会直接触发签名校验失败。
- 签名后交易被篡改:Phantom完成签名后,代码又修改了交易的指令列表、费支付者、区块哈希等字段,导致签名覆盖的交易内容和实际广播的内容不一致,签名直接失效。
排查步骤
按优先级从高到低排查:
- 校验交易基础配置:打印交易对象,确认
feePayer为当前已连接的Phantom钱包地址,recentBlockhash是发起签名前30秒内、从广播用的同一个RPC实例获取的,钱包和RPC连接的集群(主网/测试网/开发网)完全一致。 - 检查依赖版本:本地项目安装的
@solana/web3.js版本尽量使用1.9x稳定版,避免跨大版本(如使用0.x旧版本或2.x测试版)和Phantom出现兼容问题。 - 校验签名完整性:打印签名后交易的
signatures字段,确认Phantom钱包公钥对应的签名位不存在null、undefined空值。 - 确认交易类型:区分Legacy交易和V0版本化交易,两类交易的签名、序列化逻辑不能混用。
修复方案
根据业务场景调整代码:
- 单签名者(仅Phantom签名)Legacy交易场景,调整序列化和广播参数,兼容钱包返回的格式差异:
const signedTransaction = await window.solana.signTransaction(transaction); // 序列化时跳过强制全签名校验,同时开启本地签名合法性校验 const rawTransaction = signedTransaction.serialize({ requireAllSignatures: false, verifySignatures: true }); const signature = await connection.sendRawTransaction(rawTransaction, { preflightCommitment: 'confirmed', maxRetries: 3 }); await connection.confirmTransaction(signature, 'confirmed');
- V0版本化交易场景,使用版本交易对应的签名、序列化逻辑,不要复用Legacy交易的处理代码:
// 签名前再获取最新区块哈希,避免哈希过期 const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed'); // 构造V0交易消息 const txMessage = new TransactionMessage({ payerKey: wallet.publicKey, recentBlockhash: blockhash, instructions: [/* 你的交易指令数组 */] }).compileToV0Message(); const transaction = new VersionedTransaction(txMessage); // 调Phantom签名 const signedTransaction = await window.solana.signTransaction(transaction); const signature = await connection.sendRawTransaction(signedTransaction.serialize(), { preflightCommitment: 'confirmed' }); // 带区块高度确认交易,避免超时 await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, 'confirmed');
- 多签名者场景,提前把所有签名公钥加入交易签名位数组占位,按业务顺序完成所有签名后再广播,所有序列化步骤都传入
requireAllSignatures: false直到全部签名完成。 - 通用优化:签名前10秒内再获取最新区块哈希,不要提前缓存哈希重复使用;获取区块哈希和广播交易复用同一个connection实例,不要混用多个集群的RPC节点。
快速验证技巧:可以把序列化后的原始交易转成base64字符串,粘贴到Solana区块浏览器的广播页测试,如果浏览器广播也报签名错误,说明交易构造/签名本身有问题;如果浏览器广播成功,说明本地RPC连接配置存在问题。
内容的提问来源于stack exchange,提问作者Dhruvil Patel
相关产品推荐
相关产品推荐

