Skip to content

feat: intent-swap extension — solve signed Fusion orders for same-block inclusion#1

Open
kayibal wants to merge 13 commits into
mainfrom
feat/intent-swap
Open

feat: intent-swap extension — solve signed Fusion orders for same-block inclusion#1
kayibal wants to merge 13 commits into
mainfrom
feat/intent-swap

Conversation

@kayibal

@kayibal kayibal commented Jul 21, 2026

Copy link
Copy Markdown

What this does

Adds an in-process intent-swap service to the Base builder. Signed orders arrive via a new intent_submitOrder RPC, are solved immediately against committed AMM state overlaid with the in-progress block's executed transactions, and the signed settlement transaction is inserted into the builder's txpool for same-block inclusion. Settlement uses the existing Fusion resolver contracts; the solver engine is backrunner (Tycho state + Fynd routing), consumed as a git dependency pinned to feat/intent-solve-api @ d62c89c.

Structure (commits reviewable in order)

builder-core (isolated commits):

  • feat(builder-core): optional build-event stream from flashblocks payload builder — adds BuilderConfig.build_event_tx: Option<mpsc::Sender<BuildEvent>> (default None) and four emit sites (IterationStart / TxExecuted with receipt logs / IterationComplete / IterationAborted). Emission is try_send-only via BuilderConfig::emit_build_event; a full channel drops the event with a warning and never stalls building. Zero behavior change when unset.
  • test(builder-core): driver test for build-event stream sequencetests/build_events.rs builds a block through the ChainDriver and asserts event order, tx-hash match, and a single shared payload id.

new crate base-intent-swap:

  • intent_submitOrder RPC: shape + auction-window validation (no EIP-712 recovery — the LOP contract validates on-chain), distinct error codes incl. queue-full and engine-unavailable.
  • Engine task: tracks the in-progress block from build events (guarded by payload id, cleared at block seal), solves each submitted order via Backrunner::solve_orders, signs with a configured EOA (redacted from all Debug output), inserts via add_external_transaction — the same path as base_insertValidatedTransaction.
  • Extension (BaseNodeExtension) + CLI arg group (--builder.intent-swap.*, disabled by default) + bin/builder wiring. With the flag off, builder behavior is unchanged.
  • README with a Base-mainnet shadow-run runbook (note: no shadow/non-proposing mode exists in the builder; the runbook documents driving it via op-node/FCU replay).

Build notes

  • Cargo.lock pins tycho-common/tycho-simulation/tycho-execution at 0.305.1 deliberately: fynd-core at the pinned rev does not compile against 0.339.x. Regenerating the lockfile breaks the build.
  • backrunner/builder-types are ssh:// git dependencies — building requires GitHub SSH access. If cargo's libssh transport cannot reach your agent, set net.git-fetch-with-cli = true in .cargo/config.toml (not committed).

Testing

  • cargo test -p base-intent-swap — 9 tests (RPC validation paths, uuid derivation, EIP-1559 sign→decode_2718→recover roundtrip, Debug redaction)
  • cargo test -p base-builder-core --test build_events — driver integration test
  • clippy -D warnings and rustfmt clean on all touched crates

🤖 Generated with Claude Code

@socket-security

socket-security Bot commented Jul 21, 2026

Copy link
Copy Markdown

kayibal added 3 commits July 21, 2026 13:42
Distinguish a closed build-event channel (consumer gone) from a full
one (backpressure) in emit_build_event. A closed channel now warns
once per process via an atomic latch instead of on every dropped
event, which previously flooded logs for the remaining lifetime of
the builder once the consumer died.
@kayibal

kayibal commented Jul 21, 2026

Copy link
Copy Markdown
Author

Pushed a fix round addressing external review findings:

  • 81b874a fix(intent-swap): derive nonce from pool state and log settlement inclusion — removes the engine-lifetime nonce counter; the nonce is now derived per candidate from the pool's per-sender view (get_highest_transaction_by_sender), which self-heals from eviction/replacement. Post-insert log renamed to "settlement queued" (pool acceptance ≠ inclusion) and a "settlement included" log fires when the engine observes its own tx in the build-event stream — this is the fill-rate signal for the shadow run. State machine extracted to Iteration::apply with 5 new unit tests (payload-id guard, replace-on-start, clear-on-complete/abort).
  • 9c56f28 fix(deps): pin backrunner and builder-types by rev instead of branch — the manifest is now the authoritative pin (was lockfile-only).
  • e4a4dfd fix(builder-core): warn once when build-event channel is closed — isolated core commit; TrySendError::Closed now warns once per process via an atomic latch instead of once per committed tx.

Not addressed (pending decision): behavior on engine startup failure (currently error-and-stay-dead; alternative is panic → critical-task fail-fast → node restart).

Tests: 14 intent-swap + 48 core lib + driver test green; clippy -D warnings and fmt clean on touched crates.

The critical-task fail-fast in reth only triggers on panic, not a
plain return. Logging the error and returning left the intent-swap
engine silently dead. Panic instead so the task manager shuts the
node down.
@kayibal

kayibal commented Jul 21, 2026

Copy link
Copy Markdown
Author

Startup-failure decision resolved: 236ab6b fix(intent-swap): exit node when engine fails to start — the engine build's Err arm now logs and panics, so reth's critical-task fail-fast shuts the node down (non-zero exit) instead of leaving intent-swap silently dead. The RPC engine unavailable path stays for mid-run engine death. Tests 14/14, clippy/fmt clean.

@kayibal

kayibal commented Jul 21, 2026

Copy link
Copy Markdown
Author

Repointed the `backrunner`/`builder-types` git pin from the retired `pending-sim-entangled` branch to builder-integration main's merge commit `6029f1b` (intent-solve-api merge). `cargo update -p backrunner -p builder-types` resolved `fynd-core` from the git rev `af403016` (0.82.3) back to the crates.io release `0.81.1`, matching main's pin; `tycho-common`/`tycho-simulation`/`tycho-execution` stayed single-copy at 0.305.1. `cargo test -p base-intent-swap` (14/14) and `cargo clippy -p base-intent-swap --all-targets -- -D warnings` are both green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant