Binary markets — propose → challenge → finalize
Step 1 — Oracle source check
The market is configured with one or more data sources when it is listed. When the configured source(s) yield an unambiguous outcome, the market becomes ready to propose. When data is unavailable or ambiguous (no strict majority across configured sources), the market moves toDELAYED. See
Void & delayed.
Step 2 — On-chain proposal
Step 3 — Challenge window
transferFrom. The amount is fixed when the outcome is
proposed (getProposal(conditionId).bondSnapshot). Only the first
challenge is accepted. See Challenges.
Step 4a — No challenge, finalise
ConditionalTokens.reportPayouts,
unlocking redemption.
Step 4b — Challenge, re-verify
Neg-risk markets
Neg-risk markets follow the same propose → challenge → finalize lifecycle, with the same 10 USDC bond and 2-hour default window, through the neg-risk oracle (negRiskOracle in
GET /api/platform/contracts). Differences:
- Keyed by the group. Calls take the market’s
negRiskMarketId, not aconditionId:proposeOutcome(negRiskMarketId, winnerIndex),challengeOutcome(negRiskMarketId),finalizeOutcome(negRiskMarketId). - One proposal settles every outcome. On finalisation the winning
outcome’s market pays YES (
[1, 0]) and every sibling pays NO ([0, 1]), in one transaction. In exceptional cases the platform proposes a fair-price split instead of a single winner (resolution.proposalKind: "FAIR_PRICE"while pending,resolution.resolutionKind: "FAIR_PRICE"once resolved); it goes through the same challenge window. - Redemption goes through the vault like any other market — see Redemption.
Crypto markets
Crypto markets are binary markets, so they follow the propose → challenge → finalize path above. Two things differ: The evidence is a price rule, not a match result. The outcome is derived from Chainlink price data evaluated against the immutable rule captured on the market at listing time (crypto.productType /
direction / targetPrice / deadlineAt / month). Touch products
(THRESHOLD_BY_DEADLINE, THRESHOLD_DURING_MONTH) lock YES on the
first touch — equality counts — but still settle after the observation
window ends.
Up/Down windows propose within a minute or two of closing. A
15-minute window closes, and the
oracle proposes the direction against the frozen open price
(cryptoWindow.openPrice) — typically 1–2 minutes later, versus the
~15 minutes a sports market waits on its data source. What follows is
the ordinary challenge window: the platform default unless the window
was armed for the fast on-chain path, which gives it a per-market
window of zero and finalizes immediately after the proposal. Payouts
are [1, 0] for Up (outcome index 0) and [0, 1] for Down
(index 1), and cryptoWindow.outcome flips to "UP" / "DOWN" only
once the market is RESOLVED — a proposed direction is not a settled
one.
What you observe as a partner
market_lifecycle is subscribed on /ws/market with the market
symbol as the id. Every status flip, including DISPUTED and
RESOLVED, also arrives as a status_changed frame.
Redemption
Outcome tokens are held by your vault, so redemption always goes through the vault — callingConditionalTokens.redeemPositions from
your own address redeems nothing. Auto-redeem does it
for you by default; anything still redeemable you can
claim yourself.
Auto-redeem
Auto-redeem is on for every account unless you turn it off. Once a market isRESOLVED or VOIDED, the platform redeems the positions
your vault still holds on it, pays the gas, and credits the payout to
your vault:
The platform looks for redeemable positions every minute, longest-settled
markets first, so a position is normally redeemed within a few minutes
of the market’s final status; when many markets settle at once it can
take longer. An account that is paused or under another restriction is
skipped until the restriction is lifted.
Read the setting with
GET /api/me/auto-redeem (portfolio:read) and
change it with PUT /api/me/auto-redeem, body { "enabled": false } or
{ "enabled": true } (vault:write, at most 10 calls per 24 hours).
Turning it off stops new automatic redeems; a redeem already queued for
your account still completes. Claiming yourself works whether
auto-redeem is on or off.
An automatic redeem shows up like any other: the payout lands in the
USDC row’s available in GET /api/me/balances, the position stops
being redeemable and then reads redeemed: true (list it with
GET /api/me/positions?status=redeemed), and a
vault_position_redeemed frame arrives on the vault_positions
WebSocket channel. redeemed: true can trail the end of redeemable
by several minutes; in between, the position is listed under neither
status=redeemable nor status=redeemed.
Claiming yourself
Checkredeemable on GET /api/me/positions?status=redeemable first (see
Positions).
- Gasless —
POST /api/me/positions/redeemwith{ "marketId": "...", "outcomeIndex": 0 }. API-key callers need thevault:writescope and must includeauth, an owner-signedRedeemAuthorization. Returns{ "jobId": "...", "status": "pending" }; pollGET /api/me/positions/redeem/{jobId}untilconfirmed. - Self-submitted — the vault owner calls
Vault.redeemPositions(conditionId, indexSets)(binary) orVault.redeemPositionsNegRisk(negRisk.marketId, negRisk.questionIndex, amount)(neg-risk) and pays the gas.
POST /api/me/redemptions is not enabled yet (503 redeem_not_yet_enabled).
Every path credits the payout to your vault, where it shows up in the
USDC row’s available in GET /api/me/balances — no further call is
needed to “claim” winnings.