On-Chain DEX
Central Limit Order Book (CLOB) architecture, matching engine, order types, settlement, and WebSocket feeds
Liquidity.io operates a fully on-chain Central Limit Order Book (CLOB) exchange built on the Liquidity Network. The DEX provides deterministic matching with price-time priority, atomic settlement, and sub-millisecond latency for institutional trading workloads.
Architecture
The DEX is a multi-layer system with specialized components for each phase of the trade lifecycle.
Client Layer (SDKs, Web UI, Trading Bots)
|
Gateway Layer (Load Balancer, Rate Limiter, Auth, WebSocket/gRPC)
|
Application Layer (Order Management, Risk Engine, Market Data)
|
Core Engine Layer (Matching Engine, Clearing, Settlement)
|
Consensus Layer (DAG Consensus, Validator Network, State Machine)
|
Storage Layer (Order DB, Trade History, State DB, Archive)Matching Engine
The matching engine is the core of the DEX. Each trading pair has its own order book backed by a B-tree for O(log n) price-level operations.
Key design choices:
- Lock-free data structures -- atomic operations for concurrent order processing without mutex contention
- Memory pooling -- object reuse via
sync.Poolto minimize garbage collection pressure - Integer price levels -- all prices are represented as integers internally to avoid floating-point errors
- Circular trade buffers -- zero-copy recording of executed trades
- Multiple backends -- the engine auto-selects the optimal implementation for the hardware
Performance
The DEX supports multiple execution backends with verified benchmarks:
Core orderbook (Pure Go, Apple M1 Max):
| Book Depth | Latency | Throughput |
|---|---|---|
| 100 levels | 3,191ns | 313,376 orders/sec |
| 1,000 levels | 2,877ns | 347,631 orders/sec |
| 10,000 levels | 3,080ns | 324,721 orders/sec |
GPU acceleration (MLX, Apple M2 Ultra): 434,782,609 orders/sec at 2ns latency.
FIX 4.4 multi-engine benchmarks:
| Engine | NewOrderSingle | ExecutionReport | MarketDataSnapshot |
|---|---|---|---|
| Pure Go | 163K/sec | 124K/sec | 332K/sec |
| Hybrid Go/C++ | 167K/sec | 378K/sec | 616K/sec |
| Pure C++ | 444K/sec | 804K/sec | 1.08M/sec |
| Rust | 484K/sec | 232K/sec | 586K/sec |
| GPU (MLX) | 3.12M/sec | 4.27M/sec | 5.95M/sec |
See Performance Benchmarks for full results and reproduction steps.
Order Types
| Type | Behavior | Time-in-Force |
|---|---|---|
market | Execute immediately at best available price | IOC |
limit | Execute at specified price or better, rest on book | GTC, IOC, FOK, GTD, POST_ONLY |
stop_loss | Trigger market order when price crosses threshold | GTC |
stop_loss_limit | Trigger limit order when price crosses threshold | GTC |
take_profit | Trigger market order at profit target | GTC |
take_profit_limit | Trigger limit order at profit target | GTC |
limit_maker | Limit order that is rejected if it would immediately match (maker-only) | GTC |
Time-in-Force
| Value | Description |
|---|---|
GTC | Good till cancelled -- order stays on book until filled or cancelled |
IOC | Immediate or cancel -- fill what is available, cancel the rest |
FOK | Fill or kill -- fill the entire order or reject it completely |
GTD | Good till date -- expires at a specified timestamp |
POST_ONLY | Rejected if it would take liquidity (maker-only) |
Hidden and Iceberg Orders
The matching engine supports hidden orders (completely invisible to the book) and iceberg orders (only a visible slice is shown). These are available through the execution algorithms in the SDK. See Execution & Algorithms for details.
Matching Algorithm
The engine uses price-time priority (FIFO):
- Orders are first ranked by price -- the best price has priority (highest bid, lowest ask)
- At the same price level, orders are ranked by arrival time -- earlier orders fill first
- When an incoming order matches one or more resting orders, fills are generated atomically
- Partially filled orders remain on the book with the unfilled quantity
Matching Rules
- A market buy sweeps the ask side from lowest price upward until the order is fully filled
- A limit buy at price P matches any resting asks at price P or lower
- A stop order is held off-book until the trigger price is reached, then converted to a market or limit order
- Post-only orders are rejected if they would match immediately, ensuring the submitter always earns the maker fee
Settlement
All trades settle atomically on-chain. The clearinghouse executes settlement as a single transaction:
- Trade Matching -- the matching engine pairs buy and sell orders
- Clearing -- the clearinghouse verifies the trade and records it
- Settlement -- buyer and seller balances are updated atomically (debit/credit in one transaction)
- Confirmation -- participants are notified via WebSocket/SSE
There is no counterparty risk. Settlement is final at the consensus layer with 1ms deterministic finality.
Consensus
The LQDTY chain uses DAG-based Quasar consensus with the dual-certificate protocol:
- 1ms block finality -- 1,000 blocks/second, deterministic and irreversible
- Parallel validation -- DAG structure enables concurrent transaction processing
- Post-quantum consensus -- hybrid BLS + Ringtail lattice threshold signatures
- Adaptive thresholds -- vote threshold converges from 55% to 65% over 10 rounds
- K=20 sample, 80% quorum -- 16 of 20 validators must agree per round
See Post-Quantum Security for the full cryptographic specification.
WebSocket Feeds
The DEX provides real-time data via WebSocket for low-latency integrations, and SSE for simpler setups.
Connection
wss://api.liquidity.io/ws (production)
wss://api.liquidity.io/ws (Liquidity.io ATS)
ws://localhost:8080/ws (local development)Subscribe to Order Book
{
"type": "subscribe",
"channel": "orderbook",
"symbol": "BTC-USDT",
"depth": 20
}Snapshot response:
{
"type": "orderbook_snapshot",
"symbol": "BTC-USDT",
"bids": [[83400, 1.5], [83399, 2.0]],
"asks": [[83401, 1.2], [83402, 0.8]],
"timestamp": 1710807360
}Incremental update:
{
"type": "orderbook_update",
"symbol": "BTC-USDT",
"bids": [[83400, 1.8]],
"asks": [[83401, 0]],
"timestamp": 1710807361
}A size of 0 means the price level has been removed from the book.
Subscribe to Trades
{
"type": "subscribe",
"channel": "trades",
"symbol": "BTC-USDT"
}Trade event:
{
"type": "trade",
"symbol": "BTC-USDT",
"price": 83421.50,
"size": 0.5,
"side": "buy",
"timestamp": 1710807360
}REST API
Base URL
https://api.liquidity.io/v1 (production)
https://api.liquidity.io/v1 (Liquidity.io ATS)Get Order Book
GET /orderbook/{symbol}?depth=20Response:
{
"symbol": "BTC-USDT",
"bids": [
{ "price": 83400, "size": 1.5 },
{ "price": 83399, "size": 2.0 }
],
"asks": [
{ "price": 83401, "size": 1.2 },
{ "price": 83402, "size": 0.8 }
],
"timestamp": 1710807360
}Place Order
POST /orders
X-API-Key: {api_key}
X-API-Secret: {api_secret}
Content-Type: application/json
{
"symbol": "BTC-USDT",
"side": "buy",
"type": "limit",
"price": 83000,
"size": 0.1,
"time_in_force": "GTC"
}Response:
{
"order_id": "123e4567-e89b-12d3-a456-426614174000",
"symbol": "BTC-USDT",
"side": "buy",
"type": "limit",
"price": 83000,
"size": 0.1,
"status": "open",
"created_at": 1710807360
}Cancel Order
DELETE /orders/{order_id}
X-API-Key: {api_key}
X-API-Secret: {api_secret}Get Recent Trades
GET /trades?symbol=BTC-USDT&limit=100Code Examples
TypeScript
import { Client, Config, NativeVenueConfig } from '@liquidityio/trading';
const config = new Config()
.withNative('lx-dex', NativeVenueConfig.liquidDex('https://api.liquidity.io/v1'))
.withVenuePriority(['lx-dex'])
.withSmartRouting(false);
const client = new Client(config);
await client.connect();
// Get orderbook with VWAP calculation
const book = await client.orderbook('BTC-USDT');
console.log(`Best bid: ${book.bestBid}, Best ask: ${book.bestAsk}`);
console.log(`Spread: ${book.spread} (${book.spreadPercent}%)`);
console.log(`Mid price: ${book.midPrice}`);
console.log(`VWAP to buy 1 BTC: ${book.vwapBuy(1)}`);
console.log(`Bid liquidity (top 5): ${book.bidDepth(5)}`);
// Place a limit buy
const order = await client.limitBuy('BTC-USDT', '0.5', '83000');
console.log(`Order ${order.orderId} status: ${order.status}`);
// Place a market sell
const sellOrder = await client.sell('BTC-USDT', '0.25');
console.log(`Sold at ${sellOrder.averagePrice}`);
// Cancel an order
await client.cancelOrder(order.orderId, 'BTC-USDT', 'lx-dex');
// List open orders
const openOrders = await client.openOrders('BTC-USDT');
for (const o of openOrders) {
console.log(`${o.orderId}: ${o.side} ${o.quantity} @ ${o.price} [${o.status}]`);
}
await client.disconnect();Python
import asyncio
from decimal import Decimal
from lx_trading import Client, Config
from lx_trading.config import NativeVenueConfig
async def main():
config = Config()
config.with_native("lx-dex", NativeVenueConfig.liquid_dex("https://api.liquidity.io/v1"))
client = Client(config)
await client.connect()
# Get orderbook
book = await client.orderbook("BTC-USDT")
print(f"Best bid: {book.best_bid}, Best ask: {book.best_ask}")
print(f"Spread: {book.spread} ({book.spread_percent}%)")
print(f"VWAP to buy 1 BTC: {book.vwap_buy(Decimal('1'))}")
# Place a limit buy
order = await client.limit_buy("BTC-USDT", Decimal("0.5"), Decimal("83000"))
print(f"Order {order.order_id} status: {order.status}")
# Place a market sell
sell_order = await client.sell("BTC-USDT", Decimal("0.25"))
print(f"Sold at {sell_order.average_price}")
# Cancel
await client.cancel_order(order.order_id, "BTC-USDT", "lx-dex")
# Open orders
open_orders = await client.open_orders("BTC-USDT")
for o in open_orders:
print(f"{o.order_id}: {o.side} {o.quantity} @ {o.price} [{o.status}]")
await client.disconnect()
asyncio.run(main())gRPC API
For ultra-low-latency integrations, the DEX also exposes a gRPC interface:
localhost:50051 (development)
grpc.liquidity.io:443 (production)Proto definition:
syntax = "proto3";
package lxdex;
service TradingService {
rpc PlaceOrder(OrderRequest) returns (OrderResponse);
rpc CancelOrder(CancelRequest) returns (CancelResponse);
rpc GetOrderBook(OrderBookRequest) returns (OrderBookResponse);
rpc StreamTrades(StreamRequest) returns (stream Trade);
}
message OrderRequest {
string symbol = 1;
string side = 2;
string type = 3;
double price = 4;
double size = 5;
}
message OrderResponse {
string order_id = 1;
string status = 2;
int64 timestamp = 3;
}Rate Limits
| Endpoint Type | Limit |
|---|---|
| Public endpoints (orderbook, trades) | 100 requests/minute |
| Private endpoints (orders, balances) | 300 requests/minute |
| Order placement | 10 orders/second |
| WebSocket connections per user | 5 concurrent |
Rate limit headers are included in all responses:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1710807360Error Codes
| Code | Description |
|---|---|
INVALID_SYMBOL | Trading pair not supported |
INVALID_ORDER_TYPE | Order type not recognized |
INSUFFICIENT_BALANCE | Not enough balance for the order |
ORDER_NOT_FOUND | Order ID does not exist |
RATE_LIMIT_EXCEEDED | Too many requests |
UNAUTHORIZED | Authentication required |
FORBIDDEN | Access denied |
INTERNAL_ERROR | Server error |