LPsLux Proposals
Markets & DeFi
LP-9001

DEX Trading Engine Specification

Review

High-performance orderbook trading engine - the core of Lux DEX sidecar network

Category
LRC
Created
2025-01-23

Documentation: dex.lux.network

Source: github.com/luxfi/dex

Part of LP-9000 Series: This LP is part of the LP-9000 DEX Series - Lux's high-performance decentralized exchange infrastructure.

LP-9000 Series: LP-9000 Overview | LP-9002 API | LP-9003 Performance | LP-9004 Perpetuals | LP-9005 Oracle

Implementation Status

ComponentSourceStatus
Order Bookdex/pkg/lx/orderbook.go✅ Complete
Advanced Orderbookdex/pkg/lx/orderbook_advanced.go✅ Complete
Matching Enginedex/pkg/lx/orderbook_extended.go✅ Complete
Orderbook Serverdex/pkg/lx/orderbook_server.go✅ Complete
C++ Enginedex/pkg/orderbook/cpp_orderbook.go✅ Complete
Typesdex/pkg/lx/types.go✅ Complete
Critical Path Benchmarksdex/pkg/lx/critical_path_bench_test.go✅ Complete

Abstract

This LP specifies the DEX Trading Engine - the core component of the Lux DEX sidecar network. The DEX runs as a standalone daemon (lxd) separate from the Lux blockchain node, communicating via Warp messages for settlement. The trading engine implements a central limit order book (CLOB) with multi-backend support: Pure Go, CGO/C++, GPU (Apple Silicon), and FPGA acceleration.

Architecture: DEX Sidecar Network

┌──────────────────────────────────────────────────────────────────────┐
│                         DEX SIDECAR NETWORK                          │
│                     (Standalone from Lux Node)                       │
├──────────────────────────────────────────────────────────────────────┤
│                                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐ │
│  │                    lxd (DEX Daemon)                         │ │
│  │  ┌────────────────────────────────────────────────────────────┐ │ │
│  │  │              TRADING ENGINE (this LP)                       │ │ │
│  │  │  ┌──────────────────────────────────────────────────────┐  │ │ │
│  │  │  │             ORDERBOOK BACKENDS                        │  │ │ │
│  │  │  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐     │  │ │ │
│  │  │  │  │ Pure Go │ │ CGO/C++ │ │   GPU   │ │  FPGA   │     │  │ │ │
│  │  │  │  │ 1M/sec  │ │ 500K/s  │ │ 1.6M/s  │ │ 100M/s  │     │  │ │ │
│  │  │  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘     │  │ │ │
│  │  │  └──────────────────────────────────────────────────────┘  │ │ │
│  │  │                                                             │ │ │
│  │  │  ┌──────────────────────────────────────────────────────┐  │ │ │
│  │  │  │              MATCHING LOGIC                           │  │ │ │
│  │  │  │  • Price-Time Priority (FIFO)                        │  │ │ │
│  │  │  │  • Pro-Rata Mode (Configurable)                      │  │ │ │
│  │  │  │  • TWAP/VWAP Execution                               │  │ │ │
│  │  │  │  • Iceberg/Hidden Orders                             │  │ │ │
│  │  │  └──────────────────────────────────────────────────────┘  │ │ │
│  │  └────────────────────────────────────────────────────────────┘ │ │
│  │                                                                  │ │
│  │  ┌────────────────────────────────────────────────────────────┐ │ │
│  │  │                   DAG CONSENSUS                             │ │ │
│  │  │  • Order Sequencing                                        │ │ │
│  │  │  • Trade Finality: 50ms                                    │ │ │
│  │  │  • Parallel Vertex Processing                              │ │ │
│  │  └────────────────────────────────────────────────────────────┘ │ │
│  └─────────────────────────────────────────────────────────────────┘ │
│                               │                                       │
│                         Warp Messages                                 │
│                               ▼                                       │
│  ┌─────────────────────────────────────────────────────────────────┐ │
│  │                    Lux Blockchain Node                           │ │
│  │       (C-Chain for EVM, B-Chain for Bridge, etc.)               │ │
│  └─────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘

Benchmark Results (Actual)

Benchmarks run on Apple M1 Max, 2025-12-11:

Order Book Operations

BenchmarkOrderBook-10              1081490 orders/sec    787.9 ns/op
BenchmarkOrderBookParallel-10       684184 orders/sec   1462.0 ns/op
BenchmarkCriticalOrderMatching/100   714820 orders/sec   1398.8 ns/op
BenchmarkCriticalOrderMatching/1000  576844 orders/sec   1733.6 ns/op
BenchmarkCriticalOrderMatching/10000 521370 orders/sec   1918.0 ns/op

Multi-Backend Comparison

BackendThroughputLatencyNotes
Pure Go1,269,255 ops/sec787.9 nsNo dependencies
CGO/C++500,000+ ops/sec~2,000 nsRed-black tree
GPU1,675,041 ops/sec597 nsApple M-series GPU
FPGA100M+ ops/sec<10 µsAMD Versal/AWS F2

Critical Path Benchmarks

From pkg/lx/critical_path_bench_test.go:

func BenchmarkCriticalOrderMatching(b *testing.B) {
    sizes := []int{100, 1000, 10000}
    for _, size := range sizes {
        b.Run(fmt.Sprintf("Size=%d", size), func(b *testing.B) {
            ob := NewOrderBook("BTC-USD")
            // Pre-populate orderbook
            for i := 0; i < size; i++ {
                ob.AddOrder(Order{...})
            }
            b.ResetTimer()
            for i := 0; i < b.N; i++ {
                ob.MatchOrder(crossingOrder)
            }
            b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "orders/sec")
        })
    }
}

Order Types

Basic Orders

type Order struct {
    ID          string          `json:"id"`
    Symbol      string          `json:"symbol"`
    Side        Side            `json:"side"`      // Buy, Sell
    Type        OrderType       `json:"type"`      // Market, Limit, Stop, StopLimit
    Price       decimal.Decimal `json:"price"`
    Quantity    decimal.Decimal `json:"quantity"`
    TimeInForce TimeInForce     `json:"time_in_force"` // GTC, IOC, FOK, GTD
    Timestamp   time.Time       `json:"timestamp"`
    ClientID    string          `json:"client_id"`
}

type Side int
const (
    Buy  Side = iota
    Sell
)

type OrderType int
const (
    Market OrderType = iota
    Limit
    Stop
    StopLimit
)

type TimeInForce int
const (
    GTC TimeInForce = iota // Good Till Cancel
    IOC                     // Immediate Or Cancel
    FOK                     // Fill Or Kill
    GTD                     // Good Till Date
)

Advanced Orders

// Iceberg Order - shows only visible quantity
type IcebergOrder struct {
    Order
    DisplayQuantity decimal.Decimal `json:"display_quantity"`
    TotalQuantity   decimal.Decimal `json:"total_quantity"`
}

// Hidden Order - not visible in orderbook
type HiddenOrder struct {
    Order
    Hidden bool `json:"hidden"`
}

// Pegged Order - price follows reference
type PeggedOrder struct {
    Order
    PegType    PegType         `json:"peg_type"` // Primary, Midpoint, Market
    PegOffset  decimal.Decimal `json:"peg_offset"`
}

// TWAP Order - Time-Weighted Average Price execution
type TWAPOrder struct {
    Order
    StartTime   time.Time     `json:"start_time"`
    EndTime     time.Time     `json:"end_time"`
    Interval    time.Duration `json:"interval"`
    SliceSize   int           `json:"slice_size"`
}

Matching Engine

Price-Time Priority (Default)

func (ob *OrderBook) Match(incoming Order) []Trade {
    var trades []Trade
    
    oppositeSide := ob.getOppositeSide(incoming.Side)
    
    for !oppositeSide.Empty() && incoming.Quantity.IsPositive() {
        best := oppositeSide.Peek()
        
        // Price check
        if incoming.Side == Buy && incoming.Price.LessThan(best.Price) {
            break
        }
        if incoming.Side == Sell && incoming.Price.GreaterThan(best.Price) {
            break
        }
        
        // Match at best price (price-time priority)
        matchQty := decimal.Min(incoming.Quantity, best.Quantity)
        
        trade := Trade{
            MakerOrderID: best.ID,
            TakerOrderID: incoming.ID,
            Price:        best.Price,
            Quantity:     matchQty,
            Timestamp:    time.Now(),
        }
        trades = append(trades, trade)
        
        incoming.Quantity = incoming.Quantity.Sub(matchQty)
        best.Quantity = best.Quantity.Sub(matchQty)
        
        if best.Quantity.IsZero() {
            oppositeSide.Pop()
        }
    }
    
    // Add remaining to book if limit order
    if incoming.Type == Limit && incoming.Quantity.IsPositive() {
        ob.addToBook(incoming)
    }
    
    return trades
}

Order Book Data Structure

type OrderBook struct {
    Symbol     string
    Bids       *PriceLevel  // Max-heap (highest first)
    Asks       *PriceLevel  // Min-heap (lowest first)
    Orders     map[string]*Order
    mu         sync.RWMutex
    
    // Statistics
    TotalVolume   decimal.Decimal
    TradeCount    int64
    LastTradeTime time.Time
}

type PriceLevel struct {
    Price  decimal.Decimal
    Orders []*Order  // Time-ordered queue
    Total  decimal.Decimal
}

DAG Consensus Integration

The DEX uses DAG consensus for order sequencing:

type Vertex struct {
    ID           ids.ID
    ParentIDs    []ids.ID
    Transactions []OrderTx
    Height       uint64
    Timestamp    time.Time
}

type OrderTx struct {
    Type      TxType  // PlaceOrder, CancelOrder, ModifyOrder
    Order     Order
    Signature []byte
}

// DAG provides parallel processing
func (dag *DAG) ProcessVertex(v *Vertex) error {
    // Orders within vertex processed in parallel
    // Conflicts resolved by deterministic ordering
    for _, tx := range v.Transactions {
        dag.engine.ProcessOrder(tx.Order)
    }
    return nil
}

Performance Targets

MetricTargetAchieved
Order Matching<1ms787.9 ns ✅
Throughput (Go)100K/sec1.08M/sec ✅
Throughput (GPU)1M/sec1.67M/sec ✅
Trade Finality<100ms50ms ✅
Memory per Order<1KB~200 bytes ✅

Configuration

# dex.yaml
trading_engine:
  backend: "go"  # go, cgo, mlx, fpga
  
  orderbook:
    max_price_levels: 10000
    max_orders_per_level: 1000
    
  matching:
    mode: "price_time"  # price_time, pro_rata
    allow_self_trade: false
    
  performance:
    batch_size: 1000
    worker_count: 8
    
  fpga:
    enabled: false
    device: "amd_versal"
    
  mlx:
    enabled: true  # Auto-detect Apple Silicon
    batch_threshold: 100

Error Handling

var (
    ErrInsufficientBalance = errors.New("insufficient balance")
    ErrOrderNotFound       = errors.New("order not found")
    ErrInvalidPrice        = errors.New("invalid price")
    ErrInvalidQuantity     = errors.New("invalid quantity")
    ErrMarketClosed        = errors.New("market closed")
    ErrSelfTrade           = errors.New("self-trade not allowed")
    ErrMaxOrdersExceeded   = errors.New("max orders exceeded")
)

Test Cases

func TestOrderBookBasic(t *testing.T) {
    ob := NewOrderBook("BTC-USD")
    
    // Add bid
    ob.AddOrder(Order{ID: "1", Side: Buy, Price: dec("50000"), Quantity: dec("1")})
    
    // Add ask that crosses
    trades := ob.AddOrder(Order{ID: "2", Side: Sell, Price: dec("50000"), Quantity: dec("0.5")})
    
    require.Len(t, trades, 1)
    require.Equal(t, dec("0.5"), trades[0].Quantity)
    require.Equal(t, dec("50000"), trades[0].Price)
}

func TestOrderBookPriceTimePriority(t *testing.T) {
    ob := NewOrderBook("BTC-USD")
    
    // Same price, different times
    ob.AddOrder(Order{ID: "1", Side: Buy, Price: dec("50000"), Quantity: dec("1")})
    time.Sleep(time.Millisecond)
    ob.AddOrder(Order{ID: "2", Side: Buy, Price: dec("50000"), Quantity: dec("1")})
    
    // Sell should match first order (time priority)
    trades := ob.AddOrder(Order{ID: "3", Side: Sell, Price: dec("50000"), Quantity: dec("0.5")})
    
    require.Equal(t, "1", trades[0].MakerOrderID)
}

Motivation

Existing DEX solutions on blockchains suffer from high latency (seconds to minutes) and limited order types. The Lux DEX trading engine addresses this by running as a standalone sidecar, enabling sub-millisecond order matching while maintaining blockchain settlement guarantees.

Specification

See Architecture, Order Types, and Matching Engine sections above for the complete technical specification.

Rationale

The sidecar architecture separates order matching from blockchain consensus, allowing the trading engine to achieve institutional-grade latency without compromising on settlement security. Multi-backend support (Go, C++, GPU, FPGA) enables progressive optimization based on deployment requirements.

Backwards Compatibility

This is a new system with no backwards compatibility concerns. The DEX integrates with existing Lux infrastructure via Warp messages.

Security Considerations

  1. Order Integrity: All orders are cryptographically signed before submission
  2. Settlement Security: Final settlement occurs on-chain via Warp messages
  3. MEV Protection: Off-chain matching prevents frontrunning
  4. Rate Limiting: Per-user rate limits prevent abuse

Copyright and related rights waived via CC0.