How Polymarket Works: CLOB, USDC, Polygon, and UMA Resolution Explained

Published May 18, 2026 · 14 min read · By SsysTech Softwares

Polymarket looks like a normal exchange from the user side — click buy, click sell, see your P&L. Under that surface, it's a stack of four very different technologies bolted together: conditional tokens on Polygon, USDC for collateral, a central limit order book run by Polymarket's operator, and UMA's optimistic oracle for resolution. If you want to build on Polymarket, integrate it as a data source, or just reason about its failure modes, you need a real model of what each layer does.

This post is the engineering-level explainer. We'll walk top-to-bottom: what a market actually is on-chain, how orders match, how money moves, how outcomes get decided, and where the pitfalls are.

Layer 1: Conditional Tokens (the Contract Layer)

The atomic unit on Polymarket is not "a bet." It's a pair of ERC-1155 conditional tokens deployed via Gnosis's Conditional Tokens Framework (CTF). For any binary market — say, "Will the Lakers win the 2026 NBA Championship?" — the smart contract mints two distinguishable tokens:

Crucially, 1 YES + 1 NO = 1 USDC of collateral, always. This invariant is what makes a prediction market self-pricing: anyone with 1 USDC can mint one of each token (called "splitting") and sell them; anyone holding one of each can "merge" them back into 1 USDC. The arbitrage forces YES price + NO price to stay close to 100¢ in liquid markets.

Each token has a unique tokenId — a uint256 derived from the condition's question hash and the outcome index. This ID is what every API call and order references. The conditional tokens are ERC-1155 rather than ERC-20, which means a single contract holds positions for thousands of markets simultaneously, and you can transfer multiple positions in one call.

# Pseudocode for getting your position
positions = ctf_contract.balanceOfBatch(
    owners=[wallet_address] * len(token_ids),
    ids=token_ids
)

Gotcha: Polymarket's "neg-risk" markets (multi-outcome events like "Which team wins the Super Bowl?") wrap the underlying CTF tokens in a separate adapter (NegRiskAdapter), and the on-chain token IDs you trade in the CLOB do not match the IDs you redeem. We'll cover this in the redemption section.

Layer 2: USDC on Polygon (the Settlement Layer)

All collateral, fees, and payouts on Polymarket are denominated in USDC — the US-dollar-pegged stablecoin issued by Circle. Polymarket uses the Polygon network (a PoS Ethereum L2) for settlement, which is why fees are pennies and confirmation is sub-second.

For a developer building a bot, the practical consequences:

Account funding works like any DEX: you deposit USDC into Polymarket's contract (the deposit creates an entry in their off-chain order book system), then trade. Withdrawals settle back to your wallet on-chain.

The Proxy Wallet Pattern

For trading via the API, Polymarket uses a Gnosis Safe proxy pattern. Your EOA (externally-owned account, the regular wallet from your seed phrase) is the signer, but the actual holder of positions is a 1-of-1 Safe proxy deployed for you. This separation is what lets the off-chain order book operator submit orders on your behalf without ever holding your funds.

# .env config for proxy trading
POLY_PRIVATE_KEY=0x...                  # EOA private key (signer)
POLY_SIG_TYPE=2                         # 0=EOA, 1=POLY_PROXY, 2=POLY_GNOSIS_SAFE
POLY_FUNDER=0x...                       # The Safe address (holder)

When you sign an order, SIG_TYPE=2 tells the matching engine to verify your signature against the Safe's single-owner permission, not the EOA's direct ownership of the tokens.

Layer 3: The CLOB (Central Limit Order Book)

Polymarket runs an off-chain order book operated by its central matching engine. This is the part that doesn't live on-chain — on-chain matching would be too slow and too expensive for the cadence of sports trading. The on-chain layer is reserved for settlement: once two orders match off-chain, the matching engine submits an on-chain transaction that exchanges tokens between the two parties' Safes.

From an API perspective the CLOB looks like Binance or Coinbase Advanced:

from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType

client = ClobClient(
    host="https://clob.polymarket.com",
    chain_id=137,                       # Polygon mainnet
    key=os.getenv("POLY_PRIVATE_KEY"),
    funder=os.getenv("POLY_FUNDER"),    # Safe proxy address
    signature_type=2,                   # Safe signature
)
client.set_api_creds(client.create_or_derive_api_creds())

# Buy 100 YES shares at 45c
order = client.create_order(OrderArgs(
    token_id=lakers_yes_token_id,
    price=0.45,
    size=100,
    side="BUY",
))
resp = client.post_order(order, OrderType.GTC)   # Good-til-canceled

The matching engine handles partial fills, time-in-force (GTC, GTD, FOK), and a queue of orders by price-time priority. When two orders cross, the on-chain settlement is batched with other matches for gas efficiency — sub-second under normal load.

Fees and the Maker/Taker Model

Polymarket charges taker fees on most markets. As of 2026, the standard configuration is:

For a sharp trader, the maker/taker split matters enormously: posting passive liquidity (resting orders that get hit) is cost-free, while taking liquidity (market orders or limit orders that cross the spread) costs 2¢. On a 60¢ market that's a 3.3% one-way cost — before any model edge. Edge scanning on Polymarket has to account for this in the gate.

WebSocket Feeds

Polymarket exposes WebSocket streams for both market data (price book, last trades) and user data (your order updates, fills). The market feed is what bots subscribe to for real-time decision-making.

import asyncio
import websockets, json

async def stream(token_ids):
    async with websockets.connect("wss://ws-subscriptions-clob.polymarket.com/ws/market") as ws:
        await ws.send(json.dumps({
            "auth": {},                       # market channel is unauthenticated
            "type": "Market",
            "markets": token_ids,             # list of CLOB token IDs
        }))
        async for msg in ws:
            ev = json.loads(msg)
            if ev["event_type"] == "price_change":
                print(ev["asset_id"], ev["changes"])

Practical notes: market WebSockets occasionally drop, especially during high-volume sports events. A production bot needs a reconnection loop with state recovery (re-fetch top-of-book on reconnect; don't trust your in-memory state). It's also wise to combine WebSocket data with periodic REST snapshots (every 30-60 seconds) for consistency checking.

Layer 4: UMA's Optimistic Oracle (the Resolution Layer)

The hardest part of any prediction market is deciding what actually happened. Polymarket outsources this to UMA's Optimistic Oracle, a decentralized resolution mechanism that works on a "propose, dispute if needed" basis.

Flow:

  1. Event ends (game finishes, election called, deadline passes).
  2. A proposer submits an outcome on-chain via the UMA oracle, posting a bond as collateral.
  3. Dispute window opens, typically 2-4 hours.
  4. If no dispute: outcome is accepted, the bond is returned, and Polymarket's CTF reads the resolution and enables token redemption.
  5. If disputed: UMA token holders vote on the correct outcome over a multi-day period. The losing side of the dispute loses their bond.

For 95%+ of markets — "Did the Lakers win?", "Did Trump win the election?" — the outcome is uncontested and resolution is automatic within hours of the event. The other 5% are messy: ambiguously-worded markets, edge cases ("Did the player start the game?"), late-breaking schedule changes, or genuinely disputed outcomes. These can take days to resolve and have occasionally produced controversial decisions when the literal text of the market disagrees with the "obvious" intent.

Trader takeaway: always read the resolution criteria before trading. The text is what UMA resolves on, not your interpretation of the event. We've seen markets resolve "wrong" by intuition but "right" by the literal rules — and the literal rules are what UMA enforces.

Neg-Risk Markets: The Multi-Outcome Special Case

For markets with more than two outcomes (e.g., "Which team wins the Super Bowl?"), Polymarket uses a negative-risk adapter. Each outcome is its own binary market (YES = "this team wins", NO = "this team doesn't"), but they're linked: exactly one YES across all outcomes will resolve true, the rest resolve false.

For a bot, the consequences are:

  1. You can collect a "negative-risk bonus." Buying YES across all 32 teams in a Super Bowl market for slightly less than $1 total guarantees a $1 payout. The market is "neg-risk efficient" when total cost is exactly 100¢.
  2. Redemption uses a different adapter. Instead of CTF.redeemPositions(condition_id, amounts), you call NegRiskAdapter.redeemPositions(condition_id, amounts). The wrapped neg-risk token IDs are different from the underlying CLOB token IDs — conflating them is one of the most common bugs new integrators hit.
NEG_RISK_ADAPTER = "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296"
# Use this contract to redeem winnings on neg-risk markets, NOT the bare CTF.

What Happens When You Trade: End-to-End

Putting all four layers together, here's the lifecycle of a single trade on Polymarket:

  1. Discovery. You query the markets API (GET /markets) to find a market and pull its YES/NO token IDs.
  2. Signal. Your model produces a fair-value probability for the YES side (say, 58¢), and you observe the ask at 52¢. Edge: 6¢.
  3. Order. You sign a limit buy at 52¢ for 100 shares, submit to the CLOB. Sig type 2 (Safe).
  4. Match. The CLOB matches you against a resting offer, fires an on-chain settlement transaction. Your Safe now holds 100 YES tokens; the seller's Safe gets 52 USDC + taker fee credit (or pays the taker fee if they crossed).
  5. Hold. Game plays out. Prices fluctuate based on score updates and other traders' orders. You can sell at any time.
  6. Resolution. Game ends, UMA proposer submits "YES (Lakers won)", dispute window passes, outcome locked.
  7. Redemption. You call redeemPositions on the CTF (or NegRiskAdapter), receive $100 USDC into your Safe.
  8. Withdrawal. You move USDC from Safe to EOA, then off-chain wherever.

From signal to redemption is typically 2-6 hours for a sports market; an open-ended election market can take months. The bot's job is to keep state across this whole lifecycle — track which trades are settled, which are pending, which need to be redeemed manually.

Common Engineering Pitfalls

  1. Confusing CLOB token IDs with neg-risk wrapped IDs. The market data API returns CLOB IDs; the redemption contract wants wrapped IDs. You need a translation layer.
  2. Signature type mismatch. Trading from a Safe with sig type 0 will silently fail or return cryptic errors. Always set SIG_TYPE=2 if you're using a proxy wallet.
  3. Stale order book on reconnect. WebSocket drops are common during games. After reconnect, re-snapshot the order book before placing orders — do not trust accumulated deltas across a disconnection.
  4. Fee accounting. Tracking realized P&L without subtracting taker fees overstates returns by 2¢/share per filled side. For high-volume bots this is the difference between profitable and not.
  5. UMA dispute risk on edge-case markets. "Will the game be played today?" markets can resolve in unexpected ways when there's a postponement or weather delay. Read the resolution text carefully.
  6. Polygon gas spikes. Rare but real. During major DeFi events or congestion, redemption can spike to dollars per call. Batch redemptions when you can.

What You Can Build on Top of It

Once you understand the four layers, the surface area is huge:

The deeper insight: Polymarket is one of the few venues where a small developer with a good model and a $1k account can compete on roughly equal terms with institutional capital. There are no minimum sizes, no sharp-account restrictions, no "VIP rebates" only the whales get. The order book is the order book; if your edge is real, the venue will pay you for it.

Skip the integration work

ZenHodl publishes calibrated win probability APIs for 10+ sports — the model layer that drives our own Polymarket trading bots. If you want to focus on strategy, not on building the CLOB integration from scratch, the API is your shortcut.

See API Docs →

Further Reading