Phoenix: the crankless on-chain order book, and the perps extension
Phoenix is Solana's crankless on-chain limit order book — atomic fills, no separate crank, all in one Rust program. Here's the market architecture and design.
devrels.xyz/a/82short linkPhoenix is the cleanest fully on-chain limit order book on Solana. Its headline innovation: it's crankless. Earlier on-chain order books (Serum/OpenBook) needed a separate "crank" process to match resting orders and settle fills. Phoenix settles atomically inside the taker's own transaction — no crank, no separate settlement step, no MEV window between match and settle.
Why the crank was a problem
Serum-style books worked like this: makers post orders; takers post orders; a permissionless "crank" transaction later matches them and pushes fills to an event queue; another step settles balances. Three issues:
- Latency. Your fill wasn't final until the crank ran — could be several slots later.
- MEV. The gap between match and settle was a window for extraction.
- Liveness dependence. If nobody cranked, the book stalled.
Phoenix's crankless design
Phoenix collapses match + settle into the taker's instruction. When you send a market order (or a marketable limit order):
Taker submits an order in transaction T:
1. Phoenix walks the resting order book in-program
2. Matches against resting maker orders, computing fills
3. Atomically credits/debits both the taker AND the matched makers'
balances — all inside transaction T
4. Resting orders that got filled are removed from the book
5. Any unfilled taker remainder rests on the book (for limit) or
is cancelled (for IOC/market)
No crank. No event queue to drain. Fill is final when T confirms.The makers don't need to be online or sign anything at fill time — their resting orders already committed their funds to the market. Phoenix moves the funds on their behalf when a taker crosses their price.
The account model
// Market account — the order book itself
pub struct MarketHeader {
pub base_mint: Pubkey, // e.g. SOL
pub quote_mint: Pubkey, // e.g. USDC
pub base_vault: Pubkey, // token vault holding deposited base
pub quote_vault: Pubkey, // token vault holding deposited quote
pub base_lot_size: u64, // smallest tradeable base increment
pub quote_lot_size: u64, // smallest price increment
pub tick_size: u64,
pub authority: Pubkey,
pub fee_recipient: Pubkey,
// followed by the bids tree + asks tree + trader registry (in account data)
}
// Seat — a trader's authorization to place orders on a market
// (Phoenix gates makers via seats; takers can trade without one)
pub struct Seat {
pub market: Pubkey,
pub trader: Pubkey,
pub approval_status: SeatApprovalStatus,
}The order book lives entirely in the market account's data — a pair of red-black-tree-like structures for bids and asks, plus a trader registry tracking each participant's locked and free balances. Reading the book is a single getAccountInfo + deserialize.
Placing orders
import { Client, Side, OrderPacket } from "@ellipsis-labs/phoenix-sdk"
import { Connection, Keypair } from "@solana/web3.js"
const conn = new Connection("https://api.mainnet-beta.solana.com")
const client = await Client.create(conn)
const market = client.marketStates.get(marketAddress)!
// A limit order: rest on the book at a price
const limitOrder: OrderPacket = {
__kind: "Limit",
side: Side.Bid,
priceInTicks: market.floatPriceToTicks(142.50),
numBaseLots: market.rawBaseUnitsToBaseLots(10), // 10 SOL
selfTradeBehavior: 0,
matchLimit: null,
clientOrderId: 0,
useOnlyDepositedFunds: false,
}
const placeIx = client.createPlaceLimitOrderInstruction(limitOrder, marketAddress, trader.publicKey)
// An immediate-or-cancel market buy: cross the book now
const marketOrder: OrderPacket = {
__kind: "ImmediateOrCancel",
side: Side.Bid,
priceInTicks: null, // null = take any price
numBaseLots: market.rawBaseUnitsToBaseLots(5),
minBaseLotsToFill: 0,
numQuoteLots: 0,
minQuoteLotsToFill: 0,
selfTradeBehavior: 0,
matchLimit: null,
clientOrderId: 0,
useOnlyDepositedFunds: false,
}Orders are priced and sized in lots — integer multiples of the market's base_lot_size and quote_lot_size. This keeps all arithmetic in integers (no float drift in the matching engine) and bounds the precision of the book.
Reading the live book
const ladder = market.getUiLadder(10) // top 10 levels each side
console.log("bids:", ladder.bids) // [{ price, quantity }, …]
console.log("asks:", ladder.asks)
// Or get the L3 (per-order) view
const book = market.getLadder()The perps extension
Phoenix's core is a spot CLOB. The perps layer builds the same crankless matching primitive into a derivatives market — positions instead of spot balances, funding payments instead of settlement, mark-price from the book combined with an oracle. The order-matching engine underneath is the same atomic, crankless design; the difference is what gets settled (position deltas + funding vs token balances).
Update (July 2026): quietly one of the busiest programs on Solana
The perps program (EtrnLzgbS7nMMy5fbD42kXiUzGg8XQzJ972Xtk1cjWih) now ranks #6 on the entire chain by instruction invocations — 37.7 million per day per ProgramWatch's leaderboard, more than Jupiter v6. That volume is the crankless design doing its job: every match settles inside the taker's transaction, and funding plus market-maker quote churn ring the program constantly.
The odd footnote: you wouldn't know any of this from an explorer. The program carries no on-chain IDL, no verified build, and no label in most program databases — only Solana Compass's registry ties the address to Phoenix. A top-six program that passes for anonymous bytecode is the clearest argument we've seen for registering verified builds and posting IDLs on-chain.
Why this still matters
- It proved fully on-chain CLOBs are viable. The conventional wisdom was "order books need an off-chain sequencer." Phoenix showed you can do it on-chain on Solana with atomic settlement.
- No MEV from match/settle gaps. The atomic fill means there's no window to sandwich between matching and settlement.
- Composable. Because fills are atomic, another program can CPI into Phoenix and know the fill is final within the same transaction — critical for aggregators and structured products.
References
Phoenix is the reference design for crankless on-chain order books. Whether you trade on it, build on it, or just want to understand how a fully-on-chain CLOB settles atomically — the crankless model above is the core idea.
Keep reading
Card acquirers settle in three days; prediction markets and fintechs want money now. Credible Finance fronts that float with stablecoin liquidity pools, orchestrates 86+ pay-in methods across 42+ markets, and settles merchants T+0 in USDC, USDT, USD, EUR, or GBP. Colosseum-backed, $700M+ processed, $CRED ownership token live on MetaDAO. Architecture, developer surface, and the honest read.
Rank programs by what actually gets called on Solana and you get a different picture than TVL charts: SPL Token at 346M invocations a day, the Pump.fun stack summing to ~100M across three programs, Meteora's open-source DAMM v2 out-calling Jupiter, and — at #6 — a program that looks like anonymous bot infrastructure on every explorer but resolves to Phoenix Perps once you dig. Sourced from ProgramWatch's free API, then cross-checked against the OtterSec verify registry, Solana Compass, and each team's repos — which is where the real story turned out to be.
SECZ went live on the NYSE and on Solana on the same day. On Solana every Securitize asset is a Token-2022 mint that enforces its own compliance — but the tokenized stock uses defaultAccountState + pausable + scaled UI amount, while the funds use a transfer hook. Here's what that means when you integrate them, with the real mainnet mints.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.
