Polymarket Bot Tutorial · Розділ 9 із 32

Читаємо on-chain data Polymarket безпосередньо: баланси USDC/pUSD, reads контракту CTF для supply outcome, події UMA Optimistic Oracle щодо proposed/disputed, а також Polygon transaction logs - з кодом.

Що охоплює цей розділ

API Polymarket зручні, але зрештою є лише eventually consistent. Chain - це джерело істини. У цьому розділі розбираємо on-chain reads, які production bot використовує, щоб перевіряти власний облік: баланси pUSD, inventory outcome-токенів, події спорів UMA та стан контракту CTF. Підхід, до якого сходяться більшість production bot, - API-first для швидкості плюс періодична on-chain reconciliation для коректності.

  • Що живе on-chain (vs у CLOB)
  • Адреса контракту pUSD та ABI
  • Conditional Tokens Framework (CTF)
  • UMA Optimistic Oracle: події proposed і disputed
  • Читання Polygon event logs (web3.py / ethers)
  • Коли читати on-chain, а коли довіряти API
  • Код: визначити UMA dispute через event subscription

Що живе on-chain (vs у CLOB)

Дві state machine, дві правди.

On-chain (Polygon): баланси pUSD, inventory outcome-токенів (ERC-1155 supply на кожен token), allowance approvals, події propose та dispute в UMA Optimistic Oracle, події deposit і withdrawal. З часом все стає коректним; latency становить один блок Polygon - приблизно 2 секунди.

CLOB (Polymarket API): order book, recent trades, pending limit orders, підтвердження matches. У реальному часі, але eventually consistent - match підтверджується раніше, ніж ERC-1155 settle, що й породжує phantom-fill problem, описану в розділі 12.

Узгодження між ними має зрештою відбуватися завжди. Коли вони розходяться, chain є джерелом істини. Bot, який довіряє лише CLOB, буде drift; bot, який довіряє лише chain, торгуватиме повільно. Production code використовує обидва: CLOB - для рішень, чутливих до швидкості, chain - для періодичної reconciliation.

Адреса контракту pUSD та ABI

pUSD - це stablecoin wrapper Polymarket, який використовується з міграції V2 у 2025 році. Контракт за адресою 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB у Polygon mainnet є стандартним ERC-20.

Три важливі reads для bot:

  • balanceOf(proxy) - ваш доступний для витрат pUSD. Порівнюйте з тим, як CLOB бачить ваш balance, при кожному restart.
  • allowance(proxy, exchange_contract) - чи можуть контракти exchange CTF/NegRisk витрачати ваш pUSD. Потрібно для order matching.
  • Підписка на подію Transfer - виявляє deposit і withdrawal без polling.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) і далі лишається off-ramp pair. Більшості bot потрібні лише reads pUSD; USDC важливий тільки під час циклів deposit/withdrawal.

Conditional Tokens Framework (CTF)

Outcome shares - це токени ERC-1155, які mint-ить Gnosis Conditional Tokens Framework (CTF). Контракт CTF у Polygon за адресою 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 відстежує supply для кожного position-id.

Три reads:

  • balanceOf(proxy, position_id) - скільки outcome token ви фактично тримаєте для цього market+outcome.
  • getOutcomeSlotCount(condition_id) - кількість outcomes (2 для binary, N для multi-outcome).
  • payoutNumerators, payoutDenominator - встановлюються, коли UMA розв’язує market. Читаючи їх, ви дізнаєтеся, яка сторона виграла, ще до оновлення UI в CLOB.

Position_id - це hash від (condition_id, outcome_index). Обчислюйте його на клієнті через helper getPositionId у CTF або відтворіть keccak-математику у своєму стеку.

UMA Optimistic Oracle: події proposed і disputed

Optimistic Oracle (OO) від UMA обробляє всю dispute resolution Polymarket. Є дві події, на які ваш bot може підписатися.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) - спрацьовує, коли bot Polymarket пропонує outcome.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) - спрацьовує, коли хтось оскаржує запропонований outcome.

Адреса контракту OO: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Фільтруйте за адресою requester Polymarket.

Навіщо підписуватися: dispute означає, що resolution тепер оскаржується і потребуватиме голосування UMA протягом 24–72 годин. У цей період market може бути призупинений для торгівлі. Bot, який тримає позиції в disputed market, має знати про це негайно.

Читання Polygon event logs (web3.py / ethers)

Дві референсні реалізації.

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

Для безперервного моніторингу використовуйте WebSocket transport (wss://...) замість HTTP polling - менше запитів і швидша доставка. Більшість платних RPC providers включають WebSocket у entry tiers.

Коли читати on-chain, а коли довіряти API

Практичні правила з production.

  • Довіряйте API для: real-time order book, recent trades, ваших власних pending orders, market metadata (slug, question, end date), discovery events/markets.
  • Довіряйте chain для: вашого власного балансу pUSD, вашого власного inventory outcome-токенів, перевірки deposit і withdrawal, результатів resolution, стану dispute.
  • Перевіряйте обидва для: будь-якої фінансової дії, яку bot записав як fill - зіставляйте подію API “matched” з CTF transfer у chain, щоб підтвердити settlement.

Правило 5 секунд очікування після buy (розділ 12) - це on-chain reality, що втручається в API time. GTC sell, поданий одразу після market buy, побачить balance: 0 у chain check, навіть якщо CLOB щойно підтвердив match.

Код: визначити UMA dispute через event subscription

Референс: відстежуйте пов’язані з Polymarket спори UMA в реальному часі.

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)

Поле ancillaryData - це hex-encoded JSON-подібний текст, що містить запитання market. Його декодування дає вам identifier, еквівалентний slug, щоб зіставити його з вашими open positions.

Поширені запитання

Де знайти контракт pUSD Polymarket?
pUSD знаходиться за адресою 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB у Polygon. Він замінив USDC.e як канонічний collateral Polymarkets 28 квітня 2026 року. Посилання Polygonscan: https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB.
Що таке контракт CTF на Polymarket?
CTF означає Conditional Tokens Framework - похідний від Gnosis контракт ERC-1155, який випускає outcome token (частки YES і NO, якими ви торгуєте). Кожен market Polymarket - це позиція CTF із логікою redemption, пов’язаною з resolution від UMA. Bot рідко потрібно взаємодіяти з CTF напряму; це робить SDK.
Як підписатися на події UMA dispute в Polygon?
Підпишіться на події "ProposePrice" і "DisputePrice" контракту UMA Optimistic Oracle V2 через WebSocket вашого Polygon RPC provider. Фільтруйте за полем requesterAddress (oracle adapter Polymarket), щоб отримувати лише пов’язані зі Polymarket dispute. Приклади коду є в цьому розділі.
Чи потрібно читати on-chain data, якщо я довіряю Polymarket API?
Для більшості стратегій - ні. API CLOB є канонічним для order book і trade data, а gamma API - канонічним для metadata. On-chain читають тоді, коли потрібні (a) сповіщення про UMA dispute швидше, ніж вони з’являються в API, (b) перевірка, що deposit справді надійшов, або (c) custom analytics по outcomes/positions.
Яка latency on-chain даних Polygon порівняно з Polymarket API?
Час блоку Polygon - приблизно 2 секунди. Polymarket API зазвичай показує зміни order book протягом сотень мілісекунд після on-chain match. Для більшості сигналів API швидше за ваші власні on-chain reads. UMA disputes - виняток: on-chain event спрацьовує раніше, ніж UI відобразить dispute.
Чи можу я читати positions Polymarket без API CLOB?
Технічно так - читайте CTF balanceOf(walletAddress, positionId) для кожної позиції. На практиці endpoint CLOB API /trade/positions швидший, містить pricing і агрегує всі ваші positions. Переходьте до on-chain reads лише тоді, коли потрібна верифікація або API недоступний.