Documentation Index
Fetch the complete documentation index at: https://docs.polynode.dev/llms.txt
Use this file to discover all available pages before exploring further.
V2 cutover: April 28, 2026 at ~11am UTC. Polymarket announced the cutover date on April 18, 2026 (pushed from April 22 for extra builder testing time). The V2 test environment is open to all now at
clob-v2.polymarket.com. V2 mainnet contracts have been processing real trades since April 3, 2026. polynode is V2-ready today — set exchange_version: V2 in your SDK config to start placing V2 orders now, or keep V1 until cutover. After April 28, V1 orders will be rejected with order_version_mismatch.Before Cutover: Your Checklist
If you place orders on Polymarket, here’s exactly what to do before April 28:- Upgrade your SDK to the V2-ready version. Older versions won’t generate the correct V2 payload.
- Rust:
polynode >= 0.12.0. Install withcargo add polynode@0.12.0. - TypeScript:
polynode-sdk >= 0.9.0. Install withnpm install polynode-sdk@^0.9.0. - Python:
polynode >= 0.9.0. Install withpip install "polynode>=0.9.0".
- Rust:
- Flip the exchange version flag in your
TraderConfig. See The Switch below. This is the only code change required. - Mint a V2 builder code at polymarket.com/settings?tab=builder if you want attribution on your orders. Optional, orders still work without one.
- Cancel V1 resting orders you don’t want cleared at cutover. Open V1 orders get wiped when Polymarket flips the switch.
- Fund PolyUSD. V2 orders settle in PolyUSD (pUSD), not USDC.e. If your Safe holds USDC.e, call
trader.wrap_to_polyusd(amount)(Python) /trader.wrapToPolyUsd(amount)(TS) /trader.wrap_to_polyusd(amount)(Rust) to convert it via the Collateral Onramp.amountis in raw 6-decimal units (1_000_000= $1; TS takes abigint— use1_000_000n). Existing V1 pUSD balance carries over. - Test against V2 now. Point your SDK at V2 (step 2) and place a small order against
clob-v2.polymarket.com.ensure_ready/ensureReadysets the V2 approvals and refreshes the CLOB’s cached balance/allowance view for you. - Verify V2 confirmation. Your settlement stream tags V2 trades with
"exchange_version": "v2"on every event.
The Switch
V2 activation is one line in your SDK config. Flip it before April 28 and orders route through the V2 exchange automatically. Leave it as V1 and you keep working against V1 until cutover. After that, V1 orders will be rejected.- New contract addresses (V2 CTF Exchange + NegRisk A/B)
- New EIP-712 domain (version
"2", newverifyingContract) - New Order struct (adds
builder,metadata,timestamp; dropsnonce,feeRateBpsfrom the signed hash) - CLOB host swap to
clob-v2.polymarket.com - PolyUSD collateral wrapping via the Onramp contract
What We’ve Verified
Tested against live V2 contracts on Polygon mainnet:- V2 settlement decoding verified against real on-chain transactions
- V2 trade events (OrderFilled, OrdersMatched) decoded from block receipts
- PolyUSD wrapping and unwrapping tested and detected in real time
- V2 order placement tested live on the V2 CLOB
- Full order lifecycle verified: place, check status, cancel, re-place
- All existing market data, token IDs, and enrichment confirmed identical between V1 and V2
- Order hash verification: our EIP-712 order hash computation produces byte-for-byte identical results to the live V2 exchange contract’s
hashOrder()function on Polygon mainnet — cryptographic proof that our implementation is correct
V2 Contract Addresses
| Contract | Address |
|---|---|
| PolyUSD | 0xc011a7e12a19f7b1f670d46f03b03f3342e82dfb |
| Collateral Onramp | 0x93070a847efef7f70739046a929d47a521f5b8ee |
| Collateral Offramp | 0x2957922eb93258b93368531d39facca3b4dc5854 |
| CTFCollateralAdapter | 0xAdA100Db00Ca00073811820692005400218FcE1f |
| NegRiskCTFCollateralAdapter | 0xadA2005600Dec949baf300f4C6120000bDB6eAab |
| V2 CTF Exchange | 0xe111180000d2663c0091e4f400237545b87b996b |
| V2 NegRisk Exchange A | 0xe2222d279d744050d28e00520010520000310f59 |
| V2 NegRisk Exchange B | 0xe2222d002000ba0053cef3375333610f64600036 |
| ConditionalTokens (unchanged) | 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 |
How V2 Fits Together
The key architectural insight: V2 only changes the exchange layer (how orders are matched and settled). The token layer (ConditionalTokens) is completely unchanged and cannot be replaced.Why Token IDs Don’t Change
All prediction market positions live inside the ConditionalTokens contract. This is a Gnosis protocol contract that has been on Polygon since Polymarket launched. Every token ID is derived from a condition ID and outcome index inside this contract. V2 does not replace ConditionalTokens. It can’t. Doing so would invalidate every open position on the platform. Instead, V2 introduces an adapter layer between the new exchange contracts and the existing ConditionalTokens contract:- Same token IDs across V1 and V2
- Same condition IDs
- Same market metadata (Gamma API, enrichment)
- Positions opened on V1 are fully compatible with V2 and vice versa
New V2 Contracts
Five new contracts support the V2 architecture. These are all live on Polygon mainnet:| Contract | Role | Status |
|---|---|---|
| PolyUSD | Wrapped USDC.e (1:1, 6 decimals) | Deployed |
| Collateral Onramp | Wraps USDC.e → PolyUSD | Deployed |
| Collateral Offramp | Unwraps PolyUSD → USDC.e | Deployed |
| CTFCollateralAdapter | Bridges PolyUSD ↔ USDC.e for standard market settlements | Deployed |
| NegRiskCTFCollateralAdapter | Bridges PolyUSD ↔ USDC.e for multi-outcome market settlements | Deployed |
| V2 CTF Exchange | New order matching for standard markets | Deployed |
| V2 NegRisk Exchange A | New order matching for multi-outcome markets | Deployed |
| V2 NegRisk Exchange B | Additional multi-outcome capacity | Deployed |
What’s New in V2
PolyUSD Collateral — V2 uses PolyUSD instead of USDC.e as the exchange collateral. PolyUSD is a 1:1 wrapper around USDC.e with 6 decimals. See the PolyUSD Guide for details on wrapping and unwrapping. Updated Order Struct — The EIP-712 signed hash drops two fields (nonce, feeRateBps) and adds three (timestamp, metadata, builder). The HTTP POST body still carries expiration (defaulted to "0" for no expiration). The polynode SDK handles all of this automatically.
The dropped feeRateBps field was Polymarket’s protocol fee slot inside the V1 order. V2 doesn’t have a per-order protocol fee slot — Polymarket’s fee model moves to a CLOB-level config plus the builder bytes32 rev share. The polynode Fee Escrow is unaffected by this change: it was never connected to the feeRateBps field. Our fee is pulled via a separate signed authorization (FeeAuth under our own EIP-712 domain) and only moves collateral. See the Fee Escrow Guide for the V2-native FeeEscrow contract address and the three-fee breakdown.
EIP-712 Domain — The signing domain version changed from "1" to "2". The SDK handles this based on your exchange version config.
No More Settlement Routers — V1 used FeeModule router contracts between operators and the exchange. V2 eliminates routers. Operators call the exchange contracts directly.
exchange_version Field — V2 trades include "exchange_version": "v2" on each trade object in settlement and trade events. V1 trades omit this field. Use it to distinguish which exchange system processed a settlement.
What Didn’t Change
- ConditionalTokens contract — same address, same position system, same token IDs
- Market data — same condition IDs, same Gamma metadata, same enrichment pipeline
- Authentication — same API key derivation, same HMAC headers
- WebSocket subscriptions — same event types, same format
- Position splits/merges/conversions — same ConditionalTokens events
- Oracle system — unchanged UMA adapters and resolution flow
- Orderbook streaming — same WebSocket protocol and message format
Impact on polynode Users
Settlement Stream
No changes required. V2 settlements produce the same event types you already receive:settlement— early detection (3-5 seconds pre-confirmation)status_update— block confirmation with latency measurementtrade— confirmed trade from OrderFilled eventdeposit— now includes PolyUSD wrapping/unwrapping alongside USDC.e
Trading SDK
The polynode SDK supports V2 with a single config change:The SDK handles all V2 differences internally: order struct, EIP-712 signing, CLOB endpoint routing, and PolyUSD collateral. You don’t need to change how you construct orders or manage positions.
Builder Attribution in V2
V2 moves builder attribution from HTTP headers into the signed order struct itself as abytes32 field. To attribute trades to your own builder profile, mint a builder code in Polymarket’s settings and pass it to the SDK on each order.
Step 1: Mint your V2 builder code. Visit polymarket.com/settings?tab=builder with your connected wallet, create a builder profile, and copy the generated bytes32 code.
Step 2: Pass it on each order. All three polynode SDKs accept a builder field on the order params. If you don’t pass one, orders sign with 0x0000...0000 (no attribution).
builder_credentials (HMAC key/secret/passphrase) are unrelated to the V2 builder bytes32. The HMAC credentials are still used to query builder trade history at /builder/trades. The V2 bytes32 is what attributes newly-placed orders on-chain.
Pre-Migration V1 Orders
Open V1 orders resting at cutover get cleared from V1 orderbooks. Polymarket exposesGET /data/pre-migration-orders on the V2 CLOB for fetching your pre-cutover V1 order history. Cancel V1 resting orders before April 28 if you need the capital free for V2 trading.
Common V2 Errors
If something goes wrong during migration, these are the ones you’ll hit.order_version_mismatch
Your SDK sent a V1-formatted order but the V2 CLOB expected V2. Flip exchange_version: V2 in your config.
not enough balance / allowance
Most common causes, in order:
- Your wallet has USDC.e but not PolyUSD. V2 uses PolyUSD as the collateral token. Call
trader.wrap_to_polyusd(amount_raw)(Python/Rust) ortrader.wrapToPolyUsd(amount_raw)(TS) to convert. Amounts are raw 6-decimal integers. - Approvals not yet visible to the CLOB. The V2 CLOB caches per-API-key balance + allowance state.
ensureReady/ensure_readyrefreshes this cache after setting approvals; if you changed approvals outside that flow, calltrader.refreshBalanceAllowance()/trader.refresh_balance_allowance()manually. - Order notional + fee exceeds balance. V2 markets charge a fee (~2–5% of notional depending on
base_fee). For a BUY,balance >= makerAmount + platformFeemust hold or the CLOB rejects.
error parsing fee rate bps () to int64
Your SDK is too old and isn’t sending the V2 payload correctly. Upgrade to the V2-ready version listed in the checklist above.
Rust-specific: not enough balance / allowance even though you have PolyUSD
If you call link_wallet(signer, None) with an EOA wallet, the SDK silently uses the config’s default signature type (POLY_GNOSIS_SAFE) and derives a Safe address as the maker. That Safe has zero balance, so the CLOB rejects the order. For EOA wallets, pass explicit opts:
Timeline
- Now: V2 test environment live at
clob-v2.polymarket.com. V2 contracts live on Polygon mainnet processing real trades. polynode settlement stream tags V2 trades withexchange_version: "v2". - Before April 28: Flip your SDK config to
exchange_version: V2(or keep V1 until cutover). Mint a builder code if you want attribution. Cancel V1 resting orders you don’t want cleared. - April 28, ~11am UTC: Polymarket cutover. V2 becomes the primary exchange. V1 orderbooks cleared.
- After cutover: Any integration still on V1 will fail with
order_version_mismatch. Flip your config.

