Market Lifecycle

Every Fora prediction market moves through a deterministic state machine. Each state is an integer on-chain (market_state field of PredictionMarketStateFixed); each transition is a public instruction anyone can crank.

The states

Value State Trading Notes
0 INITIALIZED No Market created. Awaiting authority activation.
1 ACTIVE Yes Trading is open. Orders, swaps, cross-market matching all live.
2 PAUSED No Authority-paused. Existing orders frozen; no new trades. Returns to ACTIVE.
3 DETERMINED No Outcome decided. Winner is recorded in winning_outcome.
4 CLOSED No Trading is permanently closed. Order books frozen.
5 SETTLED No Winners can redeem winning tokens for USDC. Losers' tokens are worthless.
6 CLEANED No Manifest seats and intermediate state torn down. Collateral fully drained.
7 ARCHIVED No Terminal state. Account closed and rent reclaimed.

The transitions

INITIALIZED ──→ ACTIVE ⇄ PAUSED ──→ DETERMINED ──→ CLOSED ──→ SETTLED ──→ CLEANED ──→ ARCHIVED
     │
     └──────────── (authority cancel, no trading) ────────────→ CLEANED ──→ ARCHIVED

Each arrow corresponds to an on-chain instruction:

  • INITIALIZED → ACTIVEactivate_market. Authority-only.
  • ACTIVE ⇄ PAUSEDpause_market / activate_market. Authority-only. Used during emergencies or oracle disputes.
  • ACTIVE | PAUSED → DETERMINEDresolve_market (manual / Kalshi oracle / Vibe TWAP). Anyone can crank a Vibe or Kalshi resolution after the trigger condition; manual requires the authority.
  • DETERMINED → CLOSEDclose_market. Permissionless once determined.
  • CLOSED → SETTLEDbatch_settle_prediction_market. Permissionless. Cranks user redemptions in batches.
  • SETTLED → CLEANED — cleanup instructions. Permissionless. Tears down Manifest seats, drains the collateral vault.
  • CLEANED → ARCHIVEDarchive_market. Permissionless. Closes the account.

The shortcut path INITIALIZED → CLEANED → ARCHIVED exists for markets that are cancelled before any trading occurs. The authority calls a cancel instruction, which fast-paths to CLEANED, then anyone can archive.

Resolution mechanisms

When a market reaches DETERMINED, its winning_outcome is set:

Value Outcome Meaning
0 UNRESOLVED Default. Set during INITIALIZED/ACTIVE/PAUSED.
1 YES YES tokens redeem at $1; NO tokens worthless.
2 NO NO tokens redeem at $1; YES tokens worthless.
3 SPLIT Both YES and NO tokens redeem at $0.50. Used for true ties or insufficient TWAP data.
4 TWAP Vibe outcome. YES redeems at TWAP / 10000 of $1; NO redeems at (10000 - TWAP) / 10000. Computed TWAP in basis points stored in last_price.

Manual

The market authority calls resolve_market with the winning outcome. The simplest mechanism — used for markets where Fora chooses the resolution criteria.

Kalshi oracle

Markets whose ticker matches a Kalshi event are resolved automatically by the Kalshi Oracle service, which subscribes to Kalshi's lifecycle WebSocket and submits a resolution instruction when the upstream Kalshi market settles. Anyone can crank the resolution once Kalshi has emitted the settlement signal.

Vibe

The market is its own oracle. After expiry_slot, the on-chain TWAP from the YES book is computed and stored as last_price (in basis points). The market resolves to TWAP outcome, and YES tokens redeem at TWAP / 10000 while NO redeems at the complement.

A Vibe market requires at least GIRARD_MIN_FILLS = 10 distinct-slot fills to resolve via TWAP. With fewer fills the market resolves to SPLIT (both sides at $0.50) — there's not enough trading history for a meaningful TWAP. This protects against last-minute manipulation by a thin order book.

See the glossary entry for the design intuition behind Vibe markets.

Why it's a state machine and not a status flag

Each state is a contract. When you query /markets/{ticker}/status and see SETTLED, you know:

  • Trading is permanently over.
  • The outcome is fixed.
  • The collateral vault still holds funds (until CLEANED).
  • Token holders can call settlement instructions to redeem.

The state machine is enforced on-chain. No instruction can transition out of order. No state can be skipped (except the cancel shortcut). Every market that enters INITIALIZED will, eventually, reach ARCHIVED — or sit in an intermediate state with funds fully accounted for.

Source