Adapters pipeline: revm swap simulation + Balancer reactive + E2E validation - #13
Merged
KaiCode2 merged 3 commits intoJun 24, 2026
Merged
Conversation
…idation Completes the adapters pipeline (track -> react -> simulate) for Uniswap V2, Uniswap V3, and Balancer V2, validated offline, against RPC parity, and against a live WebSocket feed. Stacks on the Phase A4 slice-2 Balancer cold-start. Swap simulation (src/adapters/sim.rs + AmmAdapter::simulate_swap): executes the protocol's canonical quote in revm against the cold-start snapshot via AdapterCache::call_raw and decodes amount_out — the deployed bytecode does the math, no amm-math/LocalAMM/hand-rolled formulas. V2 = Router02.getAmountsOut, V3 family = QuoterV2.quoteExactInputSingle (fee from metadata), Balancer = Vault.queryBatchSwap (amount_out = -assetDeltas[1]). SwapQuote/SimError/SimConfig (mainnet quoter/router defaults + overrides) + local sol! quote ABIs; a single run_quote maps revert/halt -> SimError::Reverted. Quote-target bytecode is lazily fetched live or installed as a fixture offline. Balancer V2 reactive (was routing-only): on a Swap, decode_event now emits RepairAction::VerifySlots over the cold-start-discovered vault balance slots (persisted on BalancerV2Metadata.balance_slots by finish), which the reactive runtime lowers into a resync — keeping cached balances fresh for a subsequent simulate_swap without reverse-engineering the vault's balance-mapping layout. Tests: - tests/adapter_swap_sim.rs (8, offline): per-protocol quote vs a mock quoter (no RPC), revert -> Reverted, V3 missing-fee -> MissingMetadata, and a Balancer reactive integration test (cold-start -> Swap refresh -> re-simulate reflects the new balance). New mock fixtures. - tests/pipeline_e2e.rs (1): chained cold-start -> reactive Sync on a shared cache+registry updates the warmed reserves slot (the integration gap). - tests/adapter_swap_sim_rpc.rs (3, #[ignore], RPC-gated): sim == eth_call at a pinned block for V2/V3/Balancer. Confirmed passing against a live archive node. - tests/reactive_ws_e2e.rs (#[ignore], RPC-gated): LIVE WebSocket E2E — cold-start pinned at B0, then ONLY Sync events over a wss subscription move reserves, and simulate_swap matches on-chain getAmountsOut at the event block while NOT matching the pinned-B0 quote (proves event-sourced state, not a refetch). Confirmed passing live (6 events / 6 min; sim == eth_call to the wei). Subscribes topic-only (the provider does not push address-filtered subscriptions) and routes by the handler. Plus a fast subscription-health probe. Full matrix green: fmt; clippy default + adapters-only + no-default (-D warnings); tests default + adapters-only + no-default; cargo doc -D warnings. Live/RPC tests are #[ignore] and gated on E2E_RPC_URL (run by the manager, not CI). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add offline register -> cold-start -> reactive-event -> simulate_swap regression tests for Uniswap V2 and V3 in tests/pipeline_e2e.rs, exercising all three adapter-pipeline legs in one flow (mock quote contracts return a seeded value, so these pin the chain WIRES end-to-end; state-vs-quote correctness is covered by the RPC-parity and live-WebSocket tests). Balancer's full chain already lives in tests/adapter_swap_sim.rs. pipeline_e2e: 1 -> 3 tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The adapters pipeline (cold-start -> reactive -> simulate) is self-contained and validated, so remove the legacy stack entirely to make the crate adapters-only and agent-traversable. Net: 34 files / ~14.5k lines deleted. Deleted (all behind the now-removed `simulation`/`search` features): - legacy modules: amm_wrapper (LocalAMM), cache_sync/, configured_amms, data, discovery, events/, progress, routing/ (search/arbitrage, built on LocalAMM), and the pool-math modules balancer_pool, balancer_v3_pool, cryptoswap_math, curve_pool, slipstream_pool, solidly_v2_pool, stableswap_math, uniswap_v4_pool, plus the inline balancer_math + profit modules in lib.rs. - legacy examples (event_subscription, triangular_arbitrage, programmatic_loading, toml_loading, amms.toml) and the legacy `simulation` bench. Cargo.toml: removed the `simulation`, `search`, `toml`, `full-protocols`, `common-protocols` features and the no-adapter protocol sub-features; removed the now-orphaned deps `amms`, `amm-math`, `rayon`, `toml`, `criterion`, `tracing-subscriber` (all gone from Cargo.lock). `default` is now `["adapters", "uniswap-v2", "uniswap-v3", "balancer-v2"]`. Added examples/adapter_pipeline.rs: a runnable adapters-path demo (register -> cold-start -> WS event subscribe -> reactive apply -> simulate_swap), modeled on tests/reactive_ws_e2e.rs; env-gated, no-ops (never panics) if no RPC/WS URL. Arbitrage search (routing/) is removed with the legacy path; it can be rebuilt on the adapters `simulate_swap` later. No adapter logic changed. Full matrix green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 24, 2026
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.
Stacked on #10 (Phase A4 slice 2: Balancer cold-start). Review/merge order: #8 → #9 → #10 → this. Base is the slice-2 branch, so the diff is this milestone only.
What
Completes the adapters pipeline — track → react → simulate — for Uniswap V2, Uniswap V3, and Balancer V2, validated offline, against RPC parity, and against a live WebSocket feed.
Swap simulation (
src/adapters/sim.rs+AmmAdapter::simulate_swap)Executes the protocol's canonical quote in revm against the cold-start snapshot (
AdapterCache::call_raw) and decodesamount_out— the deployed bytecode does the math, noamm-math/LocalAMM/hand-rolled formulas.Router02.getAmountsOut· V3 family →QuoterV2.quoteExactInputSingle(fee from metadata) · Balancer →Vault.queryBatchSwap(-assetDeltas[1]).SwapQuote/SimError/SimConfig(mainnet defaults + overrides) + localsol!ABIs; onerun_quotemaps revert/halt →Reverted.Balancer V2 reactive (was routing-only)
On a
Swap,decode_eventnow emitsRepairAction::VerifySlotsover the cold-start-discovered vault balance slots (persisted onBalancerV2Metadata.balance_slots), which the runtime lowers into a resync — keeping cached balances fresh for a subsequentsimulate_swap, without reverse-engineering the vault's balance-mapping layout.Validation
tests/adapter_swap_sim.rs, 8): per-protocol quote vs a mock quoter (no RPC); revert →Reverted; V3 missing-fee →MissingMetadata; Balancer reactive integration (cold-start →Swaprefresh → re-simulate reflects the new balance).tests/pipeline_e2e.rs): cold-start → reactiveSyncon a shared cache+registry updates the warmed reserves slot.tests/adapter_swap_sim_rpc.rs,#[ignore]):sim == eth_callat a pinned block for all three. ✅ confirmed live.tests/reactive_ws_e2e.rs,#[ignore]): cold-start pinned atB0, then onlySyncevents over awss://subscription move reserves;simulate_swapmatches on-chaingetAmountsOutat the event block and not the pinned-B0quote — proving event-sourced state, not a refetch. ✅ confirmed live (6 events / 6 min; sim ==eth_callto the wei).Test plan
Full matrix green:
fmt;clippydefault + adapters-only +--no-default-features(-D warnings);cargo testdefault + adapters-only +--no-default-features;cargo doc -D warnings. Live/RPC tests are#[ignore]and gated onE2E_RPC_URL(manager-run, not CI).🤖 Generated with Claude Code