API DOCS
every relayer endpoint · REST + WebSocket · live-try buttonsCONFIG
GET
/api/config
Single source of truth — addresses, EIP-712 domain, tokens, market, MM wallets, fee. Frontend's first call.
response (sample)
{
"chainId": 31337,
"exchange": "0x9fE4…a6e0",
"infinityPool": "0x61c3…33e1",
"matchmaker": "0x6101…D788",
"liquaToken": "0x0B30…7016",
"liquaStaking": "0x9599…07B1",
"domain": { "name": "Liqua", "version": "1", ... },
"tokens": [{"symbol":"mUSDC",...}, {"symbol":"mWETH",...}],
"market": {"base":"0x…WETH", "quote":"0x…USDC"},
"fee": {"takerFeeBps":0, "feeRecipient":"0x…staking", "max_bps":100},
"mmWallets": {"quoter":{...}, "arber":{...}}
}
curl -s http://localhost:8080/api/config
ORDERS
GET/api/orders
Live orderbook · filter by ?makerToken= ?takerToken= ?maker= · annotated with watcher's lastRemaining.
response
{
"orders": [{
"orderHash": "0x…",
"order": {"maker":..., "makerToken":..., ... , "epoch":"0"},
"signature": "0x…65 bytes",
"remaining": "…takerToken units…",
"createdAt": 1780000000000
}],
"count": 24, "watcherLastBlock": 42
}
curl -s http://localhost:8080/api/orders | head -c 400
POST/api/orders
Submit a maker-signed EIP-712 order. Three gates run server-side: SCHEMA-GATE · SIG-GATE · EPOCH-GATE. The same sig is re-verified on-chain at fill.
request body
{
"order": {"maker":"0x…", "makerToken":"0x…", "takerToken":"0x…",
"makerAmount":"1000000000000000000", "takerAmount":"2000000000",
"expiry":"1800000000", "salt":"…256-bit…", "epoch":"0"},
"signature": "0x…65 bytes EIP-712"
}
response · 200
{ "ok": true, "orderHash": "0x…" }
response · 400 (gate reject)
{ "ok": false, "error": "signature does not recover to maker" }
DELETE/api/orders/:hash
Soft-remove from book (UX hint). The on-chain Cancel event is the source of truth; relayer prunes automatically too.
response
{ "ok": true }
TRADES
GET/api/trades?limit=50
Trade tape · Fill events observed by the chain watcher · capped 500 in-memory.
response
{
"trades": [{"orderHash":..., "maker":..., "taker":..., "makerToken":..., "takerToken":...,
"makerFilledAmount":..., "takerFilledAmount":...,
"blockNumber":..., "txHash":..., "ts":...}],
"count": 12, "watcherLastBlock": 42
}
CHAT
GET/api/chat?limit=100
In-memory chat ring buffer (200 cap, persisted across restarts via the kernel).
{ "chat": [{"address":..., "message":..., "ts":..., "sig":...}], "count":3, "cap":200 }
POST/api/chat
Post a wallet-signed chat message. Sig payload =
"Liqua chat\n{address-lowercase}\n{ts-seconds}\n{message}". ts must be within ±300s of server.
request body
{
"address": "0x…",
"message": "hello",
"ts": 1780000000,
"signature": "0x…65 bytes personal_sign"
}
AMM (InfinityPool · UniV2-style)
GET/api/amm
Pool address, reserves, mid (quote/base), fee, watcher block.
{
"pool":..., "factory":..., "token0":..., "token1":...,
"reserves": {"reserve0":"200000000000", "reserve1":"100000000000000000000", "ts":...},
"mid": 2000, "fee_bps": 30, "watcherLastBlock": 42
}
GET/api/amm/swaps?limit=50AMM Swap event tape (capped 200).
MATCHMAKER (orderbook ↔ AMM crosses)
GET/api/matchmakerMatchmaker address + recent atomic crosses (orderbook order filled by flash-swapping AMM, profit to keeper).
GET/api/matchmaker/crosses?limit=50Capped cross tape (100). Each entry: keeper, takerFilled, makerReceived, ammRepaid, profit, txHash.
EXTERNAL FEED
GET/api/external/binance
Live Binance ETH/USDT depth20 @ 1s · mid · mirror keeper stats (ticks/posted/rejected).
{
"source": "binance", "pair": "ETHUSDT", "connected": true,
"mid": 1857.83, "depth": {"bids":[...], "asks":[...]},
"lastTickAt": ..., "ageMs": 412, "reconnects": 0,
"mirror": {"enabled":true, "wallet":"0x…quoter", "ticks":4, "posted":24, ...}
}
HEALTH · MOLECULAR TELEMETRY
GET/api/healthHormones, somatic state (33-state classifier), ledger (boot count + hash), watcher, book/trades/chat/amm/matchmaker/external/mirror/ws counters, fleet roster, DNA versions.
ADMIN / DEBUG
POST/api/reloadRe-read shared/deployment.json without restarting the relayer (after a fresh deploy).
GET/api/transitionsLast 100 R3-labelled transitions (in-memory tracer). Useful for debugging.
WEBSOCKET
WSws://localhost:8080/wsSingle fan-out endpoint · subscribe by connecting · messages are
{ type, payload, ts }.topics (server → client)
hello — sent on connect: chainId, fleets, current binance mid
order — new order accepted into the book
trade — Fill event observed by watcher
cancel — Cancel event observed by watcher
chat — new chat message accepted
external — Binance depth tick (~1s cadence)
health — hormones + somatic + watcher block (every 5s)
order — new order accepted into the book
trade — Fill event observed by watcher
cancel — Cancel event observed by watcher
chat — new chat message accepted
external — Binance depth tick (~1s cadence)
health — hormones + somatic + watcher block (every 5s)
quickstart
// In browser:
const ws = new WebSocket("ws://localhost:8080/ws");
ws.onmessage = e => { const m = JSON.parse(e.data); console.log(m.type, m.payload); };
not connected