Tutorial de Bot de Polymarket · Capítulo 9 de 32

Lee datos on-chain de Polymarket directamente: balances de USDC/pUSD, lecturas del contrato CTF para el suministro de resultados, eventos propuestos y disputados del UMA Optimistic Oracle, y logs de transacciones de Polygon, con código.

Qué cubre este capítulo

Las APIs de Polymarket son convenientes, pero eventualmente consistentes. La cadena es la fuente de verdad. Este capítulo recorre las lecturas on-chain que usa un bot en producción para verificar su propia contabilidad: balances de pUSD, inventario de outcome tokens, eventos de disputa de UMA y estado del contrato CTF. El patrón al que convergen la mayoría de los bots de producción es API-first para velocidad, más reconciliación on-chain periódica para asegurar precisión.

  • Qué vive on-chain (vs en CLOB)
  • Dirección del contrato pUSD y ABI
  • Conditional Tokens Framework (CTF)
  • UMA Optimistic Oracle: eventos proposed y disputed
  • Lectura de logs de eventos en Polygon (web3.py / ethers)
  • Cuándo leer on-chain vs confiar en la API
  • Código: detectar una disputa de UMA mediante suscripción a eventos

Qué vive on-chain (vs en CLOB)

Dos máquinas de estado, dos verdades.

On-chain (Polygon): balances de pUSD, inventario de outcome tokens (suministro ERC-1155 por token), approvals de allowance, propuestas y disputas del UMA Optimistic Oracle, eventos de depósito y retiro. Eventualmente correcto; la latencia es de un bloque de Polygon, aproximadamente 2 segundos.

CLOB (Polymarket API): order book, trades recientes, órdenes limitadas pendientes, acuses de ejecución. En tiempo real, pero eventualmente consistente: una ejecución se confirma antes de que el ERC-1155 se liquide, lo que produce el problema de phantom-fill que se cubre en el capítulo 12.

Ambos siempre deben converger. Cuando divergen, la cadena es la autoridad. Un bot que confía solo en el CLOB se desalineará; un bot que confía solo en la cadena operará lento. El código de producción usa ambos: CLOB para decisiones críticas de velocidad y la cadena para reconciliación periódica.

Dirección del contrato pUSD y ABI

pUSD es el wrapper de stablecoin de Polymarket usado desde la migración V2 de 2025. El contrato en 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB en Polygon mainnet es un ERC-20 estándar.

Tres lecturas que le importan a un bot:

  • balanceOf(proxy) - tu pUSD gastable. Compáralo con la vista del CLOB sobre tu balance en cada reinicio.
  • allowance(proxy, exchange_contract) - si los contratos de exchange CTF/NegRisk pueden gastar tu pUSD. Requerido para el match de órdenes.
  • Suscripción al evento Transfer - detecta depósitos y retiros sin polling.

USDC (0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) sigue siendo el par de salida. La mayoría de los bots solo necesitan lecturas de pUSD; USDC importa solo durante los ciclos de depósito/retiro.

Conditional Tokens Framework (CTF)

Las participaciones de resultado son tokens ERC-1155 acuñados por el Conditional Tokens Framework (CTF) de Gnosis. El contrato CTF en Polygon en 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 rastrea el suministro por position-id.

Tres lecturas:

  • balanceOf(proxy, position_id) - cuántos outcome tokens realmente tienes para ese mercado+resultado.
  • getOutcomeSlotCount(condition_id) - número de resultados (2 para binario, N para multioutcome).
  • payoutNumerators, payoutDenominator - se establecen cuando UMA resuelve el mercado. Leerlos te dice qué lado ganó antes de que la UI del CLOB se actualice.

El position_id es un hash de (condition_id, outcome_index). Calcúlalo del lado del cliente con el helper getPositionId del CTF o replica la lógica de keccak en tu stack.

UMA Optimistic Oracle: eventos proposed y disputed

El Optimistic Oracle (OO) de UMA maneja toda la resolución de disputas de Polymarket. Dos eventos a los que tu bot puede querer suscribirse.

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice) - se dispara cuando un bot de Polymarket propone un resultado.
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer) - se dispara cuando alguien impugna el resultado propuesto.

Dirección del contrato OO: 0xeE3Afe347D5C74317041E2618C49534dAf887c24. Filtra por la dirección requester de Polymarket.

Por qué suscribirse: una disputa significa que la resolución ahora está en controversia y requerirá una votación de UMA de 24 a 72 horas. Durante esa ventana, el mercado puede quedar pausado para trading. Un bot que mantiene posiciones en un mercado disputado debe saberlo de inmediato.

Lectura de logs de eventos en Polygon (web3.py / ethers)

Dos implementaciones de referencia.

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 monitoreo continuo usa transporte WebSocket (wss://...) en lugar de polling por HTTP: menos requests y entrega más rápida. La mayoría de los proveedores RPC de pago incluyen WebSocket en planes de entrada.

Cuándo leer on-chain vs confiar en la API

Reglas prácticas de producción.

  • Confía en la API para: order book en tiempo real, trades recientes, tus órdenes pendientes, metadatos del mercado (slug, pregunta, fecha de cierre), descubrimiento de eventos/mercados.
  • Confía en la cadena para: tu propio balance de pUSD, tu inventario de outcome tokens, verificación de depósitos y retiros, resultados de resolución, estado de disputa.
  • Contrasta ambos para: cualquier dato financiero que el bot registró como fill: compara el evento "matched" de la API con el transfer de CTF en la cadena para confirmar la liquidación.

La regla de esperar 5 segundos después de una compra (capítulo 12) es la realidad on-chain irrumpiendo en el tiempo de la API. Una venta GTC enviada inmediatamente después de una compra de mercado verá balance: 0 en la verificación de cadena, aunque el CLOB haya hecho match momentos antes.

Código: detectar una disputa de UMA mediante suscripción a eventos

Referencia: vigila en tiempo real las disputas de UMA relacionadas con Polymarket.

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)

El campo ancillaryData es texto tipo JSON codificado en hex que contiene la pregunta del mercado. Decodificarlo te da el identificador equivalente al slug para cruzarlo con tus posiciones abiertas.

Preguntas frecuentes

¿Dónde puedo encontrar el contrato pUSD de Polymarket?
pUSD está en 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB en Polygon. Reemplazó a USDC.e como el collateral canónico de Polymarket el 28 de abril de 2026. Enlace de Polygonscan: https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB.
¿Qué es el contrato CTF en Polymarket?
CTF significa Conditional Tokens Framework: el contrato ERC-1155 derivado de Gnosis que emite outcome tokens (las participaciones YES y NO que negocias). Cada mercado de Polymarket es una posición CTF con lógica de redención ligada a la resolución de UMA. Los bots rara vez necesitan interactuar con CTF directamente; el SDK lo maneja.
¿Cómo me suscribo a eventos de disputa de UMA en Polygon?
Suscríbete a los eventos "ProposePrice" y "DisputePrice" del contrato UMA Optimistic Oracle V2 mediante el WebSocket de tu proveedor RPC de Polygon. Filtra por el campo requesterAddress (el oracle adapter de Polymarket) para obtener solo disputas relacionadas con Polymarket. Hay ejemplos de código en el capítulo.
¿Necesito leer datos on-chain si confío en la API de Polymarket?
Para la mayoría de las estrategias, no. La API del CLOB es la fuente canónica para datos del order book y de trades, y la API gamma es la fuente canónica para metadatos. Lees on-chain cuando necesitas (a) alertas de disputa de UMA más rápidas que lo que expone la API, (b) verificar que un depósito realmente llegó, o (c) analítica personalizada sobre resultados/posiciones.
¿Cuál es la latencia de los datos on-chain de Polygon vs la API de Polymarket?
El tiempo de bloque de Polygon es de aproximadamente 2 segundos. La API de Polymarket generalmente expone cambios del order book dentro de cientos de milisegundos del match on-chain. Para la mayoría de las señales, la API es más rápida que tus propias lecturas on-chain. Las disputas de UMA son una excepción: el evento on-chain se dispara antes de que la UI refleje la disputa.
¿Puedo leer posiciones de Polymarket sin la API del CLOB?
Técnicamente sí: lee CTF balanceOf(walletAddress, positionId) para cada posición. En la práctica, el endpoint /trade/positions de la API del CLOB es más rápido, incluye pricing y agrega todas tus posiciones. Recurre a lecturas on-chain solo si necesitas verificación o la API está caída.