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). Fees are taker-only — the resting maker pays nothing, and the crossing order bears the full fee stack (see Fees).

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 liquidity on the Normal Fill path. The SDK also provides placeMarketSellSimple for selling existing outcome tokens at market. For higher-volume flows, see Batch OperationsbatchPlaceOrders (up to 20 orders), batchCancelOrders (up to 100), and atomic cancelAndReplace.

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.

Fees come entirely out of the taker's leg. The maker receives the full ask × quantity; the taker pays price + fees.

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 taker 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 carved from the combined surplus

This path creates new liquidity — it doesn't require existing sellers. Whichever side is the taker (the newer crossing order) pays the fee stack.

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 taker 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 carved from the difference between 1.0 and the summed asks

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