feat(solver): external liquidity routing — RFQ websocket to other DEXes#7
Open
VAIBHAVJINDAL3012 wants to merge 6 commits into
Open
feat(solver): external liquidity routing — RFQ websocket to other DEXes#7VAIBHAVJINDAL3012 wants to merge 6 commits into
VAIBHAVJINDAL3012 wants to merge 6 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
af69d8b to
f76ebec
Compare
Route orders the matcher can't cross internally to allow-listed external
DEXes over a websocket RFQ: DEXes post standing {price, quantity} quotes,
the matcher matches idle notes against them and hands over the serialized
note bytes for permissionless on-chain self-consume. Off by default
(router_enabled).
- order book: park/unpark for in-flight notes (reuses the index path, so the
matching gates need no change), O(expiring) TTL reactivation
- router/select: decimals-correct export math vs oracle mid, marginal-first,
off-market guard; fill_price carried for the forthcoming overfill protocol
- router/server: websocket transport on its own OS thread, allow-list auth
- matcher: external pass + reactivation each tick (try_send handovers)
- config/pipeline/start wiring; decimals snapshot; load_token_decimals
Builds on the pswap-filler-sdk crate (shared wire protocol). See
docs/adr/0001-external-liquidity-routing.md and docs/external-liquidity-routing.md.
A DEX (FillerClient) connects to the real router thread and posts an RFQ quote; an unmatched order in run_matcher's external pass is selected and handed back to the SDK as a FillerEvent::Handover — SDK quote → router → matcher select → router → SDK, nothing mocked in between. Asserts note id, fill amount, fill_price, and exact note bytes survive the round trip.
…verage - matcher: a full handover channel drops the handover but still parks the note (TTL recovers it) and never blocks the tick — covers the try_send Full branch. - router: a message over max_msg_bytes closes only that connection; the router keeps serving a fresh client (DoS guard). - SDK ↔ router: an unparseable quote comes back to the SDK as a structured FillerEvent::Error and the session stays open.
Mirror the SDK-side removal of the never-emitted Withdrawn event in the external-liquidity-routing message list, and re-sync Cargo.lock with this branch's solver ws/futures-util deps (the rebase carried the SDK branch's pruned lock).
f76ebec to
a8dd8fc
Compare
When the handover channel is full, try_send drops the batch — but the notes were already parked, so TTL reactivation would later add a no-re-offer block for a DEX that never received them (the matcher couldn't tell "dropped" from "delivered-but-not-consumed"). Now a dropped batch is rolled back: each note is unparked and its reservation released, so it stays immediately eligible to the same DEX next tick. Adds OrderBook::unpark — a no-penalty single-note rollback that re-indexes the note and leaves a harmless park_queue tombstone. Tests: a direct unpark unit (rollback + tombstone-skip + no-op-when-unparked); the backpressure test now asserts the rollback and a same-DEX re-route on retry.
…xit) Reflect the fix: a dropped handover try_send now immediately unparks the note with no re-offer penalty, so the no-show penalty applies only to genuinely delivered handovers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Routes orders the matcher can't cross internally to allow-listed external DEXes over
a websocket RFQ: DEXes post standing
{price, quantity}quotes, the matcher matches itsidle notes against them and hands over the serialized note bytes for permissionless
on-chain self-consume. Off by default (
router_enabled).Design
Full reasoning in
docs/adr/0001-external-liquidity-routing.md; as-built reference indocs/external-liquidity-routing.md. Highlights:path, so
best_order/has_orders/active_pair_countneed no change; a parkednote is invisible to matching by construction. O(expiring) TTL reactivation via a
time-ordered
park_queue.select_notes) — exactu128,marginal-first ordering, off-market guard.
fill_priceis carried for the forthcomingoverfill protocol (today the chain still settles at the note's rate).
spawn_price_api_thread);two
Sendchannels to the matcher (watchquotes in,mpschandovers out viatry_send, so a slow DEX socket never stalls the fund-critical tick).SOLVER_ROUTER_TOKENS(env), constant-time check at thewebsocket upgrade.
Testing
select_notes/ order book / matcher / router: ≥95% line, 100% function coverageon changed files; property test asserts
active_order_count()invariance acrosspark→unpark and park→consume.
crates/solver/tests/integration_filler_sdk.rs) drives the realrouter thread through the public
FillerClient: bad token rejected →AuthOk→ quotereaches the matcher → handover surfaces as a
FillerEventwith the exact bytes +fill_price.Risks (documented in the ADR)
residual; partial mitigation (no re-offer to the same DEX on reactivation) shipped,
per-DEX cap deferred.
by the TTL.
Docs / ADR
docs/external-liquidity-routing.md,docs/adr/0001-external-liquidity-routing.md.