Skip to content

Match Types

Most order books have one kind of match: a buyer meets a seller. GoMarket has three, because outcome tokens can be created and destroyed at par.

TypeThe two ordersMechanism
COMPLEMENTARYOpposite sides of the same tokenDirect swap
MINTBoth BUYs, opposite outcomesCreate a YES+NO pair from their collateral
MERGEBoth SELLs, opposite outcomesDestroy a YES+NO pair back into collateral

The familiar case. One trader buys YES, another sells YES.

Taker BUY 100 YES @ 0.50 Maker SELL 100 YES @ 0.50
│ │
│ 50 USDC ──────────────────────▶ │
│ ◀────────────────────── 100 YES │

Tokens change hands directly. Nothing is created or destroyed, and the market vault is untouched.

Two traders both want to buy, on opposite outcomes. Neither can sell to the other — but together they’ve put up a full dollar per share.

Taker BUY 100 YES @ 0.60 Maker BUY 100 NO @ 0.40
│ │
│ 60 USDC 40 USDC │
└──────────┐ ┌────────────┘
▼ ▼
┌─────────────────────┐
│ market vault │ 100 USDC in
│ mint_tokens │ 100 YES + 100 NO out
└─────┬─────────┬─────┘
│ │
100 YES▼ ▼100 NO
Taker Maker

The prices must sum to $1 — exactly the collateral needed to mint the pair. Both traders get the side they wanted; the vault ends fully collateralised.

This is how a market bootstraps. Nobody needs to hold inventory to create two-sided liquidity. The first two participants in a brand-new market can be two buyers.

The mirror image. Two traders both want to sell, on opposite outcomes.

Taker SELL 100 YES @ 0.60 Maker SELL 100 NO @ 0.40
│ │
│ 100 YES 100 NO │
└──────────┐ ┌───────────┘
▼ ▼
┌─────────────────────┐
│ market vault │ 100 YES + 100 NO in
│ merge_tokens │ 100 USDC out
└─────┬─────────┬─────┘
│ │
60 USDC▼ ▼40 USDC
Taker Maker

Both exit their positions in one transaction, against each other, without needing a buyer at all.

All three settle through the same instruction. execute_trade handles one maker leg of a match, and the maker leg is identical in every case — a direct swap between maker and taker.

The difference is the residual. In a MINT or MERGE the taker is left holding something that must be converted:

COMPLEMENTARY [ execute_trade ]
MINT [ mint_tokens ] [ execute_trade ] [ execute_trade ] …
MERGE [ merge_tokens ] [ execute_trade ] [ execute_trade ] …

The executor prepends the conversion instruction in the same transaction, so the whole sequence is atomic. Either the pair is created and both legs settle, or nothing happens.

Two practical consequences:

  • MINT/MERGE transactions carry more accounts and overflow Solana’s 1232-byte legacy message limit. They compile to v0 messages with an address lookup table when ADDRESS_LOOKUP_TABLE is configured.
  • Mint and merge conversions are not counted as volume in the market’s total_volume accumulator. Only settled fills are. → CLOB Markets as Legs

Same-side matching is on by default:

Terminal window
CLOB_ENABLE_MINT_MERGE_MATCHING=1 # default
CLOB_ENABLE_MINT_MERGE_MATCHING=0 # complementary only

With it disabled, takers match only against complementary makers. Market makers who need to mint or merge directly then use the Market Makers API (packages/mkt-makers-api), which exposes MINT/MERGE as a REST operation. That service is only meaningful in this configuration.

The match type is an implementation detail of how the fill was sourced — you don’t request one. You post an order; the engine walks the book and uses whichever mechanism each maker leg requires.

A single taker order can produce a mix: some legs complementary, some minted. The resulting TradeSummary lists every maker leg in maker_orders, each with its own matched_amount and price.

Regardless of type:

  • Price-time priority — best price first, earliest first at a price, order-ID as the final tiebreak.
  • Self-trade filter — your own resting liquidity is excluded from the walk.
  • Price-distortion guard — the walk stops if the fill price drifts past a configured bound from the reference (0.02 in the demo config), so a market order can’t sweep a thin book to an absurd level.
  • Expiry check — expired makers are skipped and ejected rather than filled.