使用0x.js API签名订单时遇Invalid signature问题求助(Ropsten测试网)
排查ZeroEx订单签名Invalid Signature错误的思路
我来帮你梳理这个签名失败的问题,结合你用的Ropsten测试网、ZeroEx API和@0xproject/connect工具,Invalid Signature错误基本都和订单格式、签名方法、网络配置这几个核心环节有关,咱们一步步排查:
1. 先检查订单对象的完整性与格式
ZeroEx的订单有严格的字段规范,缺字段或者格式不对会直接导致签名无效:
- 你给出的代码里
makerTokenAmount的BigNumber没写完,要确认所有数值字段都是代币最小单位的准确值(比如ERC20代币通常是18位小数,1个代币对应1e18) - 必须包含所有必填字段,不能遗漏:
salt:随机数,用来防止订单重复,建议用new BigNumber(Math.floor(Math.random() * 1e18))生成exchangeAddress:Ropsten网络对应的ZeroEx交易所地址(不同版本地址不同,比如v3版本是0x4f833a24e1f95d70f028921e27040ca56e09ab0b,要和你用的API版本匹配)expirationTimeSeconds:订单过期时间戳,必须是未来的有效时间feeRecipientAddress、makerFee、takerFee:如果没有手续费需求,可设为0地址和0值
示例完整的订单结构:
const order = { maker: web3.eth.accounts[0], taker: "0x0000000000000000000000000000000000000000", makerTokenAddress: "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d", takerTokenAddress: "0xc778417e063141139fce010982780140aa0cd5ab", makerTokenAmount: new BigNumber("1000000000000000000"), // 1个代币(假设18位小数) takerTokenAmount: new BigNumber("2000000000000000000"), salt: new BigNumber(Math.floor(Math.random() * 1e18)), exchangeAddress: "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", expirationTimeSeconds: new BigNumber(Math.floor(Date.now() / 1000) + 86400), // 24小时后过期 feeRecipientAddress: "0x0000000000000000000000000000000000000000", makerFee: new BigNumber(0), takerFee: new BigNumber(0) };
2. 确认签名方法的正确性
ZeroEx的签名是基于EIP-712规范的,绝对不要手动构造签名数据,一定要用官方工具生成:
- 初始化ZeroEx合约包装器时,必须指定Ropsten的networkId(3):
import { ZeroEx } from '@0x/contract-wrappers'; const zeroEx = new ZeroEx(web3.currentProvider, { networkId: 3 }); // 3对应Ropsten - 用官方方法签名订单,比如通过钱包连接器:
const signedOrder = await zeroEx.signOrderAsync(order, web3.eth.accounts[0]); - 如果用MetaMask等钱包签名,要确保当前钱包连接的是Ropsten网络,且活跃地址就是订单里的
maker地址。
3. 检查网络与合约地址的匹配性
- 确认
exchangeAddress是Ropsten网络的正确地址,不同ZeroEx版本(v2/v3/v4)的交易所地址不同,错用主网地址会直接导致签名无效 - 确保你的API调用目标
https://api.openrelay.xyz/v0对应的是Ropsten网络(OpenRelay的v0 API确实支持Ropsten,但要确认没有配置错误)
4. 用调试工具定位具体问题
ZeroEx提供了验证方法,可以帮你找出更具体的错误:
// 验证订单可填充性,会抛出详细错误信息 try { await zeroEx.validateOrderFillabilityOrThrowAsync(signedOrder); } catch (err) { console.error('订单验证失败:', err.message); }
另外可以打印出完整的signedOrder对象,检查signature字段是否是带0x前缀的合法十六进制字符串,长度是否符合要求。
5. 钱包与地址权限检查
- 确认
web3.eth.accounts[0]确实是你要签名的maker地址,且该地址在Ropsten网络上(如果用本地私钥签名,要确保私钥没有写错) - 如果用MetaMask,要确保钱包已解锁,且授权了你的应用访问地址
如果还是解决不了,可以把完整的订单对象和签名代码贴出来(注意不要泄露私钥),这样能更精准定位问题。
内容的提问来源于stack exchange,提问作者Md. Mahbubul Haque




