DEV Community

Cover image for Polymarket Protocol Versions: V1, V2, V3 and What Trading Bots Need to Know

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Those layers can evolve independently.

For example, the current official Rust CLOB client documents:

V1
V2
V3
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The V2 order structure instead uses fields including:

timestamp
metadata
builder
Enter fullscreen mode Exit fullscreen mode

with expiration carried separately in the payload.

The EIP-712 domain version also changes:

V1 → "1"
V2 → "2"
V3 → "3"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

as a universal assumption.

Instead, it should think more like:

Order
   ↓
Match
   ↓
Protocol determines fee
   ↓
Execution result
Enter fullscreen mode Exit fullscreen mode

This matters for analytics as well.

If you're measuring:

Gross PnL
Fees
Net PnL
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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?"
Enter fullscreen mode Exit fullscreen mode

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?
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

you may need:

ORDER
  ↓
MATCHED
  ↓
TRADE ID
  ↓
TRANSACTION RESOLUTION
  ↓
CONFIRMATION
  ↓
SETTLEMENT
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

but the transaction is still unresolved.

Or:

Local position:
+100
Enter fullscreen mode Exit fullscreen mode

while the remote position is:

+40
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 metadata
[ ] Collateral path
[ ] Token / position approvals
[ ] Fee handling
[ ] Order submission
[ ] Execution events
[ ] Trade IDs
[ ] Transaction resolution
[ ] Settlement tracking
[ ] Position reconciliation
[ ] WebSocket recovery
[ ] Restart recovery
Enter fullscreen mode Exit fullscreen mode

If any of these are hardcoded assumptions, the system is carrying protocol risk.


This is also why migrations should be tested end to end

I would not consider a migration complete because:

npm install
Enter fullscreen mode Exit fullscreen mode

or:

pip install
Enter fullscreen mode Exit fullscreen mode

succeeds.

The useful test is closer to:

Market discovery
      ↓
Protocol detection
      ↓
Asset identification
      ↓
Order construction
      ↓
Signature
      ↓
Submission
      ↓
Match / fill
      ↓
Transaction
      ↓
Settlement
      ↓
Position
      ↓
PnL / fee accounting
Enter fullscreen mode Exit fullscreen mode

That tests the actual system boundary.

It also gives you a much better way to catch protocol mismatches before they become trading incidents.


My current architecture

This is the direction I'm taking with my own Polymarket infrastructure work:

                 POLYMARKET
                      │
                      ▼
              Protocol / Market
                      │
                      ▼
               Market Adapter
                      │
                      ▼
                  Strategy
                      │
                      ▼
                    Risk
                      │
                      ▼
                  Execution
                      │
                      ▼
              Execution Verifier
                      │
                      ▼
               Reconciliation
                      │
                      ▼
                Control Plane
                      │
             ┌────────┴────────┐
             ↓                 ↓
        Monitoring          Recovery
Enter fullscreen mode Exit fullscreen mode

The point is to keep protocol-specific assumptions close to the integration boundary.

The rest of the system can then work with clearer internal concepts:

Order
Fill
Position
Exposure
Risk
Execution status
System health
Enter fullscreen mode Exit fullscreen mode

That makes future migrations easier to reason about.


The bigger lesson

Polymarket protocol changes are not really a problem for the SDK alone.

They're an integration problem.

A protocol upgrade can affect:

Contracts
Signing
Collateral
Orders
Execution
Settlement
Accounting
State
Enter fullscreen mode Exit fullscreen mode

And those changes eventually show up as operational problems:

orders stop submitting
fills become harder to interpret
positions drift
retries become unsafe
accounting changes
reconciliation breaks
Enter fullscreen mode Exit fullscreen mode

That is why I think protocol compatibility should be treated as part of trading infrastructure.

Not as a dependency upgrade.


Final takeaway

When someone says:

“Polymarket V2”

I would now ask:

V2 which layer?
Enter fullscreen mode Exit fullscreen mode

Because today you may be dealing with:

CTF Exchange V2
CLOB V2
PolyV2 positions
Exchange V3
Data API V2
SDK versions
Enter fullscreen mode Exit fullscreen mode

Those are related, but they are not interchangeable labels.

For a trading bot, the useful model is:

Protocol
   ↓
Asset
   ↓
Exchange
   ↓
Signing
   ↓
Execution
   ↓
Settlement
   ↓
Position
   ↓
Risk
Enter fullscreen mode Exit fullscreen mode

That is the level at which compatibility actually matters.

And for an existing trading system, the practical question is not whether the latest SDK installs.

It is whether the complete path still agrees:

contracts
→ signing
→ order
→ match
→ execution
→ settlement
→ position
→ risk
Enter fullscreen mode Exit fullscreen mode

That is what I would test before trusting the bot with capital.

Top comments (0)