Skip to content

Swap v1 agent + demo: 3 MCP tools, fork-demo stub, swap-e2e (#26)#69

Merged
hellno merged 1 commit into
hellno/test-merged-prs-guifrom
hellno/swap-v1-agent-demo
Jun 16, 2026
Merged

Swap v1 agent + demo: 3 MCP tools, fork-demo stub, swap-e2e (#26)#69
hellno merged 1 commit into
hellno/test-merged-prs-guifrom
hellno/swap-v1-agent-demo

Conversation

@hellno

@hellno hellno commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the agent + demo layer on top of the already-built daemon swap trust path (epic #23): three new MCP tools take the surface from 6 to 9 — deckard_swap_quote (read-only CoW pricing), deckard_swap (a shaped propose that always comes back needs_approval), and deckard_submit_order (the daemon signs the stored order, then the key-less sidecar POSTs it to the CoW orderbook). A default-off fork-demo stub returns a fixture quote and simulates the fill via anvil_setStorageAt, because a real CoW order can't be accepted from a local Sepolia fork; every simulated response is marked simulated: true and never fabricates a live success. It also adds just swap-e2e (an env-gated, #[ignore]d live-Sepolia trust-path harness) plus THREAT-MODEL and CONTRIBUTING updates. The signer daemon stays HTTP-free — the cow-client feature is enabled only on the sidecar's deckard-core edge, and the existing feature_gate test enforces that the daemon never compiles it.

Linked issue

Closes #26

Definition of Done

  • cargo fmt --all --check is clean
  • just check is green — clippy -D warnings on both the default config and --features tray
  • cargo test --workspace is green
  • No new/changed deps in Cargo.lock. The only Cargo.toml change enables the existing cow-client feature on deckard-mcp's deckard-core path dep (so the sidecar can quote/POST to CoW) — reqwest/hickory are already vendored via the app's default build, so this adds zero lockfile entries. In-scope for Swap v1 agent + demo: MCP swap tools, fork-demo stub, swap-e2e harness #26.
  • No deckard-app view changed (the app only recompiles as a downstream consumer of deckard-core); no DESIGN.md surface touched.
  • Secrets stay in Zeroizing and are never logged/Debug-printed — the swap path handles no seed/key/passphrase; the only secret the sidecar ever touches (the Railgun viewing key in shield) is unchanged.
Evidence (paste command output here)
$ cargo fmt --all --check
# (clean — no output)

$ just check        # clippy -D warnings, default + --features tray
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.83s    # default config
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.61s    # --features tray
RC_JUST_CHECK=0     # zero warning:/error lines

$ cargo test --workspace
    Finished `test` profile [unoptimized + debuginfo] target(s) in 12.64s
# 28 test suites, every one "0 failed" — incl.
#   cow_client::demo_stub::tests::stub_quote_builds_a_valid_order
#   env::tests::demo_swap_stub_defaults_off_and_parses_truthy_values
#   install demo-entry 5-key test, MCP acceptance T1 (9-tool drift) + T9 (secret-free)
# Only #[ignore]d: the network e2e's (shield_e2e, swap_e2e) + the live CoW roundtrip.
RC_WORKSPACE_TEST=0

Notes for reviewers

Reviewed by codex (verdict ACHIEVED-WITH-NITS, all trust invariants holding) and a 9-angle recall review. All confirmed findings are fixed in this branch:

  • MAJORDECKARD_DEMO_SWAP_STUB was never set on the documented demo path (just demo / install --demo), so the fork-demo stub was dead code and a demo swap would have hit the live orderbook. Both entry points now set it, so the fork demo actually simulates the fill.
  • demo_stub::quote wrote the relative valid_for into the absolute valid_to (a 1970 expiry) → now now + valid_for, with a test assertion.
  • The stub knob was overloaded (on/off flag and fill URL) and read twice (route vs label). Split into a pure on/off flag + DECKARD_RPC_URL for the fill, snapshotted once at CowOrderbook construction so the simulated label can never diverge from the route taken.
  • Corrected a CONTRIBUTING provenance line and a mock comment that overclaimed mirroring the daemon's evaluate_order policy gate (that gate is unit-tested in deckard-contract::policy).

Where to look hardest: the no-self-approve path (submit_order → daemon SignOrderDenied{not_approved} when unapproved) and the stub's honest-failure design (unknown token / unreachable fill RPC → credited=false, never a fabricated success). Test caveats: the swap-e2e harness and live CoW roundtrip are #[ignore]d (need RPC_URL_SEPOLIA); the MCP acceptance swap tests are hermetic (stub flag on, no anvil).

Add the agent and demo layer on top of the already-built daemon swap
trust path (epic #23, child #26).

- deckard-mcp grows from 6 to 9 tools: deckard_swap_quote (price a CoW
  sell order, read-only), deckard_swap (shaped propose to a request_id,
  always needs human approval), and deckard_submit_order (the daemon
  signs the stored order, the sidecar POSTs it to the CoW orderbook).
  The sidecar now builds deckard-core with the cow-client feature; the
  signer daemon stays HTTP-free.
- deckard-core gains a fork-demo orderbook stub behind
  DECKARD_DEMO_SWAP_STUB: a deterministic fixture quote plus a simulated
  fill via anvil setStorageAt, because a real CoW order cannot be
  accepted from a local fork. Every stubbed response is marked
  simulated:true and never fabricates a mainnet success.
- just swap-e2e runs an env-gated live-Sepolia trust-path harness
  (ignored by default; needs RPC_URL_SEPOLIA).
- Docs move from 6 to 9 tools across the agent quickstart, mcp-shape,
  README, and STATUS; THREAT-MODEL and CONTRIBUTING gain the swap
  surface and the new harness.

Closes #26
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