4 Commits
Author SHA1 Message Date
zeekayandHanzo Dev 0b433110ac dex: the funding rail carries value, and nothing else
Move once, trade many. Value crosses the C<->D boundary twice in its life; in
between, D owns it and every order, match and trade is a local balance movement.
So the crossing has exactly one job — move ownership exactly once — and the
object shrinks to what that job needs:

    beneficiary(20) | asset(32) | amount(8)   = 60 bytes

Out of the wire: the 49-byte market/side/limit/size tail, the `spent` execution
witness, and the lane byte selecting a trading pot. Out of the precompile: the
per-order escrow with its principal cap and deadline, the taker-authenticated
price floor, the deadline reclaim and its selector, the shared-memory discovery
trait, and the .v2 domain rotation that existed only because the tail had
changed the object's width.

ONE CUSTODY POT. seamReserve and committedPositions were the swap lane and the
LP lane of one quantity — "value C holds because D owns it" — and the lane byte
was the only thing keeping them apart. Splitting them is what created the
cross-lane drain the byte then had to defend against. One number per asset, one
credit path, nothing to cross.

WHAT REPLACES THE PER-ORDER CAP AND THE PRICE FLOOR: D refuses an over-debit on
export, C refuses a credit custody cannot back, a claim is consumable exactly
once, and Block.Verify proves the carried bytes are the recorded object. Those
are properties of the value. The cap and the floor were properties of an order,
which is why the order had to ride the object for them to be checkable at all.

The claim id is one derivation for both directions and both repos:
SHA-256(domain | source | dest | sourceTx | index). It replaces DeriveOrderID,
DerivePositionCommitID and deriveSeamOutputID, which were three spellings of the
same fact.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-07 17:33:14 -07:00
zeekayandHanzo Dev 2391e31aaa dex: the seam's unit of work is an order, not an intent
Order -> Match -> Execution -> Trade is the vocabulary; "intent" was the old
name for what an Order is. Renames the identifiers across the 0x9999 settle
precompile so the code reads in the settled terms.

Values that live on a chain keep their bytes, because renaming one of those is
a migration and not a rename:

  - "lux.dex.native.intent.v1" and "lux.dex.native.intent.pending.v2" are hash
    INPUTS; a byte changed there moves every derived order id and the pending
    trait both repos must agree on.
  - settleStateNamespace + "intent" is an on-disk key prefix; renaming it
    orphans the submitted-order replay set.
  - reclaimIntent(bytes32), IntentSubmitted(...) and IntentReclaimed(...) are
    the deployed ABI; the signature is what hashes, so a rename would move a
    selector and two topics.

Each of those now carries one line saying why the literal does not track the
identifier that names it, so the inconsistency is not "fixed" later.

TestOrderID_CrossRepoGolden still reads 5b0e8d38... and
TestSeamPendingTrait_MatchesDChainGolden still reads 5f10f9ad..., which is the
evidence no derivation input moved.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-07 16:13:01 -07:00
zeekayandHanzo Dev fd1cc0904e dex: carry the cross-chain object in the transaction, not shared memory
A settled swap could never be synced past. Both C-side consume paths
(ImportSettlement, ImportPositionCollect) read the D->C object from shared
memory DURING EVM execution, while the consuming Remove landed at block
Accept. A node re-executing that block — bootstrapping, state-syncing,
re-tracing — found the object gone, computed a reverted receipt where the
network had computed a successful one, and died on the receipt root. The
seam settled live and wedged every node that tried to follow.

Move the object's 69 bytes into the transaction (Phase-B hookData, and the
collectPosition calldata) so execution is a pure function of the block and
replays byte-identically forever. Both rails now go through ONE binding
primitive, bindImportObject, which also DECLARES the consumption as a log
committing to the object's hash. The host authenticates that declaration
against shared memory at Block.Verify, so a forged object costs the
producer a block instead of forking a receipt root.

The ship rule did not weaken, it moved: a C balance is still credited only
by consuming a real D->C object. What changed is where that is proven.

Also:
- amount is no longer restated on the wire; it IS the object's amount, so
  there is one declaration of the fact instead of two to cross-check.
- the retired DS01 tag is refused BY NAME. The fallback for an unknown tag
  is Phase A, so a stale settle would otherwise have been silently re-read
  as an intent and LOCKED the sender's input — the one mixed-fleet outcome
  worse than a revert.
- the zero-amount refusal moved into the single binding point, so an absent
  object zero-padded to canonical width reports the same clear error on
  both rails rather than surfacing as a cross-rail violation.

336 tests pass, 0 fail.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-07 06:40:23 -07:00
zeekayandHanzo Dev 844f3d3587 dex: decomplect to canonical settle-only 0x9999 (remove embedded matcher)
ONE money path: D-Chain matches, C-Chain 0x9999 SETTLES, C never matches.

- 0x9999 swap() routes ONLY to SettleSwap (native C<->D atomic seam): untagged/
  DI01 => Phase A intent (lock input, write C->D object, return intent id); DS01
  => Phase B settlement (consume a real D->C atomic object once, credit RECORDED
  amount). No-receipt-no-settle: absent a real object, Phase B reverts
  ErrNativeNoSettlement (TestDecomplect_NoReceiptNoSettle).
- Deleted the embedded matcher: swap_sync*.go, swap_custody.go (maker order book),
  buildRouter/evmAMMPool in swap_amm_pool.go, and the swapDeposit/withdraw/place/
  cancel selectors. A live in-trie matcher forks consensus; deterministic
  atomic-object consumption is fork-safe inline.
- 0x9010 already non-dispatched. 0x9012 (LXRouter) value selectors exactInput*/
  exactOutput* now revert ErrPrecompileMoved (PRECOMPILE_MOVED); read-only quote/
  route views kept.
- Cleanups (dead code removal, all unreachable via any dispatched selector):
  deleted the legacy engine PoolManager.Swap + LXRouter.Exact*/executeV4Swap*;
  deleted the vestigial makerLockedVault ledger (0 callers, always 0); deleted the
  unwired Block-STM scaffolding (AssertWriteSetWithin/AccessCommitment/Predict*).
- Activation rides the EXISTING canonical gate 1766708400 (Dec 25 2025 16:20 PST);
  no new timestamp. Build CGO_ENABLED=0 (pure-Go luxfi/dex path); go.sum zap
  re-tag checksum refreshed.

327 dex tests PASS / 0 FAIL, go vet clean. RED-reviewed (0 critical, all drain
vectors safe, fund-strand cleared, negative invariant falsified-then-restored).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-04 12:52:44 -07:00