Every user-facing flow in the system, traced end-to-end with full detail. Covers onboarding, deposits, limit orders, market orders, matching, settlement, cancellation, withdrawal, and the crank lifecycle. Each diagram shows every account touched, every validation performed, and every state change made.
- Onboarding — New Trader Setup
- Deposit Tokens
- Place a Limit Order (Full Flow)
- Place a Market Order (Full Flow)
- Limit Order Through the Pipeline
- Market Order Through the Pipeline
- The Matching Process — Deep Dive
- Settlement — Updating Balances
- Cleanup — Freeing Consumed Nodes
- Cancel a Limit Order
- Withdraw Tokens
- Crank Lifecycle — Decision Tree
- Full Trade: Limit Sell + Market Buy
- Partial Fill Continuation
- Concurrent Pipeline — Multi-Batch View
Before a trader can place any order, they need an AccountStatus for the specific market. One-time setup per market.
sequenceDiagram
actor Trader
participant Wallet as Wallet Adapter
participant Frontend as Frontend UI
participant WASM as WASM Client
participant RPC as Solana RPC
participant Program as Solana Program
participant MC as MarketConfig
participant AccStatus as AccountStatus
Trader->>Frontend: Opens trading page for SOL/USDC
Frontend->>WASM: Check if AccountStatus exists
WASM->>RPC: getAccountInfo(PDA derived from trader + market)
RPC-->>WASM: Account not found
Note over Frontend: First time trading this market
Frontend->>Trader: Prompt to initialize account
Trader->>Wallet: Approve transaction
Wallet->>WASM: Signed transaction
WASM->>WASM: Build initialize_account_status instruction
Note over WASM: PDA seeds: [program_id, trader_pubkey, market_config_pubkey]
WASM->>RPC: Submit transaction
RPC->>Program: initialize_account_status
Program->>Program: Validate Owner.is_signer == true
Program->>MC: Validate MarketConfig exists and is valid
Program->>Program: Derive PDA for AccountStatus
Program->>AccStatus: Create account (rent-exempt)
Program->>AccStatus: Set owner = Trader pubkey
Program->>AccStatus: Set market_config_account = MarketConfig
Program->>AccStatus: Set quantity_amount = 0
Program->>AccStatus: Set quote_amount = 0
Program-->>RPC: Success
RPC-->>WASM: Confirmed
WASM-->>Frontend: Account initialized
Frontend-->>Trader: Account ready, deposit tokens to start trading
Trader deposits base tokens (SOL) or quote tokens (USDC) into their AccountStatus.
sequenceDiagram
actor Trader
participant Wallet
participant WASM
participant RPC
participant Program
participant SPL as SPL Token Program
participant TraderATA as Trader Token Account
participant Vault as Market Vault
participant AccStatus as AccountStatus
Trader->>WASM: Deposit 500 USDC
WASM->>WASM: Determine token type: quote = USDC
WASM->>WASM: amount = 500_000_000 (raw lamports)
WASM->>WASM: Build deposit instruction
Trader->>Wallet: Approve transaction
Wallet->>WASM: Signed
WASM->>RPC: Submit transaction
RPC->>Program: deposit instruction
Program->>Program: Validate Owner.is_signer == true
Program->>Program: Validate AccStatus.owner == Owner
Program->>Program: Validate AccStatus.market_config == MarketConfig
Program->>Program: Validate TraderATA balance >= 500_000_000
Program->>SPL: Transfer 500_000_000 from TraderATA to Vault
SPL->>TraderATA: Debit 500_000_000
SPL->>Vault: Credit 500_000_000
Program->>AccStatus: quote_amount += 500_000_000
Program-->>RPC: Success
RPC-->>WASM: Confirmed
WASM-->>Trader: Balance is now 500 USDC
Stage 1 of the pipeline. User-signed. Every validation check and every account write.
sequenceDiagram
actor Trader
participant WASM as WASM Client
participant RPC as Solana RPC
participant Program as Solana Program
participant MC as MarketConfig
participant AccStatus as AccountStatus
participant PQ as PriceQueue
participant PT as PriceTrie
participant EQ as EntriesQueue
participant AIQ as AddressIndexQueue
participant CQ as CoordinatesQueue
Note over Trader,CQ: Client-Side Pre-Computation
Trader->>WASM: Sell 100 SOL at $150
WASM->>WASM: side = ask
WASM->>WASM: price = 150_000_000 (raw)
WASM->>WASM: quantity = 100_000_000_000 (raw)
WASM->>WASM: quote = price * quantity = 15_000_000_000_000
WASM->>WASM: Validate quote % price == 0
WASM->>WASM: Validate quote % quantity == 0
WASM->>WASM: Compute sliding window slot accounts [n, n+1, n+2, n+3]
WASM->>WASM: Build limit_order_queue instruction
Note over Trader,CQ: Transaction Submission
Trader->>WASM: Sign transaction
WASM->>RPC: Submit tx with 4 slot-window accounts
Note over Trader,CQ: On-Chain Validation (Stage 1, slot n)
RPC->>Program: limit_order_queue instruction
Program->>MC: Read and validate market exists
Program->>AccStatus: Read and validate balance
Program->>Program: Validate quote % price == 0
Program->>Program: Validate quote % quantity == 0
Program->>Program: Validate ask: quantity <= AccStatus.quantity_amount
Program->>Program: Validate AccStatus.market_config == MarketConfig
Program->>Program: Validate LOQ.market_config_account == MarketConfig
Program->>Program: Validate AccStatus.owner == Owner
Program->>Program: Validate Owner.is_signer == true
Note over Trader,CQ: On-Chain Processing
Program->>Program: Store coordinates pointer in local var
Program->>PT: Traverse PriceTrie for price 150
Program->>PT: Create TrieNode(digit=1, depth=2) if needed
Program->>PT: Create TrieNode(digit=5, depth=1) if needed
Program->>PT: Push each TrieNodePointer onto path stack
Program->>PQ: Find or create PriceNode for price=150
Program->>PQ: Validate price matches
Program->>Program: Push PriceNodePointer onto stack
Program->>EQ: Insert OrderEntry (qty=100B, quote=15T, addr_ptr, status_ptr)
Program->>EQ: Set address_index_pointer on entry
Program->>Program: Store OrderEntry pointer in local var
Program->>Program: Pop PriceNodePointer from stack
Program->>EQ: Add p_pointer to OrderEntry
Program->>PQ: Add quantity + quote to PriceNode deltas
Program->>Program: Pop each TrieNodePointer from stack
Program->>PT: Add quantity + quote to each TrieNode delta
Program->>AIQ: Write address index coordinate
Program->>CQ: Write trie path coordinates
Note over Trader,CQ: State Changes Written
Program-->>RPC: Success
RPC-->>WASM: Confirmed at slot n
WASM-->>Trader: Limit sell order placed, pending pipeline
Stage 2 of the pipeline. User-signed. Concurrent with Stage 1.
sequenceDiagram
actor Trader
participant WASM as WASM Client
participant RPC as Solana RPC
participant Program as Solana Program
participant MC as MarketConfig
participant AccStatus as AccountStatus
participant MOQ as MarketOrderQueue
participant MOPQ as MarketOrderPriceQueue
participant AIC as AddressIndexCache
Note over Trader,AIC: Client-Side
Trader->>WASM: Buy 100 SOL at market
WASM->>WASM: side = buy
WASM->>WASM: target_price = 0 (no limit)
WASM->>WASM: target_amount = 100_000_000_000 (raw)
WASM->>WASM: Build event: flag(buy+quantity), price(0), amount(100B)
WASM->>WASM: Compute sliding window accounts
WASM->>WASM: Build market_order_queue instruction
Trader->>WASM: Sign transaction
WASM->>RPC: Submit tx
Note over Trader,AIC: On-Chain Validation (Stage 2, slot n)
RPC->>Program: market_order_queue instruction
Program->>MC: Read and validate market
Program->>AccStatus: Read and validate balance
Program->>Program: Validate buy: amount <= AccStatus.quote_amount
Program->>Program: Validate AccStatus.market_config == MarketConfig
Program->>Program: Validate AccStatus.owner == Owner
Program->>Program: Validate Owner.is_signer == true
Program->>Program: If price target set: validate price is non-zero rational
Note over Trader,AIC: On-Chain Processing
Program->>MOQ: Write market order event (17 bytes)
Note over MOQ: flag=buy+qty, price=0, amount=100B
Program->>MOPQ: Write price target entry (none here)
Program->>AIC: Write address index coordinate to cache
Program-->>RPC: Success
RPC-->>WASM: Confirmed at slot n
WASM-->>Trader: Market buy submitted, pending matching
After the user places a limit order (Stage 1), the crank advances it through Stages 3 and 4 into the live order book.
sequenceDiagram
participant Crank
participant RPC as Solana RPC
participant Program as Solana Program
participant LOQ_Ask as LimitOrderQueue (ask)
participant LOQ_Bid as LimitOrderQueue (bid)
participant Agg as LimitOrderAggregation
participant MC as MarketConfig
participant OBLog as OrderBookChangeLog
participant TrieSlab as TrieNode Slab (ask)
participant PriceSlab as PriceNode Slab (ask)
participant BlockSlab as OrderBlock Slab (ask)
Note over Crank,BlockSlab: Stage 3: Aggregation (slot n+1)
Crank->>Crank: Decision tree: LOQ has data, write-lock OFF
Crank->>RPC: Submit limit_order_aggregation tx
RPC->>Program: limit_order_aggregation
Program->>LOQ_Ask: Read and consume prior slot ask queue
Program->>LOQ_Bid: Read and consume prior slot bid queue
Program->>Program: Group entries by price
Program->>Program: Sort by price for efficient insertion
Program->>Agg: Write aggregated output
Program-->>RPC: Success
Note over Crank,BlockSlab: Stage 4: Order Book Update (slot n+2)
Crank->>Crank: Decision tree: Aggregation complete
Crank->>RPC: Submit order_book_update tx
RPC->>Program: order_book_update (action=create)
Program->>MC: Write: SET WRITE-LOCK ON
Program->>Agg: Read and consume aggregated orders
loop For each price group in aggregation
Program->>TrieSlab: Insert or update TrieNode path
Program->>TrieSlab: Update delta_quantity + delta_quote on each node
Program->>PriceSlab: Insert or update PriceNode
Program->>PriceSlab: Set order_block_pointer and next_entry_offset
Program->>BlockSlab: Insert OrderBlock if needed
Program->>BlockSlab: Write OrderEntry at next_entry_offset
Program->>BlockSlab: Update block delta_quantity + delta_quote
Program->>PriceSlab: Advance next_entry_offset
Program->>PriceSlab: Increment num_order_blocks_produced if new block
end
Program->>OBLog: Record all changes for pre-compute stage
Note over Crank,BlockSlab: Ledger Insert (part of OB Update or Settlement S1)
Note over Crank,BlockSlab: For each new order entry inserted:
Note over Crank,BlockSlab: - Create OrderEntryStatusNode (status=open, price, slot_open)
Note over Crank,BlockSlab: - Find or create AddressIndexNode for trader
Note over Crank,BlockSlab: - Increment num_open_entries
Note over Crank,BlockSlab: - Link into trader's order chain (ask or bid)
Program-->>RPC: Success
Note over Crank,BlockSlab: Order is now LIVE in the order book
After the user places a market order (Stage 2), the crank advances it through Stages 5 and 6.
sequenceDiagram
participant Crank
participant RPC
participant Program
participant MOQ as MarketOrderQueue
participant Cache as MarketOrderCache
participant OBLog as OrderBookChangeLog
participant PriceSlab as PriceNode Slab
participant BlockSlab as OrderBlock Slab
participant ME as Matching Engine
participant TrieSlab as TrieNode Slab
participant SQ as SettlementQueue
Note over Crank,SQ: Stage 5: Pre-Compute and Cache (slot n+3)
Crank->>Crank: Decision tree: OB updated, market orders pending
Crank->>RPC: Submit precompute_market_orders tx
RPC->>Program: precompute_market_orders
Program->>MOQ: Read and consume market orders
Program->>OBLog: Read latest order book state
Program->>PriceSlab: Read to determine which price levels exist
Program->>BlockSlab: Read to check order availability
loop For each market order
Program->>Program: If buy then scan ask side
Program->>Program: If sell then scan bid side
Program->>Program: Identify hot accounts needed for matching
Program->>Cache: Write pre-computed account list
end
Program-->>RPC: Success
Note over Crank,SQ: Stage 6: Match Orders (slot n+4)
Crank->>Crank: Decision tree: Cache ready
Crank->>RPC: Submit match_market_orders tx
RPC->>Program: match_market_orders
Program->>Cache: Load pre-computed account list
Program->>Program: Load slab byte slices from accounts
Program->>ME: Pass SlabSet + market orders
Note over ME: Pure Rust library, no Solana knowledge
loop For each market order or compatible batch
ME->>ME: Check batching: same type, same dimension, no price target
ME->>TrieSlab: Traverse trie (ask: 0 to 9, bid: 9 to 0)
ME->>ME: At each node check delta_qty >= remaining
ME->>ME: Descend to best price PriceNode
ME->>BlockSlab: Read OrderBlock at next_match_offset
ME->>ME: Consume OrderEntry in FIFO order
ME->>ME: Full fill: mark consumed, next entry
ME->>ME: Partial fill: reduce amounts, stop
ME->>BlockSlab: Update block delta_quantity -= filled
ME->>BlockSlab: Update block delta_quote -= filled
ME->>PriceSlab: Update PriceNode deltas
ME->>TrieSlab: Propagate deltas up path stack to root
ME->>ME: If price level exhausted then flag is_active=0
ME->>ME: Check CU budget: remaining less than safety margin?
ME->>ME: Produce FillRecord per consumed entry
end
ME-->>Program: MatchResult + FillRecords
Program->>SQ: Write fill records to SettlementQueue
Program-->>RPC: Success
Zooming into what happens inside the matching engine during Stage 6. Trie traversal, entry consumption, and delta propagation at the data structure level.
sequenceDiagram
participant ME as Matching Engine
participant Trie as TrieNode Slab
participant TLN as TrieLinkNode Slab
participant Price as PriceNode Slab
participant Block as OrderBlock Slab
participant Stack as Path Stack
participant Fills as Fill Records
Note over ME,Fills: Market Buy 100 SOL: traverse ASK side (0 to 9)
ME->>Trie: Read root TrieNode
ME->>ME: root.delta_qty=500 >= remaining=100 PASS
ME->>Stack: Push root address
ME->>ME: Read root.trie_link.flags
ME->>ME: bit 11 set: TrieLinkNodePointer
ME->>TLN: Read TrieLinkNode at pointer
ME->>ME: Traverse children in order 0 to 9
ME->>Trie: Read child TrieNode(digit=1, depth=2)
ME->>ME: child.delta_qty=300 >= remaining=100 PASS
ME->>Stack: Push child address
ME->>ME: Read child.trie_link.flags
ME->>ME: bit 13 set: PriceNodePointer (leaf)
ME->>Price: Read PriceNode(price=150)
Note over ME,Fills: Arrived at best ask price: consume entries
ME->>Price: Read next_match_offset = 3
ME->>ME: Read order_block_pointer
ME->>ME: Check pointer type: single OrderBlock
ME->>Block: Read OrderBlock at pointer
ME->>Block: Read entry[3]: qty=40, quote=6000
ME->>ME: remaining=100, entry_qty=40: FULL FILL
ME->>ME: remaining = 100 - 40 = 60
ME->>Block: Mark entry[3] consumed
ME->>Block: delta_qty -= 40, delta_quote -= 6000
ME->>Fills: Write FillRecord(coord, qty=40, quote=6000, price=150, ask)
ME->>Block: Read entry[4]: qty=60, quote=9000
ME->>ME: remaining=60, entry_qty=60: FULL FILL
ME->>ME: remaining = 60 - 60 = 0
ME->>Block: Mark entry[4] consumed
ME->>Block: delta_qty -= 60, delta_quote -= 9000
ME->>Fills: Write FillRecord(coord, qty=60, quote=9000, price=150, ask)
ME->>Price: Advance next_match_offset: 3 to 5
Note over ME,Fills: Delta Propagation: bottom to top
ME->>Price: delta_qty -= 100, delta_quote -= 15000
ME->>Stack: Pop leaf TrieNode address
ME->>Trie: leaf.delta_qty -= 100, leaf.delta_quote -= 15000
ME->>Stack: Pop root address
ME->>Trie: root.delta_qty -= 100, root.delta_quote -= 15000
Note over ME,Fills: Order fully filled
ME->>ME: Return MatchResult: remaining=0, stop=FullyFilled, fills=2
Stage 8 (slot n+5). Runs concurrently with Cleanup. Writes only to Ledger and AccountStatus accounts.
sequenceDiagram
participant Crank
participant Program
participant SQ as SettlementQueue
participant AIN as AddressIndexNode Slab
participant OESN as OrderEntryStatusNode Slab
participant OECLN as ChangeLogNode Slab
participant BuyerAcct as Buyer AccountStatus
participant SellerAcct as Seller AccountStatus
Crank->>Program: Submit settlement tx
Program->>SQ: Read fill records
Note over Program,SellerAcct: Process Fill 1: Seller entry (40 SOL at $150)
Program->>Program: Read FillRecord coord=(addr_ptr, status_ptr)
Program->>AIN: Resolve addr_ptr to AddressIndexNode
Note over AIN: owner = Seller pubkey
Program->>OESN: Resolve status_ptr to OrderEntryStatusNode
Program->>OESN: Update slot_update = current_slot
Program->>OESN: Update flags.status = partial (still has qty left)
Program->>OECLN: Create OrderEntryChangeLogNode
Note over OECLN: type=partial_fill, qty_delta=-40, quote_delta=-6000
Program->>SellerAcct: quote_amount += 6000 (received USDC)
Program->>SellerAcct: quantity_amount -= 40 (sent SOL)
Note over Program,SellerAcct: Process Fill 2: Seller entry (60 SOL at $150)
Program->>OESN: Resolve status_ptr to OrderEntryStatusNode
Program->>OESN: Update flags.status = closed (fully filled)
Program->>OECLN: Create OrderEntryChangeLogNode
Note over OECLN: type=full_fill, qty_delta=-60, quote_delta=-9000
Program->>SellerAcct: quote_amount += 9000
Program->>SellerAcct: quantity_amount -= 60
Program->>AIN: num_open_entries -= 1
Note over Program,SellerAcct: Credit the Buyer
Program->>BuyerAcct: quantity_amount += 100 (received SOL)
Program->>BuyerAcct: quote_amount -= 15000 (paid USDC)
Program->>SQ: Mark fill records consumed
Program-->>Crank: Success
Stage 7 (slot n+6). Runs concurrently with Settlement. Writes only to Order Book slab accounts.
sequenceDiagram
participant Crank
participant Program
participant SQ as SettlementQueue
participant BlockSlab as OrderBlock Slab
participant PriceSlab as PriceNode Slab
participant TrieSlab as TrieNode Slab
participant LinkSlab as TrieLinkNode Slab
participant MC as MarketConfig
Crank->>Program: Submit cleanup tx
Program->>SQ: Read matched and cancelled entries
Note over Program,MC: Fast Cleanup: empty nodes
loop For each consumed OrderEntry
Program->>BlockSlab: Check if OrderBlock fully consumed
alt All 16 entries consumed
Program->>BlockSlab: slab.delete(block_addr) push addr to stack
Program->>PriceSlab: Update PriceNode
Program->>PriceSlab: num_order_blocks_consumed += 1
Program->>PriceSlab: Advance to next block if match cursor was here
else Partially consumed
Program->>Program: Skip, block still has live entries
end
end
loop For each empty PriceNode (delta_qty == 0)
Program->>PriceSlab: slab.delete(price_addr)
Program->>TrieSlab: Read parent TrieNode
Program->>TrieSlab: Update trie_link: remove child pointer
Program->>TrieSlab: Update trie_link.flags: clear digit bit
Program->>TrieSlab: Decrement trie_link.size
alt TrieNode has 0 children left
Program->>TrieSlab: Set is_active = 0 (bit 14)
Program->>TrieSlab: slab.delete(trie_addr)
Note over TrieSlab: All children implicitly inactive
else TrieNode still has children
Program->>TrieSlab: Update delta_qty and delta_quote
end
end
loop For each orphaned TrieLinkNode
Program->>LinkSlab: slab.delete(link_addr)
end
Note over Program,MC: Release Write-Lock
Program->>MC: Write: SET WRITE-LOCK OFF
Program->>SQ: Mark entries processed
Program-->>Crank: Success
Note over Crank: Pipeline batch complete
Cancellation enters through Stage 1 with a cancel flag. Race conditions with fills are an open question (Q-001).
sequenceDiagram
actor Trader
participant WASM
participant RPC
participant Program
participant MC as MarketConfig
participant AccStatus as AccountStatus
participant LOQ as LimitOrderQueue
participant Agg as Aggregation
participant TrieSlab as TrieNode Slab
participant PriceSlab as PriceNode Slab
participant BlockSlab as OrderBlock Slab
participant SQ as SettlementQueue
participant AIN as AddressIndexNode Slab
participant OESN as OrderEntryStatusNode Slab
Note over Trader,OESN: Stage 1: Cancel Request (slot n)
Trader->>WASM: Cancel order XYZ
WASM->>WASM: Build limit_order_queue instruction with cancel flag
WASM->>WASM: Set cancel flag + order_entry_id
Trader->>WASM: Sign
WASM->>RPC: Submit tx
RPC->>Program: limit_order_queue (cancel)
Program->>MC: Read and validate market
Program->>AccStatus: Read and validate ownership
Program->>Program: Validate Owner.is_signer
Program->>Program: Validate AccStatus.owner == Owner
Program->>LOQ: Write cancel event with order_entry_id
Program-->>RPC: Success
Note over Trader,OESN: Stage 3: Aggregation picks up cancel (slot n+1)
Program->>LOQ: Read cancel event from prior slot
Program->>Agg: Write cancel into aggregated output
Note over Trader,OESN: Stage 4: OB Update processes cancel (slot n+2)
Program->>BlockSlab: Locate OrderEntry by ID
Program->>BlockSlab: Zero the entry (tombstone)
Program->>BlockSlab: Update OrderBlock deltas
Program->>PriceSlab: Update PriceNode deltas
Program->>TrieSlab: Propagate delta changes up trie path
Program->>SQ: Write cancel event to SettlementQueue
Note over Trader,OESN: Stage 8: Settlement processes cancel (slot n+5)
Program->>AIN: Resolve coordinate to AddressIndexNode
Program->>OESN: Update OrderEntryStatusNode: status = closed
Program->>OESN: Create ChangeLogNode (type=cancel)
Program->>AccStatus: Return locked funds to AccountStatus
Program->>AIN: num_open_entries -= 1
WASM-->>Trader: Order cancelled, funds returned
After settlement, the trader withdraws tokens back to their wallet.
sequenceDiagram
actor Trader
participant WASM
participant RPC
participant Program
participant AccStatus as AccountStatus
participant SPL as SPL Token Program
participant Vault as Market Vault
participant TraderATA as Trader Token Account
Trader->>WASM: Withdraw 15000 USDC
WASM->>WASM: amount = 15_000_000_000_000 (raw)
Trader->>WASM: Sign
WASM->>RPC: Submit withdraw tx
RPC->>Program: withdraw instruction
Program->>Program: Validate Owner.is_signer
Program->>Program: Validate AccStatus.owner == Owner
Program->>Program: Validate AccStatus.quote_amount >= amount
Program->>Program: Validate no open orders using these funds
Program->>AccStatus: quote_amount -= 15_000_000_000_000
Program->>SPL: Transfer from Vault to TraderATA
SPL->>Vault: Debit 15_000_000_000_000
SPL->>TraderATA: Credit 15_000_000_000_000
Program-->>RPC: Success
RPC-->>WASM: Confirmed
WASM-->>Trader: 15000 USDC withdrawn to wallet
The crank is a continuous loop monitoring on-chain state and submitting the right transaction at the right time.
sequenceDiagram
participant Crank as Crank (WASM Client)
participant RPC as Solana RPC
participant MC as MarketConfig
participant LOQ as LimitOrderQueue
participant MOQ as MarketOrderQueue
participant Program as Solana Program
loop Every 400ms (each slot)
Crank->>RPC: getAccountInfo(MarketConfig)
RPC-->>Crank: MarketConfig state
Crank->>Crank: Read write-lock status
alt Write-lock is ON
Crank->>Crank: Skip: OB is being written to
Note over Crank: Wait for cleanup to release lock
else Write-lock is OFF
Crank->>RPC: getAccountInfo(LimitOrderQueue)
RPC-->>Crank: LOQ state
alt LOQ has pending orders from prior slot
Crank->>RPC: Submit limit_order_aggregation tx
RPC->>Program: Stage 3 Aggregation
Program-->>RPC: Success
Crank->>RPC: Submit order_book_update tx
RPC->>Program: Stage 4 OB Update (sets write-lock)
Program-->>RPC: Success
end
Crank->>RPC: getAccountInfo(MarketOrderQueue)
RPC-->>Crank: MOQ state
alt MOQ has pending orders
Crank->>RPC: Submit precompute_market_orders tx
RPC->>Program: Stage 5 Pre-Compute
Program-->>RPC: Success
Crank->>RPC: Submit match_market_orders tx
RPC->>Program: Stage 6 Match
Program-->>RPC: Success
par Settlement and Cleanup
Crank->>RPC: Submit settlement tx
RPC->>Program: Stage 8 Settlement
Program-->>RPC: Success
and
Crank->>RPC: Submit cleanup tx
RPC->>Program: Stage 7 Cleanup (releases write-lock)
Program-->>RPC: Success
end
end
end
end
Complete end-to-end. Alice sells 100 SOL at $150. Bob buys 100 SOL at market. Every account, every slot, every state change.
sequenceDiagram
actor Alice
actor Bob
participant AW as Alice WASM
participant BW as Bob WASM
participant RPC
participant Program
participant MC as MarketConfig
participant AliceAcct as Alice AccStatus
participant BobAcct as Bob AccStatus
participant LOQ as LimitOrderQueue
participant MOQ as MarketOrderQueue
participant Agg as Aggregation
participant TrieSlab as TrieNode Slab
participant PriceSlab as PriceNode Slab
participant BlockSlab as OrderBlock Slab
participant Cache as MarketOrderCache
participant ME as Matching Engine
participant SQ as SettlementQueue
participant AIN as AddressIndex Slab
participant OESN as OrderStatus Slab
participant Crank
Note over Alice,Crank: SLOT N: Order Placement
Alice->>AW: Sell 100 SOL at $150
AW->>AW: Pre-compute quote = 150 * 100 = 15000
AW->>AW: Validate 15000 % 150 == 0
AW->>AW: Validate 15000 % 100 == 0
AW->>RPC: Submit limit_order_queue tx
RPC->>Program: limit_order_queue (ask, 150, 100, 15000)
Program->>MC: Read, valid
Program->>AliceAcct: Read, qty_amount >= 100
Program->>LOQ: Write order to ask queue
Program-->>AW: Success
Bob->>BW: Buy 100 SOL at market
BW->>RPC: Submit market_order_queue tx
RPC->>Program: market_order_queue (buy, no_limit, 100)
Program->>MC: Read, valid
Program->>BobAcct: Read, quote_amount >= needed
Program->>MOQ: Write market order
Program-->>BW: Success
Note over Alice,Crank: SLOT N+1: Aggregation
Crank->>RPC: Submit limit_order_aggregation tx
RPC->>Program: limit_order_aggregation
Program->>LOQ: Read and consume ask queue from slot N
Program->>Agg: Write aggregated output (1 order at price 150)
Program-->>Crank: Success
Note over Alice,Crank: SLOT N+2: Order Book Update
Crank->>RPC: Submit order_book_update tx
RPC->>Program: order_book_update (create)
Program->>MC: WRITE-LOCK ON
Program->>Agg: Read aggregated orders
Program->>TrieSlab: Insert TrieNode(1, depth=2)
Program->>TrieSlab: Insert TrieNode(5, depth=1)
Program->>TrieSlab: Set deltas qty=100, quote=15000
Program->>PriceSlab: Insert PriceNode(price=150)
Program->>PriceSlab: Set next_entry_offset=0, num_blocks_produced=1
Program->>BlockSlab: Insert OrderBlock
Program->>BlockSlab: Write entry[0] qty=100, quote=15000, coords
Program->>BlockSlab: Set block deltas qty=100, quote=15000
Note over Alice,Crank: Ledger: create OrderEntryStatusNode for Alice (status=open)
Note over Alice,Crank: Ledger: find/create AddressIndexNode, num_open_entries += 1
Program-->>Crank: Success
Note over Alice,Crank: SLOT N+3: Pre-Compute
Crank->>RPC: Submit precompute_market_orders tx
RPC->>Program: precompute_market_orders
Program->>MOQ: Read Bob market buy
Program->>PriceSlab: Read, ask side has price 150
Program->>BlockSlab: Read, block has entries
Program->>Cache: Write account list for matching
Program-->>Crank: Success
Note over Alice,Crank: SLOT N+4: Matching
Crank->>RPC: Submit match_market_orders tx
RPC->>Program: match_market_orders
Program->>Cache: Load account list
Program->>ME: Pass SlabSet + Bob market buy (100 SOL)
ME->>TrieSlab: Read root, delta_qty=100 >= 100
ME->>TrieSlab: Descend TrieNode(1) then TrieNode(5) then PriceNode
ME->>PriceSlab: Read PriceNode(150), next_match_offset=0
ME->>BlockSlab: Read entry[0] qty=100, quote=15000
ME->>ME: remaining=100, entry=100: FULL FILL
ME->>BlockSlab: entry[0] consumed, block delta=0
ME->>PriceSlab: PriceNode delta=0
ME->>TrieSlab: TrieNode(5) delta=0, set is_active=0
ME->>TrieSlab: TrieNode(1) delta=0, set is_active=0
ME->>TrieSlab: root delta=0
ME-->>Program: MatchResult filled=100, remaining=0
Program->>SQ: Write FillRecord(Alice_coord, 100, 15000, 150, ask)
Program-->>Crank: Success
Note over Alice,Crank: SLOTS N+5 and N+6: Settlement + Cleanup (parallel)
par Stage 8 Settlement (slot N+5)
Crank->>RPC: Submit settlement tx
RPC->>Program: settlement
Program->>SQ: Read FillRecord
Program->>AIN: Resolve Alice AddressIndexNode
Program->>OESN: Update Alice OrderEntryStatusNode to closed
Program->>OESN: Create ChangeLogNode(full_fill, 100, 15000)
Program->>AIN: num_open_entries -= 1
Program->>AliceAcct: quantity_amount -= 100 SOL
Program->>AliceAcct: quote_amount += 15000 USDC
Program->>BobAcct: quote_amount -= 15000 USDC
Program->>BobAcct: quantity_amount += 100 SOL
Program-->>Crank: Success
and Stage 7 Cleanup (slot N+6)
Crank->>RPC: Submit cleanup tx
RPC->>Program: cleanup
Program->>BlockSlab: Delete consumed OrderBlock
Program->>PriceSlab: Delete empty PriceNode(150)
Program->>TrieSlab: Delete TrieNode(5) and TrieNode(1)
Program->>MC: WRITE-LOCK OFF
Program-->>Crank: Success
end
Note over Alice,Crank: TRADE COMPLETE
AW-->>Alice: Sold 100 SOL, received 15000 USDC
BW-->>Bob: Bought 100 SOL, paid 15000 USDC
When a market order cannot be fully filled at one price level, matching continues to the next. When CU budget runs low, the engine stops and the remaining amount re-enters the pipeline.
sequenceDiagram
participant ME as Matching Engine
participant Trie as TrieNode Slab
participant Price as PriceNode Slab
participant Block as OrderBlock Slab
participant Stack as Path Stack
participant Program
Note over ME,Program: Market Buy 500 SOL: ask book has 200 at $150 and 300 at $152
ME->>Trie: Traverse ask trie (0 to 9)
ME->>Trie: Find best price $150
ME->>Price: PriceNode(150), delta_qty=200
ME->>Block: Consume entries FIFO
loop Consume all entries at $150
ME->>Block: entry qty=50: FULL FILL, remaining=450
ME->>Block: entry qty=50: FULL FILL, remaining=400
ME->>Block: entry qty=50: FULL FILL, remaining=350
ME->>Block: entry qty=50: FULL FILL, remaining=300
end
ME->>ME: Price level $150 exhausted (delta=0)
ME->>Trie: Set is_active=0 on $150 path
ME->>ME: Propagate deltas up: -200 qty
Note over ME,Program: Move to next price level
ME->>Trie: Delta traverse up, find next subtree
ME->>Trie: Find next best price $152
ME->>Price: PriceNode(152), delta_qty=300
ME->>Block: Consume entries FIFO
loop Consume entries at $152
ME->>Block: entry qty=100: FULL FILL, remaining=200
ME->>Block: entry qty=100: FULL FILL, remaining=100
ME->>Block: entry qty=100: FULL FILL, remaining=0
end
ME->>ME: Order fully filled across 2 price levels
ME->>ME: Propagate deltas: -300 qty at $152 path
ME-->>Program: MatchResult filled=500, remaining=0, fills=7
Note over Program: 4 fills at $150 + 3 fills at $152
Note over ME,Program: Alternative: CU Budget Hit
ME->>ME: After consuming 3 entries check CU budget
ME->>ME: remaining_budget less than CU_SAFETY_MARGIN
ME-->>Program: MatchResult filled=300, remaining=200, stop=BudgetApproached
Note over Program: Remaining 200 SOL re-enters pipeline
Note over Program: Next batch picks up the unfilled portion
Note over Program: Exact continuation mechanism is WIP (Q-014)
Note over ME,Program: Alternative: Book Exhausted
ME->>ME: No more price levels in trie with delta > 0
ME-->>Program: MatchResult filled=300, remaining=200, stop=BookExhausted
Note over ME,Program: Alternative: Price Target Hit
ME->>ME: Next price level exceeds target_price constraint
ME-->>Program: MatchResult filled=300, remaining=200, stop=PriceTargetHit
Multiple batches flowing through the pipeline simultaneously. Each stage writes to different accounts, so Sealevel runs them all in parallel within the same slot.
sequenceDiagram
participant BA as Batch A
participant BB as Batch B
participant BC as Batch C
participant SL as Sealevel Runtime
Note over BA,SL: Slot N
BA->>SL: Stage 1+2: Place orders (LOQ_A, MOQ_A)
Note over SL: 1 stage active
Note over BA,SL: Slot N+1
BA->>SL: Stage 3: Aggregation (Agg_A)
BB->>SL: Stage 1+2: Place orders (LOQ_B, MOQ_B)
Note over SL: 2 stages parallel, disjoint accounts
Note over BA,SL: Slot N+2
BA->>SL: Stage 4: OB Update (TrieSlab, PriceSlab, BlockSlab, MC)
BB->>SL: Stage 3: Aggregation (Agg_B)
BC->>SL: Stage 1+2: Place orders (LOQ_C, MOQ_C)
Note over SL: 3 stages parallel, disjoint accounts
Note over BA,SL: Slot N+3
BA->>SL: Stage 5: Pre-Compute (Cache_A, OB read-only)
BB->>SL: Stage 4: OB Update (writes OB slabs)
BC->>SL: Stage 3: Aggregation (Agg_C)
Note over SL: 3 stages parallel
Note over SL: Pre-compute uses OrderBookChangeLog not live slabs
Note over BA,SL: Slot N+4
BA->>SL: Stage 6: Match (SQ_A, OB slabs)
BB->>SL: Stage 5: Pre-Compute (Cache_B)
BC->>SL: Stage 4: OB Update
Note over SL: 3 stages parallel
Note over BA,SL: Slot N+5
BA->>SL: Stage 8: Settlement (Ledger, AccountStatus)
BB->>SL: Stage 6: Match (SQ_B, OB slabs)
BC->>SL: Stage 5: Pre-Compute (Cache_C)
Note over SL: 3 stages parallel
Note over BA,SL: Slot N+6
BA->>SL: Stage 7: Cleanup (OB slabs, MC unlock)
BB->>SL: Stage 8: Settlement (Ledger)
BC->>SL: Stage 6: Match (SQ_C)
Note over SL: 3 stages parallel
Note over BA,SL: Slot N+7
BB->>SL: Stage 7: Cleanup
BC->>SL: Stage 8: Settlement
Note over SL: Batch A complete
Note over BA,SL: Slot N+8
BC->>SL: Stage 7: Cleanup
Note over SL: Batch B complete, Batch C complete
Every pipeline stage and the accounts it touches. This is the disjointness guarantee that makes concurrent execution possible.
| Stage | Slot | Writes To | Reads From |
|---|---|---|---|
| 1. Limit Order Queue | n | LimitOrderQueue, PriceQueue, PriceTrie, EntriesQueue, AddressIndexQueue, CoordinatesQueue | MarketConfig, AccountStatus |
| 2. Market Order Queue | n | MarketOrderQueue, MarketOrderPriceQueue, AddressIndexCache | MarketConfig, AccountStatus |
| 3. Aggregation | n+1 | LimitOrderAggregation | LimitOrderQueue (prior slot) |
| 4. OB Update | n+2 | MarketConfig (write-lock), TrieNode Slab, PriceNode Slab, OrderBlock Slab, OrderBookChangeLog | LimitOrderAggregation |
| 5. Pre-Compute | n+3 | MarketOrderCache | MarketOrderQueue, OrderBookChangeLog, PriceNode Slab (read), OrderBlock Slab (read) |
| 6. Match | n+4 | SettlementQueue, TrieNode Slab, PriceNode Slab, OrderBlock Slab (deltas) | MarketOrderCache |
| 7. Cleanup | n+6 | Order Book Slabs (delete nodes), MarketConfig (release lock) | SettlementQueue |
| 8. Settlement | n+5 | AddressIndexNode Slab, OrderEntryStatusNode Slab, ChangeLogNode Slab, AccountStatus | SettlementQueue |
Settlement writes to Ledger + AccountStatus. Cleanup writes to Order Book slabs + MarketConfig. Zero overlap: they run in parallel.
Every order transitions through these states as it moves through the pipeline:
stateDiagram-v2
[*] --> Submitted: User signs tx
Submitted --> Queued: Stage 1 or 2 validates and writes to queue
state LimitOrderPath {
Queued --> Aggregated: Stage 3 groups by price
Aggregated --> InOrderBook: Stage 4 inserts into slabs
InOrderBook --> PartiallyMatched: Stage 6 partial fill
InOrderBook --> FullyMatched: Stage 6 full fill
InOrderBook --> CancelRequested: User submits cancel
PartiallyMatched --> FullyMatched: Stage 6 subsequent fill
PartiallyMatched --> CancelRequested: User submits cancel
CancelRequested --> Cancelled: Stage 4 processes cancel
}
state MarketOrderPath {
Queued --> Cached: Stage 5 pre-computes accounts
Cached --> PartiallyFilled: Stage 6 partial fill
Cached --> FullyFilled: Stage 6 full fill
PartiallyFilled --> FullyFilled: Next batch continues
PartiallyFilled --> Unfillable: Book exhausted or price target hit
}
FullyMatched --> Settled: Stage 8 updates ledger and balances
Cancelled --> Settled: Stage 8 returns funds
FullyFilled --> Settled: Stage 8 updates balances
Unfillable --> Settled: Stage 8 returns remaining funds
Settled --> CleanedUp: Stage 7 frees slab nodes
CleanedUp --> [*]: Pipeline batch complete