Polymarket CLOB V2 Migration Plan


Generated: 2026-04-29 | Target: Upgrade all Polymarket API calls to CLOB v2
Reference: @polymarket/clob-client-v2@1.0.2 (npm, TypeScript source)
Status: βœ… COMPLETE β€” Signature verified working



Overview


The project uses Polymarket's CLOB API across multiple modules. The v2 upgrade involves:


1. Order signing format (EIP-712 struct changed from 12 β†’ 11 fields)

2. Order wire format (API POST body format)

3. New/renamed endpoints (where applicable)

4. py_clob_client dependency version bump (in requirements.txt)




Current State


ComponentFileAPI Usage
CLOB Client (core)src/mm/clob_client.pyFull REST client: orders, orderbook, markets
Web Appsrc/web/app.pyDirect HTTP: /book, /tick-size, gamma-api, data-api, lb-api
Weather MM Runnersrc/mm/weather_mm_runner.pyDirect HTTP: /book, gamma-api events
Market Selectorsrc/mm/market_selector.pyVia CLOBClient
Paper Tradersrc/mm/paper_trader.pyVia CLOBClient
Configsrc/mm/config.pyDefines base URLs
Scraperssrc/scrapers/collector.pygamma-api, data-api, lb-api
Scraperssrc/scrapers/import_top.pylb-api, data-api
Scraperssrc/scrapers/reimport_trades.pydata-api



Migration Steps


Step 1: Clean up order wire format (clob_client.py)


File: src/mm/clob_client.py


The _sign_order_v2() method returns convenience fields price and size inside the signed order dict. These are NOT part of the CLOB v2 wire format (NewOrderV2 interface). They should be removed from the API payload to avoid potential issues.


v2 wire format (from @polymarket/clob-client-v2 NewOrderV2):


{
  "salt": int,
  "maker": "0x...",
  "signer": "0x...",
  "taker": "0x0000...",
  "tokenId": "123...",
  "makerAmount": "500000",
  "takerAmount": "500000",
  "side": "BUY",
  "signatureType": 0,
  "timestamp": "1714400000",
  "expiration": "0",
  "metadata": "0x0000...",
  "builder": "0x0000...",
  "signature": "0x..."
}

Changes needed in _sign_order_v2() return dict:

  • Remove price convenience field from returned dict
  • Remove size convenience field from returned dict
  • Keep price and size as separate attributes or log-only

  • Changes needed in create_order() and create_order_l1():

  • Extract price/size for logging before sending, or store in a separate variable
  • Ensure only valid fields go into the order payload

  • Step 2: Remove deprecated v1 EIP-712 struct references (clob_client.py)


    File: src/mm/clob_client.py


    The code already uses v2 EIP-712 order struct. Verify there are no remaining v1 references:

  • EIP712_ORDER_TYPES_V2 β€” correct βœ“
  • 11-field struct (salt, maker, signer, tokenId, makerAmount, takerAmount, side, signatureType, timestamp, metadata, builder) β€” correct βœ“
  • No nonce, feeRateBps in EIP-712 struct β€” correct βœ“

  • Double-check: The EIP-712 domain still uses 'version': '2' and 'name': 'Polymarket CTF Exchange' β€” these are correct per v2 spec.


    Step 3: Update CLOB REST endpoint paths (clob_client.py)


    File: src/mm/clob_client.py


    Compare current endpoints with v2 npm client:


    PurposeCurrent Pathv2 PathChange?
    List marketsGET /marketsGET /marketsNo
    Get marketGET /markets/{cid}GET /markets/{cid}No
    OrderbookGET /book?token_id=GET /book?token_id=No
    MidpointGET /midpoint?token_id=GET /midpoint?token_id=No
    PriceGET /price?token_id=&side=GET /price?token_id=&side=No
    SpreadGET /spread?token_id=GET /spread?token_id=No
    Last tradeGET /last-trade-price?token_id=GET /last-trade-price?token_id=No
    Tick sizeGET /tick-size?token_id=GET /tick-size?token_id=No
    Neg riskGET /neg-risk?token_id=GET /neg-risk?token_id=No
    Fee rateGET /fee-rate?token_id=GET /fee-rate?token_id=No
    VersionGET /versionGET /versionNo
    Place orderPOST /orderPOST /orderNo
    Cancel orderDELETE /orderDELETE /orderNo
    Cancel allDELETE /cancel-allDELETE /cancel-allNo
    Open ordersGET /data/ordersGET /ordersYES ⚠️
    Auth keysPOST /auth/api-keyPOST /auth/api-keyNo
    Derive keyGET /auth/derive-api-keyGET /auth/derive-api-keyNo

    Action: Change GET /data/orders β†’ GET /orders in get_orders() method.


    Step 4: Add v2 bulk endpoints (optional enhancement)


    The v2 client adds bulk endpoints for efficiency:


    New EndpointPurpose
    POST /booksBulk orderbook fetch
    POST /midpointsBulk midpoint fetch
    POST /pricesBulk price fetch
    POST /spreadsBulk spread fetch
    POST /last-trades-pricesBulk last trade price

    These are optional - existing single-token endpoints still work. The weather MM runner and market selector could benefit from bulk orderbook fetching when querying many tokens.


    Step 5: Update Gamma API usage (multi-file)


    Gamma API has no v1/v2 versioning β€” it's a separate REST API unchanged between CLOB versions. No changes needed.


    Files using Gamma API:

  • src/mm/clob_client.py β€” get_gamma_markets(), get_gamma_market() βœ“ no change
  • src/mm/weather_mm_runner.py β€” /events?slug= βœ“ no change
  • src/web/app.py β€” /events?slug= βœ“ no change
  • src/scrapers/collector.py β€” /markets βœ“ no change

  • Step 6: Update data-api usage (multi-file)


    data-api.polymarket.com has no v1/v2 versioning β€” it's the off-chain data service. No changes needed.


    Files using data-api:

  • src/web/app.py β€” /positions, /activity βœ“ no change
  • src/scrapers/reimport_trades.py β€” /activity βœ“ no change
  • src/scrapers/import_top.py β€” /positions, /activity βœ“ no change
  • src/scrapers/collector.py β€” /leaderboard, /positions, /trades, /activity βœ“ no change

  • Step 7: Update lb-api usage (multi-file)


    lb-api.polymarket.com has no v1/v2 versioning β€” it's the leaderboard API. No changes needed.


    Files using lb-api:

  • src/web/app.py β€” /profit βœ“ no change
  • src/scrapers/import_top.py β€” /profit βœ“ no change

  • Step 8: Update requirements.txt


    File: requirements.txt


    Bump py_clob_client to latest:

    
    - py_clob_client>=0.17
    + py_clob_client>=0.34.6
    

    Note: The project uses a custom CLOBClient implementation rather than the py_clob_client library. The version bump is for any indirect usage or future compatibility. The custom client already implements v2 signing and payload format.


    Step 9: Update proxy domain list (app.py)


    File: src/web/app.py, line ~90


    The proxy domain list already includes all current endpoints:

    
    _PROXY_DOMAINS = {
        'www.hko.gov.hk', 'data.weather.gov.hk', 'www.weather.gov.hk',
        'polymarket.com', 'gamma-api.polymarket.com', 'lb-api.polymarket.com',
        'data-api.polymarket.com', 'clob.polymarket.com',
    }
    

    No changes needed.


    Step 10: Verify L2 auth header format


    File: src/mm/clob_client.py, _l2_sign() method


    Compare with v2 npm client (createL2Headers):

  • POLY_ADDRESS βœ“
  • POLY_SIGNATURE (HMAC-SHA256, base64 url-safe) βœ“
  • POLY_TIMESTAMP βœ“
  • POLY_API_KEY βœ“
  • POLY_PASSPHRASE βœ“

  • No changes needed β€” L2 auth format is identical.




    Summary of Actual Changes Needed


    #FileChangeImpact
    1src/mm/clob_client.pyRemove price/size from order wire dictRequired
    2src/mm/clob_client.pyChange /data/orders β†’ /ordersRequired
    3requirements.txtBump py_clob_client>=0.34.6Recommended
    4src/mm/clob_client.pyAdd optional bulk endpointsOptional

    Everything else (EIP-712 v2 struct, L2 auth, Gamma API, data-api, lb-api) is already correct and needs no changes.




    Risk Assessment


  • Low risk: The v2 EIP-712 signing format is already implemented and working
  • Low risk: The order wire format cleanup removes non-standard fields
  • Medium risk: The /data/orders β†’ /orders endpoint change β€” needs testing
  • No risk: Gamma API, data-api, lb-api are version-independent

  • Testing Plan


    1. Call GET /version on clob.polymarket.com to confirm v2 is live

    2. Place a test order via create_order() and verify it appears in open orders

    3. Verify get_orders() returns correctly after endpoint change

    4. Run weather MM runner --scan to verify orderbook fetching works

    5. Check web dashboard loads without errors




    Execution Order


    The changes should be made in this order:

    1. requirements.txt β€” version bump (safe, no runtime impact)

    2. clob_client.py β€” remove price/size from wire format + fix endpoint path

    3. Test manually

    4. All other files confirmed no changes needed