Skip to content

Market Making

Market making on GoMarket means posting resting orders on both sides and earning the spread. This page covers what’s specific to this venue.

Your maker tokens move at settlement through a program delegate PDA under a standing SPL Approve.

Terminal window
cargo run -p delegate --quiet -- set --keypair ~/.config/solana/id.json --amount 1000000000
cargo run -p delegate --quiet -- show --keypair ~/.config/solana/id.json
cargo run -p delegate --quiet -- revoke --keypair ~/.config/solana/id.json

The allowance is your real risk ceiling. The program keeps no per-order fill state, so the total that can ever move out of your account for a given mint is bounded by this number, not by the size of the orders you posted. Size it to what you’re willing to have at risk, and revoke when you stop quoting.

A missing allowance is only a warning at insert time — the order will rest and then fail at settlement. Set it before your first quote.

SIWS tokens expire after 300 seconds by default. A long-running quoter should regenerate on a timer well inside that window; signing is local and cheap.

→ Authentication

You are the maker when your order rests. Post limit orders inside the spread you’re willing to trade:

ASK 0.53 ← your offer
─────────────
BID 0.47 ← your bid

The validator checks feeRateBps against the role your order will play:

  • Resting (maker) — you don’t pay. But if your order is marketable on arrival it will be treated as a taker and must carry the taker fee, or it is rejected outright.
  • Marketable (taker) — must carry at least the taker fee.

So an order priced through the spread is a different object to the validator than one priced inside it, even if you intended both as quotes. Price defensively, or set the taker rate and accept paying it when you cross.

The fee scales by min(price, 1 − price):

PriceRelative fee
$0.50maximum
$0.20 / $0.8040% of max
$0.05 / $0.9510% of max

Longshot markets are cheap to trade. → Fees

MINT matching lets two buyers of opposite outcomes fill each other by minting a fresh YES+NO pair from their combined collateral. You can quote the NO side of a market holding nothing but USDC.

Same-side matching is on by default (CLOB_ENABLE_MINT_MERGE_MATCHING=1).

mint_tokens n USDC → n YES + n NO
merge_tokens n YES + n NO → n USDC

Both are par conversions with no fee and no counterparty. Use mint to manufacture the side you want to sell; use merge to flatten a matched pair back to collateral.

When same-side matching is disabled, the Market Makers API (packages/mkt-makers-api) exposes these as REST operations. It is only meaningful in that configuration.

Inserting an order reserves the maker amount against your balance. A $100 balance cannot back two $100 orders. Cancel to free the reservation — a quoter that re-posts without cancelling will start getting balance rejections.

When a market’s game start fires, every order created before it is ejected — not just stale ones. Quoting a market with a scheduled start means expecting to be flat at the whistle and re-quoting deliberately.

Orders that arrive inside the window come back status: "delayed" and are inserted when it opens.

Settlement can fail after you’re matched

Section titled “Settlement can fail after you’re matched”

A match is not money until it’s CONFIRMED. On final failure the executor writes UpdateTrade(FAILED) and invalidates the resting orders involved. From your side the order vanishes and the fill never happened.

Causes worth designing around: a counterparty’s revoked allowance, a moved balance, or compute exhaustion on a large multi-leg transaction.

Your own resting liquidity is excluded from the walk. A crossing order of yours doesn’t error — it simply skips your own orders and fills against whatever else is there.

A taker walking the book is stopped when the fill price drifts past a configured bound from the reference (0.02 in the demo config). Good news if you’re resting deep in the book: a fat-finger market order won’t reach you.

Run a loop:

  1. GET /v1/open-orders — the ledger’s view of your resting orders.
  2. GET /v1/orders — the book’s view.
  3. GET /v1/trades since your cursor — what filled.
  4. Re-post anything ejected that you still want.

The two views can disagree briefly while a settlement is in flight. Persistent disagreement means an ejection you missed.

For a push-based feed instead of polling, consume the ledger’s Redis notifications stream. → Real-Time Data

Parlays do not trade against the order book. A parlay is priced against the vault at a per-leg probability locked at create time, and the house takes the other side — there is no maker leg to quote. → How Parlays Work