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.
1. Fund and approve
Section titled “1. Fund and approve”Your maker tokens move at settlement through a program delegate PDA under a
standing SPL Approve.
cargo run -p delegate --quiet -- set --keypair ~/.config/solana/id.json --amount 1000000000cargo run -p delegate --quiet -- show --keypair ~/.config/solana/id.jsoncargo run -p delegate --quiet -- revoke --keypair ~/.config/solana/id.jsonThe 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.
2. Authenticate
Section titled “2. Authenticate”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.
Quoting
Section titled “Quoting”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 bidFee rate matters at insert
Section titled “Fee rate matters at insert”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.
Fees fall at the extremes
Section titled “Fees fall at the extremes”The fee scales by min(price, 1 − price):
| Price | Relative fee |
|---|---|
| $0.50 | maximum |
| $0.20 / $0.80 | 40% of max |
| $0.05 / $0.95 | 10% of max |
Longshot markets are cheap to trade. → Fees
Inventory
Section titled “Inventory”You may not need any
Section titled “You may not need any”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).
Managing it directly
Section titled “Managing it directly”mint_tokens n USDC → n YES + n NOmerge_tokens n YES + n NO → n USDCBoth 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.
Reservations
Section titled “Reservations”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.
Operational gotchas
Section titled “Operational gotchas”Game-start ejection is not selective
Section titled “Game-start ejection is not selective”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.
Self-trades are filtered, not rejected
Section titled “Self-trades are filtered, not rejected”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.
The distortion guard caps sweeps
Section titled “The distortion guard caps sweeps”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.
Reconciliation
Section titled “Reconciliation”Run a loop:
GET /v1/open-orders— the ledger’s view of your resting orders.GET /v1/orders— the book’s view.GET /v1/tradessince your cursor — what filled.- 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 are not quoted
Section titled “Parlays are not quoted”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