Polymarket Bot Tutorial · Capitolo 9 di 32

Leggi direttamente i dati on-chain di Polymarket: saldi USDC/pUSD, letture del contract CTF per la supply degli outcome, eventi proposed/disputed di UMA Optimistic Oracle e transaction log di Polygon - con codice.

Cosa copre questo capitolo

Le API di Polymarket sono comode ma eventualmente consistent. La chain è la fonte autorevole. Questo capitolo illustra le letture on-chain che un bot in produzione usa per verificare la propria contabilità: saldi pUSD, inventory di outcome token, eventi di disputa UMA e stato del contract CTF. Il pattern verso cui convergono la maggior parte dei bot in produzione è API-first per la velocità, più reconciliation on-chain periodica per la correttezza.

Questo è il capitolo 9 della nostra serie in 32 parti sulla costruzione di un Polymarket trading bot. Trattiamo l'argomento in profondità nelle sezioni qui sotto. Il contenuto del corpo per ogni sezione viene scritto e pubblicato capitolo per capitolo; le risposte della FAQ e i riferimenti sono già completi e riflettono l'esperienza in produzione maturata gestendo il nostro trader.

  • Cosa vive on-chain (vs in CLOB]
  • Indirizzo contract pUSD e ABI
  • Conditional Tokens Framework (CTF)
  • UMA Optimistic Oracle: eventi proposed e disputed
  • Lettura dei Polygon event log (web3.py / ethers)
  • Quando leggere on-chain vs fidarsi dell'API
  • Codice: rilevare una disputa UMA tramite event subscription

Cosa vive on-chain (vs in CLOB]

Due state machine, due verità.

On-chain (Polygon): saldi pUSD, inventory di outcome token (supply ERC-1155 per token), approval di allowance, proposizioni e dispute di UMA Optimistic Oracle, eventi di deposito e prelievo. Corretto in modo eventuale; la latenza è di un blocco Polygon (~2 secondi).

CLOB (Polymarket API): order book, trade recenti, pending limit order, acknowledgment dei match. Real-time ma eventualmente consistent — un match viene acknowledged prima che l'ERC-1155 si assesti, generando il problema del phantom-fill trattato nel capitolo 12.

I due devono sempre convergere. Quando divergono, la chain è la fonte autorevole. Un bot che si fida solo del CLOB andrà fuori sync; un bot che si fida solo della chain traderà lentamente. Il codice di produzione usa entrambi: CLOB per decisioni critiche in velocità e chain per reconciliation periodica.

Indirizzo contract pUSD e ABI

pUSD è il wrapper stablecoin di Polymarket usato dalla migrazione V2 del 2025. Il contract su Polygon mainnet all'indirizzo 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB è un ERC-20 standard.

Tre letture importanti per un bot:

  • balanceOf(proxy) — il tuo pUSD spendibile. Confrontalo con la view del CLOB sul tuo saldo a ogni riavvio.
  • allowance(proxy, exchange_contract) — se i contract CTF/NegRisk exchange possono spendere il tuo pUSD. Richiesto per il matching degli ordini.
  • Subscription all'evento Transfer — rileva depositi e prelievi senza polling.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) rimane la coppia off-ramp. La maggior parte dei bot ha bisogno solo di letture pUSD; USDC serve solo durante i cicli di deposito/prelievo.

Conditional Tokens Framework (CTF)

Le quote di outcome sono token ERC-1155 mintati dal Conditional Tokens Framework (CTF) di Gnosis. Il contract CTF su Polygon all'indirizzo 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 traccia la supply per position-id.

Tre letture:

  • balanceOf(proxy, position_id) — quanti outcome token possiedi davvero per quel market+outcome.
  • getOutcomeSlotCount(condition_id) — numero di outcome (2 per binary, N per multi-outcome).
  • payoutNumerators, payoutDenominator — impostati quando UMA risolve il market. Leggerli ti dice quale lato ha vinto prima che la UI del CLOB si aggiorni.

Il position_id è un hash di (condition_id, outcome_index). Calcolalo lato client tramite l'helper getPositionId del CTF oppure replica la keccak math nel tuo stack.

UMA Optimistic Oracle: eventi proposed e disputed

L'Optimistic Oracle (OO) di UMA gestisce tutta la dispute resolution di Polymarket. Due eventi a cui il tuo bot potrebbe voler iscriversi.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) — emesso quando un bot di Polymarket propone un outcome.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) — emesso quando qualcuno contesta l'outcome proposto.

Indirizzo contract OO: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Filtra per l'indirizzo requester di Polymarket.

Perché iscriversi: una disputa significa che la resolution è ora contestata e richiederà un voto UMA di 24-72 ore. Durante quella finestra, il market può essere sospeso dal trading. Un bot che detiene posizioni su un market disputato dovrebbe saperlo immediatamente.

Lettura dei Polygon event log (web3.py / ethers)

Due implementazioni di riferimento.

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 });
});

Per il monitoraggio continuo usa WebSocket transport (wss://...) invece del polling HTTP — meno request e consegna più rapida. La maggior parte dei provider RPC a pagamento include WebSocket già nei piani entry-level.

Quando leggere on-chain vs fidarsi dell'API

Regole pratiche dalla produzione.

  • Fidati dell'API per: order book real-time, trade recenti, i tuoi pending order, metadata del market (slug, question, end date), discovery di eventi/market.
  • Fidati della chain per: il tuo saldo pUSD, il tuo inventory di outcome token, verifica di depositi e prelievi, esiti di resolution, stato delle dispute.
  • Confronta entrambi per: qualsiasi dato finanziario che il bot ha registrato come fill — abbina l'evento "matched" dell'API con il transfer CTF della chain per confermare il settlement.

La regola dei 5 secondi di attesa dopo un buy (capitolo 12) è la realtà on-chain che irrompe nel tempo dell'API. Un sell GTC inviato subito dopo un market buy vedrà balance: 0 dal controllo on-chain anche se il CLOB ha matched pochi istanti prima.

Codice: rilevare una disputa UMA tramite event subscription

Riferimento: monitorare in tempo reale le dispute UMA relative a Polymarket.

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)

Il campo ancillaryData è testo in stile JSON codificato in hex che contiene la market question. Decodificarlo ti dà l'identificatore equivalente allo slug da cross-referenziare con le tue posizioni aperte.

Domande frequenti

Dove posso trovare il contract pUSD di Polymarket?
pUSD si trova a 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB su Polygon. Ha sostituito USDC.e come collateral canonico di Polymarkets il 28 aprile 2026. Link Polygonscan: https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB.
Cos'è il contract CTF su Polymarket?
CTF sta per Conditional Tokens Framework - il contract ERC-1155 derivato da Gnosis che emette gli outcome token (le quote YES e NO che scambi). Ogni market di Polymarket è una posizione CTF con logica di redemption legata alla resolution di UMA. I bot raramente hanno bisogno di interagire direttamente con CTF; lo gestisce l'SDK.
Come faccio a sottoscrivermi agli eventi di disputa UMA su Polygon?
Sottoscrivi gli eventi "ProposePrice" e "DisputePrice" del contract UMA Optimistic Oracle V2 tramite il WebSocket del tuo provider RPC Polygon. Filtra per il campo requesterAddress (l'oracle adapter di Polymarkets) per ottenere solo le dispute relative a Polymarket. Esempi di codice nel capitolo.
Devo leggere i dati on-chain se mi fido dell'API di Polymarket?
Per la maggior parte delle strategie, no. La CLOB API è canonica per order book e trade data, e la gamma API è canonica per i metadata. Leggi on-chain quando ti serve (a) alert UMA dispute più rapidi di quanto l'API li mostri, (b) verifica che un deposito sia effettivamente arrivato, oppure (c) analytics personalizzate su outcome/position.
Qual è la latenza dei dati on-chain Polygon rispetto all'API di Polymarket?
Il block time di Polygon è di ~2 secondi. L'API di Polymarket in genere mostra i cambiamenti dell'order book entro centinaia di millisecondi dal match on-chain. Per la maggior parte dei segnali, l'API è più veloce delle tue letture on-chain. Le dispute UMA sono un'eccezione - l'evento on-chain scatta prima che la UI mostri la disputa.
Posso leggere le posizioni di Polymarket senza la CLOB API?
Tecnicamente sì - leggi CTF balanceOf(walletAddress, positionId) per ogni posizione. In pratica l'endpoint CLOB API /trade/positions è più veloce, include il pricing e aggrega tutte le tue posizioni. Ricorri alle letture on-chain solo se ti serve verifica o se l'API non è disponibile.