Polymarket Bot Tutorial · 第32章中9章目

Polymarketのオンチェーンデータを直接読む:USDC/pUSD残高、結果供給のためのCTFコントラクト読み取り、UMA Optimistic Oracleのproposed/disputedイベント、Polygonのトランザクションログ - コード付き。

この章で扱う内容

PolymarketのAPIは便利ですが、最終的整合性です。チェーンが正です。この章では、本番Botが自分の記帳を検証するために使うオンチェーン読み取りを解説します:pUSD残高、結果トークンの在庫、UMAの紛争イベント、CTFコントラクト状態です。本番Botの多くがたどり着くパターンは、高速化のためのAPI優先と、正確性のための定期的なオンチェーン再照合です。

  • オンチェーンにあるもの(CLOBと比較して)
  • pUSDコントラクトアドレスとABI
  • Conditional Tokens Framework(CTF)
  • UMA Optimistic Oracle: proposed と disputed イベント
  • Polygonイベントログの読み取り(web3.py / ethers)
  • いつオンチェーンを読むか、いつAPIを信頼するか
  • コード:イベント購読でUMAの紛争を検出する

オンチェーンにあるもの(CLOBと比較して)

2つのステートマシン、2つの真実。

オンチェーン(Polygon): pUSD残高、結果トークンの在庫(トークンごとのERC-1155供給量)、allowanceの承認、UMA Optimistic Oracleの提案と紛争、入出金イベント。最終的には正しくなるが、遅延はPolygon 1ブロック分(約2秒)です。

CLOB(Polymarket API): 注文板、最近の約定、保留中の指値注文、マッチの確認応答。リアルタイムですが最終的整合性です。ERC-1155が確定する前にマッチが確認されるため、12章で扱う phantom-fill 問題が発生します。

この2つは常に収束すべきです。ずれるときは、チェーンが正です。CLOBだけを信じるBotはずれていき、チェーンだけを信じるBotは遅くなります。本番コードでは両方を使います。速度が重要な判断にはCLOBを、正確性のための定期再照合にはチェーンを使います。

pUSDコントラクトアドレスとABI

pUSDは、2025年のV2移行以降に使われているPolymarketのステーブルコインラッパーです。Polygonメインネット上の 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB にあるコントラクトは標準的なERC-20です。

Botにとって重要な3つの読み取り:

  • balanceOf(proxy)-実際に使えるpUSD残高。起動のたびにCLOBの残高表示と比較します。
  • allowance(proxy, exchange_contract)-CTF/NegRiskのexchangeコントラクトがpUSDを使えるかどうか。注文マッチに必要です。
  • Transfer イベント購読-ポーリングなしで入出金を検出します。

USDC(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174)は引き続きオフランプのペアです。多くのBotではpUSDの読み取りだけで十分で、USDCが必要になるのは入出金サイクルのときだけです。

Conditional Tokens Framework(CTF)

結果シェアは、GnosisのConditional Tokens Framework(CTF)が発行するERC-1155トークンです。Polygon上の 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 にあるCTFコントラクトは、position-idごとの供給量を追跡します。

3つの読み取り:

  • balanceOf(proxy, position_id)-その市場+結果について、実際に保有している結果トークン数。
  • getOutcomeSlotCount(condition_id)-結果の数(バイナリなら2、多結果ならN)。
  • payoutNumerators, payoutDenominator-UMAが市場を解決したときに設定されます。これを読むと、CLOBのUIが更新される前にどちらが勝ったか分かります。

position_idは、(condition_id, outcome_index) のハッシュです。CTFの getPositionId ヘルパーを使ってクライアント側で計算するか、スタック内でkeccak計算を再実装してください。

UMA Optimistic Oracle: proposed と disputed イベント

UMAのOptimistic Oracle(OO)が、Polymarketのすべての紛争解決を処理します。Botが購読したい可能性のあるイベントは2つです。

  • ProposePrice(requester, identifier, timestamp, ancillaryData, proposer, proposedPrice)-Polymarket Botが結果を提案したときに発火します。
  • DisputePrice(requester, identifier, timestamp, ancillaryData, disputer)-誰かが提案された結果に異議を唱えたときに発火します。

OOコントラクトアドレス: 0xeE3Afe347D5C74317041E2618C49534dAf887c24。Polymarketのrequesterアドレスでフィルタしてください。

購読する理由:紛争が起きると、その解決は争点化され、24〜72時間のUMA投票が必要になります。その間、市場は取引停止になることがあります。紛争中の市場でポジションを持つBotは、すぐにそれを知るべきです。

Polygonイベントログの読み取り(web3.py / ethers)

2つの参考実装です。

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

継続的な監視には、HTTPポーリングではなくWebSocketトランスポート(wss://...)を使ってください。リクエスト数が減り、配信も速くなります。多くの有料RPCプロバイダーは、エントリーレベルでもWebSocketを含んでいます。

いつオンチェーンを読むか、いつAPIを信頼するか

本番運用から得た実践ルールです。

  • APIを信頼する: リアルタイムの注文板、最近の約定、保留中の自分の注文、マーケットメタデータ(slug、question、終了日)、イベント/マーケットの探索。
  • チェーンを信頼する: 自分のpUSD残高、自分の結果トークン在庫、入出金の検証、解決結果、紛争状態。
  • 両方を突き合わせる: Botが約定として記録した金額に関わるすべて。APIの「matched」イベントとチェーン上のCTF転送を照合して、確定を確認します。

購入後に5秒待つルール(12章)は、API時間にオンチェーンの現実が割り込む例です。市場買いの直後にGTC売りを出すと、CLOBでは数瞬前にマッチしていても、チェーン確認では balance: 0 になります。

コード:イベント購読でUMAの紛争を検出する

参考例:Polymarket関連の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..."  # 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 フィールドは、マーケットのquestionを含むhexエンコードされたJSON風テキストです。これをデコードすると、保有中ポジションと照合するためのslug相当の識別子を復元できます。

よくある質問

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コントラクトで、結果トークン(取引するYES/NOシェア)を発行します。各Polymarket市場はCTFポジションであり、UMAの解決に連動した償還ロジックを持ちます。BotがCTFに直接触る必要はほとんどなく、SDKが処理します。
Polygon上のUMA紛争イベントを購読するにはどうすればいいですか?
Polygon RPCプロバイダーのWebSocket経由で、UMA Optimistic Oracle V2コントラクトの "ProposePrice" と "DisputePrice" イベントを購読してください。requesterAddressフィールド(Polymarketsのoracle adapter)でフィルタすると、Polymarket関連の紛争だけを取得できます。コード例はこの章にあります。
Polymarket APIを信頼している場合でも、オンチェーンデータを読む必要はありますか?
多くの戦略では不要です。CLOB APIは注文板と取引データの正本で、gamma APIはメタデータの正本です。オンチェーンを読むのは、(a) APIより速くUMA紛争アラートを受けたい、(b) 入金が本当に着金したことを検証したい、(c) 結果/ポジションの独自分析をしたい、という場合です。
オンチェーンのPolygonデータとPolymarket APIの遅延はどのくらい違いますか?
Polygonのブロック時間は約2秒です。Polymarket APIは一般に、オンチェーンのマッチから数百ミリ秒以内に注文板の変化を反映します。多くのシグナルでは、APIのほうが自前のオンチェーン読み取りより速いです。UMA紛争は例外で、UIが紛争を反映する前にオンチェーンイベントが発火します。
CLOB APIなしでPolymarketのポジションを読めますか?
技術的には可能です。各ポジションについて CTF balanceOf(walletAddress, positionId) を読めばよいです。実務上は、CLOB APIの /trade/positions エンドポイントのほうが速く、価格情報も含み、全ポジションを集約してくれます。検証が必要なときやAPIが落ちているときだけ、オンチェーン読み取りにフォールバックしてください。