Polymarket Bot Tutorial · Глава 9 из 32

Читайте on-chain data Polymarket напрямую: балансы USDC/pUSD, CTF contract reads для supply исходов, события UMA Optimistic Oracle proposed/disputed и Polygon transaction logs - с code.

Что охватывает эта глава

APIs Polymarket удобны, но eventually consistent. Истина - в chain. В этой главе рассматриваются on-chain reads, которые production bot использует для проверки собственной бухгалтерии: pUSD balances, inventory outcome-токенов, события споров UMA и state CTF contract. Паттерн, к которому приходят большинство production bots: API-first для скорости плюс periodic on-chain reconciliation для корректности.

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

Что живет on-chain (vs in CLOB)

Две state machines, две истины.

On-chain (Polygon): pUSD balances, inventory outcome-токенов (ERC-1155 supply на каждый token), allowance approvals, предложения и disputes UMA Optimistic Oracle, события deposit и withdrawal. Eventually correct; latency - один Polygon block (~2 секунды).

CLOB (Polymarket API): order book, recent trades, pending limit orders, match acknowledgments. Real-time, но eventually consistent - match подтверждается до того, как ERC-1155 settled, что и создает проблему phantom-fill, описанную в главе 12.

Обе стороны должны всегда converge. Когда они расходятся, chain - authoritative. Bot, который доверяет только CLOB, будет drift; bot, который доверяет только chain, будет торговать медленно. Production code использует оба источника: CLOB для speed-critical решений, chain - для periodic reconciliation.

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

pUSD - это wrapper stablecoin Polymarket, используемый с migration V2 в 2025 году. Контракт по адресу 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB в Polygon mainnet - стандартный ERC-20.

Три reads, важные для bot:

  • balanceOf(proxy) - ваш spendable pUSD. Сравнивайте с view CLOB на ваш balance при каждом restart.
  • allowance(proxy, exchange_contract) - могут ли CTF/NegRisk exchange contracts тратить ваш pUSD. Требуется для order matching.
  • Подписка на event Transfer - detects deposits и withdrawals без polling.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) по-прежнему остается off-ramp pair. Большинству bot нужны только pUSD reads; USDC важен только во время циклов deposit/withdrawal.

Conditional Tokens Framework (CTF)

Outcome shares - это ERC-1155 tokens, minted Gnosis Conditional Tokens Framework (CTF). Контракт CTF в Polygon по адресу 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 tracks supply по каждому position-id.

Три reads:

  • balanceOf(proxy, position_id) - сколько outcome tokens вы реально держите для этого market+outcome.
  • getOutcomeSlotCount(condition_id) - число outcomes (2 для binary, N для multi-outcome).
  • payoutNumerators, payoutDenominator - задаются, когда UMA resolves market. Чтение этого показывает, какая сторона победила, еще до того, как CLOB UI обновится.

position_id - это hash от (condition_id, outcome_index). Вычисляйте его на клиенте через helper getPositionId в CTF или воспроизведите keccak math в своем stack.

UMA Optimistic Oracle: события proposed и disputed

UMA Optimistic Oracle (OO) обрабатывает все dispute resolution в Polymarket. Два события, на которые ваш bot может захотеть подписаться.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) - срабатывает, когда bot Polymarket предлагает outcome.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) - срабатывает, когда кто-то оспаривает предложенный outcome.

Адрес OO contract: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Фильтруйте по requester address Polymarket.

Почему стоит подписаться: dispute означает, что resolution теперь contested и потребует 24-72h UMA vote. В течение этого окна market может быть paused для trading. Bot, удерживающий позиции в disputed market, должен узнать об этом немедленно.

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

Две reference implementation.

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

Для continuous monitoring используйте WebSocket transport (wss://...) вместо HTTP polling - меньше requests и быстрее delivery. У большинства paid RPC providers WebSocket входит в entry tiers.

Когда читать on-chain, а когда доверять API

Практические правила из production.

  • Доверяйте API для: real-time order book, recent trades, ваших pending orders, market metadata (slug, question, end date), event/market discovery.
  • Доверяйте chain для: вашего собственного pUSD balance, вашего собственного inventory outcome-токенов, проверки deposit и withdrawal, outcomes resolution, dispute state.
  • Сверяйте оба источника для: любой финансовой операции, которую bot записал как fill - сопоставляйте API-событие "matched" с CTF transfer в chain, чтобы подтвердить settlement.

Правило 5-second-wait после buy (глава 12) - это on-chain reality, врывающаяся в API time. GTC sell, отправленный сразу после market buy, увидит balance: 0 в chain check, хотя CLOB matched его мгновения назад.

Code: определение dispute UMA через event subscription

Reference: отслеживайте связанные с Polymarket disputes UMA в 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)

Поле ancillaryData - это hex-encoded JSON-ish text, содержащий question рынка. Его decode дает identifier, эквивалентный slug, чтобы сверить его с вашими open positions.

Часто задаваемые вопросы

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