feat(clob): add spot order book module#117
Conversation
Add the standalone CLOB primitive ahead of perps wiring so spot and derivatives can share deterministic market, order, matching, and fill state without embedding book logic in consumers. Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
distractedm1nd
left a comment
There was a problem hiding this comment.
Very nice start
My biggest question/concern is: Why do we want order placement to be fully onchain?
I know hyperliquid does this, but for us its going to make pretty tough bottlenecks since our chain's db and lifecycle patterns have to also cater to other uses. The bottlenecks are already visible in this PR, with it's table layout and pruning issues.
Theres some really cool stuff we can do here and keep it performant without putting everything on chain. Placing orders in particular and having all of those updates merkleized will kill us the second we get any real activity.
We can reuse the p2p overlay like we do in mempool and have orders and cancels be gossiped but only live in validators' in-memory books (which can be super performant); only fills/matches are committed to state. Placement and cancellation are free and fast; the trade-off ofc is trusting the block proposer not to censor/reorder within its block, but I am assuming we are not the kind of chain or hub whose users care about that. That would make us more dydx v4 shaped. There are probably other things we can do but I am not fully aware of the ecosystem yet
Canonicalize asset pairs in market_id, expose programmatic place_order, prune terminal account_orders entries, and document the no-STP policy. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Pushed Fixed in this commit
Acknowledged — needs separate design discussion
Let me know if you want any of the architectural items tackled in this PR or tracked as follow-ups. |
Keep market fill indexes as a bounded recent-history window so old fills cannot block matching once the query index reaches capacity. Co-authored-by: Cursor <cursoragent@cursor.com>
Exercise the CLOB RPC query paths through a shared ledger so patch coverage includes the newly added RPC module. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Pushed the remaining fix in b6fd97e. Summary:
Validation:
Only remaining blocker is the existing requested-changes review state, so this should be ready for re-review. |
Replace the on-chain order matcher with proposer-carried match batches that validators replay from signed order intents before recording fills. Co-authored-by: Cursor <cursoragent@cursor.com>
Exercise the CLOB actor, validator replay rejection paths, and extension state-apply hook so CI and Codecov cover the new off-chain matching boundary. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep fill history bounded under match-batch application, stop matcher scans at the first non-crossing price, and align docs with the off-chain CLOB boundary. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Force-pushed PR #117 to the off-chain CLOB stack from PR #125, replayed on top of the current #117 base. Preserved/folded in the review fixes:
Validation:
|
Persist active order snapshots for validator replay, keep proposer-side matching state across batches, and preserve bounded fill pruning under the shared MatchEngine path. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Follow-up fix pushed on top of the PR #125/#117 integration: What changed:
Validation:
|
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Final update on What this commit adds (not covered by earlier follow-up comments)
Validation on
|
|
I think there's a liveness issue in the matcher: accepted orders can still hit
To confirm it isn't just theoretical, I reproduced it: two individually-valid orders (a resting bid at a very large on-tick price + a normal crossing ask) each pass A small structural fix is to reject the order up front in if price.checked_mul(base_quantity).is_none() {
return Err(ClobError::InvalidOrder("price times quantity overflows u128"));
}
Since every fill uses base <= maker.original_base, bounding price * original_base at acceptance should make QuoteOverflow unreachable for accepted orders. I have a passing regression test for this if it's useful.
(This is a liveness/DoS concern, not a consensus-safety one — the canonical replay path looks sound.) |
distractedm1nd
left a comment
There was a problem hiding this comment.
A lot closer, the main thing missing is that p2p got removed, but it shouldn't be that difficult of a fix. Please remember when adding it back in that every validator should NOT match independently or submit CommitFills for its own locally computed fills, the proposer's book is the only authority at proposal
Also, eren's QuoteOverflow finding definitely needs to be fixed as well
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Addressed @erenyegit's Fix
Regression
|
Gossip accepted CLOB order intents over the validator P2P overlay, remove the legacy match-batch resting hint, and keep proposer batches out of the normal transaction runtime. Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve the coins-chain runtime test conflict by preserving both CLOB and Oracle storage error coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Addressed Ryan's latest review comments in What changed:
Validation:
GitHub now reports the PR as mergeable; Rust CI and CodeQL are queued on the latest head. |
distractedm1nd
left a comment
There was a problem hiding this comment.
Let's merge once clippy is fixed and merge conflicts are resolved. Everything mentioned in reviews has been resolved
Iterate queue keys directly instead of discarding values in ready_count. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep both bridge and CLOB transaction wrappers after main advanced, assign CLOB tag 4, and preserve bridge runtime/tests from main. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Follow-up on Ryan's review ( Review fixes landed
Merge/main follow-ups
CI on
DS/index layout optimization remains intentionally deferred per discussion. |
Summary
nunchi-clobas a standalone workspace module for shared spot/perps order-book state.Test plan
cargo test -p nunchi-clobcargo check --workspace --all-targetscargo check -p nunchi-clob --no-default-featuresCoordination notes
examples/coins-chaintransaction wrapper tag yet; that should be settled with Jacob against the final module set before perps wiring.mainso it can land before Add oracle-backed perpetuals module #79/Track perpetuals production follow-ups #80 per the CLOB-first sequencing.Made with Cursor