Polymarket Protocol Versions: V1, V2, V3 and What Trading Bots Need to Know
Polymarket version numbers are getting harder to talk about casually. You can see: V1 V2 V3 PolyV2 and assume there is one protocol that simply moved from version 1 to version 2 and then version 3. That is not how the current stack is organized. There are different versions for different parts of the system: Exchange Order signing Position protocol Market metadata Data APIs SDK packages That distinction matters when you maintain a trading bot. A package upgrade might be trivial. A protocol change can affect: Contracts Collateral Order structure EIP-712 signing Asset identifiers Execution Settlement State reconciliation The April 2026 Polymarket exchange upgrade was a coordinated change to the smart contracts, order-book system, and collateral layer. Polymarket describes the upgrade as moving to CTF Exchange V2 and pUSD, with changes to order structure, matching, fees, and order management. Since then, the protocol surface has continued to evolve. The current official clients now distinguish token-backed V1/V2 flows from PolyV2 position-backed V3 flows. For someone maintaining a Polymarket trading system, that means protocol compatibility needs to be treated as part of the infrastructure. There is no single Polymarket "version" This is the first thing worth getting straight. A useful mental model is: Polymarket │ ├── Exchange protocol │ ├── Order signing │ ├── Position protocol │ ├── Market metadata │ ├── Data services │ └── SDK packages Those layers can evolve independently. For example, the current official Rust CLOB client documents: V1 V2 V3 as protocol variants for order construction. Its README describes V1 as the legacy CTF-token path, V2 as the current CTF-token exchange path, and V3 as the Exchange V3 path used for Polymarket V2 positions. That is very different from saying: API version = 3 There is no reason to add /v3 to every Polymarket endpoint just because Exchange V3 exists. The versions belong to different layers. CLOB / Exchange V2 is a real protocol change The April 28, 2026 upgrade was not just a new SDK release. Polymarket changed the exchange stack itself. The official migration announcement describes three coordinated changes: New smart contracts + Rewritten order book + New collateral token The new exchange contracts are CTF Exchange V2, and the new collateral token is pUSD, replacing USDC.e as the trading collateral layer. The contract repository describes CTF Exchange V2 as the core smart-contract system for trading Conditional Token Framework assets. It currently lists the deployed Polygon contracts for the collateral token, collateral adapters, standard exchange, and negative-risk exchange. This matters because an integration that only changes its Python or TypeScript dependency is not necessarily migrated. The underlying assumptions may also have changed. The order structure changed One of the clearest examples is the signed order itself. The current Rust client defines separate order structures for V1 and V2. The V1 structure contains fields such as: taker nonce feeRateBps expiration The V2 order structure instead uses fields including: timestamp metadata builder with expiration carried separately in the payload. The EIP-712 domain version also changes: V1 → "1" V2 → "2" V3 → "3" That is not cosmetic. The exchange contract and signed typed-data structure have to agree. A bot that manually constructs EIP-712 messages therefore needs to know which protocol it is signing for. Contract addresses are part of the migration A protocol migration also changes the contracts that the trading system ultimately interacts with. The current CTF Exchange V2 repository lists these Polygon contracts: CTFExchangeV2 0xE111180000d2663C0091e4f400237545B87B996B NegRiskCtfExchangeV2 0xe2222d279d744050d28e00520010520000310F59 CollateralToken proxy 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB CtfCollateralAdapter 0xADa100874d00e3331D00F2007a9c336a65009718 NegRiskCtfCollateralAdapter 0xAdA200001000ef00D07553cEE7006808F895c6F1 These are documented by the official V2 exchange repository. For a trading bot, hardcoded contract addresses are therefore part of the compatibility surface. So are: verifying contracts allowances collateral handling settlement assumptions A migration audit should look for all of them. pUSD is part of the protocol change The collateral model also changed. Polymarket's April 2026 upgrade introduced pUSD, an ERC-20 collateral token on Polygon backed 1:1 by USDC. The exchange documentation describes pUSD as the new technical collateral layer while trading settles in native USDC. That creates another compatibility boundary: Old USDC.e ↓ CTF / Exchange New USDC / pUSD ↓ Collateral layer ↓ CTF / Exchange A bot that checks balances, approves contracts, wraps collateral, or manages inventory directly onchain needs to understand that layer. This becomes especially important for systems that are not simply using the web interface but are managing their own wallet flow. Fees also moved closer to protocol state Another important change is fee handling. Polymarket's current fee documentation says fees are applied at match time, not included as a fee field in the order itself. The current formula is based on share count, fee rate, and share price. That means a trading system should avoid treating: fee = property of order creation as a universal assumption. Instead, it should think more like: Order ↓ Match ↓ Protocol determines fee ↓ Execution result This matters for analytics as well. If you're measuring: Gross PnL Fees Net PnL the accounting layer needs to correspond to the actual execution model. It also matters for strategy selection because Polymarket currently charges taker fees on several market categories while makers are not charged fees and can receive rebates. Then there is PolyV2 This is where version naming gets even more confusing. The current Polymarket clients support PolyV2 position identifiers. These are not simply another name for normal CTF token IDs. The official Python SDK changelog shows the progression: 0.8.0 → expose market protocol versions 0.9.0 → support Poly V2 identifiers and trading 0.10.0 → migrate data reads to Data API v2 These are SDK changes, but they reflect underlying protocol concepts that the application has to understand. The official Python models explicitly expose market protocol versions as: v1 v2 and distinguish those values from the package version itself. PolyV2 orders use Exchange V3 This is probably the easiest place for a developer to make the wrong assumption. The current official Rust CLOB client documents: CTF token ↓ V2 exchange flow Polymarket V2 position ↓ V3 exchange flow Position-backed orders bypass the normal protocol lookup and use Exchange V3, with EIP-712 domain version "3" . The TypeScript CLOB V2 release also added support for positionID and explicitly says that it selects Exchange V3 signing for limit and market orders. So a trading system should not simply ask: "What version of Polymarket am I using?" It should ask: What asset am I trading? What protocol does that asset use? Which exchange signs that order? Which contract verifies it? What collateral path applies? How is the resulting execution reported? That is a much better compatibility model. Execution changed too Protocol upgrades don't stop at signing. The execution path itself has also changed. The official Rust CLOB changelog records a July 2026 change for an asynchronous execution pipeline in which matched orders can return tradeIDs while transaction hashes are resolved later. The client added internal transaction-hash resolution for this flow. That changes how a bot should model execution. Instead of: ORDER ↓ FILLED ↓ TRANSACTION HASH you may need: ORDER ↓ MATCHED ↓ TRADE ID ↓ TRANSACTION RESOLUTION ↓ CONFIRMATION ↓ SETTLEMENT That is directly related to the execution-verification architecture I've been working on. A match tells you something important. It does not necessarily represent the final state of the entire execution lifecycle. Why this matters for reconciliation This is where protocol knowledge becomes operational engineering. Suppose your local system records: Order: MATCHED but the transaction is still unresolved. Or: Local position: +100 while the remote position is: +40 Or the market changes protocol representation while your application still has older assumptions in memory. The recovery problem is the same: Local assumptions ↓ Current protocol state ↓ Compare ↓ Reconcile ↓ Verify Protocol-awareness therefore belongs inside the state and execution layers. It is not something you check once during installation. What a protocol-aware trading bot should track I would keep protocol information explicit in the system. For example: Market ↓ Protocol version ↓ Asset identifier ↓ Exchange path ↓ Signing version ↓ Contract ↓ Collateral ↓ Execution state ↓ Settlement state That can be represented as internal metadata rather than scattered assumptions. For example: asset_type protocol_version position_id token_id exchange_version chain_id verifying_contract collateral_type The exact schema will depend on the implementation. The important part is not hiding these distinctions. Don't build version logic around package versions A common mistake is: SDK v0.10 → therefore protocol v2 That is not a safe relationship. The official Python SDK is currently on its own semantic versioning track, with the package at 0.12.0 in the repository metadata, while its changelog separately records support for market protocol versions, PolyV2 identifiers, and Data API v2. Likewise, the dedicated CLOB V2 TypeScript package has its own release numbers such as 1.2.0 . These numbers describe software releases. They do not define the onchain protocol. What I would check before deploying a Polymarket bot For an existing system, I would treat this as a compatibility audit. [ ] Exchange contract addresses [ ] EIP-712 domain version [ ] Signed order fields [ ] Asset identifiers [ ] Protocol version metad
Comments
No comments yet. Start the discussion.