Files
dex/pkg
zeekayandHanzo Dev 9109a24081 dchain: the seam imported money and never placed an order
The C->D object carried value only, so executeImport credited the taker's
account and stopped. Its one reference to TxSubmit was a comment. Nothing placed
an order, so nothing crossed, so driveSeamExports — which fired only when a
non-input asset appeared — never fired, so Phase B had no object and the settle
reverted. The seam was unreachable by construction, which is why 0x9999 has
emitted zero events on every chain since genesis.

The object now carries the operation the taker authorized on C (market, side,
limit, size) appended to the unchanged 69-byte value head, and the drive builds
the taker's order from it: BuildBlock emits TxImport and TxIntentSubmit as a
pair, in one block, so value is never on D without an order against it.

TxIntentSubmit is the object-authorized sibling of TxSubmit, as TxImport is of
TxDeposit. It cannot be a plain TxSubmit — that type requires a signature at
parse, at the RPC edge, and in authorizeTx, and weakening any of those would let
an unsigned submit move any account's funds. It carries the intent id alone; the
zapwire Submit frame is derived from the escrow by seamSubmitBody, so the
operation is declared once and never restated for the two sides to reconcile.
From there it flows through the identical custody, matcher and settlement path a
signed dex_submit takes.

Three things this fixes on the way:

D could never sync past a settled swap. executeImport read the object from
shared memory during execute() while the consuming Remove landed at Accept, so
any node re-executing the block found it gone, derived a different ledger root
and died on `execution root mismatch`. The object's bytes now ride in the
TxImport body and Block.verifySeamImports authenticates them at Verify, where a
forgery costs the producer a block instead of forking a root. Accept now checks
the root it derives too: that branch is the bootstrap path and it was committing
whatever it computed while persisting the block's claimed root.

The seam ran in the taker's own ledger account, and the export drive settles an
account's balances back to C. A taker holding native D balance would have had
all of it exported, and C credits that out of the shared seam reserve — a raid
on other takers' pooled input. Each intent now runs in its own account, so the
question does not arise and the spent witness becomes exact rather than
inferred.

A zero-fill order left only its input behind, which the old export gate could
never match, so the principal sat on D while C's deadline reclaim refunded the
taker the same principal. The escrow now records that the order RAN — including
when the custody gate refused it — and the drive gates on that fact.

A market id named by the other chain reached bookForPool and aborted the block.
Any C caller could have halted D with it. Unknown market and unbound assets are
now per-tx rejects, and the intent settles back in full.

SeamPendingTrait rotates to .v2 alongside the wire. Old and new nodes cannot
disagree about a block: the TxImport body is 150 bytes and an old node's
bodySize says 32, so ParseBlock refuses the frame outright. It stalls rather
than forking. No historical block anywhere contains a TxImport.

121 tests pass in pkg/dchain, 0 fail; whole repo green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-07 08:13:43 -07:00
..