Учебник по ботам Полимаркет · Глава 9 из 32
Читайте ончейн-данные Полимаркет напрямую: балансы USDC/pUSD, чтения CTF-контракта для объёма выпуска исходов, события предложения/оспаривания UMA Optimistic Oracle и логи транзакций Polygon — с кодом.
Что охватывает эта глава
API Полимаркет удобны, но согласуются не мгновенно. Истина — в блокчейне. В этой главе рассматриваются чтения ончейн, которые боевой бот использует для проверки собственной бухгалтерии: балансы pUSD, запас токенов исходов, события споров UMA и состояние CTF-контракта. Паттерн, к которому приходит большинство боевых ботов: сначала API для скорости плюс периодическая ончейн-сверка для корректности.
- Что живёт ончейн (в отличие от CLOB)
- Адрес и ABI контракта pUSD
- Conditional Tokens Framework (CTF)
- UMA Optimistic Oracle: события предложения и оспаривания
- Чтение логов событий Polygon (web3.py / ethers)
- Когда читать ончейн, а когда доверять API
- Код: определить спор UMA через подписку на события
Что живёт ончейн (в отличие от CLOB)
Два конечных автомата, две истины.
Ончейн (Polygon): балансы pUSD, запас токенов исходов (объём выпуска ERC-1155 на каждый токен), одобрения allowance, предложения и споры UMA Optimistic Oracle, события депозита и вывода. В конечном счёте корректно; задержка — один блок Polygon (~2 секунды).
CLOB (API Полимаркет): стакан заявок, последние сделки, ожидающие лимитные ордера, подтверждения совпадений. В реальном времени, но согласуется не мгновенно — совпадение подтверждается до того, как ERC-1155 рассчитан по сети, что и создаёт проблему фантомного исполнения, описанную в главе 12.
Обе стороны всегда должны сходиться. Когда они расходятся, блокчейн — авторитетный источник. Бот, который доверяет только CLOB, будет дрейфовать; бот, который доверяет только блокчейну, будет торговать медленно. Боевой код использует оба источника: CLOB для критичных к скорости решений, блокчейн — для периодической сверки.
Адрес и ABI контракта pUSD
pUSD — это обёрточный стейблкоин Полимаркет, используемый с миграции V2 в 2026 году. Контракт по адресу 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB в Polygon mainnet — стандартный ERC-20.
Три чтения, важные для бота:
balanceOf(proxy)— ваш доступный для траты pUSD. Сравнивайте с представлением CLOB о вашем балансе при каждом перезапуске.allowance(proxy, exchange_contract)— могут ли контракты обмена CTF/NegRisk тратить ваш pUSD. Требуется для сопоставления ордеров.- Подписка на событие
Transfer— обнаруживает депозиты и выводы без опроса.
USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) по-прежнему остаётся парой для вывода в фиат. Большинству ботов нужны только чтения pUSD; USDC важен только во время циклов депозита/вывода.
Conditional Tokens Framework (CTF)
Доли исходов — это токены ERC-1155, выпускаемые Gnosis Conditional Tokens Framework (CTF). Контракт CTF в Polygon по адресу 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 отслеживает объём выпуска по каждому position-id.
Три reads:
balanceOf(proxy, position_id)— сколько токенов исходов вы реально держите для этого рынка и исхода.getOutcomeSlotCount(condition_id)— число исходов (2 для бинарного, N для многовариантного).payoutNumerators,payoutDenominator— задаются, когда UMA рассчитывает рынок. Чтение этого показывает, какая сторона победила, ещё до того, как обновится интерфейс CLOB.
position_id — это хеш от (condition_id, outcome_index). Вычисляйте его на клиенте через вспомогательную функцию getPositionId в CTF или воспроизведите вычисления keccak в своём стеке.
UMA Optimistic Oracle: события proposed и disputed
UMA Optimistic Oracle (OO) обрабатывает все расчёты по спорам в Полимаркет. Два события, на которые ваш бот может захотеть подписаться.
ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice)— срабатывает, когда бот Полимаркет предлагает исход.DisputePrice(requester, identifier, timestamp, ancillaryData, disputer)— срабатывает, когда кто-то оспаривает предложенный исход.
Адрес контракта OO: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Фильтруйте по адресу requester Полимаркет.
Почему стоит подписаться: спор означает, что расчёт теперь оспаривается и потребует 24-72 ч голосования UMA. В течение этого окна рынок может быть приостановлен для торговли. Бот, удерживающий позиции в оспоренном рынке, должен узнать об этом немедленно.
Чтение логов событий Polygon (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 (wss://...) вместо опроса по HTTP — меньше запросов и быстрее доставка. У большинства платных RPC-провайдеров WebSocket входит в начальные тарифы.
Когда читать ончейн, а когда доверять API
Практические правила из боевой эксплуатации.
- Доверяйте API для: стакана заявок в реальном времени, последних сделок, ваших ожидающих ордеров, метаданных рынка (slug, вопрос, дата окончания), обнаружения событий/рынков.
- Доверяйте блокчейну для: вашего собственного баланса pUSD, вашего собственного запаса токенов исходов, проверки депозита и вывода, расчёта исходов, состояния спора.
- Сверяйте оба источника для: любой финансовой операции, которую бот записал как исполнение — сопоставляйте API-событие «matched» с переводом CTF в блокчейне, чтобы подтвердить расчёт по сети.
Правило 5-секундного ожидания после покупки (глава 12) — это ончейн-реальность, врывающаяся во время API. GTC-продажа, отправленная сразу после рыночной покупки, увидит balance: 0 при проверке блокчейна, хотя CLOB сопоставил её мгновения назад.
Код: определение спора UMA через подписку на события
Эталон: отслеживайте связанные с Полимаркет споры 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..." # Полимаркет's UMA requester address
def on_dispute(event):
args = event["args"]
if args["requester"].lower() != POLY_REQUESTER.lower(): return
print(f"DISPUTE on Полимаркет 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-кодировке, похожий на JSON, содержащий вопрос рынка. Его декодирование даёт идентификатор, эквивалентный slug, чтобы сверить его с вашими открытыми позициями.


