Polymarket Bot Tutorial · Capítulo 9 de 32

Leia dados on-chain da Polymarket diretamente: saldos de USDC/pUSD, leituras do contrato CTF para supply de outcome, eventos proposed/disputed do UMA Optimistic Oracle e logs de transação da Polygon - com código.

O que este capítulo aborda

As APIs da Polymarket são convenientes, mas eventualmente consistentes. A chain é a autoridade. Este capítulo mostra as leituras on-chain que um bot de produção usa para verificar sua própria contabilidade: saldos de pUSD, inventário de outcome-token, eventos de disputa da UMA e estado do contrato CTF. O padrão para o qual a maioria dos bots de produção converge é API-first para velocidade + reconciliação on-chain periódica para correção.

  • O que vive on-chain (vs no CLOB)
  • Endereço do contrato pUSD e ABI
  • Conditional Tokens Framework (CTF)
  • UMA Optimistic Oracle: eventos proposed e disputed
  • Leitura de logs de eventos da Polygon (web3.py / ethers)
  • Quando ler on-chain vs confiar na API
  • Código: detectar uma disputa da UMA via subscription de eventos

O que vive on-chain (vs no CLOB)

Duas state machines, duas verdades.

On-chain (Polygon): saldos de pUSD, inventário de outcome-token (supply ERC-1155 por token), approvals de allowance, propostas e disputas do UMA Optimistic Oracle, eventos de depósito e saque. Eventualmente correto; a latência é de um bloco da Polygon (~2 segundos).

CLOB (Polymarket API): order book, trades recentes, limit orders pendentes, acknowledgments de match. Em tempo real, mas eventualmente consistente - um match é confirmado antes de o ERC-1155 ser liquidado, o que produz o problema de phantom-fill coberto no capítulo 12.

Os dois devem sempre convergir. Quando divergem, a chain é a autoridade. Um bot que confia só no CLOB vai ficar desalinhado; um bot que confia só na chain vai operar devagar. O código de produção usa ambos: CLOB para decisões críticas de velocidade e chain para reconciliação periódica.

Endereço do contrato pUSD e ABI

pUSD é o wrapper de stablecoin da Polymarket usado desde a migração V2 de 2025. O contrato em 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB na Polygon mainnet é um ERC-20 padrão.

Três leituras que importam para um bot:

  • balanceOf(proxy) - seu pUSD disponível para gastar. Compare com a visão do CLOB sobre seu saldo em cada restart.
  • allowance(proxy, exchange_contract) - se os contratos de exchange do CTF/NegRisk podem gastar seu pUSD. Necessário para matching de ordens.
  • subscription do evento Transfer - detecta depósitos e saques sem polling.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) continua sendo o par de off-ramp. A maioria dos bots só precisa de leituras de pUSD; USDC importa apenas durante ciclos de depósito/saque.

Conditional Tokens Framework (CTF)

As shares de outcome são tokens ERC-1155 mintados pelo Conditional Tokens Framework (CTF) da Gnosis. O contrato CTF na Polygon em 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 rastreia o supply por position-id.

Três leituras:

  • balanceOf(proxy, position_id) - quantos outcome tokens você realmente possui para aquele market+outcome.
  • getOutcomeSlotCount(condition_id) - número de outcomes (2 para binário, N para multi-outcome).
  • payoutNumerators, payoutDenominator - definidos quando a UMA resolve o mercado. Ler isso mostra qual lado venceu antes de a UI do CLOB atualizar.

O position_id é um hash de (condition_id, outcome_index). Calcule-o no lado do cliente via o helper getPositionId do CTF ou replique a lógica de keccak no seu stack.

UMA Optimistic Oracle: eventos proposed e disputed

O Optimistic Oracle (OO) da UMA lida com toda a resolução de disputas da Polymarket. Dois eventos nos quais seu bot pode querer fazer subscription.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) - disparado quando um bot da Polymarket propõe um outcome.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) - disparado quando alguém contesta o outcome proposto.

Endereço do contrato OO: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Filtre pelo endereço requester da Polymarket.

Por que fazer subscription: uma disputa significa que a resolução agora está contestada e vai exigir um voto da UMA em 24-72h. Durante essa janela, o mercado pode ficar pausado para trading. Um bot que mantém posições em um mercado disputado deve saber disso imediatamente.

Leitura de logs de eventos da Polygon (web3.py / ethers)

Duas implementações de referência.

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

Para monitoramento contínuo, use transporte WebSocket (wss://...) em vez de polling HTTP - menos requests e entrega mais rápida. A maioria dos provedores pagos de RPC inclui WebSocket nos planos de entrada.

Quando ler on-chain vs confiar na API

Regras práticas de produção.

  • Confie na API para: order book em tempo real, trades recentes, suas próprias ordens pendentes, metadata do mercado (slug, question, data de encerramento), descoberta de eventos/mercados.
  • Confie na chain para: seu próprio saldo de pUSD, seu próprio inventário de outcome-token, verificação de depósito e saque, outcomes de resolução, estado de disputa.
  • Compare ambos para: qualquer coisa financeira que o bot registrou como fill - faça o match do evento "matched" da API com a transferência CTF da chain para confirmar a liquidação.

A regra dos 5 segundos de espera após uma compra (capítulo 12) é a realidade on-chain invadindo o tempo da API. Um sell GTC enviado imediatamente após uma compra no mercado verá balance: 0 na checagem on-chain, mesmo que o CLOB tenha feito o match segundos antes.

Código: detectar uma disputa da UMA via subscription de eventos

Referência: acompanhe disputas da UMA relacionadas à Polymarket em tempo real.

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)

O campo ancillaryData é texto em estilo JSON, codificado em hex, que contém a pergunta do mercado. Decodificá-lo fornece o identificador equivalente ao slug para cruzar com suas posições abertas.

Perguntas frequentes

Onde posso encontrar o contrato pUSD da Polymarket?
pUSD fica em 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB na Polygon. Ele substituiu USDC.e como collateral canônico da Polymarket em 28 de abril de 2026. Link do Polygonscan: https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB.
O que é o contrato CTF na Polymarket?
CTF significa Conditional Tokens Framework - o contrato ERC-1155 derivado da Gnosis que emite tokens de outcome (as shares YES e NO que você negocia). Cada mercado da Polymarket é uma posição CTF com lógica de resgate ligada à resolução da UMA. Bots raramente precisam interagir diretamente com o CTF; o SDK cuida disso.
Como faço subscription para eventos de disputa da UMA na Polygon?
Faça subscription aos eventos "ProposePrice" e "DisputePrice" do contrato UMA Optimistic Oracle V2 via o WebSocket do seu provedor RPC da Polygon. Filtre pelo campo requesterAddress (o adapter oracle da Polymarket) para ver apenas disputas relacionadas à Polymarket. Exemplos de código neste capítulo.
Preciso ler dados on-chain se eu confio na API da Polymarket?
Para a maioria das estratégias, não. A API do CLOB é canônica para dados de order book e trade, e a API gamma é canônica para metadata. Você lê on-chain quando precisa de (a) alertas de disputa da UMA mais rápidos do que a API mostra, (b) verificação de que um depósito realmente chegou ou (c) analytics customizados sobre outcomes/posições.
Qual é a latência dos dados on-chain da Polygon vs a API da Polymarket?
O tempo de bloco da Polygon é de ~2 segundos. A API da Polymarket geralmente expõe mudanças no order book dentro de centenas de milissegundos após o match on-chain. Para a maioria dos sinais, a API é mais rápida do que suas próprias leituras on-chain. Disputas da UMA são uma exceção - o evento on-chain dispara antes de a UI refletir a disputa.
Posso ler posições da Polymarket sem a API do CLOB?
Tecnicamente, sim - leia CTF balanceOf(walletAddress, positionId) para cada posição. Na prática, o endpoint /trade/positions da API do CLOB é mais rápido, inclui pricing e agrega todas as suas posições. Só recorra às leituras on-chain se precisar de verificação ou se a API estiver fora do ar.