Polymarket Bot 教程 · 第 9 章,共 32 章

直接读取 Polymarket 链上数据:USDC/pUSD 余额、用于查看 outcome supply 的 CTF 合约读数、UMA Optimistic Oracle 的 proposed/disputed 事件,以及 Polygon 交易日志-附代码。

本章内容

Polymarket 的 API 很方便,但最终一致。链上数据才是权威。本章会讲解生产环境 bot 用来校验自身账本的链上读取:pUSD 余额、outcome-token 库存、UMA dispute 事件,以及 CTF 合约状态。大多数生产 bot 最终都会采用的模式是:API 优先以追求速度,再定期进行链上对账以保证正确性。

  • 链上有哪些内容(与 CLOB 相比)
  • pUSD 合约地址和 ABI
  • Conditional Tokens Framework(CTF)
  • UMA Optimistic Oracle:proposed 和 disputed 事件
  • 读取 Polygon event logs(web3.py / ethers)
  • 何时读链上,何时信任 API
  • 代码:通过事件订阅检测 UMA dispute

链上有哪些内容(与 CLOB 相比)

两个 state machine,两种事实。

链上(Polygon):pUSD 余额、outcome-token 库存(每个 token 的 ERC-1155 supply)、allowance 授权、UMA Optimistic Oracle 的提案和 dispute、deposit 和 withdrawal 事件。最终会正确;延迟大约是一个 Polygon block(约 2 秒)。

CLOB(Polymarket API):订单簿、最近成交、待处理限价单、撮合确认。实时但最终一致-在 ERC-1155 完成结算之前,撮合就已经被确认,这会产生第 12 章会讲到的 phantom-fill 问题。

两者应始终收敛。当它们不一致时,以链上为准。只信 CLOB 的 bot 会逐渐漂移;只信链上的 bot 会交易变慢。生产代码会同时使用两者:CLOB 负责对速度敏感的决策,链上负责周期性对账。

pUSD 合约地址和 ABI

pUSD 是 Polymarket 的抵押品代币,随 2026 年 4 月的 V2 平台升级推出。Polygon mainnet 上地址为 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB 的合约是标准 ERC-20(其链上 symbol 就是 “pUSD”,可在 Polygonscan 上核实)。

对 bot 来说,最重要的三个读取:

  • balanceOf(proxy)-你可支配的 pUSD。每次重启时都要与 CLOB 对你余额的视图进行对比。
  • allowance(proxy, exchange_contract)-CTF/NegRisk 交易所合约是否可以花费你的 pUSD。撮合订单时需要。
  • Transfer 事件订阅-无需轮询即可检测 deposit 和 withdrawal。

USDC(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174)仍然是出入金配对资产。大多数 bot 只需要读取 pUSD;USDC 只在 deposit/withdrawal 周期中才重要。

Conditional Tokens Framework(CTF)

outcome shares 是由 Gnosis 的 Conditional Tokens Framework(CTF)铸造的 ERC-1155 token。Polygon 上位于 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 的 CTF 合约会跟踪每个 position-id 的 supply。

三个读取:

  • balanceOf(proxy, position_id)-你在该 market+outcome 下实际持有多少 outcome token。
  • getOutcomeSlotCount(condition_id)-outcome 数量(二元市场为 2,多 outcome 市场为 N)。
  • payoutNumeratorspayoutDenominator-在 UMA 结算 market 时设置。读取这些值可以让你在 CLOB UI 更新前就知道哪一边获胜。

position_id 是(condition_id,outcome_index)的哈希。可通过 CTF 的 getPositionId helper 在客户端计算,或者在你的技术栈中复现 keccak 计算逻辑。

UMA Optimistic Oracle:proposed 和 disputed 事件

UMA 的 Optimistic Oracle(OO)负责所有 Polymarket dispute resolution。你的 bot 可能希望订阅两个事件。

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice)-当 Polymarket bot 提议一个 outcome 时触发。
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer)-当有人质疑该提议 outcome 时触发。

OO 合约地址:0xeE3Afe347D5C74317041E2618C49534dAf887c24。按 Polymarket 的 requester 地址进行过滤。

为什么要订阅:一旦发生 dispute,resolution 就变成争议状态,并需要 24-72 小时的 UMA 投票。在这段时间里,market 可能会暂停交易。持有该 disputed market 仓位的 bot 应该立即知晓。

读取 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 传输(wss://...)而不是 HTTP polling-请求更少,交付更快。大多数付费 RPC provider 都在入门套餐中包含 WebSocket。

何时读链上,何时信任 API

来自生产环境的实用规则。

  • 信任 API 的场景:实时订单簿、最近成交、你自己的待处理订单、market 元数据(slug、question、end date)、event/market discovery。
  • 信任链上 的场景:你自己的 pUSD 余额、你自己的 outcome-token 库存、deposit 和 withdrawal 验证、resolution 结果、dispute 状态。
  • 同时交叉核对 的场景:任何被 bot 记为成交的金融数据-将 API 的 “matched” 事件与链上的 CTF transfer 对照,以确认结算。

买入后等待 5 秒的规则(第 12 章)体现的就是链上现实对 API 时间的侵入。刚提交市场买单后立即再提交 GTC 卖单,即使 CLOB 刚刚匹配成功,链上检查也会显示 balance: 0

代码:通过事件订阅检测 UMA dispute

参考:实时监控与 Polymarket 相关的 UMA dispute。

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 编码的类似 JSON 的文本,包含 market question。对其进行解码后,你就能得到类似 slug 的标识符,并将其与你持有的 open positions 进行交叉引用。

常见问题

我在哪里可以找到 Polymarket 的 pUSD 合约?
pUSD 位于 Polygon 上的 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB。它在 2026 年 4 月 28 日取代了 USDC.e,成为 Polymarkets 的标准抵押资产。Polygonscan 链接:https://polygonscan.com/token/0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB。
Polymarket 上的 CTF 合约是什么?
CTF 是 Conditional Tokens Framework 的缩写-一个源自 Gnosis 的 ERC-1155 合约,用于发行 outcome token(你交易的 YES 和 NO shares)。每个 Polymarket market 都是一个 CTF position,其 redemption 逻辑与 UMA 的 resolution 绑定。bot 很少需要直接与 CTF 交互;SDK 会处理这些细节。
我如何在 Polygon 上订阅 UMA dispute 事件?
通过你的 Polygon RPC provider 的 WebSocket,订阅 UMA Optimistic Oracle V2 合约的 "ProposePrice" 和 "DisputePrice" 事件。按 requesterAddress 字段(Polymarkets oracle adapter)过滤,就能只获取与 Polymarket 相关的 dispute。章节中有代码示例。
如果我信任 Polymarket API,还需要读取链上数据吗?
对于大多数策略,不需要。CLOB API 是订单簿和交易数据的 canonical 来源,gamma API 是元数据的 canonical 来源。只有在你需要 (a) 比 API 更快地收到 UMA dispute 警报,(b) 验证 deposit 是否真的到账,或 (c) 对 outcome/position 做自定义分析时,才读取链上。
链上 Polygon 数据和 Polymarket API 的延迟是多少?
Polygon 的 block time 大约是 2 秒。Polymarket API 通常会在链上撮合后的几百毫秒内展示订单簿变化。对于大多数信号来说,API 比你自己读取链上数据更快。UMA dispute 是个例外-链上事件触发早于 UI 显示 dispute。
不使用 CLOB API,我能读取 Polymarket positions 吗?
技术上可以-对每个 position 读取 CTF 的 balanceOf(walletAddress, positionId)。但实际上,CLOB API 的 /trade/positions endpoint 更快,包含定价,并会聚合你所有的 positions。只有在你需要验证或 API 挂掉时,才退回到链上读取。