如何修复合约调用中的Invalid Signature错误及生成正确签名
解决方案:生成正确签名修复Invalid Signature错误
错误原因
你的签名生成逻辑和合约验证逻辑不匹配,核心差异有两点:
- 参数打包方式不一致:合约用
abi.encodePacked紧凑打包参数后哈希,而你用solidityKeccak256结合类型数组的方式,本质是基于abi.encode(带内存对齐的打包)生成哈希,两者结果完全不同。 - 缺少以太坊签名前缀:合约通过
ECDSA.toEthSignedMessageHash给原始哈希添加了以太坊标准签名前缀(\x19Ethereum Signed Message:\n32),但你的代码直接签名了原始哈希,未添加该前缀。
修正后的代码
替换原签名生成部分的逻辑即可,以下是完整修正后的lending函数:
const lending = async () => { const id = 992581; const tokenId = 16587857756452; const price = 500000000000; const expiredAt = Date.now() + 60; // 1. 对应合约的abi.encodePacked,紧凑打包参数 const packedParams = ethers.utils.solidityPack( ["uint256", "uint256", "uint256", "uint256"], [id, tokenId, price, expiredAt] ); // 2. 计算打包后的原始哈希 const criteriaMessageHash = ethers.utils.keccak256(packedParams); // 3. 用signer直接签名,自动处理以太坊签名前缀,和合约逻辑匹配 const signatureString = await signer.signMessage(ethers.utils.arrayify(criteriaMessageHash)); const tx = await contract.lending( id, tokenId, price, expiredAt, signatureString, { gasLimit: 500000, // 建议提高gasLimit,避免因gas不足交易失败 } ); const receipt = await tx.wait(); console.log(receipt); };
额外注意事项
- 确保
privateKey对应的地址,和合约中signer变量指定的地址完全一致,否则签名验证必然失败。 - 原代码中
gasLimit设为50000过低,BSC链上合约调用通常需要更高的gas,调整为500000可有效避免gas不足问题。
内容的提问来源于stack exchange,提问作者junis087678
相关产品推荐
相关产品推荐

