Kurs budowy bota na Polymarket · Rozdział 9 z 32

Czytaj dane on-chain Polymarket bezpośrednio: salda USDC/pUSD, odczyty kontraktu CTF dla podaży wyników, zdarzenia UMA Optimistic Oracle proposed/disputed oraz logi transakcji Polygon - z kodem.

Co obejmuje ten rozdział

API Polymarket są wygodne, ale ostatecznie spójne. Łańcuch jest źródłem prawdy. Ten rozdział prowadzi przez odczyty on-chain, których bot produkcyjny używa do weryfikacji własnej księgowości: salda pUSD, zapas tokenów wyniku, zdarzenia sporu UMA oraz stan kontraktu CTF. Wzorzec, do którego dochodzi większość botów produkcyjnych, to najpierw API dla szybkości, a następnie okresowe uzgadnianie on-chain dla poprawności.

To jest rozdział 9 naszej 32-częściowej serii o budowie bota tradingowego na Polymarket. Omawiamy temat szczegółowo w sekcjach poniżej. Treść każdej sekcji jest pisana i publikowana rozdział po rozdziale; odpowiedzi FAQ i sekcje referencyjne są już kompletne i odzwierciedlają doświadczenie produkcyjne z prowadzenia naszego własnego bota.

  • Co żyje on-chain (a co w CLOB)
  • Adres kontraktu pUSD i ABI
  • Conditional Tokens Framework (CTF)
  • UMA Optimistic Oracle: zdarzenia proposed i disputed
  • Odczyt logów zdarzeń Polygon (web3.py / ethers)
  • Kiedy czytać on-chain, a kiedy ufać API
  • Kod: wykrywanie sporu UMA przez subskrypcję zdarzeń

Co żyje on-chain (a co w CLOB)

Dwie maszyny stanów, dwie prawdy.

On-chain (Polygon): salda pUSD, zapas tokenów wyniku (podaż ERC-1155 na token), zatwierdzenia (allowance), propozycje i spory w UMA Optimistic Oracle, zdarzenia wpłat i wypłat. Ostatecznie poprawne; opóźnienie to jeden blok Polygon (~2 sekundy).

CLOB (API Polymarket): arkusz zleceń, ostatnie transakcje, oczekujące zlecenia z limitem, potwierdzenia dopasowania. W czasie rzeczywistym, ale ostatecznie spójne - dopasowanie jest potwierdzane, zanim ERC-1155 zostanie rozliczony, co powoduje problem fantomowej realizacji omawiany w rozdziale 12.

Oba powinny zawsze się zbiegać. Gdy się rozchodzą, łańcuch jest źródłem prawdy. Bot, który ufa wyłącznie CLOB, będzie dryfował; bot, który ufa wyłącznie łańcuchowi, będzie handlował wolno. Kod produkcyjny używa obu: CLOB do decyzji krytycznych dla szybkości, łańcucha do okresowego uzgadniania.

Adres kontraktu pUSD i ABI

pUSD to opakowany stablecoin Polymarket używany od migracji do V2 w 2026 roku. Kontrakt pod adresem 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB na Polygon mainnet jest standardowym ERC-20.

Trzy odczyty, które mają znaczenie dla bota:

  • balanceOf(proxy) - twoje pUSD, które możesz wydać. Porównuj z widokiem salda w CLOB przy każdym restarcie.
  • allowance(proxy, exchange_contract) - czy kontrakty giełdy CTF/NegRisk mogą wydawać twoje pUSD. Wymagane do dopasowania zlecenia.
  • Zdarzenie Transfer - wykrywa wpłaty i wypłaty bez odpytywania.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) pozostaje parą do wyjścia (off-ramp). Większość botów potrzebuje tylko odczytów pUSD; USDC ma znaczenie wyłącznie podczas cykli wpłat/wypłat.

Conditional Tokens Framework (CTF)

Udziały wyniku to tokeny ERC-1155 wybijane przez Conditional Tokens Framework (CTF) Gnosis. Kontrakt CTF na Polygon pod adresem 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 śledzi podaż dla każdego position-id.

Trzy odczyty:

  • balanceOf(proxy, position_id) - ile tokenów wyniku faktycznie posiadasz dla danego rynku i wyniku.
  • getOutcomeSlotCount(condition_id) - liczba wyników (2 dla binarnego, N dla wielowynikowego).
  • payoutNumerators, payoutDenominator - ustawiane, gdy UMA rozstrzyga rynek. Odczyt tych wartości mówi ci, która strona wygrała, zanim interfejs CLOB się zaktualizuje.

position_id to hash z (condition_id, outcome_index). Oblicz go po stronie klienta przez pomocnika getPositionId w CTF albo odtwórz matematykę keccak w swoim stosie.

UMA Optimistic Oracle: zdarzenia proposed i disputed

UMA Optimistic Oracle (OO) obsługuje całe rozstrzyganie sporów w Polymarket. Dwa zdarzenia, na które bot może chcieć się zasubskrybować.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) - wywoływane, gdy bot Polymarket proponuje wynik.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) - wywoływane, gdy ktoś kwestionuje zaproponowany wynik.

Adres kontraktu OO: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Filtruj po adresie requester Polymarket.

Dlaczego warto się zasubskrybować: spór oznacza, że rozstrzygnięcie jest teraz kwestionowane i będzie wymagało głosowania UMA przez 24-72 h. W tym oknie rynek może zostać wstrzymany do handlu. Bot trzymający pozycje na rynku ze sporem powinien wiedzieć o tym natychmiast.

Odczyt logów zdarzeń Polygon (web3.py / ethers)

Dwie referencyjne implementacje.

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

Do ciągłego monitorowania używaj transportu WebSocket (wss://...) zamiast odpytywania HTTP - mniej żądań i szybsze dostarczanie. Większość płatnych dostawców RPC ma WebSocket już w planach startowych.

Kiedy czytać on-chain, a kiedy ufać API

Praktyczne zasady z produkcji.

  • Ufaj API dla: arkusza zleceń w czasie rzeczywistym, ostatnich transakcji, twoich własnych oczekujących zleceń, metadanych rynku (slug, pytanie, data zakończenia), odkrywania wydarzeń/rynków.
  • Ufaj łańcuchowi dla: twojego własnego salda pUSD, twojego zapasu tokenów wyniku, weryfikacji wpłat i wypłat, wyników rozstrzygnięcia, stanu sporu.
  • Sprawdzaj oba dla: wszystkiego finansowego, co bot zapisał jako realizację - dopasuj zdarzenie „matched" z API do transferu CTF w łańcuchu, aby potwierdzić rozliczenie.

Zasada 5-sekundowego oczekiwania po kupnie (rozdział 12) to rzeczywistość on-chain wkraczająca do czasu API. Sprzedaż GTC wysłana natychmiast po kupnie rynkowym zobaczy z odczytu łańcucha balance: 0, mimo że CLOB potraktował dopasowanie chwilę wcześniej.

Kod: wykrywanie sporu UMA przez subskrypcję zdarzeń

Referencja: śledź spory UMA związane z Polymarket w czasie rzeczywistym.

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)

Pole ancillaryData to zakodowany szesnastkowo tekst w stylu JSON zawierający pytanie rynku. Jego dekodowanie daje identyfikator równoważny slugowi, który można skorelować z otwartymi pozycjami.

Najczęściej zadawane pytania

Gdzie mogę znaleźć kontrakt pUSD Polymarket?
pUSD znajduje się pod adresem 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB na Polygon. Zastąpił USDC.e jako kanoniczne zabezpieczenie Polymarket 28 kwietnia 2026. Link do Polygonscan: https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB.
Czym jest kontrakt CTF na Polymarket?
CTF oznacza Conditional Tokens Framework - kontrakt ERC-1155 wywodzący się z Gnosis, który emituje tokeny wyniku (udziały YES i NO, którymi handlujesz). Każdy rynek Polymarket jest pozycją CTF z logiką wykupu powiązaną z rozstrzygnięciem UMA. Boty rzadko muszą wchodzić w interakcję z CTF bezpośrednio; SDK załatwia to za nie.
Jak subskrybować zdarzenia sporu UMA na Polygon?
Subskrybuj zdarzenia „ProposePrice" i „DisputePrice" kontraktu UMA Optimistic Oracle V2 przez WebSocket swojego dostawcy RPC dla Polygon. Filtruj po polu requesterAddress (adapter wyroczni Polymarket), aby dostać tylko spory związane z Polymarket. Przykłady kodu są w rozdziale.
Czy muszę czytać dane on-chain, jeśli ufam API Polymarket?
Dla większości strategii nie. API CLOB jest kanoniczne dla danych arkusza zleceń i transakcji, a API gamma jest kanoniczne dla metadanych. Czytasz on-chain, gdy potrzebujesz (a) alertów o sporach UMA szybciej, niż pojawią się w API, (b) weryfikacji, że wpłata faktycznie dotarła, lub (c) niestandardowej analityki dotyczącej wyników/pozycji.
Jaka jest latencja danych on-chain Polygon względem API Polymarket?
Czas bloku Polygon to około 2 sekundy. API Polymarket zazwyczaj pokazuje zmiany arkusza zleceń w ciągu setek milisekund od dopasowania on-chain. Dla większości sygnałów API jest szybsze niż własne odczyty on-chain. Spory UMA są wyjątkiem - zdarzenie on-chain pojawia się, zanim interfejs odzwierciedli spór.
Czy mogę czytać pozycje Polymarket bez API CLOB?
Technicznie tak - odczytaj CTF balanceOf(walletAddress, positionId) dla każdej pozycji. W praktyce endpoint API CLOB /trade/positions jest szybszy, zawiera wyceny i agreguje wszystkie twoje pozycje. Do odczytów on-chain wracaj tylko, jeśli potrzebujesz weryfikacji albo API nie działa.