The keeper/venue model is abandoned. The D-Chain (dexvm) trades via its own
consensus-driven state transition (matcher-at-Verify), not via an off-chain
keeper polling dex.getSettlement to drive 0x9999. Revert the three v1.3.16
commits' additions to the v1.3.15 working state:
- vm.go: remove GetSettlement + the proceeds-coordinate record
- chainvm.go: remove the SubmitTx RPC seam additions
- api/service.go: remove dex.submitTx + dex.getSettlement handlers
- state/state.go: remove PutSettlement/GetSettlement settlement index
- api/submit_test.go, state/settlement_test.go: remove keeper-RPC tests
Deps are unchanged from v1.3.15 (go.mod/go.sum identical). bridgevm + dexvm
build clean and all tests pass.
settleFromFills now records the proceeds D->C object's (outputID, amount) under the
collateral ref (the C->D intentID) via state.PutSettlement, written into the versiondb
so it commits atomically with the block. outputID = deriveUTXOID(settlementExportTx.ID(),
0) — the SAME key executeExport puts into shared memory — and the amount is the realized
proceeds; both are pure functions of consensus-agreed inputs (blockHash+txIndex seed the
export identity), so every validator writes the identical record and the StateRoot stays
consensus-safe. The record is purely informational (moves no value; never consulted by
the deterministic settle/consume path).
dex.getSettlement(collateralRef) reads it back (VM.GetSettlement -> state.GetSettlement)
so the off-chain keeper, after submitting the ImportTx + settling RelayOrderTx and the
proposer settles, learns the D->C object's outputID + amount and builds the C-side Phase-B
ImportSettlement (DS01 outputID|amount|intentID) that consumes the object and emits DEXFill.
This closes the keeper's export-discovery gap.
Tests: 3 state round-trip/isolation/escrow-coexistence + 3 RPC pending/found/bad-ref, all
pass (CGO_ENABLED=0; local cgo accel toolchain is broken — CI builds linux/amd64).
The dexvm is a stateless atomic ZAP proxy whose ImportTx/RelayOrderTx/ExportTx
are deterministic block inputs, drawn from the proposer's pending pool. That pool
(ChainVM.SubmitTx -> pendingTxs + engine notify) was unreachable from outside the
process: CreateHandlers exposed only Ping/Status/Relay, so an off-chain keeper had
no way to inject the ImportTx that consumes the C->D atomic object the C-side
0x9999 SubmitSwapIntent writes, nor the settling RelayOrderTx. The full two-phase
seam therefore could not land a DEXFill.
This adds a dex.submitTx JSON-RPC method (api.Service.SubmitTx) that forwards
wire-encoded tx bytes to an api.TxSubmitter and returns the canonical
ids.Checksum256 tx id. The submitter is wired ONLY on the node path
(ChainVM.CreateHandlers builds the service with the ChainVM as submitter); the
inner VM's read-only CreateHandlers (standalone/test) reports ErrSubmitUnavailable.
Bootstrap-gated; admission/fee gate stays in ChainVM.SubmitTx. 6 unit tests cover
unavailable/not-bootstrapped/bad-hex/empty/success(verbatim+TxID)/submitter-error.
orderbook/perpetuals/lending/mev dirs + backend.go deleted; vm.go 2230->830 lines.
NEW atomic.go (shared-memory import/export at Block.Accept) + relay.go (rpc.ZAPDial,
frame byte-identical to zapwire, no luxfi/dex dep). State holds only nonce:/receipt:/
consumed: -- no order/pool/position keys. txs reduced to import/export/relay. NEW
conservation_test.go::TestEndToEndAtomicValueConservation. Verified -tags dchain build+tests
green -race; grep matchAllOrders|tryMatch|crossOrders empty.
VMs now live in ONE place: chains/<name>/ owns the full implementation.
Previously split across node/vms/<name>/ (impl) + chains/<name>/main.go
(plugin wrapper). Now consolidated.
New layout:
chains/<name>vm/*.go — package <name>vm (VM code)
chains/<name>vm/cmd/plugin/main.go — package main (plugin binary)
chains/<name>vm/go.mod — module github.com/luxfi/chains/<name>vm
Moved 11 VMs: aivm, bridgevm, dexvm, graphvm, identityvm, keyvm,
oraclevm, quantumvm, relayvm, thresholdvm, zkvm.
External callers now import github.com/luxfi/chains/<name> directly.