Skip to content

feat(dlv): settle against the composed vault state — delegated liquidity across generations - #672

Merged
cryptskii merged 1 commit into
mainfrom
feat/dlv-settle-against-composed-vault-state
Aug 18, 2026
Merged

cryptskii merged 1 commit into
mainfrom
feat/dlv-settle-against-composed-vault-state

Conversation

@cryptskii

@cryptskii cryptskii commented Aug 18, 2026 •

Copy link
Copy Markdown
Collaborator

The finding

Multi-generation settlement was not wired at all — LP online or offline. A vault was effectively one-settlement-ever:

  • dlv.unlockRouted demanded an owner-published reserve proof at the exact hop generation (fetch_verified_reserve_proof(vault, hop.vault_state_anchor_seq), dlv_routes.rs:1605). The owner publishes anchor/state/reserve proofs only in dlv.create at generation 0; dlv.reconcile publishes nothing. So the second trade on any vault was refused "no verified reserve proof … at sequence 1".
  • The mirror's LimboVault.current_sequence was pinned at 0 (bump_sequence had zero callers), so the anchor gate would have refused a Required vault at generation 1 regardless.
  • Meanwhile the quote side already composed the vault's state (route.findAndBindBestPath → compose_vault_state) and bound hops at that generation. The router quoted generation 1; the settle side refused it.

The change

The settle side now derives the vault's reserves at the hop's generation from the composed state — the owner's seq-0 baseline (signed anchor + state-inclusion + reserve-inclusion proof) plus every verified trader generation folded on (trader-signed pointer, SMT-verified trader receipt matching the pointer's committed hash, RouteCommit bound to X and eligible, digest match, AMM re-simulation). That is exactly the authority the quote side already trusts, and it is what lets the market advance a vault while the LP is offline: no owner signature on any transition after the baseline. Storage nodes remain dumb mirrors — every artifact is signature- and SMT-verified on the trader.

The delegation guard, policy-independent, before anything moves: composed.sequence == hop.vault_state_anchor_seq.

  • Behind → the parent was already consumed (the trader-side twin of feat(dlv): enforce consume-once per vault generation + prove reserve authority #670's consume-once claim).
  • Ahead → the trader is pre-settling a generation that doesn't exist. A probe that computes its amounts against the current reserves while naming a future parent passes every other check and would emit a receipt for a parent it never consumed — a self-credit no owner fold could honour.

Also: ComposedVaultState carries the baseline root + owner ids (one verification path, no second fetch); enforce_anchor_binding gets the composed sequence/digest instead of the dead mirror value; dead bump_sequence deleted; the DLV test module now resets the process-global object store per test (vault ids are deterministic — one test's pointers leaked into the next's composition, and the guard correctly saw "already at generation 3").

Proof

lp_offline_market_advances_three_generations_and_lp_reconciles_each_once — owner funds a Required vault and goes offline; three independent traders settle 0→1→2→3 through the production route (composition checkpoint at each generation, receipts (N, N+1)); stale-behind and future-ahead hops refused; the LP returns: out-of-order fold refused (#670 CAS), in-order folds each consume exactly one parent with reserves equal to the composed state and consumption rows naming each trader's receipt, LP spendable balance untouched (no second debit), replay idempotent.

Mutation: dropping the sequence guard lets the ahead probe settle → RED. The behind case stays caught by AMM re-sim + slot claim (defense in depth) — documented in the test.

Gates

dlv_routes 15/15 (serial), composition 25/25, route_routes 5/5, settlement_slot 10/10, consumption 3/3, dsm vault 126/126, device_state 42/42, integration suites green; make lint (fmt --check + clippy --all-targets -D warnings) clean; no_clock_and_no_json + production_safety_checks (prod clippy + TLA+) pass.

Closes invariant 2 (delegated liquidity: the market progresses while the owner is offline). Builds on #670 (invariant 3) and #671 (serial CI).

…ity across generations

Multi-generation settlement was not wired at all, LP online or offline: a vault
was effectively one-settlement-ever. dlv.unlockRouted demanded an OWNER-published
reserve proof at the exact hop generation (fetch_verified_reserve_proof(vault,
hop.vault_state_anchor_seq)), but the owner publishes anchor/state/reserve
proofs only in dlv.create at generation 0 and dlv.reconcile publishes nothing,
so the second trade on any vault was refused "no verified reserve proof … at
sequence 1". The mirror's LimboVault.current_sequence was pinned at 0
(bump_sequence had no callers), so the anchor gate would have refused a
Required vault at generation 1 regardless. Meanwhile the QUOTE side already
composed the vault's state from the seq-0 baseline plus verified trader
receipts and bound hops at that generation — the router quoted generation 1
and the settle side refused it.

The settle side now derives the vault's reserves at the hop's generation from
the COMPOSED state (compose_vault_state): the owner's baseline — signed anchor,
state-inclusion proof and reserve-inclusion proof, published once at creation —
plus every verified trader generation folded on (trader-signed pointer,
SMT-verified trader receipt matching the pointer's committed hash, RouteCommit
bound to X and eligible, digest matching the fold cursor, AMM re-simulation).
This is exactly the authority the quote side already trusts, and it is what
lets the market advance a vault while the LP is offline: no owner signature on
any transition after the baseline.

The delegation guard, policy-independent, before anything moves:
composed.sequence == hop.vault_state_anchor_seq. Behind it, the parent was
already consumed (the trader-side twin of the owner's consume-once claim).
Ahead of it, the trader is pre-settling a generation that does not exist — a
probe that computes its amounts against the CURRENT reserves while naming a
future parent passes every other check and would emit a receipt for a parent
it never consumed, a self-credit no owner fold could honour. Mutation-tested:
dropping the guard lets that probe settle (RED); the behind case stays caught
by the AMM re-simulation and the slot claim (defense in depth).

- ComposedVaultState now carries baseline_reserve_root / owner_devid /
  owner_genesis / owner_public_key from the verified baseline reserve proof,
  so the DlvSettle op records the baseline root and owner without a second
  fetch (one verification path).
- enforce_anchor_binding is fed the composed sequence + digest instead of the
  dead mirror value; bump_sequence deleted (zero callers).
- Test harness: install_identity() now resets the process-global in-memory
  object store — vault ids are deterministic, so one test's published
  pointers/receipts leaked into the next test's composition of the same
  vault (the guard correctly saw "already at generation 3").

Test: lp_offline_market_advances_three_generations_and_lp_reconciles_each_once
— owner funds a Required vault and goes offline; three independent traders
settle 0->1->2->3 through the production route (composition checkpoint at each
generation, receipts (N, N+1)); stale-behind and future-ahead hops refused; the
LP returns: out-of-order fold refused (parent-consumption CAS), in-order folds
each consume exactly one parent with reserves equal to the composed state and
consumption rows naming each trader's receipt, LP spendable balance untouched
(no second debit), replay idempotent.
Comment thread dsm_client/deterministic_state_machine/dsm_sdk/src/handlers/dlv_routes.rs Dismissed
Comment thread dsm_client/deterministic_state_machine/dsm_sdk/src/handlers/dlv_routes.rs Dismissed
@cryptskii
cryptskii merged commit 9be61ab into main Aug 18, 2026
18 checks passed
@cryptskii
cryptskii deleted the feat/dlv-settle-against-composed-vault-state branch August 18, 2026 13:25
cryptskii added a commit to cryptskii/dsm that referenced this pull request Sep 10, 2026
… proof

Hardware-proved 2026-08-18 on the 3-phone rig against the live Alibaba fleet
(schema v4, APK carrying deterministicstatemachine#670 + deterministicstatemachine#672 + the deterministicstatemachine#673 SoFi UI ports):

  LP (8XK) created SOFI (CPTA), funded a Required SOFI/ERA vault
  (25,000,000 / 100, 30 bps) — head: SOFI 100,000,000 -> 75,000,000,
  ERA 290 -> 190, exactly the two reserve leaves at gen 0 — then was
  force-stopped. With the LP process dead, T1 (9FF) and T2 (5GN) settled
  four generations through the production SwapTab (0->1 T1 20 ERA -> 4,156,244;
  1->2 T2 15 ERA -> 2,309,794; 2->3 T1 10 -> 1,274,633; 3->4 T1 8 -> 899,882),
  every quote exact against the COMPOSED reserves the trader derived from the
  prior receipts alone. T2 then confirmed a quote bound to gen 3 after T1 had
  consumed it: refused by the delegation guard ("is at generation 4 but the
  route binds generation 3 — that parent is already consumed"), T2's root
  byte-identical, one unreceipted pointer left on the fleet and nothing else.
  The LP relaunched, saw its vault (persisted-state listing) with "4 settled
  trades to reconcile", tapped Reconcile: leaves at gen 4, reserves
  16,359,447 / 153 == funding + Σ inputs − Σ outputs, consumption rows 0..3
  by four distinct receipts, LP spendable untouched (no second debit).

scripts:
- rig_dlv_market.py      — step-wise CDP driver over the PRODUCTION UI (create-token,
                           anchors, create-vault, vaults, swap [quote|execute|full],
                           reconcile, balances, offline/online). CDP substitutes for
                           finger taps only; every protocol step is the real route.
- dsm_head_decode.py     — host-side DeviceState v0x06 decoder for a pulled
                           dsm_client.db: balances + reserve leaves, legs named via
                           amm_vault_records + BLAKE3 leaf keys (b3sum). No hex.
- rig_settle_foreground.py — clears Android permission dialogs + the lock prompt so
                           the WebView owns the foreground (fresh-onboarding trap).
- dlv_market_rig_proof.sh — read-only proof over the three pulled DBs + the fleet's
                           public object listings; 17 assertions, all PASS.
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.

2 participants