OddMaki
Operations

Matching & Settlement

How orders are matched on-chain and the three settlement paths — Normal Fill, Mint-to-Fill, and Merge-to-Fill.

OddMaki runs a fully on-chain central limit order book (CLOB). Orders are matched through a permissionless matchOrders function that anyone can call to earn the operator fee (10 bps per fill).

Order Types

TypeBehaviorSettlement Paths
LimitRests on the book at a specified price until filled, cancelled, or expiredNormal, Mint, Merge
Fill-Or-Kill (FOK)Must fill completely or the entire transaction revertsNormal only
Fill-And-Kill (FAK)Fills as much as available, returns remaining collateralNormal only

Limit Orders

const tx = await client.trade.placeOrderSimple({
  marketId: 1n,
  outcomeId: 0n,        // YES
  side: 0,              // BUY
  price: '0.65',        // $0.65
  quantity: '100',      // 100 tokens
  expiry: '24h',        // expires in 24 hours
});

Collateral locking:

  • BUY orders lock USDC (pulled via ERC-20 transfer)
  • SELL orders lock outcome tokens (pulled via CTF safeTransferFrom)

Market Orders

const tx = await client.trade.placeMarketOrderSimple({
  marketId: 1n,
  outcomeId: 0n,        // YES
  amount: '50',         // spend up to 50 USDC
  maxPrice: '0.80',     // slippage protection
  orderType: 'FAK',     // fill what's available
});

Market orders execute immediately against resting sell-side liquidity. They only use the Normal Fill path.

Settlement Paths

The matching engine evaluates paths in a fixed priority order each step:

PriorityPathConditionWhat Crosses
1Normal Fill (YES)YES bestBid >= YES bestAskSame-outcome BUY/SELL
2Normal Fill (NO)NO bestBid >= NO bestAskSame-outcome BUY/SELL
3Mint-to-FillyesBid + noBid >= 1.0 + feesCross-outcome BUY/BUY
4Merge-to-FillyesAsk + noAsk <= 1.0 - feesCross-outcome SELL/SELL

The first path that successfully executes a fill consumes one step. If no path fills, the loop terminates.

Normal Fill

Standard buyer-seller matching within the same outcome. A BUY order crosses with a SELL order when bestBid >= bestAsk. Execution price is always at the ask price.

The seller receives collateral minus fees. The buyer receives outcome tokens from the vault.

Mint-to-Fill

When both a YES buyer and a NO buyer exist and their combined bids cover the full token price (1.0) plus fees, the protocol mints new YES and NO tokens from collateral via the CTF's splitPosition.

  • YES buyer receives YES tokens
  • NO buyer receives NO tokens
  • Fees are taken from the surplus collateral

This path creates new liquidity — it doesn't require existing sellers.

Merge-to-Fill

When both a YES seller and a NO seller exist and their combined asks are below the full token price (1.0) minus fees, the protocol merges outcome tokens back into collateral via the CTF's mergePositions.

  • YES seller receives collateral for their ask price
  • NO seller receives collateral for their ask price
  • Fees are taken from remaining collateral

This path removes liquidity — it doesn't require existing buyers. Volume is not recorded for Merge-to-Fill.

Triggering Matching

Anyone can call matchOrders to earn the operator fee:

const tx = await client.trade.matchOrders({
  marketId: 1n,
  maxSteps: 10n,  // max fill iterations
});

Each step processes one fill. The caller receives the operator fee (10 bps fixed) on every fill executed. Gas usage scales linearly with maxSteps.

Order Cancellation

Only the order owner can cancel. Remaining quantity is fully refunded (no penalty):

const tx = await client.trade.cancelOrder(42n);

Orders with a nonzero expiry are automatically cleaned up during matching when expired.

What's Next