Order Book#
Seesaw's on-chain matching engine pairs buyers and sellers of YES shares.
Order Book Architecture#
Each side of the book holds up to 63 resting orders. Prices are in
basis points of one stablecoin unit: 10,000 bps = 1.00 USDT, and valid
trading prices live in [1, 9999].
Single Book Design#
Seesaw maintains one order book per market for YES shares only. All NO orders are converted by price complement:
| Your Order | Becomes |
|---|---|
| Buy YES @ 0.55 | Bid @ 0.55 |
| Sell YES @ 0.60 | Ask @ 0.60 |
| Buy NO @ 0.45 | Ask @ 0.55 (sell YES) |
| Sell NO @ 0.40 | Bid @ 0.60 (buy YES) |
Matching is complementary only: BuyYes↔SellYes and SellNo↔BuyNo pairs meet on the canonical book. One book concentrates liquidity, eliminates YES/NO arbitrage, and keeps YES @ 0.60 complementary to NO @ 0.40 by construction.
Escrow-Based: Fills Move Real Assets#
Every resting order is fully backed before it can rest:
- A bid (buy) locks its full collateral (
shares × price) in the market vault at placement. - An ask (sell) escrows the actual SPL share tokens in the market's YES or NO escrow PDA at placement.
A fill is therefore an escrow transfer, never a mint: shares move
from the maker's escrow to the taker, and stablecoin moves through the
vault to the seller. New shares come into existence only through
MintShares (pair-minting YES+NO 1:1 against stablecoin) and
WithdrawShares (materializing internal-ledger shares); shares are
destroyed only by Redeem. See Flow of Funds.
The *WithFreeFunds order variants (0x0D–0x0F) place the same orders
against your internal trader-ledger balances — no wallet token transfer
per order, same matching rules.
Order Types#
| Type | Behavior |
|---|---|
| Limit | Match what crosses; rest the remainder on the book at your price |
| PostOnly | Rejected (WouldCross) if any part would match immediately — maker only |
| ImmediateOrCancel | Match what's possible now; cancel the remainder — taker only |
IOC protections#
IOC orders may additionally set:
worst_acceptable_price_bps— a hard slippage bound; the program will not fill past it.min_fill_quantity— cancel rather than accept a fill below this size.match_limit— caps how many resting orders one instruction visits (default 63, i.e. effectively unlimited relative to a full side).
Market-style orders: use IOC#
To "buy at market," submit an IOC order with a generous limit and a
worst_acceptable_price_bps you're comfortable with. Don't submit a
Limit order at an extreme price (e.g. 9900) — Limit and PostOnly orders
must pass the maker price band (±10% around the
midpoint on a two-sided book), so an extreme resting price is rejected.
IOC orders are exempt from the band because they never rest.
Per-order TTL#
Resting orders may carry max_age_seconds > 0. Once expired, the order
is ignored by matching and becomes reclaimable by anyone via
ReclaimExpiredOrder (0x19) — the refund goes to the maker, and the
caller may take a bounty of 10 bps of the refund (capped at 0.1
stablecoin). The TTL may not outlive the market (expiry ≤ t_end).
Price-Time Priority#
Orders match on price first, then arrival order (FIFO):
Same-price ties break by the order's monotonic order_id (allocation
order), not by timestamp.
Matching Algorithm#
Fills execute at the maker's resting price — price improvement goes to the taker:
incoming = Sell 100 YES @ 0.55 (Limit)
while incoming.quantity > 0:
best_bid = book.best_bid()
if best_bid is None or best_bid.price < incoming.price:
break # nothing crosses
fill_qty = min(incoming.quantity, best_bid.quantity)
execute_fill(price = best_bid.price, quantity = fill_qty)
# maker's escrowed/locked assets move; taker pays the fee
incoming.quantity -= fill_qty
if incoming.quantity > 0:
book.rest_ask(incoming) # Limit only; IOC cancels instead
Tick Size#
Prices must align to the market's tick:
| Parameter | Value |
|---|---|
| Default | 100 bps (0.01 USDT) |
| Range | 1–1000 bps, must divide 10,000 evenly |
| Tunable | UpdateTickSize (0x29, admin) |
Tick Rounding Rules#
- Bids round DOWN to the nearest tick
- Asks round UP to the nearest tick
Both directions are conservative for the order's owner and the book:
Submitted: Buy @ 0.5567, tick 0.01 → Buy @ 0.55 (down)
Submitted: Sell @ 0.5567, tick 0.01 → Sell @ 0.56 (up)
An ask that would round to ≥ 10,000 bps is rejected (there is no valid price at or above 1.00).
Resting-Order Quality Gates#
Two placement-time gates keep the book clean:
- Maker price band — Limit/PostOnly orders must price within ±10% of the midpoint on a two-sided book (static 1%–99% band otherwise). IOC is exempt.
- Minimum resting notional — a remainder too small to be worth
matching is rejected rather than allowed to rest
(
UpdateMinRestingNotional, 0x2A).
No Crossed Book Invariant#
The order book cannot have best bid ≥ best ask:
If a new order would cross, it immediately executes against resting orders until uncrossed or fully filled.
No Naked Shorts#
You can only sell shares you own (in your wallet or your internal ledger balance):
Alice owns: 50 YES shares
✓ Sell 50 YES @ 0.60 (valid — 50 shares escrowed)
✗ Sell 100 YES @ 0.60 (rejected — insufficient shares)
To bet against YES without owning it:
- Buy NO shares, OR
- Mint a YES+NO pair (
MintShares) and sell the YES
Order Lifecycle#
| State | Meaning |
|---|---|
| Resting | On book, fully backed, awaiting match |
| Partially Filled | Some quantity executed; remainder rests or cancels |
| Fully Filled | Complete execution |
| Cancelled | Owner cancelled; collateral/escrow returned instantly |
| ExpiredClaimable | TTL elapsed; ignored by matching until reclaimed |
Reading the Order Book#
Depth Chart#
Price Bid Size Ask Size Cumulative
─────────────────────────────────────────────
0.65 200 650
0.60 300 450
0.58 150 150
────────── spread ──────────
0.55 100 100
0.54 250 350
0.52 500 850
Key Metrics#
| Metric | Formula | Meaning |
|---|---|---|
| Spread | Best Ask − Best Bid | Cost to cross |
| Mid Price | ⌊(Best Bid + Best Ask)/2⌋ | Fair value estimate |
| Depth | Sum of sizes at level | Liquidity available |
| Imbalance | Bid Vol / Ask Vol | Directional pressure |
For how the app turns book depth into a fill preview (average price, slippage, price impact), see Slippage & Fill Estimation.
Order Book Events#
Every book mutation is recorded on-chain through the program's binary
event recorder (the internal LOG self-CPI), so indexers and UIs can
reconstruct the book deterministically. The order-flow event kinds:
| Event | Emitted when |
|---|---|
OrderPlaced | An order (or its remainder) rests on the book |
OrderFilled / OrderFilledMaker | A fill executes (taker and maker legs) |
OrderCancelled | Owner cancels a resting order |
OrderReclaimed | A TTL-expired order is reclaimed |
OrderEvicted | A resting order is evicted by a better-priced one on a full side |
OrderForceCancelled | Admin emergency cancel (ForceCancelMarketOrders) |
How-to guides#
For task-oriented guidance on using this order book:
- Market makers (quoting both sides, PostOnly, spread capture, inventory management): Market Making
- Takers (fill preview, IOC slippage protection, splitting large orders, fee curve): Placing Orders