Polymarket Bot Tutorial · Chapter 18 of 32

UMA dispute prediction bots on Polymarket: detect Optimistic Oracle proposals, predict dispute likelihood, exploit pre-and-post-dispute price asymmetry, and avoid disputed-market death spirals.

What this chapter covers

UMA's Optimistic Oracle resolves Polymarket markets, and disputes create price anomalies before and after they fire. Tradeable patterns exist on both sides of a dispute, but the strategy is operationally complex and has burned more bots than it has fed. This chapter is the honest playbook.

  • How UMA Optimistic Oracle works
  • Detecting a proposal on-chain
  • Dispute predictors (volume, ambiguity, history)
  • Pre-dispute price asymmetry
  • Post-dispute trade setups
  • When NOT to trade disputed markets
  • Code: subscribe to UMA proposed/disputed events

How UMA Optimistic Oracle works

UMA's Optimistic Oracle (OO) is the dispute resolution layer for Polymarket. Every market resolution goes through OO; most are uncontested and settle automatically. The contested ones - disputes - trigger a 24-72 hour voting period during which UMA token holders decide the outcome.

The lifecycle: Polymarket's resolver proposes a price (0 = NO won, 1 = YES won). After a 2-hour challenge window, if no one disputes, the price is finalized and the CTF contract distributes payouts. If someone disputes, the market enters a voting window; UMA holders cast votes, the majority wins.

For a bot, the relevant events are ProposePrice (proposal entered, challenge window opens) and DisputePrice (dispute filed, voting period begins). Subscribe to these to track market resolution state in real time.

Detecting a proposal on-chain

The UMA OO contract on Polygon emits a ProposePrice event with the parameters (requester, identifier, timestamp, ancillaryData, proposer, proposedPrice). Filter by Polymarket's known requester address to limit to relevant proposals.

POLY_REQUESTER = "0x..."  # Polymarket Adjudicator
filt = oo_contract.events.ProposePrice.create_filter(
    fromBlock="latest",
    argument_filters={"requester": POLY_REQUESTER}
)
for event in filt.get_new_entries():
    market_id = decode_ancillary(event.args.ancillaryData)
    proposed = "YES" if event.args.proposedPrice == 1e18 else "NO"
    print(f"PROPOSE: market {market_id} → {proposed}")

The ancillaryData field is hex-encoded JSON describing the market question. Decoding it gives you the market identifier you can cross-reference against your open positions.

Dispute predictors (volume, ambiguity, history)

Three pre-dispute signals correlate with later actual disputes.

  • Total volume: markets with > $1M in lifetime volume are disputed at 4x the rate of small markets. More capital at stake = more incentive to challenge.
  • Ambiguous wording: any market with "or similar," "officially confirmed," or compound conditions (date AND specific outcome) has elevated dispute rates.
  • Past disputes on the same event: if an earlier proposal was already disputed and re-proposed, the second proposal is disputed at 2-3x normal rate.

A bot can compute a "dispute probability" score from these features and avoid taking positions in markets above a threshold close to resolution.

Pre-dispute price asymmetry

In the hours before a likely dispute, the market price often shows asymmetric movement: the side that the proposer named as YES drifts down (because traders fear a dispute will flip it), the other side drifts up.

If you have a directional view on which way the dispute will resolve, this is a tradeable window. The risk: if the dispute does not happen, the asymmetry reverses when the challenge window closes uneventfully and prices snap back to the proposed direction.

Honest: most pre-dispute asymmetry trades are losing trades because most challenges resolve in favor of the original proposal. The strategy only works when you have specific information about why this dispute is likely to be sustained.

Post-dispute trade setups

After a dispute is filed, the market trades for 24-72 hours in "limbo" - known to be disputed, outcome to be voted. Two setups exist.

Convergence to UMA consensus: if the dispute resolution is signaled early (e.g. a prominent UMA voter publicly takes a side), the price moves toward that resolution. A bot watching UMA Discord / Twitter signals + price action can catch this 30-60% of the time.

Volatility farming: limbo periods have wide spreads. A patient market maker can earn the spread tax across multiple traders rotating in and out during the voting window. Inventory risk is high; size accordingly.

Both require comfort with the genuine possibility of resolution against your position. Treat dispute-period inventory as half-size at most.

When NOT to trade disputed markets

Three situations where the dispute trade is wrong by default.

  • You do not have a UMA-specific view. If your only edge is "the original proposal looks correct to me," you have no edge over the original proposer - and the dispute filer thinks the opposite. The voting outcome is a coin flip you cannot predict.
  • The dispute is on an ambiguous wording. UMA voters generally side with strict-reading-of-the-question. If the market said "by January 31" and the event happened February 1, UMA will resolve NO regardless of the trader population's intuition.
  • You hold inventory from before the dispute. Adding to an existing position to "average down" through limbo is the classic capital-destruction pattern. Hold or exit, never add.

Code: subscribe to UMA proposed/disputed events

Reference: WebSocket subscription to UMA OO events, filtered by Polymarket requester.

from web3 import Web3
w3 = Web3(Web3.WebsocketProvider(POLYGON_WSS))
oo = w3.eth.contract(address=UMA_OO_ADDR, abi=UMA_OO_ABI)
POLY = "0x...".lower()

dispute_filter = oo.events.DisputePrice.create_filter(fromBlock="latest")
propose_filter = oo.events.ProposePrice.create_filter(fromBlock="latest")

while True:
    for event in dispute_filter.get_new_entries():
        if event.args.requester.lower() == POLY:
            on_dispute(event)
    for event in propose_filter.get_new_entries():
        if event.args.requester.lower() == POLY:
            on_propose(event)
    time.sleep(2)

def on_dispute(event):
    market_q = decode_ancillary_to_question(event.args.ancillaryData)
    send_telegram(f"DISPUTE: {market_q}")
    # If we hold a position in this market, alert + consider exit
    if market_q in our_positions:
        flag_position_for_review(market_q)

The pattern: subscribe, decode, alert. Acting on disputes algorithmically is high-risk; the bot's job is usually to surface the event to a human reviewer.

Frequently asked questions

What is the UMA Optimistic Oracle?
UMAs Optimistic Oracle is the system that resolves Polymarket markets. A proposer submits a proposed answer; if no one disputes within a window, the answer becomes final. If disputed, UMA token holders vote (DVM) to settle. Most Polymarket markets resolve undisputed - disputes are the edge case.
How can I detect a UMA proposal in real time?
Subscribe to the UMA Optimistic Oracle V2 contract on Polygon for ProposePrice events, filtered by the Polymarket adapter address. The proposal triggers a 2-hour dispute window during which the market price often diverges from 1.00 / 0.00 because traders price in dispute risk.
What predicts a UMA dispute?
Three signals: (1) Volume - high-volume markets (>$10M) attract more disputes because the prize is bigger. (2) Ambiguity in the resolution criteria - if the market title is fuzzy, dispute risk rises. (3) Past dispute history of the proposer wallet. Combine these in a logistic regression for a baseline dispute predictor.
Can I trade after a dispute is filed?
You can but it is risky. Once disputed, the market enters DVM voting, which takes ~48-72 hours and the outcome is binary (and final). The price typically converges to one side ahead of voting. Bots that take a side based on legal/factual analysis can profit, but a wrong call is total loss.
Is the UMA dispute strategy crowded?
Less than market making. UMA dispute prediction requires reading legal and political context, which most quant bots dont do. The strategy has room for human judgment plus quant infrastructure - well suited for hybrid bots.
What is the worst case for a UMA dispute bot?
Holding a position when DVM votes the opposite way. Cap risk per disputed market - we use 50 USD max per single disputed market regardless of confidence, because every "obvious" call eventually misses.