Polymarket Bot Tutorial · Hoofdstuk 9 van 32

Lees Polymarket on-chain data direct: USDC/pUSD balances, CTF contract-reads voor outcome supply, UMA Optimistic Oracle proposed/disputed events en Polygon transaction logs — met code.

Wat dit hoofdstuk behandelt

Polymarkets API's zijn handig maar eventually consistent. De chain is gezaghebbend. Dit hoofdstuk wandelt door de on-chain reads die een productie-bot gebruikt om eigen boekhouding te verifiëren: pUSD balances, outcome-token inventory, UMA dispute events en CTF contract state. Het patroon waar de meeste productie-bots op convergeren is API-first voor snelheid plus periodieke on-chain reconciliation voor correctheid.

Dit is hoofdstuk 9 van onze 32-delige serie over het bouwen van een Polymarket trading bot. We behandelen het onderwerp in detail in de secties hieronder. De body content voor elke sectie wordt geschreven en hoofdstuk-per-hoofdstuk uitgerold; FAQ-antwoorden en referenties zijn al compleet en weerspiegelen production-ervaring van het draaien van onze eigen trader.

  • Wat on-chain leeft (vs in CLOB)
  • pUSD contract-adres en ABI
  • Conditional Tokens Framework (CTF)
  • UMA Optimistic Oracle: proposed en disputed events
  • Polygon event logs lezen (web3.py / ethers)
  • Wanneer on-chain te lezen vs de API vertrouwen
  • Code: detecteer een UMA dispute via event-subscription

Wat on-chain leeft (vs in CLOB)

Twee state machines, twee waarheden.

On-chain (Polygon): pUSD balances, outcome-token inventory (ERC-1155 supply per token), allowance approvals, UMA Optimistic Oracle proposals en disputes, deposit- en withdrawal-events. Uiteindelijk correct; latency is één Polygon block (~2 seconden).

CLOB (Polymarket API): order book, recente trades, pending limit orders, match acknowledgments. Real-time maar eventually consistent — een match wordt erkend voordat de ERC-1155 settled, wat het phantom-fill probleem produceert behandeld in hoofdstuk 12.

De twee moeten altijd convergeren. Wanneer ze divergeren, is de chain gezaghebbend. Een bot die alleen de CLOB vertrouwt drift; een bot die alleen de chain vertrouwt trade traag. Productiecode gebruikt beide: CLOB voor speed-critical beslissingen, chain voor periodieke reconciliation.

pUSD contract-adres en ABI

pUSD is Polymarkets stablecoin wrapper in gebruik sinds de 2025 V2-migratie. Het contract op 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB op Polygon mainnet is een standaard ERC-20.

Drie reads die tellen voor een bot:

  • balanceOf(proxy) — je besteedbare pUSD. Vergelijk tegen de view van de CLOB van je balance op elke restart.
  • allowance(proxy, exchange_contract) — of de CTF/NegRisk exchange-contracten je pUSD kunnen besteden. Vereist voor order matching.
  • Transfer event-subscription — detecteert deposits en withdrawals zonder polling.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) blijft het off-ramp pair. De meeste bots hebben alleen pUSD-reads nodig; USDC telt alleen tijdens deposit/withdrawal-cycli.

Conditional Tokens Framework (CTF)

Outcome shares zijn ERC-1155 tokens minted door Gnosis's Conditional Tokens Framework (CTF). Het CTF-contract op Polygon op 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 trackt per-position-id supply.

Drie reads:

  • balanceOf(proxy, position_id) — hoeveel outcome tokens je daadwerkelijk houdt voor dat market+outcome.
  • getOutcomeSlotCount(condition_id) — aantal uitkomsten (2 voor binary, N voor multi-outcome).
  • payoutNumerators, payoutDenominator — gezet wanneer UMA de markt resolved. Deze lezen vertelt je welke zijde won voordat de CLOB UI updatet.

De position_id is een hash van (condition_id, outcome_index). Bereken hem client-side via de CTF's getPositionId helper of repliceer de keccak-math in je stack.

UMA Optimistic Oracle: proposed en disputed events

UMA's Optimistic Oracle (OO) handelt alle Polymarket dispute resolution af. Twee events waar je bot op zou willen abonneren.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) — gefired wanneer een Polymarket-bot een outcome voorstelt.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) — gefired wanneer iemand de voorgestelde outcome uitdaagt.

OO contract-adres: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Filter op Polymarkets requester-adres.

Waarom abonneren: een dispute betekent dat de resolution nu betwist is en een 24-72h UMA-vote vereist. Tijdens dat venster kan de markt gepauzeerd zijn voor trading. Een bot die posities houdt op een disputed markt moet het direct weten.

Polygon event logs lezen (web3.py / ethers)

Twee referentie-implementaties.

Python (web3.py):

from web3 import Web3
w3 = Web3(Web3.HTTPProvider(POLYGON_RPC))
ctf = w3.eth.contract(address=CTF_ADDR, abi=CTF_ABI)
filter = ctf.events.PayoutRedemption.create_filter(fromBlock="latest")
for event in filter.get_new_entries():
    print(event["args"])

Node (ethers v6):

import { ethers } from "ethers";
const p = new ethers.JsonRpcProvider(POLYGON_RPC);
const ctf = new ethers.Contract(CTF_ADDR, CTF_ABI, p);
ctf.on("PayoutRedemption", (redeemer, collateral, parentId, conditionId) => {
  console.log("redemption", { redeemer, conditionId });
});

Voor continue monitoring gebruik WebSocket transport (wss://...) in plaats van HTTP-polling — minder requests en snellere delivery. De meeste betaalde RPC providers includeren WebSocket op entry-tiers.

Wanneer on-chain te lezen vs de API vertrouwen

Praktische regels uit productie.

  • Vertrouw de API voor: real-time order book, recente trades, je eigen pending orders, market-metadata (slug, vraag, end date), event/market discovery.
  • Vertrouw de chain voor: je eigen pUSD-balance, je eigen outcome-token inventory, deposit- en withdrawal-verificatie, resolution outcomes, dispute state.
  • Cross-check beide voor: alles financieel dat de bot vastlegde als een fill — match het "matched" event van de API tegen de CTF-transfer van de chain om settlement te bevestigen.

De 5-seconden-wacht regel na een buy (hoofdstuk 12) is de on-chain realiteit die de API-tijd binnendringt. Een GTC sell ingediend direct na een market buy zal balance: 0 zien vanaf de chain-check ook al matched de CLOB momenten geleden.

Code: detecteer een UMA dispute via event-subscription

Referentie: kijk naar Polymarket-gerelateerde UMA disputes in real time.

from web3 import Web3
w3 = Web3(Web3.WebsocketProvider(POLYGON_WSS))
oo = w3.eth.contract(address=UMA_OO_ADDR, abi=UMA_ABI)
POLY_REQUESTER = "0x..."  # Polymarket's UMA requester address

def on_dispute(event):
    args = event["args"]
    if args["requester"].lower() != POLY_REQUESTER.lower(): return
    print(f"DISPUTE on Polymarket market: ancillary={args['ancillaryData'][:40]}...")
    # decode ancillaryData to recover the market question

event_filter = oo.events.DisputePrice.create_filter(fromBlock="latest")
while True:
    for ev in event_filter.get_new_entries():
        on_dispute(ev)
    time.sleep(2)

Het ancillaryData veld is hex-encoded JSON-achtige tekst die de vraag van de markt bevat. Het decoderen geeft je de slug-equivalente identifier om cross-te-referencen tegen je open posities.

Veelgestelde vragen

Waar vind ik het Polymarket pUSD-contract?
pUSD leeft op 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB op Polygon. Het verving USDC.e als Polymarkets canonical collateral op 28 april 2026. Polygonscan link: https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB.
Wat is het CTF-contract op Polymarket?
CTF staat voor Conditional Tokens Framework — het Gnosis-afgeleide ERC-1155 contract dat outcome tokens uitgeeft (de YES en NO shares die je trade). Elke Polymarket-markt is een CTF-positie met redemption-logica gekoppeld aan UMA's resolution. Bots hoeven zelden direct met CTF te interacten; de SDK handelt het af.
Hoe abonneer ik op UMA dispute events op Polygon?
Abonneer op de UMA Optimistic Oracle V2 contract`s "ProposePrice" en "DisputePrice" events via de WebSocket van je Polygon RPC provider. Filter op het requesterAddress veld (Polymarkets oracle adapter) om alleen Polymarket-gerelateerde disputes te krijgen. Code samples in het hoofdstuk.
Moet ik on-chain data lezen als ik de Polymarket API vertrouw?
Voor de meeste strategieën, nee. De CLOB API is canonical voor order book en trade data en de gamma API is canonical voor metadata. Je leest on-chain wanneer je nodig hebt (a) UMA dispute-alerts sneller dan de API ze surfacet, (b) verificatie dat een deposit daadwerkelijk aankwam of (c) custom analytics op outcomes/posities.
Wat is de latency van on-chain Polygon-data vs de Polymarket API?
Polygon block time is ~2 seconden. De Polymarket API surfacet doorgaans order book changes binnen honderden milliseconden van de on-chain match. Voor de meeste signalen is de API sneller dan je eigen on-chain reads. UMA disputes zijn een uitzondering — het on-chain event fired voordat de UI de dispute reflecteert.
Kan ik Polymarket-posities lezen zonder de CLOB API?
Technisch ja — lees CTF balanceOf(walletAddress, positionId) voor elke positie. Praktisch is de CLOB API /trade/positions endpoint sneller, bevat pricing en aggregeert al je posities. Val alleen terug op on-chain reads als je verificatie nodig hebt of de API down is.