Skip to content

feat(signing): migrate order signing to CLOB V2/V3#28

Merged
danielgnh merged 8 commits into
mainfrom
feat/clob-v2-migration
Jul 12, 2026
Merged

feat(signing): migrate order signing to CLOB V2/V3#28
danielgnh merged 8 commits into
mainfrom
feat/clob-v2-migration

Conversation

@danielgnh

Copy link
Copy Markdown
Member

Why

Polymarket cut production over to CLOB V2 on 2026-04-28 (see the official changelog): new Exchange contracts, a new 11-field EIP-712 order struct, domain version "2", and no backward compatibility — V1-signed orders are rejected. This PR migrates the signing path so Orders::post() works on production again. It also supports the Exchange V3 domain already rolling out (same struct, domain version "3", resolvable via GET /version).

All struct fields, domain values, and contract addresses were verified against the official py-clob-client-v2 and clob-client-v2 sources.

What

  • OrderPayloadV2 — V2/V3 EIP-712 order struct (timestamp, metadata, builder added; taker/expiration/nonce/feeRateBps removed from the signed struct), domain version matching the order version, and contract auto-selection: V2 0xE111…996B, V2 neg-risk 0xe222…0F59, V3 per chain. OrderPayload (V1) is kept but deprecated.
  • Orders::post() — signs and sends the V2 wire format (salt as int, side as string, expiration JSON-only defaulting to "0"), with new negRisk, version, and postOnly options and official defaults (millisecond timestamp, zero-bytes32 metadata/builder, random salt).
  • SignatureType — canonical values: EOA=0, POLY_PROXY=1, POLY_GNOSIS_SAFE=2, POLY_1271=3. POLY_1271 signing (nested Solady TypedDataSign flow) is out of scope and throws a clear SigningException.
  • Server::getVersion() — exposes GET /version so callers can resolve the active order version like the official client (defaults to 2). No hidden HTTP calls in post().
  • ClobAuth (L1) is untouched — it stays at domain version "1" per the official docs.

Testing

Developed test-first. The key evidence is four golden-signature tests: reference signatures were generated with eth-account (the library the official Python SDK signs with) for the official test fixture, and our signer reproduces them byte-for-byte across V2 standard, V2 neg-risk, and V3 domains on Polygon and Amoy. Full suite: 282 tests / 656 assertions, PHPStan clean.

Relationship to #27

This branch is based on #27 and includes its commits — it upgrades the V1 signing path introduced there to V2. Recommended order: merge #27 first, after which this PR reduces to the two migration commits (cc4eae1 design spec, 5f9cf9c implementation).

Design doc: docs/superpowers/specs/2026-07-11-clob-v2-order-signing-design.md

🤖 Generated with Claude Code

venturarome and others added 8 commits April 10, 2026 18:05
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Polymarket cut production over to CLOB V2 on 2026-04-28; V1-signed
orders are rejected. Sign the 11-field V2 order struct (timestamp,
metadata, builder; taker/expiration/nonce/feeRateBps removed) against
the V2/V3 exchange contracts with a matching domain version.

- OrderPayloadV2: V2/V3 domains, neg-risk and per-chain contract
  selection, version validation; OrderPayload deprecated
- SignatureType: canonical values incl. POLY_1271 (signing deferred)
- Orders::post(): V2 wire format with postOnly, negRisk and version
  options; salt/timestamp/metadata/builder defaults
- Server::getVersion(): expose GET /version for order-version resolution
- Golden-value tests pinned against eth-account reference signatures

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… guard

Rector CI resolves the latest rector (no committed composer.lock) and
2.4+ ships NegatedAndsToPositiveOrsRector, which flags the negated-and
type guard added in the sign-orders work. Equivalent De Morgan form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@danielgnh
danielgnh merged commit 0ab747b into main Jul 12, 2026
4 checks passed
@danielgnh
danielgnh deleted the feat/clob-v2-migration branch July 12, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants