Skip to main content
When an option series reaches its expiry timestamp, a resolution price is computed off-chain and submitted on-chain via a signed attestation. Holders and writers then claim their respective payouts.
The writer is whoever posted collateral at fill time, recorded by ConvallaxCore.mintFor during the atomic fill — the maker for a long trade (makerSelling = true) and the taker for a short trade (makerSelling = false). The holder is whoever received the freshly minted option tokens.

Resolution Price

The resolution price S determines payoffs for all options in a series. It is expressed as resolutionBps — an integer from 0 to 100 representing the YES token price at expiry.

Resolution Methods

The on-chain contract accepts any resolutionBps in [0, 100]. The backend determines the value with a tiered waterfall — it tries the most authoritative source first and falls back to a market-price signal only when needed. The first tier that produces a price wins, and the chosen method is recorded in the response meta.method.
1

1. Official resolution — meta.method: official

If the underlying Polymarket market has resolved (closed), read the YES token’s settled price directly. The closed market’s outcomePrices is mapped to the option’s YES token via the market’s clobTokenIds, so the result is independent of Yes/No ordering:
  • YES wins → resolutionBps = 100
  • NO wins → resolutionBps = 0
  • Rare UMA 50/50 draw → resolutionBps = 50
A market is only flagged closed once its UMA proposal has cleared the dispute window, so this is authoritative ground truth. Used whenever the market resolves at or before expiry.
2

2. Price TWAP — meta.method: twap

For options that expire before the market resolves, use the time-weighted average price of the YES token over the 30 minutes before expiry:
  1. Fetch the YES token’s price history from the Polymarket CLOB prices-history endpoint over [expiry − 1800s, expiry] at 1-minute fidelity
  2. Drop the trailing current-time datapoint the endpoint appends, keeping only samples inside the window
  3. Compute the time-weighted average, holding each sample until the next: TWAP = Σ pᵢ·(tᵢ₊₁ − tᵢ) / (t_last − t_first)
  4. Map to basis points: resolutionBps = clamp(round(TWAP × 100), 0, 100)
The prices-history series is the order-book midpoint when the bid/ask spread is tight (≤ $0.10) and automatically falls back to the last-traded price when the spread is wider, so a single source covers both regimes. Time-weighting (rather than volume-weighting) resists manipulation from large or wash trades, since moving the average requires holding the book displaced for the whole window.
Manual review for thin windows. If the 30-minute TWAP window contains no price points (an illiquid or inactive market with no continuous data), the backend does not auto-resolve from a single stale trade — doing so would be a cheap manipulation vector. Instead it refuses to sign and the series is escalated to manual review, then settled via the owner-only break-glass settle().Manual review generally follows the same logic the automated tier would have used, but with human approval: locate the most recent YES trade at or before expiry, then compute a TWAP over the 30-minute window ending at that trade’s timestamp (again using prices-history midpoints where available, falling back to traded prices). A reviewer confirms the window is representative and not the product of a manipulative print before settling. This approach was recommended by the protocol’s auditor to eliminate the single-trade manipulation surface.

Settlement Attestation (EIP-712)

The resolution signer creates a signed attestation that anyone can relay on-chain:
EIP-712 domain: The attestation is valid for 15 minutes after creation.

Settlement Flow

Two settlement paths

Settlement is automatic. A backend keeper continuously watches for expired-but-unsettled series, resolves the price via the waterfall above, and submits settleWithAttestation() on-chain itself — so holders never need to trigger settlement. The permissionless path remains available as a backstop: any holder can settle their own series by relaying an attestation from POST /settlement/prepare.

Payoff Formulas

Once a series is settled with resolution price S (resolutionBps), the payoffPerWhole (USDC raw units per 1 whole option) is computed by OptionMath.payoffPerWhole:
  • payoffPerOption = (80 − 50) × $0.01 = $0.30
  • Holder with 100 options claims: 100 × $0.30 = 30 USDC
  • Writer collateral was: 100 × $0.50 = 50 USDC
  • Writer reclaims: 50 − 30 = 20 USDC
  • payoffPerOption = (60 − 0) × $0.01 = $0.60 (maximum put payoff)
  • Holder with 50 options claims: 50 × $0.60 = 30 USDC
  • Writer posted 50 × $0.60 = 30 USDC collateral → writer reclaims 0 USDC
  • 30-minute TWAP = 0.5923 → resolutionBps = 59
  • Call at K=50: payoff = (59 − 50) × 0.01=0.01 = **0.09 per option**
  • Put at K=65: payoff = (65 − 59) × 0.01=0.01 = **0.06 per option**

Claiming Payouts

After settlement, participants claim their payouts:

Holders — claimHolderPayout(seriesId, amount)

Burns the specified amount of option tokens and transfers the USDC payout:
If the option expired worthless (payoffPerOption = 0), the tokens are burned but no USDC is transferred.

Writers — claimWriterCollateral(seriesId)

The writer is the party that posted collateral at fill (the maker on long trades, the taker on short trades). This returns the writer’s remaining collateral after holder payouts are deducted:
This is a one-shot operation — the writer’s recorded collateral is zeroed after claiming.

Trust Model

The resolution signer is an operational trust assumption. The on-chain contract verifies the signature’s authenticity but cannot independently verify the TWAP computation. This is analogous to oracle trust in DeFi protocols.