CLOB v2 "invalid signature" 调试文档


Status: ✅ RESOLVED (2026-04-29)

问题


通过 web 界面挂单时,返回 HTTP 400:


{"error":"invalid signature"}

根因(3 个)


🔴 根因 1: eth_account 0.13.x 非标准 EIP-712 编码


eth_account 0.13.7 使用 \x01 作为 EIP-712 version byte,而非传统规范的 \x19\x01 前缀。

这导致签名的 digest hash 与 viem(npm 客户端使用的签名库)和 Polymarket 链上合约不一致。


修复: 降级到 eth_account==0.12.4,该版本使用标准 \x19\x01 前缀。


🔴 根因 2: Order timestamp 单位错误(秒 vs 毫秒)


npm v2 的 buildOrderCreationArgs 使用 Date.now()(毫秒,13位整数),

而 Python 使用 int(time.time())(Unix 秒,10位整数)。

这导致 EIP-712 签名中的 timestamp 字段值不同,签名哈希不匹配。


修复: 改为 int(time.time() * 1000)


🔴 根因 3: Verifying contract 使用 v1 地址


EIP-712 domain 的 verifyingContract 必须是 v2 交易所合约地址,

而非 v1 地址。不同的合约地址产生不同的 domain separator,导致签名无效。


类型v1 地址v2 地址
CTF Exchange0x4bFb41...0xE11118...
Neg Risk Exchange0xC5d563...0xe2222d...

修复: 添加 EXCHANGE_ADDRESS_V2NEG_RISK_EXCHANGE_ADDRESS_V2_get_verifying_contract() 返回 v2 地址。


修复验证


  • Before: HTTP 400 {"error":"invalid signature"}
  • After: HTTP 400 {"error":"not enough balance / allowance"} — 签名已验证通过

  • 额外改进


  • _l2_sign(): 添加服务器时间同步(GET /time),避免时钟偏差
  • _l2_sign(): 添加诊断日志(HMAC message、secret hex、signature 等)
  • 添加 get_clob_version() 方法(GET /version
  • get_orders() 端点确认为 /data/orders(npm v2 的 GET_OPEN_ORDERS

  • 排查过程中确认无问题的项