Files
zeekayandHanzo Dev 996677759a One request the edge permits was a thousand questions it did not
A price is a fan-out. The edge limits requests — thirty a second from one
address — and each may name fifty tokens, read at two sizes against two
numéraires across every arm. Nothing bounded what came out the other side, and
what comes out lands on public endpoints we hold no account with; being refused
there takes quoting down for everybody, on every chain.

So the budget is sixteen questions in flight against one chain for the whole
process, rather than eight per request multiplied by however many requests
arrive. It is taken around a single reading and not around a whole price,
because a price against the hub waits for the hub's own price, and a slot held
across that wait deadlocks the first time every slot is held by something
waiting on the hub.

Measured: one request of 50 cold Ethereum tokens went from 10.1s to 8.6s, and
four chains of 40 at once from 10.7s to 9.3s — and returned the same counts on
a repeat, where the same burst before this returned a different set of prices
each time.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-09 12:31:14 -07:00

96 KiB
Raw Permalink Blame History

LX - Complete Architecture Documentation

Executive Summary

LX is a planet-scale, fully on-chain decentralized exchange built on the Lux Network. It combines ultra-low latency matching (<1μs), quantum-resistant security, and a design target of supporting all global markets (784,000+ trading pairs — a coverage goal, not a measured benchmark) in a single unified system.

Measured performance (Apple M1 Max, first-hand):

  • Throughput: 11.88M orders/sec (C++ engine, 10 threads); 2.2M orders/sec (pure Go pkg/lx)
  • Latency: 169 ns avg match (p50 125 ns, p99 292 ns) on C++; 381 ns/order in pure Go; 49 ns cancel
  • Allocations: 1–2 allocs/op on the Go matching path (not zero-alloc)
  • GPU: the default (CGO-off) build matches on CPU; a GPU-native deterministic per-book matcher (byte-identical to the CPU oracle, parity-verified) is available with CGO_ENABLED=1 via the unified lux-gpu backend (runtime-select CUDA/HIP/Metal), sustaining up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10); kernels ship prebuilt from luxcpp/dex. GPU also drives FHE (Metal NTT, 23.6× at N=4096, batch=128)
  • CI/CD: Fully automated with GitHub Actions

Key Innovations

  1. Full On-Chain Architecture: Unlike competitors (High-performance DEX, dYdX) that match off-chain, LX runs the entire orderbook and clearinghouse directly on-chain with 1ms block finality
  2. Planet-Scale Capacity (design target): 5M markets simultaneously per node — a capacity goal, not a measured benchmark
  3. Quantum-Resistant: QZMQ protocol with post-quantum cryptography for node communication
  4. Multi-Engine Performance: pure Go 2.2M orders/sec (381 ns/order), C++ 11.88M orders/sec (10 threads, 169 ns avg match) — CPU default build. A GPU-native deterministic per-book matcher (parity-verified GPU==CPU, CGO_ENABLED=1, unified lux-gpu backend) sustains up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10). GPU also drives FHE (Metal NTT 23.6×)
  5. Universal Protocol Support: JSON-RPC, gRPC, WebSocket, QZMQ, ZAP (HFT)

On-Chain Settlement: D matches · C settles (0x9999)

The DEX matching engine runs on the D-Chain (dexvm) and does not move EVM balances directly. Settlement uses a strict D matches · C settles split:

  • D-Chain matches the order, emits a DFillReceipt, and a D-validator quorum BLS-signs the receipt root.
  • C-Chain precompile 0x9999 (Uniswap-V4 PoolManager ABI, receipt-settlement only — not a matcher) verifies that certificate inline (BLS verify is deterministic → fork-safe), debits/credits balances, and marks the receipt consumed. Settlement is Block-STM-parallel with fine-grained keys (no global hot slots). The verify path NEVER calls a live matcher.
  • certType (BLS day-1 → Q / PQ / ZK) upgrades via an on-chain verifier registry with no ABI change. 0x9010 is deprecated (alias/disabled, same impl + dex.precompile.v1.9999.* namespace).

Slogan: D matches · C settles · BLS certifies day-1 · Q later · X finalizes. Normative spec: LP-9999 (~/work/lux/lps/LPs/lp-9999-dex-v4-receipt-settlement-precompile.md). This file summarizes; it does not duplicate the spec.

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                    LX ARCHITECTURE                       │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  Client Layer                                                │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  SDKs: TypeScript | Python | Go | Rust | Java       │    │
│  │  Protocols: JSON-RPC | gRPC | WebSocket | REST      │    │
│  └─────────────────────────────────────────────────────┘    │
│                           ↓                                  │
│  API Gateway Layer                                          │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  Load Balancer | Rate Limiter | Auth | Caching      │    │
│  └─────────────────────────────────────────────────────┘    │
│                           ↓                                  │
│  Matching Engine Layer                                      │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  Pure Go | Hybrid C++ | GPU/MLX | Auto-Selection    │    │
│  │  OrderBook | Risk Engine | Settlement | Clearing    │    │
│  └─────────────────────────────────────────────────────┘    │
│                           ↓                                  │
│  Consensus Layer                                            │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  FPC Consensus | K=3 Validators | 1ms Finality      │    │
│  │  QZMQ Network | Post-Quantum Crypto | DAG Backend   │    │
│  └─────────────────────────────────────────────────────┘    │
│                           ↓                                  │
│  Storage Layer                                              │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  BadgerDB | State Tree | Block Archive | Snapshots  │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

Core Components

1. Matching Engine (pkg/lx/)

Two-tier matching architecture (CPU):

  • Pure Go (pkg/lx): 2.2M orders/sec, 381 ns/order, 1–2 allocs/op
  • C++/CGO: 11.88M orders/sec (10 threads), 5.91M single-thread, 169 ns avg match (p50 125 ns, p99 292 ns), 49 ns cancel

Key files:

  • orderbook.go: Core order book implementation
  • orderbook_advanced.go: Advanced order types (iceberg, stop, bracket)
  • orderbook_cgo.go: C++ bridge for performance
  • matching_engine.go: Order matching logic

2. API Layer

JSON-RPC (pkg/api/jsonrpc.go)

Standard JSON-RPC 2.0 implementation for HTTP clients:

  • Place/cancel orders
  • Market data queries
  • Account management

gRPC (pkg/grpc/server.go)

High-performance binary protocol:

  • Streaming order books
  • Real-time trades
  • Bulk operations

WebSocket (pkg/websocket/server.go)

Real-time market data streaming:

  • Order book updates
  • Trade feed
  • OHLCV candles

ZAP (pkg/api/zap_server.go) - NEW

Ultra-low-latency binary protocol for HFT:

  • Zero-copy order placement/cancellation
  • Binary wire format (64-byte fixed orders)
  • Sub-100μs round-trip latency
  • Low allocation on hot path (see benchmark below)

Wire Protocol:

Order (64 bytes):
  [0:8]   symbol (8 bytes, null-padded)
  [8:16]  order_id (uint64, big-endian)
  [16:24] price (float64, IEEE 754)
  [24:32] size (float64, IEEE 754)
  [32]    side (uint8: 0=buy, 1=sell)
  [33]    order_type (uint8: 0=limit, 1=market)
  [34:36] flags (uint16: post-only, reduce-only, STP)
  [36:44] timestamp (uint64, unix nanos)
  [44:60] user_id (16 bytes)
  [60:64] padding

Quote (24 bytes):
  [0:8]   price (float64)
  [8:16]  size (float64)
  [16:20] count (uint32)
  [20:24] padding

Benchmark Results (Apple M1 Max):

BenchmarkZAPOrderPlacement    ~42μs/op    5.7KB/op    24 allocs
BenchmarkZAPBestBid           ~48μs/op    5.7KB/op    18 allocs
BenchmarkZAPRoundTrip         ~44μs/op    4.9KB/op    10 allocs

Usage:

// Server
server := api.NewZAPServer(orderBook, ":9000", logger)
server.Start(ctx)

// Client
client, _ := rpc.Dial(ctx, "localhost:9000")
resp, _ := client.CallRaw(ctx, "place_order", orderPayload)
resp, _ := client.CallRaw(ctx, "best_bid", nil)
resp, _ := client.CallRaw(ctx, "orderbook", depthReq)

3. Consensus Integration

QZMQ (pkg/qzmq/qzmq.go)

Quantum-resistant ZeroMQ for node communication:

  • Post-quantum key exchange
  • Encrypted order propagation
  • Consensus messaging

Integration (cmd/luxd/qzmq_integration.go)

  • Order propagation between nodes
  • Trade confirmation broadcasting
  • State synchronization
  • Block proposals

4. Market Data (pkg/marketdata/)

Real-time OHLCV aggregation:

  • 19 time intervals (1s to 1M)
  • Volume-weighted calculations
  • Technical indicators (RSI, MA, VWAP)

5. SDKs

TypeScript (sdk/typescript/)

const client = new LXDexClient();
const order = await client.placeOrder({
  symbol: "BTC-USD",
  type: OrderType.LIMIT,
  side: OrderSide.BUY,
  price: 50000,
  size: 0.1
});

Python (sdk/python/)

client = LXDexClient()
order = client.place_order(
    symbol="BTC-USD",
    order_type=OrderType.LIMIT,
    side=OrderSide.BUY,
    price=50000,
    size=0.1
)

Go (sdk/go/)

client := client.NewClient()
order, _ := client.PlaceOrder(ctx, &Order{
    Symbol: "BTC-USD",
    Type:   OrderTypeLimit,
    Side:   OrderSideBuy,
    Price:  50000,
    Size:   0.1,
})

Performance Characteristics

Latency Benchmarks

  • Order Matching: 169 ns avg (C++ engine), 381 ns (pure Go)
  • Consensus Round: <1ms
  • Block Finality: 1ms (1000 blocks/sec)
  • End-to-end Trade: <5ms

Throughput Capacity

  • Orders/sec: 11.88M (C++, 10 threads); 2.2M (pure Go) — CPU default build. GPU-native per-book matcher (CGO_ENABLED=1, lux-gpu, parity-verified GPU==CPU): up to 12.76B (AMD 8060S) / 9.13B (GB10)
  • Trades/sec: 10M+ (design target — no benchmark backing)
  • Markets: 5M simultaneous (design target — no benchmark backing)
  • Connections: 1M+ WebSocket (design target — no benchmark backing)

Memory Requirements

  • Development: 16GB (top 100 pairs)
  • Production: 64GB (all crypto)
  • Global Scale: 128-512GB (all markets)

Deployment Options

Single Node Development

./bin/luxd \
  --enable-mlx \
  --block-time 1ms \
  --http-port 8080 \
  --ws-port 8081

3-Node Cluster (K=3)

# Node 1
./bin/luxd --node-id 1 --enable-qzmq --qzmq-pub-port 5555

# Node 2
./bin/luxd --node-id 2 --enable-qzmq --qzmq-pub-port 5565

# Node 3
./bin/luxd --node-id 3 --enable-qzmq --qzmq-pub-port 5575

Docker Deployment

make up  # Starts complete stack with monitoring

The trading gateway (cmd/gateway, pkg/gateway)

One image, two binaries. dexd is the D-Chain venue; gateway is the HTTP trading surface. They share the venue types, which is why they ship together.

Everything answers under /v1/trade, and api/openapi.yaml describes exactly that. pkg/gateway.Server.routes() is the surface written once; TestTheDocumentIsTheSurface reads the document and holds the two to each other, in both directions, so a route added in code and not written down fails the build and so does a path promised in the document and not served.

Ten paths, and every one of them answers:

GET  /v1/trade/venues            what this deployment can price, per chain
GET  /v1/trade/tokens            what it can trade there, and their decimals
GET  /v1/trade/price             what those tokens are worth, in dollars
POST /v1/trade/quote             the best price across the venues that hold the pair
POST /v1/trade/quotes            every venue's price, best first
POST /v1/trade/swap              the transaction that takes that price
POST /v1/trade/approval/check    what the spender may already move
POST /v1/trade/approval/build    an unsigned ERC-20 approve
POST /v1/trade/permit2/check     whether a live Permit2 grant covers it
POST /v1/trade/permit2/build     a Permit2 grant, as a tx or as typed data

That prefix replaced three names for one API: /v1/* here, /trading/* beside it in Uniswap's shapes, and a published openapi.yaml describing a third set that pkg/trading implemented and no binary ever mounted. pkg/trading was a second copy of the venue interface, the constant-product math and the eth_call client; it is gone, along with the /trading/* handlers and their types.

Every chain is read from its own pools. Ours through the V4 precompiles with a V2 router beside them where one is deployed; every other chain through the V2 Router02 and V3 QuoterV2 Uniswap published there, over JSON-RPC, with no API key and no upstream account. The hosted trade API answers ACCESS_DENIED without a contract, so uniswap.NewProvider is registered ONLY when UNISWAP_API_KEY is set — a provider that always refuses turns a pair with no pool into an error about somebody else's quota.

Environment: GATEWAY_ADDR (:8080), LUX_RPC, LUX_CHAIN_ID (96369), LUX_V2_ROUTER, LUX_V3_QUOTER, LUX_V3_ROUTER, RPC_<chainid> per chain, GATEWAY_CACHE_TTL (seconds), UNISWAP_API_KEY (optional). Chains with venues: 1, 10, 56, 137, 8453, 42161, 96369.

GET /v1/trade/venues is the question a screen asks before it asks anything else — which chains this deployment can price, and from what. It is grouped by chain because a venue is a contract on a chain, and native marks the ones we settle ourselves. Measured against 96369 with LUX_V3_QUOTER set:

96369  native  [v4_native, uniswap_v3]
1              [uniswap_v2, uniswap_v3]
10, 56, 137, 8453, 42161 the same

⚠ The v4_native arm on 96369 is configured and silent. 0x9010 answers 0x there — measured with the venue's own quoter selector — so the arm quotes nothing and every 96369 price today comes from uniswap_v3, reading the QuoterV2 the venue deployment put on that chain. native: true says the arm is attached, not that it answered; a quote is what tells you. It starts answering the day the precompile does, with no configuration change.

What 96369 actually carries, from luxfi/standard deployments/venue/96369.json:

V3Factory   0x6E5884084814F4785e21f6f9C11D3C299Ef5d7f1
Quoter (V2) 0x6EA2F79f743C809D1152657Ef5d5907f47a34cfc   LUX_V3_QUOTER
Router (02) 0xbbD8d9A1E6bf5627A2F6D2aF38664bbe1cEF63Bb   LUX_V3_ROUTER
Positions   0xd5350c2f13772f126F942b152BaeFee943df4e5a
WLUX        0x66dbed9572eb9be45ef05526c65beddf8d60a672

Its Router key is the V3 SwapRouter, NOT a V2 Router02 — factory() answers the V3 factory and WETH() reverts — so it belongs to LUX_V3_ROUTER and never to LUX_V2_ROUTER. The 12 V2 pairs on that chain hold reserves and become quotable when a Router02 is deployed, not before.

Prices measured through this surface, one whole unit in, on every configured chain:

96369     WLUX  -> LUSD   997001483075056712      uniswap_v3  tier 3000
1         WETH  -> USDC   2517103282              uniswap_v3  tier  100
8453      WETH  -> USDC   2519069935              uniswap_v3  tier  500
42161     WETH  -> USDC   2519534429              uniswap_v3  tier  500
10        WETH  -> USDC   2509863629              uniswap_v3  tier  500
137       WPOL  -> USDC   99582                   uniswap_v3  tier  500
56        WBNB  -> USDT   755677742862096479703   uniswap_v3  tier  100

What a chain lists, and what it is worth

A screen cannot draw a market until it knows a token's name, symbol and decimals, and every chain but ours has no indexer behind it. So the list travels in the binary: pkg/gateway/tokens.json, 935 tokens over the seven chains this gateway prices, embedded and served with no upstream, no key and no round trip. Identity only — address, chainId, symbol, name, decimals.

It carries no logo, and the struct has nowhere to put one. Public token lists give logos as URLs on assets.coingecko.com, coin-images.coingecko.com, raw.githubusercontent.com and s2.coinmarketcap.com: three companies fetched by every viewer's browser on every market screen. Marks come from cdn.lux.cloud, and a token with no mark there draws its own letters. TestTheEmbeddedListIsWellFormed refuses any key that is not one of the five.

The file is the boundary, so it is checked at build time rather than per request: valid addresses, decimals in range, no duplicates, no control characters in a symbol that something is going to render.

GET /v1/trade/price?chainId=&token= prices one token or fifty, answered in the order asked. There is no oracle behind it and no vendor — it is a reading of the same pools /v1/trade/quote reads, and it is the same number:

spend some dollars of a numéraire → see what comes back → put the fee back

Dollars rather than one whole token, because one whole token is a fifty-cent trade in one market and a hundred-thousand-dollar trade in the next, and the second one moves the pool it is measuring — priced that way SHIB came out 40% high. The fee correction matters as much: a pool hands back the mid price LESS its tier, so an uncorrected reading is high by exactly that tier — $1.0031 for a $1.00 token on a 0.3% pool, and $3018.51 for a $3000 one two hops deep.

Two numéraires per chain (Numeraires in venue_chains.go): the dollar stablecoin, worth one by construction, and the wrapped native token, whose own mark is read against the dollar. Most V3 liquidity is against the native token, not the dollar, so a gateway that knew only the dollar could price the majors and nothing behind them. Every route is read and the cheapest wins — a price is what somebody actually receives, and the route handing over the most tokens is nearest the middle of the market.

Twice, ten times apart. A pool with almost nothing left in it still answers, and the implied price of a rounding error comes out in the millions. So the pools are asked at $10 and at $100 and the two best readings are compared; more than 2% between them and nothing is returned. Measured over the fifty tokens Ethereum lists first:

one reading      50 asked, 44 priced, half of them >1% off, AUCTION at
                 $889,434,176 for a token worth $3.44
both readings    50 asked, 27 priced, 25 of 27 within 2%

The two that remain apart — ASM +621%, AGLD +122% — are real pools here that sit off the wider market. That number is not an error: /v1/trade/quote for the same size implies $0.036806 for ASM where /v1/trade/price says $0.036834, so the screen and the swap panel agree, and agreeing with each other is what matters. Gating each numéraire separately was tried and is wrong: it refuses the cheapest route for being thin and then quotes a dearer one that was not, which is a price nobody would have paid. The gate is on the best reading at each size.

Cross-chain, same minute, against an independent source:

1      WETH   2487.03   -0.09%     8453  cbETH   2831.86   -0.17%
1      WBTC  78414.92   -0.01%     42161 ARB        0.154  -0.16%
1      UNI       6.608  -0.22%     10    OP         0.103  -0.23%
1      AAVE    128.59   +0.05%     137   WMATIC     0.0965 -0.04%
1      PEPE      3.6e-6 -0.32%     56    WBNB     742.72   +0.46%
1      SHIB      5.37e-6 +0.07%

A token no pool holds — or holds too thinly to price — comes back WITHOUT priceUSD, never with a zero. A screen can draw a dash; it cannot un-draw a wrong number. venue and via go missing with it, because a number nobody can trace is a number nobody can check.

The bound is on what leaves, not on what arrives. The edge limits requests — thirty a second from one address — and each may name fifty tokens read at two sizes against two numéraires across every arm, so one permitted request becomes up to a thousand eth_calls landing on public endpoints we hold no account with. readingsInFlight is sixteen questions in flight against ONE chain for the whole process, not per request, so a second screen shares them instead of doubling them.

Cost, measured: 50 cold Ethereum tokens in 8.6s, the same 50 warm in 36ms, and 160 tokens across four chains at once in 9.3s — and the same counts on a repeat run, where before the bound a four-chain burst returned a different set of prices each time. The two sizes are asked concurrently, so the second one costs calls and not latency.

A reading stands for a minute (markTTL) and asOf says when it was taken; a chain that could not be read is remembered for ten seconds, not a minute, because the pools have not changed — our access to them has. Fifty tokens per request and eight readings in flight, so one HTTP request cannot turn into five hundred eth_calls against an endpoint we hold no account with. Thirty-two readers arriving for the same cold price produce ONE fan-out, not thirty-two.

One unit for a fee, everywhere. Hundredths of a basis point — how V3 states a tier, how SwapOrder.Fee is read, and how a price puts back what a pool took. The V2 arm answered 30 where the V3 arm answered 3000 for the same three tenths of a percent; feeFromBPS converts once, in venue.go, and nothing else means anything else by that number.

The native arm no longer hides a chain it cannot reach. Every other arm separates a reverting contract from an endpoint that never answered, and the router reports a chain it could not read only when EVERY arm on it failed — so one arm answering "no liquidity" to an unreachable endpoint was enough on its own to turn an unreadable chain into a pair nobody holds.

The venue that quoted is the venue that builds

/v1/trade/swap asked the hosted provider registry for a price — which this deployment has none of, so it answered 500 while /v1/trade/quote priced the same pair from the pools a line away — and then encoded whatever came back for the PoolManager precompile at 0x9010, regardless of where the price came from. A router on Ethereum quoted and a precompile on our chain addressed, in one response. 0x9010 answers 0x on 96369, measured with the venue's own quoter selector, so the calldata named a contract that is not there.

Venue has a Swap method now (venue_swap.go). Each venue builds against the contract it read: UniswapV3Venue against the SwapRouter02 beside its quoter, UniswapV2Venue against the same Router02 that answered getAmountsOut. A venue that prices a market it cannot settle returns nil, and the surface answers 404 naming it rather than calldata for something else.

The selector was wrong, and it is the kind of wrong that spends money. calldata_lxrouter.go sent 04e45aaf under a signature it called ExactInputSingle(address,address,uint256,uint256,uint160,bytes32). That signature hashes to f48f227e. 04e45aaf is SwapRouter02's exactInputSingle((address,address,uint24,address,uint256,uint256,uint160)) — a SEVEN-field tuple. A router handed the six-field form reads amountIn where it expects the fee tier and amountOutMinimum where it expects the recipient. Those builders were reachable only from their own tests; what survives is the padding and decoding, in abi.go.

Proof, end to end, against the live chain — the gateway's own calldata replayed through eth_call on 96369's real router from the account that holds the allowance:

POST /v1/trade/swap  1 WLUX -> LUSD, slippage 0.5
  to     0xbbD8d9A1E6bf5627A2F6D2aF38664bbe1cEF63Bb   (SwapRouter02)
  fee    3000            the tier the quote was read from
  minOut 992016475589681300   99.5% of the quote
eth_call that calldata, from 0x9011E8…, latest
  -> 997001483075056712
the gateway quoted        997001483075056712

The floor is not optional. A router handed the quoted amount as its amountOutMinimum reverts on any movement at all, including the movement the caller's own trade causes. slippage is a percentage; zero or nonsense means half a percent.

It is computed in hundredths of a basis point — the unit a V3 fee tier is already stated in. In whole basis points a tolerance finer than 0.01% truncated to nothing, so slippage: 0.005 produced a floor EQUAL to the quote: a request for very tight protection answered with none at all, and a transaction that reverts on the first wei of movement. Measured on 96369, 1 WLUX into LUSD quoting 997001483075056712:

slippage 0.005  ->  996951633000902959   99.9950%
slippage 0.5    ->  992016475659681428   99.5000%

The tier travels with the quote. A V3 quote asks all four tiers and keeps the best, so it is a reading of ONE pool. The winning tier rides on route[0].fee and the swap names the same one — without it the transaction executes against a different pool at a different price.

The deadline is honoured on every arm. SwapRouter02 dropped the field from exactInputSingle's tuple and takes it through multicall(uint256,bytes[]) instead, which is how Uniswap's own interface sends one; the V2 router takes it directly. Without the wrap a deadline was accepted and silently dropped on every V3 route while V2 honoured it — one field meaning two things depending on which pool won the quote. amountOutMinimum bounds the price, the deadline bounds the time, and a signed swap that lands an hour late still passes its floor at a price nobody would choose now.

Both directions measured against 96369's live router:

deadline ahead of block.timestamp -> 997001483075056712, the quoted amount
deadline behind it                -> execution reverted: Transaction too old

⚠ 96369's clock is not wall clock. It seals a block when there is a transaction, so block.timestamp was 4709 seconds behind wall clock while this was measured. A deadline computed from wall clock is generous here rather than tight, which is the safe direction — but a test that expects now - 60 to be expired will not see it expire.

A dead endpoint is not an empty pool. Both used to come out as an empty list, so WETH/USDC on Ethereum — one of the deepest pools in existence — was reported as a pair nobody holds whenever its RPC was down, which sends a reader looking for liquidity instead of at their endpoint. EVMClient marks the answers it never received with ErrUnreachable (a connection failure, a 5xx, a 429, a body that is not JSON-RPC) and the venues pass that through, while a contract answering by REVERTING stays what it always was: this pool does not exist. Three of the four V3 tiers revert on most pairs; that is the ordinary case and must not read as an outage.

QueryAllVenues returns the reason only when EVERY arm it asked failed — one arm down while another answers is a quote. Measured, with chain 1's endpoint pointed at a closed port:

chain 1      502  chain 1 could not be read: endpoint unreachable: dial tcp …
chain 96369  200  997001483075056712
a pair with no pool on 96369
             404  no venue here holds this pair
/providers   200  one dark chain does not take a pod out of rotation

A direction is not a missing market. getAmountsOut and quoteExactInputSingle price a known INPUT and have no other direction, so an exact-output request gets nothing back however deep the pool is. Answering that with "no venue here holds this pair" sends someone looking for liquidity that is sitting right there; it now says which of the two it was, and what to ask instead.

The allowance is read, not assumed

/v1/trade/approval/check and /v1/trade/permit2/check return what the chain says, over the same endpoint the pool is quoted from — Server.read in server_approval.go. Both used to answer allowance: "0", needsApproval: true on every request, under a comment claiming the gateway had no way to read a chain; it has one per chain, one field away. The cost of that guess was not a wrong number on a screen: a wallet told it needs an approval for a token it has already approved sends an approve transaction, and the user pays gas for a state change that changes nothing, before every swap, forever.

Permit2 answers (amount, expiration, nonce) and the expiration is half the answer — a grant that has run out is not a grant. The unsigned tx and the EIP-712 request ride along ONLY when one is needed; handed back beside "you already approved" they are transactions somebody sends.

Permit2 is at one address everywhere it exists, and it does not exist everywhere. 0x000000000022D473030F116dDEE9F6B43aC78BA3 holds 9152 bytes on Ethereum and nothing on 96369. Both paths check before answering, so our own chain gets permit2 is not deployed on chain 96369 — approve the spender directly instead of calldata addressed to an empty account. A transaction that costs gas to do nothing is the failure worse than an error.

Three things to know before deploying it

The image is amd64 and says so nowhere but the Dockerfile. GOARCH=amd64 is written out in the build, and what is published is a single OCI manifest, not an index — so a kubelet on an arm64 node pulls it, believes it, and the container exits with exec format error. Where a cluster is mixed, the workload states nodeSelector: kubernetes.io/arch: amd64. Where binfmt happens to be registered the failure is worse than a crash: the container runs, uname -m inside it says x86_64, and a matching engine executes under instruction emulation.

runAsNonRoot needs the uid, not the name. The image declares USER dexd; a kubelet cannot check a string against runAsNonRoot and refuses the container with image has non-numeric user (dexd). State runAsUser: 1000.

/healthz is not a readiness probe until it has a source. It answers from the venues and the hosted provider registry together; before that it read the registry alone, so the ordinary configuration — no hosted provider, pools as the source — answered 503 forever and any probe on it held every replica out of its own Service. /providers is the narrower question (does the mux answer) and is what the lux-mainnet deployment probes.

What is deliberately not here

There is no /v1/admin/*. It paused the DEX, paused a pool and froze one on the strength of X-User-Role: admin — a header the caller writes — and drove state nothing read: PauseState had no caller outside its own file, per replica, lost on restart. A switch wired to nothing is worse than no switch. The real gate is checkPauseState in the pool manager, on chain, where a market is.

What this surface is not, and where each of those lives instead

Five paths answered 500 no providers available in the deployment that actually runs, and four more built transactions for contracts that are not there. A path in a published contract that cannot work is worse than a missing one: a client writes against it and finds out in production.

gone why where it lives
/v1/tokens /v1/pools /v1/pool/ /v1/positions /v1/stats /v1/price /v1/prices enumerating what exists on a chain is an INDEX read; this reads a pool by address, right now, and cannot walk every pool on Ethereum api-explore.lux.cloud — measured returning 16 pools, $39.9M TVL, real symbols and decimals for 96369
/v1/route the same read in a hat: needs a pool graph, and without one answered {"routes":[]} forever, which reads as "no path exists" rather than "I cannot answer" same
/v1/order /v1/order/ an in-memory map behind two replicas: an order placed on one pod was a 404 on the other about half the time, and every order died on restart the D-Chain venue IS the order book — dex_place, dex_get_orders, dex_get_book over ZAP, deployed as dex.yaml
/v1/position /v1/position/{increase,decrease,claim} every builder addressed 0x9010, which answers 0x; liquidity on 96369 is managed through the position manager the venue deployment actually put there not here

TestWhatThisSurfaceIsNot keeps them gone and records the reason beside each.

Nothing here invents a number. /v1/history/prices and /v1/history/tvl returned a random walk seeded from hardcoded base prices — LUX at 2.47, WBTC at 96420, 12.5M of TVL on 96369 — and both were routed to the public internet. A screen drawing that chart shows a market that does not exist, and on the wire it is indistinguishable from one that does. Price history belongs to the indexer, which reads the chain: api-explore.lux.cloud. /v1/tokens/search answered 501 on a TODO, which is a route lying about the surface in the other direction. All three are gone, and TestNothingHereInventsANumber keeps them gone.

API Endpoints

JSON-RPC Methods

  • lx_placeOrder: Place new order
  • lx_cancelOrder: Cancel existing order
  • lx_getOrderBook: Get order book snapshot
  • lx_getTrades: Get recent trades
  • lx_getOrder: Get order details
  • lx_getBestBid: Get best bid price
  • lx_getBestAsk: Get best ask price
  • lx_getInfo: Get node information

WebSocket Channels

  • orderbook:{symbol}: Order book updates
  • trades:{symbol}: Trade feed
  • candles:{symbol}:{interval}: OHLCV updates

gRPC Services

  • PlaceOrder: Unary order placement
  • CancelOrder: Unary order cancellation
  • StreamOrderBook: Server streaming order book
  • StreamTrades: Server streaming trades

Order Types

Basic Orders

  • Limit: Price-specific order
  • Market: Immediate execution
  • Stop: Trigger at price
  • Stop-Limit: Stop that becomes limit

Advanced Orders

  • Iceberg: Hidden quantity
  • Peg: Track best bid/ask
  • Bracket: Entry with stop-loss/take-profit
  • Trailing Stop: Dynamic stop price

Time in Force

  • GTC: Good Till Cancelled
  • IOC: Immediate Or Cancel
  • FOK: Fill Or Kill
  • DAY: Day order

Security Features

Quantum Resistance

  • Post-quantum key exchange (Kyber)
  • Quantum-resistant signatures (Dilithium)
  • SHA3 hashing
  • QZMQ encrypted messaging

Consensus Security

  • BFT with K=3 validators
  • Deterministic finality
  • No rollbacks after 1ms
  • Slashing for misbehavior

Application Security

  • Self-trade prevention
  • Position limits
  • Rate limiting
  • API key authentication

Monitoring & Observability

Prometheus Metrics

  • lx_orders_processed_total: Total orders
  • lx_trades_executed_total: Total trades
  • lx_matching_latency_seconds: Matching latency
  • lx_consensus_latency_seconds: Consensus latency
  • lx_block_height: Current block height

Health Endpoints

  • /health: Node health status
  • /metrics: Prometheus metrics
  • /debug/pprof: Go profiling

Development Workflow

Go toolchain policy

Every Dockerfile stage that compiles Go must (1) pin its base to the latest stable patch — currently 1.26.5, never below the go.mod go directive — and (2) set ENV GOTOOLCHAIN=auto.

The official golang images ship GOTOOLCHAIN=local, which turns "base older than the governing go directive" into a hard failure — go: go.mod requires go >= X (running go Y; GOTOOLCHAIN=local) — instead of fetching the needed toolchain. This is not hypothetical here: sdk/lx-trading-go/go.mod declares go 1.26.5, above the root module's 1.26.4, so a submodule build under GOTOOLCHAIN=local dies at exactly that.

The root go directive stays at 1.26.4 — raising it pushes a hard patch-level floor onto every consumer. Building an older directive with a newer toolchain is always valid. docs/Dockerfile is exempt (no Go).

Building

# Build all components
make build

# Build with GPU support
CGO_ENABLED=1 make build-gpu

# Run tests
make test

# Run benchmarks
make bench

Testing

# Unit tests
go test ./pkg/...

# Integration tests
go test ./test/integration/...

# E2E tests with Docker
make docker-test

Contributing

  1. Fork repository
  2. Create feature branch
  3. Write tests
  4. Implement feature
  5. Run linters
  6. Submit PR

Configuration

Environment Variables

LXD_DATA_DIR=~/.lxd
LXD_LOG_LEVEL=info
LXD_HTTP_PORT=8080
LXD_WS_PORT=8081
LXD_ENABLE_MLX=true
LXD_BLOCK_TIME=1ms

Config File (config.yaml)

node:
  id: 1
  data_dir: ~/.lxd
  
network:
  http_port: 8080
  ws_port: 8081
  
consensus:
  block_time: 1ms
  validators: 3
  
engine:
  type: hybrid
  max_batch: 10000

Troubleshooting

Common Issues

  1. Port already in use

    lsof -i :8080
    kill -9 <PID>
    
  2. MLX not available

    • Ensure Apple Silicon Mac
    • Update MLX framework
    • Fallback to CPU mode
  3. QZMQ connection failed

    • Check firewall rules
    • Verify ZeroMQ installation
    • Check network connectivity

Roadmap

Q1 2025

  • Production mainnet launch
  • Cross-chain bridges
  • Mobile SDKs
  • Hardware wallet support

Q2 2025

  • Derivatives trading
  • Options markets
  • Lending/borrowing
  • Staking rewards

Q3 2025

  • Institutional APIs
  • Regulatory compliance
  • Fiat on/off ramps
  • Multi-region deployment

Q4 2025

  • AI-powered trading
  • Social trading features
  • Copy trading
  • Strategy marketplace

Performance Optimizations

Memory Management

  1. Lock-Free Data Structures

    • Atomic operations for concurrent access
    • RCU (Read-Copy-Update) patterns for orderbook updates
    • Memory pools to eliminate GC pressure
  2. Low-Allocation Design

    • Pre-allocated order pools
    • Reusable message buffers
    • Fixed-point arithmetic (7 decimal precision)
    • Measured: 1–2 allocs/op on the Go matching path (not zero)
  3. Buffer Management

    • Ring buffers for order queues
    • Memory-mapped files for persistence
    • NUMA-aware memory allocation

Network Optimizations

  1. Kernel Bypass

    • DPDK/XDP support for packet processing
    • Zero-copy networking with io_uring
    • TCP_NODELAY for minimal latency
  2. Protocol Efficiency

    • Binary FIX: 60-byte fixed messages
    • Custom binary formats for internal communication
    • Multicast for market data distribution
  3. Connection Management

    • Connection pooling
    • Persistent WebSocket connections
    • Graceful degradation under load

Algorithm Optimizations

  1. Order Matching

    • Red-black trees for price levels
    • Heap-based priority queues for orders
    • O(log n) insertion and deletion
  2. GPU Acceleration

    • Metal NTT kernel (FHE): 23.6× over CPU NTT (N=4096, batch=128)
    • GPU-native deterministic per-book matcher (CGO_ENABLED=1, unified lux-gpu backend, runtime-select CUDA/HIP/Metal; byte-identical to the CPU oracle, parity-verified): up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10); kernels ship prebuilt from luxcpp/dex
    • The default (CGO-off) build matches on CPU: a single hot-book 169 ns match is smaller than integrated-GPU dispatch overhead, so the CPU wins the single-book hot path; the GPU wins at planet scale (one thread per book across millions of books)
  3. Caching Strategy

    • L1: Hot orders in CPU cache
    • L2: Active price levels in memory
    • L3: Historical data in BadgerDB

Benchmarking Results

Engine Operation Throughput Latency
Pure Go (pkg/lx) Match order 2.2M orders/sec 381 ns (1–2 allocs/op)
C++ (single thread) Match order 5.91M orders/sec 169 ns avg (p50 125, p99 292)
C++ (10 threads) Match order 11.88M orders/sec —
C++ Cancel order — 49 ns
GPU per-book (lux-gpu, CGO=1) Match order (parity-verified GPU==CPU) 12.76B (AMD 8060S) / 9.13B (GB10) / 5.60B (M4 Max) / 2.80B (M1 Max); 21.9B two-node —
GPU (Metal) FHE NTT (N=4096, batch=128) 23.6× vs CPU —
Consensus Block finality 1000/sec 1 ms

Production Deployment

  1. Hardware Requirements

    • Minimum: 8 cores, 32GB RAM, NVMe SSD
    • Recommended: 32 cores, 128GB RAM, Optane SSD
    • Optimal: Mac Studio M2 Ultra, 512GB RAM
  2. Scaling Strategy

    • Horizontal: Multiple nodes for different markets
    • Vertical: more cores / NUMA-aware C++ engine for hot markets
    • GPU: FHE (Metal NTT) plus the GPU-native per-book matcher (CGO_ENABLED=1, unified lux-gpu backend, parity-verified GPU==CPU) for planet-scale fan-out across millions of books
  3. Monitoring & Metrics

    • Prometheus for metrics collection
    • Grafana for visualization
    • Custom dashboards for order flow analysis

Testing & Quality Assurance

Test Coverage Status (January 22, 2025)

  • pkg/lx: 39.1% coverage (all tests passing)
  • pkg/mlx: 96.2% coverage (comprehensive MLX testing)
  • Integration Tests: 100% passing
  • Performance Tests: Exceeding all targets by 4.34x
  • Market Data Tests: Alpaca and professional feeds tested
  • X-Chain Tests: Settlement and clearing validated

Test Categories

  1. Unit Tests: Individual component validation
  2. Integration Tests: Multi-component workflows
  3. Performance Tests: Throughput and latency benchmarks
  4. Stress Tests: High-load scenarios
  5. Chaos Tests: Failure recovery validation

CI/CD Pipeline

  • GitHub Actions for automated testing
  • Docker containerization for deployment
  • Semantic versioning with automated releases
  • Multi-platform binary builds (Linux, macOS, Windows)

References

Production Infrastructure

Kubernetes Deployment

The LX includes comprehensive Kubernetes manifests for production deployment:

Production Environment (k8s/production/)

  • StatefulSet: 3-node cluster with anti-affinity rules
  • Services: LoadBalancer for HTTP/WS, ClusterIP for gRPC
  • Ingress: NGINX with SSL termination and WebSocket support
  • Monitoring: ServiceMonitor and PrometheusRule for alerts
  • Autoscaling: HPA (3-9 replicas), VPA, and PodDisruptionBudget
  • Security: NetworkPolicy, Secrets management, TLS certificates

Staging Environment (k8s/staging/)

  • Simplified single-node deployment for testing
  • LoadBalancer service for external access
  • Debug logging enabled

Helm Chart (helm/lxdex/)

Production-ready Helm chart with:

  • Configurable replica count and resource limits
  • External service dependencies (PostgreSQL, Redis, NATS)
  • GPU support for MLX acceleration
  • Prometheus and Grafana monitoring integration
  • Multiple storage class support

Installation:

helm install lxdex ./helm/lxdex \
  --namespace lxdex-production \
  --values values.production.yaml

CI/CD Pipeline

GitHub Actions Workflows

  1. CI Pipeline (.github/workflows/ci.yml)

    • Linting with golangci-lint
    • Security scanning with gosec
    • Multi-platform testing (Ubuntu, macOS)
    • Code coverage reporting
    • Benchmarking
  2. Deploy Pipeline (.github/workflows/deploy.yml)

    • Docker image building (multi-arch)
    • Staging deployment on develop branch
    • Production deployment on tags
    • Automated rollback on failure
    • Slack notifications

Deployment Scripts

Automated Deployment (scripts/deploy.sh):

./deploy.sh staging deploy   # Deploy to staging
./deploy.sh production deploy # Deploy to production
./deploy.sh production rollback # Rollback production

Features:

  • Prerequisites checking
  • Docker image building and pushing
  • Kubectl or Helm deployment
  • Health checks and integration tests
  • Status monitoring and log viewing

Production Checklist

Before deploying to production:

  • All tests passing (unit, integration, E2E)
  • Security scan completed
  • Performance benchmarks met
  • Docker images built and pushed
  • Kubernetes cluster ready
  • SSL certificates configured
  • Monitoring dashboards set up
  • Backup strategy in place
  • Disaster recovery plan documented
  • Load testing completed

Infrastructure Requirements

Minimum Production Setup

  • Kubernetes: v1.25+
  • Nodes: 3x (32 CPU, 128GB RAM, 1TB NVMe)
  • GPU: Optional (NVIDIA A100 or Apple M2 Ultra)
  • Network: 100Gbps interconnect
  • Storage: Fast SSD with 100K+ IOPS
  • Kubernetes: Managed service (EKS, GKE, AKS)
  • Nodes: 9x with GPU acceleration
  • Load Balancer: Global with GeoDNS
  • CDN: CloudFlare or Fastly
  • Monitoring: Full observability stack
  • Backup: Cross-region replication

Latest Updates (January 19, 2025)

Testing Status - 100% Passing ✅

  • Core DEX Tests: All 144 tests passing
  • Test Coverage: Improved from 22.4% to 39.1%
  • Performance: 11.88M orders/sec (C++, 10 threads), 2.2M (pure Go) — CPU default build; GPU-native per-book matcher (CGO_ENABLED=1, lux-gpu, parity-verified GPU==CPU) up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10)
  • Integration: All components fully integrated

Professional Market Data Sources

Successfully integrated professional-grade market data feeds:

  • Alpaca Markets: Real-time equities and crypto
  • NYSE Arca: Direct exchange feeds
  • IEX Cloud: Low-latency market data
  • Polygon.io: Comprehensive aggregation
  • CME Group: Futures and derivatives
  • Refinitiv: Institutional data
  • ICE Data Services: Fixed income
  • Bloomberg B-PIPE: Enterprise data
  • NASDAQ TotalView: Full depth
  • Coinbase Pro: Cryptocurrency

New Features Implemented

  1. Liquidation Engine: Complete with insurance fund, ADL, socialized losses
  2. X-Chain Settlement: On-chain clearing and settlement
  3. Advanced Orders: Iceberg, bracket, hidden orders
  4. Risk Management: Real-time margin monitoring
  5. Market Data Aggregation: Multi-source with latency tracking

SDK Updates

All three SDKs updated with new features:

Go SDK (/sdk/go):

  • market_data.go: Market data client methods
  • Liquidation monitoring
  • Settlement tracking
  • WebSocket subscriptions

Python SDK (/sdk/python):

  • market_data.py: MarketDataClient class
  • LiquidationMonitor for real-time events
  • Type-safe dataclasses
  • Async/await support

TypeScript SDK (/sdk/typescript):

  • marketData.ts: Full TypeScript types
  • MarketDataClient and LiquidationMonitor
  • Promise-based operations
  • WebSocket integration

Price Feed Architecture (pkg/price/)

Multi-source price aggregation for sub-millisecond latency trading with quantum finality verification:

┌─────────────────────────────────────────────────────────────────────┐
│                     LUX DEX PRICE ORACLE                             │
│                                                                       │
│  DEX/AMM Sources:               Oracle Sources:                      │
│  ┌──────────────┐              ┌──────────────┐                     │
│  │  X-Chain     │ Weight: 2.0  │  A-Chain     │ Weight: 1.5         │
│  │ Native DEX   │──┐           │ Validators   │──┐                  │
│  └──────────────┘  │           └──────────────┘  │                  │
│  ┌──────────────┐  │           ┌──────────────┐  │  ┌────────────┐  │
│  │  C-Chain     │  │           │    Pyth      │  │  │  Oracle    │  │
│  │ AMM Pools    │──┤ Weight:   │   Network    │──┼──│ Aggregator │  │
│  │ (Liquid)     │  │  1.8      └──────────────┘  │  │            │──→
│  └──────────────┘  │           ┌──────────────┐  │  │ • Weighted │  │
│  ┌──────────────┐  │           │  Chainlink   │  │  │   Median   │  │
│  │  Zoo Chain   │──┘ Weight:   │   Oracle     │──┘  │ • TWAP/VWAP│  │
│  │  EVM AMM     │     1.7      └──────────────┘     │ • Circuit  │  │
│  │ (Zoo Labs)   │                                   │   Breakers │  │
│  └──────────────┘                                   └────────────┘  │
│                                                            │        │
│  ┌──────────────────────────────────────────────────────────┘        │
│  │                                                                   │
│  ▼                                                                   │
│  ┌────────────────────────────────────────────────────────────────┐  │
│  │  Q-Chain Verifier (NOT a price source)                         │  │
│  │  Verifies quantum finality for prices from other sources:      │  │
│  │  • Post-quantum signatures (dilithium, sphincs+)               │  │
│  │  • Cross-chain order inclusion proofs                          │  │
│  │  • Validator quorum consensus                                  │  │
│  └────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

Price Sources (Ordered by Trust Weight)

Source Weight Type Interval Features
X-Chain 2.0 DEX 50ms Native DEX orderbook, highest trust
C-Chain 1.8 AMM 100ms AMM pools, liquid tokens (LZOO, LETH, etc.)
Zoo Chain 1.7 AMM 100ms Zoo Labs EVM DEX, ZOO token pairs
A-Chain 1.5 Oracle 100ms Validator-attested network oracle
Pyth 1.2 Oracle Real-time External oracle, WebSocket streaming
Chainlink 1.0 Oracle 1s External oracle, reference only

Weight Priority: DEX (native orderbook) > AMM (on-chain pools) > Network Oracles > External Oracles

Note: Q-Chain is NOT a price source. It's a finality verification layer that verifies prices/orders from other sources have achieved quantum finality with post-quantum signatures.

Latency-Adjusted Weighting (Planned):

  • Weights should be dynamically adjusted based on detected latency
  • Lower latency sources get boosted weight for time-sensitive decisions
  • High latency or stale feeds get weight penalties
  • Formula: effective_weight = base_weight * (1 / (1 + latency_ms/100))
// Planned: Adaptive weight calculation based on measured latency
func (s *Source) EffectiveWeight() float64 {
    baseWeight := s.Weight()
    latencyMs := s.MeasuredLatency().Milliseconds()

    // Latency penalty: halve weight for every 100ms of latency
    latencyFactor := 1.0 / (1.0 + float64(latencyMs)/100.0)

    // Staleness penalty: reduce weight if data is old
    age := time.Since(s.LastUpdate())
    staleFactor := math.Max(0.1, 1.0 - float64(age.Seconds())/10.0)

    return baseWeight * latencyFactor * staleFactor
}

Current Static Weights (to be replaced with adaptive):

  • Native X-Chain (50ms) provides fastest updates for trading decisions
  • AMMs (100ms) are reliable for larger trades and reference
  • External oracles (1s+) are reference-only, not for time-sensitive trading

Future External DEX Integrations (Omni-DEX)

Planned cross-chain DEX integrations for comprehensive price discovery:

DEX Chain Type Priority
Uniswap V3 Ethereum AMM P1
SushiSwap Multi-chain AMM P1
Astar Polkadot DEX P2
dYdX Cosmos Perps P2
GMX Arbitrum Perps P2
Raydium Solana AMM P3
Orca Solana AMM P3

This enables true omni-DEX price aggregation across all major chains and protocols.

Liquid Token Pairs (C-Chain AMM)

Real market data from Lux C-Chain AMMs:

Symbol Price (USD) Description
LUX $0.00232 Native Lux token
LZOO $0.000107 Liquid ZOO
LETH $4,078.55 Liquid ETH
LSOL $325.69 Liquid SOL
LUSD $1.00 Lux USD stablecoin
LBTC $124,217.54 Liquid BTC
LTON $10.67 Liquid TON
LAVAX $72.26 Liquid AVAX
LBNB $1,065.75 Liquid BNB
LBLAST $0.0178 Liquid BLAST
LPOL $0.436 Liquid POL

Zoo Chain Token Pairs

Symbol Description
ZOO-USDC Native ZOO token
ZOO-LUX ZOO/LUX cross-chain
LZOO-ZOO Liquid ZOO on Zoo Chain
ETH-ZOO ETH/ZOO ratio
WBTC-ZOO BTC/ZOO ratio

Q-Chain Quantum Finality

Post-quantum cryptographic verification for all price feeds:

type QuantumFinality struct {
    BlockHash   string
    BlockHeight uint64
    StateRoot   string
    Timestamp   time.Time
    Signatures  []QuantumSignature  // dilithium3, dilithium5, sphincs+
    Finalized   bool
    Latency     time.Duration       // ~50ms
}

type QValidator struct {
    Address   string
    PublicKey []byte
    Stake     uint64
    Active    bool
    Algorithm string  // dilithium3, sphincs-sha2-256f, etc.
}

Quantum Signature Algorithms:

  • Dilithium3: Primary lattice-based signatures
  • Dilithium5: High-security variant
  • SPHINCS+: Hash-based backup signatures

Verification Functions:

// Verify order inclusion across chains
qchain.VerifyInclusion(orderID, chain, txHash) (*OrderInclusion, error)

// Verify price was finalized with quantum signatures
qchain.VerifyOrderPrice(symbol, price, chain) bool

// Cross-chain finality verification
qchain.CrossChainVerify([]string{"x-chain", "c-chain", "zoo-chain"}) (bool, map[string]*QuantumFinality)

Symbol Normalization

Unified symbol format across disparate sources:

// All variants normalize to canonical form
"LUX/USD"   → "LUX-USD"
"LUXUSD"    → "LUX-USD"
"LUX-USDC"  → "LUX-USD"
"LUX/USDT"  → "LUX-USD"

// SymbolMap provides bidirectional mapping
symbolMap := price.NewSymbolMap()
normalized := symbolMap.Map("LUX/USDC")     // "LUX-USD"
variants := symbolMap.Reverse("LUX-USD")    // ["LUX-USD", "LUX-USDC", "LUX/USD", ...]

Usage

oracle := price.NewOracle()

// Native Lux chain sources
oracle.AddSource("x-chain", price.NewXChainSource(rpcURL, wsURL))
oracle.AddSource("a-chain", price.NewAChainSource(rpcURL, wsURL))
oracle.AddSource("c-chain", price.NewCChainSource(rpcURL, wsURL))
oracle.AddSource("q-chain", price.NewQChainSource(rpcURL, wsURL))

// Zoo Labs network
oracle.AddSource("zoo-chain", price.NewZooChainSource(rpcURL, wsURL))

// External oracles
oracle.AddSource("pyth", price.NewPythSource(wsURL, apiURL))
oracle.AddSource("chainlink", price.NewChainlinkSource())

// Watch symbols
oracle.Watch("LUX-USD")
oracle.Watch("LZOO-USDC")
oracle.Watch("ZOO-USDC")
oracle.Start()

// Get aggregated price
data, _ := oracle.Data("LUX-USD")
fmt.Printf("Price: $%.6f, Source: %s, Confidence: %.2f\n",
    data.Price, data.Source, data.Confidence)

// Get TWAP/VWAP
twap := oracle.TWAP("LUX-USD")
vwap := oracle.VWAP("LUX-USD")

// Verify quantum finality
qchain := oracle.Source("q-chain").(*price.QChainSource)
allFinalized, finality := qchain.CrossChainVerify([]string{"x-chain", "c-chain", "zoo-chain"})
if allFinalized {
    fmt.Println("QUANTUM finality achieved across all chains")
}

Price Feed CLI

# Run with all sources
go run ./cmd/price-feed

# Specific sources only
go run ./cmd/price-feed -sources xchain,cchain,zoo

# With quantum finality verification
go run ./cmd/price-feed -verify

# Custom symbols and interval
go run ./cmd/price-feed -symbols "LUX-USDC,LZOO-USDC,ZOO-USDC" -interval 100ms -verify

Output with -verify flag:

SYMBOL          PRICE        TWAP         VWAP         CONF       SOURCE     FINALITY   AGE
----------------------------------------------------------------------------------------------------
LUX-USDC        $0.002320    $0.002320    $0.000000    0.70       aggregated QUANTUM    0ms
LZOO-USDC       $0.000107    $0.000107    $0.000000    0.70       aggregated QUANTUM    0ms
LETH-USDC       $4078.550000 $4078.550000 $0.000000    0.70       aggregated QUANTUM    0ms
ZOO-USDC        $0.000150    $0.000150    $0.000000    0.70       aggregated QUANTUM    0ms
Quantum finality latency: 50ms

Features

  • Weighted median aggregation - Outlier resistant with source weights
  • Circuit breakers - Prevent erroneous prices (max change threshold)
  • TWAP/VWAP - 5-minute time and volume weighted averages
  • Health monitoring - Auto-failover on source failure
  • Alert system - Real-time anomaly detection
  • Symbol normalization - Unified format across all sources
  • Quantum finality - Post-quantum signature verification
  • Cross-chain verification - Verify finality across x-chain, c-chain, zoo-chain

Remaining Work

  • Add X-Chain native DEX source
  • Add A-Chain attestation source
  • Add C-Chain AMM with liquid tokens
  • Add Zoo Chain EVM AMM source
  • Add Q-Chain quantum finality verification
  • Symbol normalization layer
  • Adjust weights: DEX > AMM > Attestations > Oracles
  • Implement adaptive latency-based weighting
  • Add Uniswap/SushiSwap/perps-DEX sources (omni-DEX)
  • Add REST API endpoints for price feeds
  • Complete WebSocket real-time streaming
  • Add Prometheus metrics endpoints
  • Create Grafana dashboards

Contact


Last Updated: December 11, 2025 Version: 1.1.0 Performance (Apple M1 Max): 11.88M orders/sec C++ (10 threads), 2.2M Go — CPU default build; GPU-native per-book matcher (CGO_ENABLED=1, lux-gpu, parity-verified GPU==CPU) up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10) / 5.60B (M4 Max) / 2.80B (M1 Max) Test Status: 100% passing Production Ready: Full Kubernetes + Helm deployment Price Feeds: 7 sources with quantum finality verification

COMPREHENSIVE CODE REVIEW: DEX Consensus and Network Layers

Review Date: 2025-12-11
Scope: Consensus (/pkg/consensus/), Network (/pkg/network/), DPDK (/pkg/dpdk/), FPGA (/pkg/fpga/)
Reviewer: AI Architect/CTO Analysis

Executive Summary

Overall Assessment: Architecture shows ambitious design with multiple acceleration technologies (GPU, FPGA, DPDK) but has significant implementation gaps between documented capabilities and actual code.

Risk Level: MEDIUM-HIGH
Recommendation: Requires completion of core components before production deployment


1. CONSENSUS LAYER ANALYSIS

1.1 DAG Consensus Architecture (/pkg/consensus/dag.go)

Implemented Components ✅

LuxDAGOrderBook (Lux Consensus Implementation):

type LuxDAGOrderBook struct {
    *DAGOrderBook
    luxConfig     LuxConsensusConfig
    blsKey        *SecretKey
    corona      *CoronaEngine      // Post-quantum signatures
    quasar        *Quasar              // Dual-certificate protocol
    votes         map[ID]*VoteState
    certificates  map[ID]*QuantumCertificate
    voteThreshold float64              // Adaptive 0.55-0.65
    finalityCount atomic.Uint64
}

Key Features:

  • ✅ DAG vertex structure with parent references
  • ✅ Adaptive vote thresholds (θ_min=0.55, θ_max=0.65)
  • ✅ Quantum-resistant certificates (BLS + Corona hybrid)
  • ✅ Vote state tracking with confidence metrics
  • ✅ FPC (Fast Probabilistic Consensus) rounds

Consensus Protocol Flow

50ms Finality Claim Analysis:

func (lux *LuxDAGOrderBook) RunLuxConsensus() error {
    ticker := time.NewTicker(50 * time.Millisecond)  // 20 rounds/second
    defer ticker.Stop()

    for {
        select {
        case <-ticker.C:
            lux.round++
            _ = lux.runFPCRound(lux.round)
            lux.checkQuantumFinality()
        case <-lux.shutdown:
            return nil
        }
    }
}

Verdict: ✅ 50ms finality is FEASIBLE but depends on:

  1. Network round-trip time < 25ms (half the ticker interval)
  2. Vote collection from K=3 validators in parallel
  3. Quorum threshold met (typically 2/3 = 67%)
  4. No Byzantine behavior detected

Adaptive Threshold Mechanism:

func (lux *LuxDAGOrderBook) runFPCRound(round int) error {
    progress := float64(round) / 10.0
    if progress > 1.0 {
        progress = 1.0
    }
    lux.voteThreshold = lux.luxConfig.ThetaMin +
        (lux.luxConfig.ThetaMax - lux.luxConfig.ThetaMin) * progress
    // Starts at 0.55, converges to 0.65 over 10 rounds (500ms)
}

Critical Issues Found

Issue 1: Mock Implementations ⚠️

// Many cryptographic operations are mocked
func (r *CoronaEngine) Sign(msg []byte, sk []byte) ([]byte, error) {
    sig := make([]byte, 64)  // Returns empty signature!
    return sig, nil
}

func (r *CoronaEngine) Verify(msg []byte, sig []byte, pk []byte) bool {
    if len(sig) != 64 || string(msg) == "Wrong message" {
        return false
    }
    return true  // Always returns true except for literal "Wrong message"
}

Impact: Security NOT production-ready. Needs integration with the actual Corona threshold implementation (github.com/luxfi/corona).

Issue 2: Missing Network Layer Integration ❌

// No actual P2P message passing implemented
func (dob *DAGOrderBook) AddOrder(order *lx.Order) (*OrderVertex, error) {
    // Vertex created but NOT broadcast to network
    vertex := &OrderVertex{...}
    dob.vertices[vertex.ID] = vertex
    // MISSING: Broadcast vertex to peers
    // MISSING: Receive votes from validators
    return vertex, nil
}

Issue 3: Vote Collection Not Implemented ❌

  • No code for querying K validators
  • No vote aggregation mechanism
  • No timeout handling for slow validators

Multi-Node Testing

File: /pkg/consensus/multinode_test.go (692 lines)

Test Coverage:

  • ✅ 3-node consensus with parallel block production
  • ✅ 5-node fault tolerance (node 2 failure simulation)
  • ✅ High throughput stress test (1000+ blocks/sec target)
  • ✅ Byzantine fault tolerance (4 nodes, 1 Byzantine)
  • ✅ Network partition and recovery
  • ✅ Variable block sizes (1KB - 100KB)

Key Test Results:

func TestThreeNodeConsensus(t *testing.T) {
    // Creates 3 nodes, each submits 100 blocks
    // Expects finalized heights within 5 blocks of each other
    // Expects at least 10 blocks finalized
    
    assert.LessOrEqual(t, maxHeight-minHeight, uint64(5),
        "Nodes should have similar finalized heights")
}

Verdict: ✅ Test harness is comprehensive, but tests use mock DAGConsensus not production consensus.


2. NETWORK LAYER ANALYSIS

2.1 Network Package Status

Finding: /pkg/network/ directory DOES NOT EXIST ❌

Searched locations:

find /Users/z/work/lux/dex -name "network" -type d
# Returns: (empty)

Impact: Critical gap in architecture. No P2P networking implementation found.

2.2 Expected Network Protocol Specification

Based on architecture diagrams and whitepaper claims, the network layer should implement:

Message Types

// Expected (NOT FOUND in codebase)
type NetworkMessage struct {
    Type      MessageType     // VERTEX_PROPOSAL, VOTE_REQUEST, VOTE_RESPONSE
    Sender    NodeID          // 32-byte node identifier
    Timestamp uint64          // Unix nanoseconds
    Payload   []byte          // Serialized message
    Signature []byte          // BLS or Corona signature
}

type MessageType uint8
const (
    MSG_VERTEX_PROPOSAL MessageType = 0x01
    MSG_VOTE_REQUEST    MessageType = 0x02
    MSG_VOTE_RESPONSE   MessageType = 0x03
    MSG_CERTIFICATE     MessageType = 0x04
)

State Machine (NOT IMPLEMENTED)

┌─────────────────────────────────────────────────────────┐
│              CONSENSUS STATE MACHINE                     │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  [VERTEX_CREATED]                                       │
│        │                                                │
│        ├──> Broadcast to K validators                   │
│        │                                                │
│        ▼                                                │
│  [WAITING_VOTES]                                        │
│        │                                                │
│        ├──> Collect votes (timeout: 25ms)              │
│        │                                                │
│        ▼                                                │
│  [QUORUM_REACHED] (2/3 threshold)                       │
│        │                                                │
│        ├──> Generate quantum certificate                │
│        │                                                │
│        ▼                                                │
│  [FINALIZED]                                            │
│                                                          │
└─────────────────────────────────────────────────────────┘

Recommendation: Implement network layer as separate package with clear message protocol.


3. DPDK KERNEL BYPASS ANALYSIS

3.1 Implementation Status (/pkg/dpdk/kernel_bypass.go)

Architecture

type KernelBypassEngine struct {
    mode           string   // "dpdk", "xdp", "afpacket", "raw", "bpf"
    socket         int      // Raw socket file descriptor
    bufferSize     int      // 1MB default
    ringBuffer     *RingBuffer
    stats          *Stats
    orderProcessor OrderProcessor
}

Platform Detection ✅

func NewKernelBypassEngine(processor OrderProcessor) (*KernelBypassEngine, error) {
    switch runtime.GOOS {
    case "linux":
        // Try AF_PACKET (zero-copy) → raw sockets
    case "darwin":
        // Try BPF → raw sockets  
    default:
        // Optimized UDP sockets
    }
}

Modes Supported:

  • Linux: AF_PACKET (PACKET_MMAP), raw sockets
  • macOS: BPF (not implemented), raw sockets
  • Fallback: Optimized UDP with large buffers

Performance Claims

From comments (lines 210-216):

// Benchmark results with FPGA acceleration:
// - Order matching latency: 100-500 nanoseconds (10-100x faster than CPU)
// - Network latency: <1 microsecond with kernel bypass
// - End-to-end latency: 1-5 microseconds
// - Throughput: 500M+ orders/second per FPGA

No benchmark backs the "500M+/FPGA" or "100–500 ns" figures — these are aspirational source comments, not measured (see the DPDK/FPGA verdict below).

Critical Issues

Issue 1: Binary Protocol Parsing ⚠️

func (e *KernelBypassEngine) parseOrder(data []byte) *lx.Order {
    if len(data) < 32 {
        return nil
    }
    // Fixed 32-byte format:
    // [8:orderID][8:price][8:size][1:side][7:padding]
    order := &lx.Order{
        ID:    *(*uint64)(unsafe.Pointer(&data[0])),
        Price: *(*float64)(unsafe.Pointer(&data[8])),
        Size:  *(*float64)(unsafe.Pointer(&data[16])),
        Side:  lx.Side(data[24]),
        Type:  lx.Limit,
    }
    return order
}

Concern: Only 32 bytes per order. Missing fields:

  • User ID (authentication)
  • Symbol/market ID
  • Order flags (post-only, reduce-only, STP)
  • Timestamp (replay protection)
  • Signature (integrity)

Issue 2: No DPDK Integration ❌

func initDPDK() error {
    // Initialize DPDK for kernel bypass
    // This would call into DPDK C libraries
    return nil  // NOT IMPLEMENTED
}

Verdict: DPDK claims are ASPIRATIONAL, not implemented.


4. FPGA ACCELERATION ANALYSIS

4.1 FPGA Interface (/pkg/fpga/fpga_interface.go)

Device Types Supported

type FPGAType int
const (
    FPGATypeNone FPGAType = iota
    FPGATypeAMDVersal      // AMD Versal VCK190 (AI engine)
    FPGATypeAWSF2          // AWS EC2 F1.2xlarge
    FPGATypeIntelStratix   // Intel Stratix 10 GX
    FPGATypeXilinxAlveo    // Xilinx Alveo U250
)

Wire Protocol Specification ✅

Fixed-size binary messages (lines 56-63):

const (
    OrderWireSize  = 48  // 48 bytes per order
    AckWireSize    = 32  // 32 bytes per acknowledgment
    CancelWireSize = 24  // 24 bytes per cancel
    TradeWireSize  = 64  // 64 bytes per trade
)

Order Format (48 bytes):

type FPGAOrder struct {
    Symbol    [8]byte  // Fixed-length symbol
    OrderID   uint64   // 8 bytes
    Price     uint64   // 8 bytes - fixed-point (8 decimals)
    Quantity  uint64   // 8 bytes
    Side      uint8    // 1 byte (0=buy, 1=sell)
    OrderType uint8    // 1 byte (0=limit, 1=market, 2=stop)
    Flags     uint16   // 2 bytes
    Timestamp uint64   // 8 bytes - Unix nanoseconds
    UserID    uint32   // 4 bytes
    // Total: 48 bytes (cache-line aligned)
}

Verdict: ✅ Wire protocol is well-designed for FPGA processing (fixed-size, aligned).

FPGA Manager Implementation

File: /pkg/fpga/fpga_interface.go (259 lines)

Key Features:

  • ✅ Device multiplexing (multiple FPGAs)
  • ✅ Round-robin load balancing
  • ✅ Batch processing support
  • ✅ Health monitoring
  • ✅ Temperature/power tracking

Manager Operations:

func (m *FPGAManagerImpl) ProcessOrder(order *FPGAOrder) (*FPGAResult, error) {
    // Round-robin load balancing
    selectedID := deviceIDs[m.roundRobin % len(deviceIDs)]
    device := m.devices[selectedID]
    
    start := time.Now()
    result, err := device.ProcessOrder(order)
    latency := time.Since(start).Nanoseconds()
    
    // Update statistics
    stats.AverageLatencyNs = (stats.AverageLatencyNs + uint64(latency)) / 2
    return result, err
}

Critical Issues

Issue 1: Stub Implementations ❌

All device types return errors:

// In fpga_engine.go:
func programVersalFPGA(device *FPGADevice) error {
    // Program AMD Versal FPGA
    return nil  // NOT IMPLEMENTED
}

func programAWSF2FPGA(device *FPGADevice) error {
    // Program AWS F2 instance FPGA
    return nil  // NOT IMPLEMENTED
}

Issue 2: DMA Transfers Not Implemented ❌

type FPGAAccelerator interface {
    AllocateDMABuffer(size int) (uintptr, error)
    FreeDMABuffer(addr uintptr) error
    DMATransfer(src, dst uintptr, size int, direction DMADirection) error
}
// No implementations found

Verdict: FPGA interface is specification-only, no hardware integration.


5. LP-9003 COMPLIANCE CHECK

5.1 LP-9003 Requirements

Lux Proposal 9003: High-Performance DEX with MEV Protection

Required Features:

  1. ✅ GPU-accelerated matching — GPU-native deterministic per-book matcher (pkg/lx/orderbook_gpu.go, CGO_ENABLED=1, unified lux-gpu backend, runtime-select CUDA/HIP/Metal; byte-identical to MatchOrderCPU, parity-verified); the default CGO-off build matches on CPU
  2. ❌ Commit-reveal MEV protection
  3. ⚠️ Cross-chain settlement

5.2 GPU Acceleration Status

File: /pkg/mlx/mlx.go (does not exist — see Verdict below)

MLX Engine (Apple Silicon GPU):

type MLXEngine struct {
    device       mlx.Device
    orderBuffer  mlx.Buffer     // GPU memory
    resultBuffer mlx.Buffer
    kernel       mlx.Kernel     // GPU matching kernel
}

func (e *MLXEngine) ProcessOrdersGPU(orders []*Order) ([]*Trade, error) {
    // Copy orders to GPU memory
    e.orderBuffer.CopyFromHost(unsafe.Pointer(&orders[0]), len(orders))
    
    // Launch GPU kernel (matching happens in parallel on GPU cores)
    e.kernel.Launch(len(orders))
    
    // Copy results back
    e.resultBuffer.CopyToHost(unsafe.Pointer(&trades[0]), maxTrades)
    
    return trades, nil
}

Performance (measured, Apple M1 Max):

  • CPU (Go, pkg/lx): 2.2M orders/sec, 381 ns/order, 1–2 allocs/op
  • CPU (C++): 11.88M orders/sec (10 threads), 5.91M single-thread, 169 ns avg match
  • GPU (MLX) matching: the prior "434M orders/sec" was a fabrication — it came from a pure-Go simulation (archive/_lp108-2026-05-04/mlx_engine.go, hardcoded OrdersPerSecond: 1000000.0), not a Metal kernel; there is no pkg/mlx.
  • GPU-native per-book matcher (real): pkg/lx/orderbook_gpu.go (+pkg/lxgpu/), CGO_ENABLED=1, unified lux-gpu backend (runtime-select CUDA > HIP > Metal > CPU), byte-identical to MatchOrderCPU and parity-verified (pkg/lxgpu/orderbook_parity_test.go, three_mode_parity_test.go) — up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10) / 5.60B (M4 Max) / 2.80B (M1 Max); 21.9B on a two-node fabric. Kernels ship prebuilt from luxcpp/dex.

Verdict: There is no MLX/pkg/mlx matcher and the "434M orders/sec" figure is debunked. A separate, real GPU-native deterministic per-book matcher DOES exist (pkg/lx/orderbook_gpu.go via the unified lux-gpu backend, parity-verified GPU==CPU), available with CGO_ENABLED=1; the default CGO-off build matches on CPU. The GPU also drives FHE (Metal NTT, 23.6× at N=4096, batch=128).

5.3 MEV Protection Analysis

Expected: Commit-reveal scheme to prevent front-running

Searched codebase:

grep -r "commit.*reveal\|MEV\|front.*run" /Users/z/work/lux/dex/pkg
# No matches found

Finding: ❌ NO MEV PROTECTION implemented.

Recommendation: Implement 2-phase commit:

// Phase 1: Commit (hash of order)
type OrderCommitment struct {
    CommitHash [32]byte  // SHA256(orderID || price || size || nonce || signature)
    Timestamp  uint64
}

// Phase 2: Reveal (actual order after N blocks)
type OrderReveal struct {
    Order     *Order
    Nonce     uint64
    Signature []byte
}

5.4 Cross-Chain Settlement

File: /pkg/lx/bridge.go (exists but not reviewed in detail)

Status: ⚠️ Bridge implementation exists but needs separate review.


6. IETF-STYLE PROTOCOL DOCUMENTATION

6.1 Message Formats

FPGA Wire Protocol (Binary)

Order Message (48 bytes):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Symbol (8 bytes)                        |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Order ID (8 bytes)                       |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Price (8 bytes)                         |
|                      Fixed-point, 8 decimals                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Quantity (8 bytes)                        |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|S|T|   Flags   |                Timestamp (8 bytes)            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       User ID (4 bytes)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Where:
  S = Side (1 bit): 0=Buy, 1=Sell
  T = Type (1 bit): 0=Limit, 1=Market
  Flags = 14 bits for order flags

Acknowledgment Message (32 bytes):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Order ID (8 bytes)                       |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Status  |RejectCode|           Reserved (6 bytes)           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Timestamp (8 bytes)                       |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Sequence Number (8 bytes)                   |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Status: 0=Accepted, 1=Rejected, 2=Cancelled
RejectCode: Reason if status=Rejected

6.2 State Machines

Order Lifecycle State Machine

                  ┌──────────────┐
                  │   CREATED    │
                  └──────┬───────┘
                         │
                         ▼
          ┌──────────────┴──────────────┐
          │                             │
          ▼                             ▼
  ┌──────────────┐            ┌──────────────┐
  │   PENDING    │            │   REJECTED   │
  └──────┬───────┘            └──────────────┘
         │
         ├──> OPEN (in order book)
         │
         ├──> PARTIAL_FILL
         │         │
         │         └──> FILLED
         │
         └──> CANCELLED

Transitions:
- CREATED → PENDING: Order submitted to network
- PENDING → REJECTED: Validation failure
- PENDING → OPEN: Passed validation, added to book
- OPEN → PARTIAL_FILL: Matched partially
- PARTIAL_FILL → FILLED: Fully matched
- OPEN/PARTIAL_FILL → CANCELLED: User cancellation

Consensus State Machine

┌────────────────────────────────────────────────────────────────┐
│                   CONSENSUS PROTOCOL                           │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  [VERTEX_PROPOSED]                                             │
│        │                                                       │
│        ├──> Broadcast to K validators                          │
│        │    (Multicast via QZMQ)                               │
│        │                                                       │
│        ▼                                                       │
│  [COLLECTING_VOTES]                                            │
│        │                                                       │
│        ├──> Wait for 2/3 votes (timeout: 25ms)                │
│        │                                                       │
│        ├──> If timeout: retry or skip                         │
│        │                                                       │
│        ▼                                                       │
│  [QUORUM_REACHED]                                              │
│        │                                                       │
│        ├──> Generate BLS aggregate signature                  │
│        ├──> Generate Corona quantum signature               │
│        ├──> Create QuantumCertificate                         │
│        │                                                       │
│        ▼                                                       │
│  [CERTIFIED]                                                   │
│        │                                                       │
│        ├──> Broadcast certificate to network                  │
│        │                                                       │
│        ▼                                                       │
│  [FINALIZED]                                                   │
│        │                                                       │
│        └──> Update finalized height                           │
│                                                                │
└────────────────────────────────────────────────────────────────┘

6.3 Timing Requirements

Performance Targets (from whitepaper):

Operation Target Achieved Status
Network round-trip <1μs TBD ⚠️
Consensus finality 50ms TBD ⚠️
Block propagation <25ms TBD ⚠️

Critical Timing Constraints:

Total Finality Time = 50ms
├─ Round-trip to K validators: 25ms (50%)
├─ Vote collection: 10ms (20%)
├─ Certificate generation: 10ms (20%)
└─ Block propagation: 5ms (10%)

6.4 Security Considerations

Threat Model

Byzantine Validators:

  • Assumption: Up to f < N/3 validators are Byzantine
  • Protection: 2/3 quorum threshold (67%)
  • Detection: Conflicting votes, invalid signatures

Network Attacks:

  • DDoS: Rate limiting at gateway layer
  • Eclipse: Minimum peer connections (3-5)
  • Sybil: Stake-based admission (1M LUX minimum)

MEV Attacks:

  • Front-running: ❌ NOT PROTECTED (needs commit-reveal)
  • Sandwich attacks: ❌ NOT PROTECTED
  • Time-bandit attacks: ⚠️ Mitigated by fast finality (50ms)

Quantum Threats:

  • Key compromise: ✅ Protected by Corona (post-quantum)
  • Signature forgery: ✅ Protected by lattice-based crypto
  • Future attacks: ✅ Hybrid BLS+Corona provides transition path

7. CRITICAL FINDINGS SUMMARY

7.1 Architecture Strengths ✅

  1. Multi-engine design allows performance optimization per deployment
  2. GPU acceleration: FHE (Metal NTT, 23.6× at N=4096, batch=128) plus a real GPU-native deterministic per-book matcher (CGO_ENABLED=1, unified lux-gpu backend, parity-verified GPU==CPU) up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10); the default CGO-off build matches on CPU
  3. FPGA wire protocol is well-designed for hardware acceleration
  4. Test coverage is comprehensive (multi-node, Byzantine, partition tests)
  5. Quantum-resistant crypto architecture is sound (BLS+Corona hybrid)

7.2 Critical Gaps ❌

  1. No P2P network layer - /pkg/network/ does not exist
  2. Mock cryptographic implementations - Corona not integrated
  3. No vote collection mechanism - Consensus cannot finalize
  4. DPDK not implemented - Kernel bypass claims are aspirational
  5. FPGA integration missing - All device drivers are stubs
  6. MEV protection absent - No commit-reveal scheme
  7. No message protocol specification - Vertex/vote wire formats undefined

7.3 Implementation Priority List

P0 (Blocking):

  1. Implement P2P network layer with QZMQ/ZeroMQ
  2. Integrate real Corona signatures from threshold package
  3. Implement vote collection and aggregation
  4. Define and implement network message protocol

P1 (Required for Production): 5. Add MEV protection (commit-reveal) 6. Complete DPDK kernel bypass (Linux only acceptable) 7. Add comprehensive network fault injection tests 8. Implement Byzantine behavior detection

P2 (Performance Optimization): 9. FPGA device drivers (AMD Versal, AWS F2) 10. RDMA integration for state replication 11. Advanced order types (iceberg, pegged, TWA P) 12. Cross-chain bridge security audit

7.4 50ms Finality Feasibility Assessment

Theoretical Analysis:

  • Single consensus round: 50ms
  • Network latency budget: 25ms (50%)
  • Vote processing: 10ms (20%)
  • Certificate generation: 10ms (20%)
  • Propagation overhead: 5ms (10%)

Network Assumptions:

  • Validators in same datacenter: RTT <1ms ✅
  • Validators in same region: RTT <5ms ✅
  • Cross-continental: RTT 100-200ms ❌

Verdict: ✅ 50ms finality is ACHIEVABLE in single-region deployment with optimized network stack.

Realistic Targets:

  • Same datacenter: 10-20ms finality
  • Same region: 50-100ms finality
  • Global: 200-500ms finality

8. RECOMMENDATIONS

8.1 Immediate Actions

  1. Create /pkg/network/ package with:

    • QZMQ transport layer
    • Message serialization (protobuf or custom binary)
    • Peer management and health checking
    • Retransmission and timeout logic
  2. Integrate Corona crypto from github.com/luxfi/corona:

    • Replace mock Sign() and Verify() implementations
    • Test quantum certificate generation end-to-end
    • Benchmark signature performance (target: <1ms)
  3. Implement vote collection:

    • Parallel vote requests to K validators
    • Timeout handling (25ms)
    • Vote verification and aggregation
    • Quorum detection (2/3 threshold)

8.2 Code Quality Improvements

Add comprehensive error handling:

// Current (bad):
func (e *Engine) Process() {
    result := doSomething()
    // No error check!
}

// Recommended:
func (e *Engine) Process() error {
    result, err := doSomething()
    if err != nil {
        return fmt.Errorf("process failed: %w", err)
    }
    return nil
}

Add metric instrumentation:

import "github.com/luxfi/metric"

var (
    consensusLatency = metric.NewHistogram(...)
    voteCount = metric.NewCounter(...)
    byzantineDetected = metric.NewCounter(...)
)

8.3 Documentation Improvements

  1. Add IETF-style RFC for network protocol
  2. Document all message formats with packet diagrams
  3. Add sequence diagrams for consensus protocol
  4. Document Byzantine behavior detection logic
  5. Add runbook for operators (monitoring, troubleshooting)

9. CONCLUSION

The LX architecture shows ambitious vision with cutting-edge technologies (DAG consensus, quantum resistance, GPU/FPGA acceleration), but has significant implementation gaps that prevent production deployment.

Core Strength: matching engine — C++ at 11.88M orders/sec (10 threads, 169 ns avg match) and pure Go at 2.2M orders/sec on the default CPU build, plus a GPU-native deterministic per-book matcher (CGO_ENABLED=1, unified lux-gpu backend, parity-verified GPU==CPU) up to 12.76B ord/s (AMD 8060S) / 9.13B (GB10). GPU also drives FHE (Metal NTT, 23.6×).

Critical Blocker: Network layer and consensus protocol are incomplete. The 50ms finality claim is architecturally sound but requires network implementation to validate.

Estimated Completion Time:

  • P0 tasks (network layer, crypto integration): 4-6 weeks
  • P1 tasks (MEV protection, testing): 2-3 weeks
  • P2 tasks (FPGA, RDMA): 8-12 weeks

Overall Risk: MEDIUM-HIGH until network layer is complete.


End of Code Review
Next Steps: Prioritize P0 tasks, create network package, integrate Corona crypto.


Code Review Summary (2025-12-12)

A comprehensive code review was conducted focusing on compound word usage, code duplication, error handling, API surface area, and test coverage. Full details in CODE_REVIEW_2025-12-12.md.

Key Findings

Critical Issues:

  1. Compound Word Overuse - 30+ compound identifiers found (OrderBook, TradingEngine, ClearingHouse, etc.). Recommend decomposition to simpler names following Go conventions.
  2. Error Handling Inconsistency - Mix of sentinel errors and string-based errors. Need standardization across 218+ error sites.

Major Concerns: 3. SDK Duplication - Identical logic implemented 3x (Go/TS/Python). Recommend gRPC service to eliminate duplication. 4. API Surface Area - 24+ public methods on OrderBook with redundancies. Recommend reduction to minimal interface.

Test Coverage: 75.3% (good baseline, needs edge case improvement)

Overall Assessment: Production-ready with Medium risk level. Approve with recommended changes.

Priority Actions

  1. Begin compound word deprecation cycle (type aliases → migration → removal)
  2. Standardize error handling with sentinel errors
  3. Extract SDK business logic to shared gRPC service
  4. Reduce OrderBook API surface area

Estimated Effort: 2-3 sprints for high priority fixes, 1-2 quarters for complete refactoring.

See CODE_REVIEW_2025-12-12.md for detailed recommendations with file:line references.


pkg/trading is gone — the surface it described lives in pkg/gateway

There were two implementations of one trading API in this repo, and neither one was mounted by the binary that shipped.

pkg/trading carried its own Venue interface, its own V4Venue, NativeDEXVenue, UniswapV2Venue, UniswapV3Venue and broker venues, its own constant-product math and its own eth_call client — all of it a copy of what pkg/gateway already had. Its RegisterRoutes was called by its own tests and by nothing else: grep -rn 'luxfi/dex/pkg/trading' --include='*.go' . outside that directory returned empty. api/openapi.yaml documented it anyway, so the one published contract in the repo described the one package no binary served.

The surface it described — quote, swap, order, approval, venues — is what pkg/gateway serves under /v1/trade, and api/openapi.yaml now describes that. The old package is at ~/work/_archive/dex-duplicate-surfaces/, with the /trading/* compat handlers and their Uniswap-shaped types.

Read this before adding a venue. One Venue interface, in pkg/gateway/venue.go. One place that says which contracts a chain is read from, DefaultChainVenues in venue_chains.go. One route table, Server.routes(). A second copy of any of them is how this happened.

The C↔D seam: how a cross-chain swap becomes a trade

The shared-memory object between the C-Chain (0x9999 precompile) and this D-Chain has two canonical widths, and width is the discriminator:

Width What it is Who writes it Decoder
69 B a value object — rail|owner|asset|amount|spent D→C settlements, C→D LP commits decodeSeamObject
118 B a C→D swap intent — value + market|side|limitPrice|size 0x9999 SubmitSwapIntent decodeSeamIntentObject

A value says what moves; only an intent says what to do with it. Before the operation segment existed, executeImport credited the taker and stopped — nothing placed an order, so nothing crossed, so nothing was ever exported back to C. Anything that is neither width is refused, never reinterpreted.

Cross-repo pins (the two repos cannot import each other): precompile/dex/native_seam_parity_test.go and dex/pkg/dchain/seam_reproducible_test.go hold the same golden hex for the 118-byte object, and both pin SeamPendingTrait = sha256("lux.dex.native.intent.pending.v2").

The three legs

BuildBlock enumerates shared memory by SeamPendingTrait
  ├─ TxImport(intentID, object[118])   consume + credit seamAccount(intentID)
  ├─ TxIntentSubmit(intentID)          derive the zapwire Submit from the escrow,
  │                                    run the SAME custody→match→settle path a
  │                                    signed dex_submit takes
  └─ (next block) TxExport × n         proceeds + leftover back to C

TxIntentSubmit is the object-authorized sibling of TxSubmit, exactly as TxImport is of TxDeposit. It cannot be a plain TxSubmit: that type's requiresAuth() is true and weakening it would let any unsigned submit move any account's funds.

Two rules that are easy to get wrong

  1. Never sm.Get inside execute(). The object's bytes ride in the TxImport body; Block.verifySeamImports (gated on vm.normalOp) authenticates them against shared memory at Verify. Reading shared memory during execution makes the block unreplayable — the consuming Remove lands at Accept, so the next node to sync finds the object gone and dies on execution root mismatch.
  2. The seam runs in seamAccount(intentID), never the taker's own account. The export drive settles an account's whole balance back to C; sharing the account with the taker's native D balance means exporting value the seam never backed, which C credits out of the shared seam reserve — a raid on other takers' pooled input.

seamIntentRecord.Status (open → submitted → reclaimed) is the state machine. The export drive gates on submitted, a recorded fact, not on "does the account hold some other asset?" — that inference could never export a zero-fill swap, which stranded the principal on D while C's deadline reclaim paid the taker a second time.

Flag day

The intent object (69→118) and the TxImport body (32→150) both changed width. An old node's bodySize(TxImport) is 32, so a new seam block fails parseTxFrame → decodeTxList → ParseBlock: it is rejected as unparseable, so an old node never computes a state root for it and cannot compute a different one. Mixed fleets stall; they cannot fork. No historical block anywhere contains a TxImport, so there is no retroactive effect. Upgrade every D validator before the first v2 intent is minted on C.

D-Chain HTTP surface — and how to read a 404

CreateHandlers mounts /v1/chain/D/dex/<method> (ingest.go). The method names were clob_* up to dex v1.5.x and dex_* after (commit 28970d8). So on a fleet running an older plugin:

/v1/chain/d/dex/dex_get_markets   -> 404   (new names, not deployed)
/v1/chain/d/dex/clob_get_markets  -> 200   (old names, live)

A 404 on dex_* means "old method names", not "no surface" and not "dead chain". Probe clob_* before concluding anything, and check what the deployed plugin actually vendors rather than trusting DEX_REF in luxfi/node's Dockerfile — the running image can predate the pin:

kubectl exec <pod> -c luxd -- sh -c \
  "grep -a -oE 'luxfi/dex.v[0-9]+[.][0-9]+[.][0-9]+' /data/plugins/mDVT5EW..."

A D-Chain on dex < v1.14 has no atomic.go and no drive.go at all: it cannot import a C->D intent or export a D->C fill under any configuration. That is a structurally absent seam, not a misconfiguration.

D-Chain genesis changed between dex v1.5.x and v1.14.x

A fleet carrying a v1.5 D-Chain store cannot be joined by a v1.14 node. The two lineages derive different genesis blocks, so they disagree at height 0 and no amount of syncing fixes it:

dex v1.5.15  genesis  MuetnVSbs1UnPUDTH5q4kgbKcfRx97Djmz...  root f8e013a4...
dex v1.14.x  genesis  mpxP6xF3ahpjdwP6YgjtagSWQCZSR6pziE...  root 92ae9d5c...

Nodes that keep their old store carry the v1.5 genesis and keep working; a node whose store is wiped (or any newly added validator) adopts the v1.14 genesis and is stranded at height 0 forever, isBootstrapped:false, with no error that names the cause.

So the v1.5 -> v1.14 bump is a D-Chain re-genesis, not an upgrade. Roll it as one: wipe /data/chainData/network-<id>/<D-chain-id> on every validator as part of the rollout, one node at a time. Do it while D is at height 0 and there is nothing to lose. Verify afterwards that all validators report the same lastAccepted — a matching height is not enough, since every node reports height 0 either way.

Getting liquidity onto D

A seam order is IOC — it never rests — so a cross-chain swap can only trade against a signed maker order. Funding one needs either:

  • TxDeposit, which requires depositAuthority in the D chain-config (/data/configs/chains/D/config.json, schema in zapingest.go). It is a consensus parameter: every validator must carry the byte-identical value or they fork on deposit authorization. Empty (the default) rejects every deposit, fail-closed.
  • or a C->D atomic import — which funds a per-intent seamAccount that no signature can authorize, so it cannot place a resting order.

So a devnet trade proof needs the deposit authority configured first.