Commit Graph
245 Commits
Author SHA1 Message Date
zeekayandHanzo Dev c60bf1ca12 routes: /ext/bc/D -> /v1/dex (DEX HTTP surface under /v1/dex)
Co-authored-by: Hanzo Dev <[email protected]>
venue-v1.6.0 v1.11.0
2026-07-01 12:17:47 -07:00
zeekay 88c3b22e3b merge dex/clob-rename-amm-gpu-rip to main v1.10.0 2026-07-01 06:29:38 -07:00
zeekay 7c3e3bb4db Merge branch 'dex/clob-rename-amm-gpu-rip' 2026-07-01 06:29:30 -07:00
zeekay 8a336cf225 docs(brand): add hero banner 2026-06-28 20:37:08 -07:00
zeekay 433b781c8e chore(brand): dynamic hero banner 2026-06-28 20:37:07 -07:00
zeekay 014ce05279 dex: drop cmd/dexfill one-off (old standalone-venue path) — replaced by net-agnostic luxfi/trader on the native 0x9999 money path 2026-06-27 19:27:22 -07:00
zeekay d7edc9d715 dex/lx: rip AMM GPU accel, clob→dex, add HIP+Vulkan orderbook cgo backends
CORRECTION 2 (AMM GPU rip): the constant-product xy=k AMM runs on-chain in
the EVM/consensus — GPU-accelerating it was a hallucination. Remove the GPU
AMM surface: pkg/lx/amm_gpu{,_cuda,_metal,_stub}.go + amm_nogpu.go (the
BatchEvalConstantProduct dispatcher) + amm_gpu_test.go; strip the AMM bridge
(AMMSwap, fnAMMSwap, call_amm_xyk_batch, LuxAmmReservePair) from pkg/lxgpu so
it bridges only the order-book path; drop the obsolete GPU_Batch sub-bench.
PRESERVED: pkg/lx/amm.go (ConstantProductOut/ReservePair/BatchEvalConstantProductCPU,
the 128-bit-exact CPU math) — it is the deterministic pricing used by the DEX
router's AMM source (pkg/dex/source_amm.go), untouched.

CORRECTION 1 (clob→dex): rename Go identifiers clobGPUMatch→dexGPUMatch,
clobShadowInput→dexShadowInput, runCLOBShadow→runDEXShadow,
captureCLOBShadowLocked→captureDEXShadowLocked, clobBackendLabel→dexBackendLabel,
clobScenario→dexScenario, TestCLOB*→TestDEX*, MatchDivergence.Kind "clob"→"dex".

CORRECTION 3 (host drivers): add orderbook_gpu_hip.go (cgo && linux && hip &&
!vulkan) and orderbook_gpu_vulkan.go (cgo && linux && vulkan), mirroring the
CUDA binding; narrow orderbook_gpu_cuda.go to (cgo && linux && !hip && !vulkan)
so exactly one backend compiles per linux tag combo (verified via go list).

Verified: CGO_ENABLED=0 go build ./... GREEN; go test ./pkg/lx ./pkg/dex
./pkg/dchain GREEN; gofmt clean; cgo bridge compiles; build-tag exclusivity
confirmed for ''/hip/vulkan.
2026-06-27 11:51:48 -07:00
zeekay 46f8158b0f chore: move LP-108 in-tree archive OUT to ~/archive (no backups in tree) 2026-06-26 22:32:06 -07:00
zeekay a03ede9580 chore: untrack LaTeX build artifact + gitignore (whitepaper .out is cruft) 2026-06-26 22:24:30 -07:00
zeekay 0964289c93 feat(dex): real deterministic Metal CLOB matcher binding (Apple Silicon)
orderbook_gpu_metal.go (cgo && darwin) links the single-thread Metal
matcher (luxcpp/dex/gpu/metal/dex_orderbook_driver.mm) via the
lux-dex-orderbook-metal pkg-config bundle. The kernel walks book_indices
in one deterministic GPU lane -- byte-identical to MatchOrderCPU by
construction, the property matcher-at-Verify requires.

Proven on M1 Max: the 76-scenario determinism corpus + the existing
GPU/CPU parity test pass with backend=metal (real device), GPU==CPU
byte-identical over fills + remaining + resulting book.

Honest perf (M1 Max): the single-cross flat ABI is dispatch-bound, so the
1-lane Metal kernel is ~400x slower than the CPU matcher (500us vs ~1-4us).
The GPU win lives in batching many books per dispatch, not one serial
cross; the kernel is wired for correctness/determinism + defense-in-depth
today. Narrowed orderbook_gpu_stub.go to !darwin (Metal now owns darwin).
recovery/dex-gpu-clob-c6d2ff4
2026-06-26 21:53:42 -07:00
zeekay f0eef3db06 feat(dchain): keeper-less proposer-side drive for the native co-located atomic seam
Closes the DRIVE gap in the native C<->D settlement seam: the EXECUTION half
(atomic.go executeImport/executeExport) was real and unit-tested, but NOTHING in
production generated TxImport/TxExport — only the e2e harness, playing the keeper
by hand. So a real 0x9999 SubmitSwapIntent staged a C->D object that nothing
imported: no taker funding, no crossing, no D->C settlement object, no DEXFill.

drive.go is the proposer-side DRIVE — the keeper, but in-consensus. During normal
block production BuildBlock now:

  - IMPORT: enumerates the committed C->D intent objects in shared memory (tagged
    with the fixed SeamPendingTrait so they are discoverable owner-agnostically),
    filters those already imported (committed seamintent: escrow), sorts by
    intentID, and prepends a TxImport for each. Double-import-guarded by the
    escrow filter AND executeImport's own replay-reject.
  - EXPORT: enumerates the open intent escrows whose owner now holds realized
    OUTPUT in committed state (the output gate => no premature refund, no
    export-before-trade), and appends a TxExport binding owner/asset/amount/spent
    exactly as 0x9999 ImportSettlement reads (byte-identical seam wire). The
    spent witness = original principal - leftover input. execute then CLOSES the
    escrow once the taker's cross-chain account is drained (one-shot per swap).

Consensus-safe BY DESIGN (the seam's own note, atomic.go:47-55): both legs are
pure, deterministic functions of committed state (shared memory + the escrow
index + the ledger) — no wallclock, no mempool, no nondeterministic iteration, no
external I/O — so every validator re-derives the identical effects in execute and
a divergent proposer is rejected on the tx root. Enumeration results are sorted
into a total order so two proposers on the same committed partition build
byte-identical blocks. Keeper-less and co-located-correct: no external venue.

The seam wire and executeImport/executeExport are REUSED unchanged. autoDriveSeam
is enabled exactly when the seam is wired (runtime shared memory + resolved
C-Chain id); BuildBlock builds a pure-seam block on an empty mempool and
WaitForEvent signals seam work so the engine drives it.

Tests (drive through the REAL BuildBlock, not manual mempool.Add):
  - TestDrive_AutonomousImportCrossExport: the VM's OWN BuildBlock imports the
    intent, the taker's signed order crosses, the VM's OWN BuildBlock exports the
    D->C object the modeled 0x9999 Phase B consumes once; conservation holds;
    escrow closed.
  - TestDrive_NoExportBeforeImportOrTrade, TestDrive_ReplayImportedOnce,
    TestDrive_DeterministicOrdering (two proposers => identical blocks).
  - The existing manual-drive seam mechanics tests stay green WITH the drive on,
    proving the autonomous drive emits byte-identical txs to a correct keeper
    (deterministic convergence + tx dedup).

Companion (coordinated cutover, NOT in this commit): precompile/dex
native_staging.go collectRange must add SeamPendingTrait to the swap intent's
Element.Traits (one line) so a production 0x9999 intent is discoverable here;
pinned to the drive.go constant by the existing wire-golden discipline. The e2e
models that corrected flush. dex v1.9.2 readiness.
recovery/dex-drive-3d0d25cf
2026-06-26 21:51:39 -07:00
zeekay 1951c41aea test(dex): GPU shadow determinism corpus + fail-closed negative test
- TestCLOBShadow_GPUMatchesCPU_Corpus: 76 scenarios (empty book, full/
  partial fills, multi-level sweep, price barriers, exact-cross boundary,
  300-deep book past a GPU block, market sweep, 64 random seeds) assert
  GPU == CPU byte-identical over fills + remaining + resulting book.
- TestCLOBGate_FailClosed_DivergentGPU: a corrupt GPU (off by one unit) is
  discarded, the CPU authority is committed unchanged, a divergence is
  recorded -- proving a divergent GPU result can never reach state.
- TestCLOBGate_NoFork_CPUvsGPU: EngineCPU and EngineGPUVerified commit
  byte-identical fills (the anti-fork property).
- clobBackendLabel() per backend so the corpus log states GPU vs fallback.
2026-06-26 21:45:03 -07:00
zeekay 854dec28fd feat(dex): GPU shadow gate for the dexvm consensus match path
Wire a GPU CLOB matcher into the dexvm match path (applySubmit ->
SubmitMarketableVerified) behind a determinism gate that runs the GPU
kernel as a CHECKED SHADOW of the pure-Go authority:

- EngineCPU (default): byte-for-byte the original SubmitMarketable.
- EngineGPUVerified (node-local opt-in, LUX_DEX_MATCH_ENGINE=gpu-verified):
  capture the pre-cross opposite side atomically with the match, run the
  GPU kernel on those exact inputs, byte-compare fills+remaining+book
  against the CPU authority, record the outcome, and commit the CPU
  result REGARDLESS. A GPU result that differs by one byte is recorded as
  a divergence and discarded -- structurally impossible to commit.

Because the committed bytes are always the CPU authority's, a mixed
GPU/CPU validator set cannot fork. Divergences surface as a metric
(MatchShadowSnapshot) and a loud log (node ERROR via the VM).
2026-06-26 21:35:49 -07:00
zeekay ec0b0deef3 feat(dchain): native co-located C<->D atomic settlement seam
Port the atomic import/export into the native dexvm matcher so the in-luxd
D-Chain PRODUCES and CONSUMES the same primary-network shared-memory objects
the 0x9999 precompile speaks — the owner's chosen model (D matches under its
own consensus; C-Chain 0x9999 settles by consuming a node-local atomic object
D produces; no BLS receipt, no external venue).

- atomic.go: the seam. encodeSeamObject/decodeSeamObject reproduce the
  precompile's 69-byte wire (rail|owner|asset|amount|spent) BYTE-FOR-BYTE, and
  DeriveIntentID its id derivation — ONE wire across precompile/proxy/native.
  executeImport consumes a C->D object (Get under the C chain + shared-memory
  Remove) and funds the taker's native D account; executeExport debits the
  matched proceeds and writes a D->C object keyed exactly as ImportSettlement
  reads it, bound to the per-intent escrow (owner/asset/remaining) so Phase B's
  owner/asset/amount + per-taker-cap checks pass. commitSeamAtomic applies the
  removes/puts atomically with the block overlay (the platformvm acceptor
  pattern). No root change needed: the in-consensus matcher makes the atomic
  ops a pure function of the already-rooted txs (unlike the proxy's live venue).
- vm.go: capture init.Runtime -> shared-memory handle + C-Chain id.
- tx.go: TxImport (intentID) / TxExport (intentID|asset|amount|spent), both
  authorized by the cross-chain object, not a signature.
- block.go: execute drives the seam in the account-scoped lane; Accept commits
  via commitSeamAtomic.
- atomic_seam_e2e_test.go: two-phase e2e over REAL shared memory — Phase A intent
  -> native D import + a real crossing under D consensus -> native D export ->
  Phase B (the exact 0x9999 ImportSettlement consume) credits once; replay
  rejected; over-export beyond the locked principal rejected; conservation holds.
  Plus a golden-wire test pinning encodeSeamObject to the SAME cross-repo golden
  the precompile pins ImportSettlement against (native == precompile == proxy).

go.sum: re-record re-tagged luxfi/[email protected] (stale hash blocked the build).
go.mod: luxfi/runtime indirect -> direct (atomic.go uses it).
v1.9.1 recovery/dex-atomic-seam-af4031d
2026-06-26 20:11:14 -07:00
zeekay 86cf63d81c feat(dchain): dex_get_nonce read + hex-encode order owner (maker restart reconcile)
Adds the dex_get_nonce read so a signed client (luxfi/maker) resyncs its nonce to the venue's expected-next on restart/redeploy — without it a fresh process starts at nonce 0 and is rejected once the account has transacted. Also hex-encodes orderJSON.User: the raw 16-byte settlement id is not valid UTF-8, so the prior string emit was lossy (json -> U+FFFD) and an owner could never round-trip; hex matches dex_get_nonce's account field (one account encoding) and lets the maker's startup reconcile cancel its own stale orders. Re-realigns luxfi/[email protected] go.sum (re-tagged upstream; keeps reverting). Verified: dchain tests green.
v1.8.3
2026-06-26 19:58:46 -07:00
zeekay bd3375ffdc ci: self-contained docker.yml (drop broken reusable, mirror node)
The shared hanzoai/.github docker-build.yml@main 422s org-wide ('error parsing
called workflow') — broken for dex since 2026-06-19. Replace the reusable call
with node/docker.yml's proven inline build-push-action pattern: build
ghcr.io/luxfi/dex (CPU dexd venue, CGO_ENABLED=0) on lux-build, gh_token secret
for private modules, semver+sha tags. Unblocks the dexd venue image.
2026-06-26 19:18:30 -07:00
zeekay 8df70d5023 ci: self-contained docker.yml (drop broken reusable, mirror node)
The shared hanzoai/.github docker-build.yml@main 422s org-wide ('error parsing
called workflow') — broken for dex since 2026-06-19. Replace the reusable call
with node/docker.yml's proven inline build-push-action pattern: build
ghcr.io/luxfi/dex (CPU dexd venue, CGO_ENABLED=0) on lux-build, gh_token secret
for private modules, semver+sha tags. Unblocks the dexd venue image.
2026-06-26 19:17:52 -07:00
zeekay e5f411cb25 wip(dex): GPU dexd orderbook cuda→gpu rename + cmd/dexfill client (in-flight checkpoint)
Saves the GPU-venue build work: pkg/lx/orderbook_cuda*→orderbook_gpu*, the
clob→gpu cgo binding rename needed for the GB10 build, and cmd/dexfill (the
real-fill ZAP client). Checkpoint — build-verify pending.
2026-06-26 19:10:13 -07:00
zeekay 52b01001e5 fix(dex): GOPRIVATE must cover hanzos3 (+ all our orgs) — CI proxy-fetch failure
dex's dep graph pulls github.com/hanzos3/go-sdk, but the Dockerfile GOPRIVATE listed only luxfi+hanzoai, so CI routed hanzos3 through proxy.golang.org+sumdb and the build failed (private repo, no proxy access) — even though go.sum was correct. Expanded GOPRIVATE to all our private orgs (luxfi/hanzoai/hanzos3/zooai/parsdao/lux-private), matching the working local env. This was the real v1.8.0/v1.8.1 build blocker; the go.sum poison was a separate, already-fixed issue.
v1.8.2
2026-06-26 15:32:40 -07:00
zeekay 8c85386363 feat(dex): dexd run -http serves the chain read+write surface under /ext/bc/D
Mounts vm.CreateHandlers (the same dex_*/dex_get_* map luxd mounts for the in-process plugin, ingest.go) on an HTTP listener, so a single-operator CPU venue is a byte-identical drop-in for the in-luxd D-Chain: exchange-api reads dex_get_markets, the maker writes via DEX_HTTP_URL — no luxd required. Writes still cross the full sealer consensus path. Verified: 11 routes mounted, GET /ext/bc/D/dex/dex_get_markets -> 200.
v1.8.1
2026-06-26 14:13:51 -07:00
zeekay bdafddaf49 fix(dex): realign luxfi/[email protected] go.sum to current tag content
The v1.5.0 tag was rewritten upstream (zip h1 G69Hb… -> zC/Fw…); the stale go.sum failed every CI Docker build with a clean-fetch SECURITY ERROR. Only the zip hash drifted (go.mod hash unchanged). Verified: clean-cache CGO_ENABLED=0 linux/amd64 build + pkg/dchain tests green against the new bits.
2026-06-26 14:13:51 -07:00
zeekay cb46f347b6 testnet: multi-node dexd DEX testnet harness (evo amd64 + spark arm64)
deploy/testnet: one-command-per-box bring-up for a fleet of standalone
`dexd run` venues across two boxes, a cross-arch determinism proof, and a
ZAP load/throughput bench (drives the existing cmd/dexbench).

- compose.yml + gen-compose.sh: N independent venues/box (default 3, scales
  to ~11), one ZAP port/node, per-node data dirs, 128GB-box resource caps.
- Dockerfile: pure-Go CPU image (dexd + dexbench), native amd64/arm64.
- Makefile: make up/bench/verify/down — git pull + one command per box.
- topology.md: honest consensus model (independent venues, deterministic
  per-node genesis, no gossip) + the luxd `dexd plugin` BFT path.
- overlay/: opt-in hanzozt (OpenZiti) tunneler for NAT; direct 2.5GbE is the
  default for true wire numbers.
- README.md: exact per-box commands, 128GB sizing, reading bench output.

Validated locally: signed place/cross load 0 rejects (cross=1 fill/submit);
dexbench -verify across two independent venues PASS (byte-identical 3-fill
multi-level sweep).
v1.8.0
2026-06-26 13:22:15 -07:00
zeekay 7f87251b7f refactor(lx): rip compliance/KYC from permissionless DEX engine
The public permissionless DEX must be provably KYC-free. Compliance/KYC
belongs in lux-private (dex/compliance/sovereign), never in luxfi/dex.

- delete compliance.go + compliance_types.go: EligibilityChecker.CanTrade
  pre-trade gate, StandardEligibilityChecker (KYC/AML/accreditation/
  jurisdiction enforcement), InvestorProfile/InvestorStatus, PEPStatus,
  TransferRestriction, ExemptionType, ComplianceError + codes.
- delete market_config.go: the SecuritiesMarket wrapper existed solely to
  gate AddOrder on EligibilityChecker.CanTrade. Zero production consumers —
  the permissionless engine uses AdvancedOrderBook directly.
- funds.go: remove preCheck compliance hook + AML/sanctions/compliance
  fields + ComplianceGates; permissionless default is FundsStatusApproved.
- reconciliation.go: relocate neutral AssetClass + ReconciliationMode types
  here (cross-venue metadata, not gates); drop CEXComplianceID /
  ReportedToRegulator / RegulatoryReportID fields.
- tests updated to match.

Green (CGO off): go build ./..., go vet + go test ./pkg/lx ./pkg/dchain.
2026-06-26 13:20:02 -07:00
zeekay 1722b23b89 dex: purge CLOB — DEX (service) + OrderBook (engine)
Decentralized exchange; the engine acts like an order book but is decentralized,
so 'Central Limit Order Book' is a misnomer. Branded/service surface → DEX
(RegisterDEX, DEXMethod*, dex_* wire). Matching engine + GPU → OrderBook
(OrderBookMatch/Source/Arena, source_orderbook.go), preserving the AMM-vs-orderbook
distinction. C-ABI → dex_orderbook_* (matches luxcpp). SDKs/clients/docs aligned.
CGO=0 + cgo builds clean; full suite 23 pkgs green (dchain/dex/lx/fix/gateway/zapwire).
Legit financial-term 'Central Limit Order Book' retained in hummingbot taxonomy.
2026-06-26 13:05:07 -07:00
zeekay 670aec5261 deps: pin luxfi/[email protected] (re-tagged v0.8.10 had inconsistent content across hosts) v1.9.0 v1.7.3 2026-06-26 12:56:10 -07:00
zeekay c9daf10e22 fix(lx): delete fake benchmarks + false perf claims; use real measured numbers
Delete 3 AI-slop benchmarks from pkg/lx/critical_path_bench_test.go that measured no real work and reported fabricated throughput:
- BenchmarkMLXAcceleration: b.Skip + no-op slice index, then fabricated orders/sec
- BenchmarkQuantumSignatures (+verifyQuantumSignature): verify == len(sig)==512 && len(pub)==256
- BenchmarkConsensusFinalization (+hashBlock/verifyBlock): byte copy + len(hash)==32
Real benchmarks (CriticalOrderMatching, TradeExecution, RiskCheck, EndToEndLatency, ...) untouched; no imports left unused.

Replace fake '434,782,609 orders/sec (GPU/MLX) - 2ns/order - zero-alloc' claims in README.md and LLM.md (traced to archive/_lp108-2026-05-04/mlx_engine.go, a 'pure Go simulation' hardcoding OrdersPerSecond: 1000000.0) with numbers measured first-hand on Apple M1 Max:
- C++: 11.88M orders/s (10 threads), 169 ns avg match (p50 125 / p99 292), 5.91M single-thread, 49 ns cancel
- Go pkg/lx: 2.2M orders/s, 381 ns/order, 1-2 allocs/op (NOT zero-alloc)
- DEX matching stays on CPU; the real GPU win is FHE Metal NTT (23x speedup, N=4096 batch=128).
2026-06-26 12:55:14 -07:00
zeekay 8f9e335393 deps: re-record re-tagged luxfi/[email protected] go.sum (clean dexd build) 2026-06-26 12:54:14 -07:00
zeekay 21301212f9 refactor(cmd): consolidate cmd/* into one binary — dexd
dexd is now the ONLY command in the repo. One binary, two run modes:

  dexd            run as a luxd rpcchainvm PLUGIN. luxd execs the plugin from
  dexd plugin     its PluginDir with NO positional args (engine address arrives
                  via the runtime.EngineAddressKey env var) and probes the
                  version with `dexd version`. No-subcommand == plugin is
                  REQUIRED to preserve that contract — byte-for-byte the old
                  cmd/dchain behavior (rpc.Serve over the plugin transport).
  dexd run        run the STANDALONE D-Chain venue: open the on-disk zapdb,
  dexd standalone serve the frozen dex_* surface over ZAP, and drive the
                  consensus sealer loop (WaitForEvent->BuildBlock->Verify->
                  Accept). -addr/-db flags preserved from the old cmd/dvenue.

Relocated logic (engine code NOT duplicated — pkg/dchain + pkg/lx untouched):
  cmd/dchain/{main,runner}   -> internal/plugin     (plugin.Run)
  cmd/dvenue/{main,engine_*} -> internal/standalone (standalone.Run + engineName)
  cmd/dexd/main.go            = thin run-mode dispatcher

Removed cmd dirs (12): dchain, dvenue, demo, dex-api-server, dex-server,
dexfillproof, dexseed, fix-gateway, gateway, monitor, persistent-server,
price-feed. Removed committed build artifacts: gateway, dex-server-linux.

Build/ship ONLY dexd:
  - Dockerfile: canonical CPU image (CGO=0, ghcr.io/luxfi/dex) running
    `dexd run`; no GPU/MLX required.
  - Dockerfile.dvenue: GPU operator bundle repointed cmd/dvenue -> cmd/dexd.
  - Deleted Dockerfile.{gateway,devnet,minimal,dvenue-cpu} and
    docker/{Dockerfile,Dockerfile.cuda,backend/Dockerfile,compose-simple.yml}.
  - Makefile rewritten to build/run/ship dexd only.
  - docker.yml: dropped the dex-gateway image; dex-venue-image.yml: dvenue->dexd.
  - Deleted legacy scripts that built removed/long-gone cmds; fixed deploy.sh +
    dev-setup.sh; .gitignore ignores root build binaries.

Also included (coupled, environment-applied, settled): the in-progress
clob -> dex/orderbook terminology refactor across pkg/* + sdk/* + tests/*
(identifier + file renames, e.g. RegisterCLOB->RegisterDEX,
source_clob.go->source_orderbook.go). The relocated standalone venue calls the
renamed API, so it lands in the same consistent snapshot.

Verified (GOWORK=off CGO_ENABLED=0): `go build ./cmd/dexd`, `go build ./...`,
`go vet ./...` all exit 0; `go test ./pkg/dchain` (renamed RegisterDEX socket
path) green. GPU/cgo path not compiled locally (no CUDA); its rename mirrors
the verified nocgo twins and preserves the C ABI symbol names.
2026-06-26 12:24:34 -07:00
zeekay afcc765854 Merge main-pub into main v1.7.2 2026-06-26 00:53:15 -07:00
zeekay 265873e025 deps: bump luxfi/zap v0.8.10→v0.8.11 (clean tag; v0.8.10 was re-tagged → go.sum mismatch on fresh builders) 2026-06-25 23:22:58 -07:00
zeekay ad3129ec7a dex: drop redundant 'core' — pkg/dexcore → pkg/dex (package + dex_ error prefixes)
The package lived at dex/pkg/dexcore (package dexcore) with 'dexcore:' error
prefixes, while every sibling is short (api, client, dchain, consensus) and every
other dex error says 'dex:'. The 'core' qualifier is redundant inside the dex
module. Rename pkg/dexcore → pkg/dex (package dex), unify error prefixes
dexcore: → dex:, update the 5 importers (dexseed, dexfillproof). Tests green
(pkg/dex, 1.398s); dvenue + dexvm plugin rebuild; e2e swap re-proven (seed 12
orders + cross → fill @ 12.5125).
2026-06-25 23:15:44 -07:00
zeekay b0bea31b18 build(dex): add CPU venue Dockerfile (CGO_ENABLED=0 pure-Go matcher)
Dockerfile.dvenue-cpu builds cmd/dvenue for linux/amd64 with no CUDA/GPU,
selecting pkg/lx's pure-Go CPU matcher via the !cgo build tag; serves the
frozen clob_* surface over ZAP with the consensus sealer loop. Complements
the GPU Dockerfile.dvenue (CUDA, arm64/spark-only) with a venue image that
runs on any amd64 node — the deployed devnet dchain-venue binary.

Verified: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./cmd/dvenue links
the pure-Go path (amm_nogpu / orderbook_cuda_stub) clean on this base.
v1.7.1 mirror/main-pub-3392393
2026-06-26 04:39:40 +00:00
zeekay f4bcdbca39 feat(rfq): non-custodial cross-chain swap coordinator (pkg/rfq)
The venue V of the HTLC atomic-swap design: a pure relay that serves a
maker-signed quote book and sequences a swap session between taker U (the
secret-holder) and a CEX-backed maker M, validating each typed signed
transition — role bindings (HTLC_A recipient=U/refund=M, HTLC_B
recipient=M/refund=U), the cross-leg hashlock, and the timeout ordering
T_B > T_A + Δ (maker locks first/shorter; spec Δ table: Lux<->BTC 2h,
EVM<->EVM 5m).

Non-custody is STRUCTURAL: the Coordinator holds no private key of any
asset, is the recipient/refund of no HTLC, and has no fund-moving path —
TestNonCustody reflects over it and fails if any field is a key type. After
the hashlock commit V is irrelevant to safety; its crashing or lying can
only deny service or relay a stale quote.

Composes pkg/htlc for the shared hashlock/preimage and authenticates every
message through crypto.Ecrecover directly (recoverAddr) with its own venue
domain tags — a leaf, so the relay never pulls the GPU CLOB matcher. Builds
and passes go test -race off a non-GPU box.
v1.7.0
2026-06-26 04:26:54 +00:00
zeekay 9c9106017e feat(htlc): cross-chain HTLC leg builders (pkg/htlc)
The single place a Lux cross-chain atomic swap is constructed across all
three legs, composed from one shared primitive:

- secret.go  — Secret [32]byte, Hashlock() = sha256(secret), constant-time
  VerifyPreimage. THE source of the SHA-256 hashlock every leg shares (one
  32-byte preimage unlocks BTC, the LP-90A0 swap precompile, and the EVM
  LXSwapHTLC.sol); keccak is explicitly excluded.
- bitcoin.go — the fixed P2WSH HTLC script (OP_IF SHA256/EQUALVERIFY/CHECKSIG
  // OP_ELSE CLTV/DROP/CHECKSIG), P2WSHAddress, and claim/refund witnesses
  signed with real BIP143 segwit-v0 sighash via btcd txscript (no hand-rolled
  sighash; low-S RFC6979 sigs).
- evm.go     — lock/claim/refund calldata; selectors DERIVED from the canonical
  ABI signatures and asserted equal to the precompile's 0x4da2c728 /
  0x84cc9dfb / 0x7249fbb6.

Tests (-race) include real txscript.Engine execution proofs: claim spends
with the correct preimage and fails with a wrong one; refund spends at/after
locktime and fails before / with CLTV disabled. btcd pinned v0.24.2 (v0.26.0
split chaincfg/wire/txscript into /v2 modules and breaks the build).
2026-06-26 04:26:54 +00:00
zeekay 035b30818a release: v1.6.1 — matcher self-trade prevention (conservation) v1.6.1 2026-06-26 01:18:15 +00:00
zeekay dd228b211c lx: self-trade prevention in SubmitMarketable via canonical owner fold (fixes conservation seed 4242)
A rested maker carries an 8-byte-truncated User (from persist.go userToUint64);
a fresh taker carries the full 16-byte identity. The marketable matcher's raw
User== self-trade check missed the same-account self-cross, desyncing the int/
float quantity lanes -> maker reserve drained + orderuser row deleted -> later
cross stranded settlement -> conservation broke. Add selfTradeKey() (one fold,
used by both place + marketable paths) and skip-and-cancel the self-maker leg.
settle.go arithmetic untouched. seed 4242 re-included + conserves.
2026-06-26 01:18:15 +00:00
zeekay 14d6d21321 release: v1.6.0 — signed-order authorization boundary (non-custodial settlement hardening) v1.6.0 2026-06-26 00:52:52 +00:00
zeekay b30f276a90 dchain: enforce signed-order authorization on every fund-moving tx (closes audit C1/H2/H3)
Every state-mutating D-Chain tx now carries a signature + per-account nonce,
verified in consensus before any ledger mutation: recovered signer must equal
the asserted 16-byte user, and the digest binds tx type + nonce + full body
(so the withdraw ref and cancel orderId are signed). secp256k1 + ML-DSA-65,
fail-closed. Previously any caller of the venue RPC could move anyone's funds.
Conservation, identity-width, and ownership invariants preserved; the
signed-order primitive that existed without a caller is now the auth boundary.
Tests across ingest/read/zapingest/e2e adapted to sign; no checks weakened.
2026-06-26 00:52:52 +00:00
zeekay 38485adee3 Merge branch 'test/dexvm-purity-lock' into main-pub 2026-06-25 16:37:02 -07:00
zeekay 4d5038a402 deps: bump crypto v1.19.26 + consensus v1.25.29 (go-live cascade)
Aligns the dex leaf onto the canonical crypto/consensus go-live tags. dexcore
(permissionless AssetResolver) + dchain (dex_get_* read RPC, pure block.ChainVM)
tests green (GOWORK=off). No source change — dep alignment.
v1.5.20
2026-06-25 16:08:34 -07:00
zeekay 6c088ef199 test(dchain): fix CGO-on test build + sync canonical zap go.sum
poolIDForSymbol was defined only in localnet_e2e_test.go (//go:build !cgo) but
read_test.go (no build tag) used it, so the package test binary failed to
compile under CGO_ENABLED=1 (undefined: poolIDForSymbol). Move the helper to an
untagged poolid_helper_test.go — it is pure-Go (a byte copy) and belongs in both
test binaries. Both CGO_ENABLED=1 (read/purity) and CGO_ENABLED=0 (venue/4-path/
ingest/conservation) suites now compile and pass.

go.sum: luxfi/zap v0.8.10 content hash updated to the canonical registry hash
(h1:QKNTAsenkke+...) after an upstream re-tag; 'go mod verify' = all modules
verified. Regenerated, not bypassed.
2026-06-25 15:10:07 -07:00
zeekay f7c9c91055 test(dchain): broaden purity denylist — catch generic gossip/broadcast/p2p verbs 2026-06-25 14:51:42 -07:00
zeekay 5daa702f25 test(dchain): purity lock — dexvm must stay a pure block.ChainVM
Structural regression lock for the consensus write-path fix (luxfi/consensus
fix/fetch-on-unknown-vote). The wedge was a SHARED-engine bug, not a dexvm bug:
the dexvm has — and must keep — ZERO networking/gossip primitives. It parses,
verifies, accepts, and matches blocks under consensus but NEVER propagates them;
propagation, vote distribution, and ancestor fetch live in luxfi/consensus.

TestDChainVM_IsPureBlockChainVM walks the package's own non-test .go files and
fails (with file:line) if any references AppGossip, SendAppGossip, PushQuery,
PullQuery, SendChits, common.Sender, or RequestAncestors. Verified to FAIL on an
injected sentinel and PASS on the real tree (12 source files, zero hits).

CGO_ENABLED=0 go test ./pkg/dchain/... green.
2026-06-25 14:07:29 -07:00
zeekay 6c28480234 fix(dexfillproof): match poolId as hex (read.go encoding), purge stale clob_ strings
dexfillproof compared after.Markets[].PoolID against ids.ID.String() (cb58),
but pkg/dchain/read.go encodes poolId as lowercase hex of the 32-byte id, so
the read-back market-presence assertion never matched and the tool exited 1
even after a real FILL landed. Compare on hex (the canonical wire form). Also
rename the residual clob_ doc/error strings to dex_ — the public surface is
dex_* (the engine's internal clobMethods identifiers stay as-is).
2026-06-25 11:47:43 -07:00
zeekay 8c46d75c5e test(dchain): use neutral seed in conservation property test v1.5.18 2026-06-24 08:59:22 -07:00
zeekay 84e8968b40 dex: rename wire methods clob_* -> dex_* (public DEX namespace)
The D-Chain DEX wire methods now use the dex_ namespace (dex_place,
dex_submit, dex_cancel, dex_ensure_market, dex_open_market, dex_deposit,
dex_withdraw, dex_get_markets/book/orders/trades) per the luxd
service-prefix convention (eth_/avm./platform.). On the D-Chain the DEX
IS the CLOB (the AMM lives in C-Chain contracts, not this VM), so the
public wire exposes the chain's purpose, not the internal engine name.

The internal Go identifiers (clobMethods, MethodPlace, the CLOB engine
name) are unchanged — only the on-wire string VALUES move. Covers BOTH
transports via the one clobMethods table (ZAP RegisterCLOB + HTTP
ingest.go httpHandlers) plus read.go GET endpoints. Forwards-only (DEX
not live yet). dexseed + dexfillproof clients aligned.

zapwire + dchain tests green; four-path + venue E2E pass.
v1.5.19
2026-06-23 17:46:09 -07:00
zeekay 812ea50c0a refactor(dchain): drop dead ctx param from startZAPIngest
The serve goroutine deliberately uses context.Background() (its lifetime is
the VM's, cancelled by Shutdown via zapIngestCancel, not the short-lived
Initialize ctx), so the ctx parameter was never used. Remove it — no slop.
Functionally identical to v1.5.17; the param carried no behavior.
2026-06-23 15:54:50 -07:00
zeekay 53e0c44402 feat(dchain): ZAP socket is the canonical in-luxd CLOB ingestion (transport-decision)
The in-luxd native D-Chain plugin served HTTP only (the dev left the ZAP
socket to standalone cmd/dvenue: handler.go said 'the in-luxd plugin does
NOT use this path'). Owner transport decision: the ZAP socket is the
CANONICAL native ingestion in-luxd (the HFT path — binary wire, streaming,
co-located on the pod), HTTP stays as the compat surface (web/exchange-api/
debug). Both fold over the ONE clobMethods core; transport is orthogonal to
consensus, so it is safe to serve both — an order from either transport hits
the identical submitTx -> mempool.Add -> Verify-match path, and validators
replay from accepted block BYTES, never the wire.

zapingest.go: the VM owns its transports. Initialize parses init.Config for
an optional zapIngestAddr and, when set, opens rpc.Listen co-located in the
plugin process bound to clobMethods (reusing RegisterCLOB, the existing
socket seam) — served concurrently, closed on Shutdown. Enabled by DATA (the
chain config the operator/genesis sets), NOT a build tag or forked entry
point: one binary, one core, the transport set is a per-environment knob.
Empty addr => HTTP-compat-only (in-process tests + cmd/dvenue, which runs its
own socket, are unaffected). Malformed config fails fast at Initialize.

TDD (all !cgo):
 - TestZAPIngestCrossingOrdersMatchInBlock: an order over the VM's OWN
   config-started socket (no manual RegisterCLOB) -> consensus -> committed
   fill.
 - TestZAPIngestSharesOneCoreWithHTTP: maker rests over ZAP, taker crosses
   over HTTP against the SAME book -> proves one core, two transports.
 - TestParseConfig / TestNoZAPIngestWhenUnset / TestZAPIngestStopsOnShutdown:
   config contract (forwards-only), no-op path, clean idempotent teardown.

Additive: RegisterCLOB unchanged; CreateHandlers/ingest.go unchanged; the
runner (cmd/dchain) unchanged — the socket is a VM concern driven by config.
v1.5.17
2026-06-23 15:24:27 -07:00
zeekay 02e5254ca8 refactor(dex): decomplect the synthetic-seed/guard footgun (3 layers -> 0)
The mess was three layers defending a self-inflicted footgun:
 (a) cmd/clobverify + cmd/fourpath-live SEED ascii-of-symbol synthetic
     markets (poolID = ASCII of "LUX/LUSD"), orders with no orderuser row;
 (b) internal/localguard refused those tools off-loopback;
 (c) VM.assertOrderUserCoverage BRICKED the chain at boot if a custody
     market had a resting order with no orderuser row.

Decomplect-perfect (NOT another guard):
 1. DELETE cmd/clobverify + cmd/fourpath-live. Real markets come from
    permissionless OpenMarket + real ERC-20s + the maker; the real-market
    e2e supersedes them. cmd/dexseed (canonical, structurally synthetic-safe)
    stays.
 2. DELETE internal/localguard (+ test) — it existed ONLY to fence the
    deleted seeders.
 3. The settlement-identity invariant already holds BY CONSTRUCTION at order
    creation: lockOrderSpend writes orderuser: and putOrderRow writes order:
    to the SAME versiondb overlay, committed in ONE atomic Block.Accept
    overlay.Commit(); an unfunded place never rests. So a resting custody
    order without its orderuser row is UNREPRESENTABLE in committed state ->
    the boot scan was provably dead -> DELETE VM.assertOrderUserCoverage.
    The single remaining settlement-identity guard is the consensus-time
    fail-closed in settleOrderEffects (ErrMissingSettlementUser), which can
    never fire on honest committed state.

TDD:
 - TestCommittedStateNeverHasOrderWithoutIdentity: drives the real commit
   path (rest + reject + fill); committed order: set == orderuser: set.
 - TestRestartDoesNotBrickBoot: hand-corrupts state the commit path cannot
   produce; boot now SUCCEEDS (no brick); consensus-time guard still fails
   closed when a fill touches the corrupt order.
 - All prior settlement-identity regression tests still pass.

Result: zero guards, illegal state unrepresentable. Removes the footgun
instead of guarding the footgun we created.
2026-06-23 15:18:32 -07:00
zeekay 93fa24e705 dex(cmd/dexseed): canonical REAL-market seeder over the native D-Chain seam
cmd/dexseed seeds REAL markets onto the live in-luxd native D-Chain CLOB
ingestion seam (POST /ext/bc/D/dex/clob_* with FROZEN zapwire frames),
using consensus-native asset identities for every market side.

Identity rule (the property that makes this seeder SAFE against a shared
cluster, unlike the loopback-gated cmd/clobverify): every asset handle is
the dexcore canonical AssetID = DeriveAssetID(networkID, C-chainID, kind,
canonicalRef) — the SAME id the chain's resolver derives — NEVER an
ascii-of-symbol id (the synthetic form, e.g. 0x4c5558 'LUX', that bricked
the chain). A synthetic/malformed ref is refused at frame-build time,
before a single frame is sent; the chain's permissionless resolver then
proves each side is backed by live on-chain code (EXTCODESIZE) before
binding the market.

End-to-end smoke path for one real LUX/<ERC20> market: clob_open_market
(bind real base+quote ids) -> clob_deposit (fund maker base) -> clob_place
(rest maker ask) -> clob_get_markets + clob_get_book (read back & confirm).

Pure, testable core (seed.go): assetSpec.resolveID, poolIDFor (canonical
domain-separated SHA-256 over the derived ids, NON-ascii), depositRefFor,
realMarketFrames. Tests (main_test.go): golden AssetID vectors, OpenMarket
96B + slot equality, synthetic/malformed-ref rejection, deterministic
non-ascii poolID, frozen-frame field round-trips. CGO_ENABLED=0, pure-Go,
luxfi packages only.
2026-06-23 15:09:01 -07:00