Repository navigation
v0.2.0 — Relayer Data API
Relayer Data API — v0.2.0
The Relayer Data API is a high-throughput, read-only data service for the Twilight BTC derivatives protocol. It consists of two independent binaries — archiver and api — that together ingest, persist, and serve all relayer state to external clients.
Architecture Overview
relayer-core
│
▼ (Kafka topics)
┌─────────┐ ┌───────────┐ ┌──────────────────────┐
│ archiver│────▶│ PostgreSQL│────▶│ api (JSON-RPC) │
│ binary │ │ (Diesel) │ │ public :8987 │
│ │────▶│ Redis │────▶│ private :8989 │
└─────────┘ └───────────┘ └──────────────────────┘
archiver
Consumes events from Kafka, applies batch inserts into PostgreSQL, and maintains a live Redis cache for low-latency reads. Key behaviours:
- Batch inserts — 2000-item capacity per entity type; flushes automatically every 100 ms or when the batch is full.
- Redis cache — maintains the live order book (bid/ask sorted sets,
recent_orders), the latest risk state (risk_statekey), and the current pool share price. - Event types handled — trader orders, lend orders, lend pool snapshots, price ticks, funding events, candle updates, risk engine commands, risk parameter updates, account link events, and transaction hashes.
api
A stateless JSON-RPC 2.0 server backed by a PostgreSQL connection pool (r2d2). Exposes two ports:
:8987— public endpoint (no authentication required):8989— private endpoint (JWT / API-key authenticated, rate-limited per header)
Public RPC Methods (:8987)
| Method | Description |
|---|---|
lend_pool_info |
Current lending pool state (TLV, pool shares, sequence) |
pool_share_value |
Latest share price (total_locked_value / total_pool_share) |
btc_usd_price |
Latest BTC/USD price tick |
historical_price |
BTC/USD price series over a time range |
apy_chart |
APY time-series with configurable range, step, and lookback |
last_day_apy |
Single trailing 24-hour APY value |
open_limit_orders |
Current open limit order book |
recent_trade_orders |
Trades closed in the last 24 hours |
trader_order_info |
Single trader order by ID |
historical_trader_order_info |
Paginated trader order history |
lend_order_info |
Single lend order by ID |
historical_lend_order_info |
Paginated lend order history |
candle_data |
OHLCV candle data (1m, 5m, 15m, 30m, 1h, 4h, 8h, 12h, 24h) |
open_interest |
Total long and short BTC exposure |
position_size |
Long, short, and net position sizes |
get_funding_rate |
Current funding rate |
historical_funding_rate |
Funding rate history |
get_funding_payment |
Funding payments for a given address |
get_fee_rate |
Current fee rate |
historical_fee_rate |
Fee rate history |
trade_volume |
Aggregate trade volume over a period |
order_history |
Combined order history for an address |
open_orders |
Currently open orders for an address |
unrealized_pnl |
Unrealized PnL for open positions |
last_order_detail |
Most recent order detail for an address |
get_market_stats |
Market-wide risk statistics derived from the latest RiskState |
server_time |
Server UTC timestamp |
account_summary_by_twilight_address |
Per-address account summary with date-range filtering |
Private RPC Methods (:8989)
| Method | Description |
|---|---|
submit_trade_order |
Submit a signed trade order |
submit_lend_order |
Submit a signed lend order |
submit_bulk_order |
Submit multiple orders in one call |
cancel_trader_order |
Cancel an open trader order |
settle_trade_order |
Settle a trade order on-chain |
settle_lend_order |
Settle a lend order on-chain |
transaction_hashes |
Retrieve transaction hashes for a set of orders |
Database Schema
PostgreSQL with Diesel ORM and automated migrations. Key tables:
| Table | Purpose |
|---|---|
trader_order |
All trader order records |
lend_order |
All lend order records |
lend_pool |
Lending pool snapshots |
lend_pool_price_minute |
Per-minute share price history (source for APY) |
btc_usd_price |
BTC/USD price ticks |
candle |
OHLCV candle data across all resolutions |
funding_rate |
Funding rate history |
fee_rate |
Fee rate history |
risk_engine_update |
Risk engine command audit log with full RiskState snapshot |
risk_params_update |
Risk parameter change history |
open_interest |
Aggregate long/short exposure snapshots |
twilight_qq_account_link |
Twilight address ↔ QQ account mapping |
position_size_log |
Historical position size snapshots |
Migrations are embedded into the binary via diesel_migrations and run automatically at startup.
APY Calculation
The apy_series() SQL function computes annualised yield at each time bucket:
APY = (price_at_bucket / price_(lookback)_before_bucket) ^ (365_days_in_seconds / lookback_in_seconds) − 1
The exponent is generalised so any lookback window (24h, 7d, 30d) produces a correct annualised figure. A companion last_day_apy_now() function returns the instantaneous trailing-24h APY.
Risk Engine Integration
The archiver processes RiskEngineCommand events emitted by relayer-core and:
- Persists each command and the resulting
RiskStatesnapshot torisk_engine_update. - Caches the latest
RiskStatein Redis under the keyrisk_statefor O(1) API reads. - Exposes
get_market_statswhich computes live risk utilisation ratios from the cached state and current pool equity.
Supported commands: AddExposure, RemoveExposure, SetManualHalt, SetManualCloseOnly, SetPauseFunding, SetPausePriceFeed.
Configuration
All configuration is via environment variables (see .env.example):
| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
REDIS_HOSTNAME |
Redis connection string |
BROKER |
Kafka broker address(es), comma-separated |
CORE_EVENT_LOG |
Primary Kafka topic for relayer-core events |
RUST_LOG |
Log level (info, debug, warn, error) |
RISK_MAX_OI_MULT |
Max open interest as a multiple of pool equity |
RISK_MAX_NET_MULT |
Max net exposure as a multiple of pool equity |
RISK_MAX_POSITION_PCT |
Max single position as a fraction of pool equity |
RISK_MIN_POSITION_BTC |
Minimum position size in sats |
RISK_MAX_LEVERAGE |
Maximum allowed leverage |
Running
# Archiver (event consumer + database writer)
cargo run --release --bin archiver
# API server
cargo run --release --bin api
What's New in v0.2.0
Features
- APY chart endpoint (
apy_chart) with configurable range, step, and lookback intervals - Trailing APY (
last_day_apy) — single-value 24-hour yield - Open interest endpoint (
open_interest) — live long/short BTC exposure - Market statistics (
get_market_stats) — risk utilisation ratios from liveRiskState - Extended trader order info (
trader_order_info_v1) — includes latest close limit and funding applied - Account summary (
account_summary_by_twilight_address) — per-address history with date-range filter - Risk engine archiving — full audit log of all
RiskEngineCommandevents with state snapshots - Risk parameter tracking —
risk_params_updatetable records every parameter change - Candle data pipeline — improved OHLCV aggregation across all resolutions
- Twilight QQ account linking — address mapping persisted and queryable
Bug Fixes
- Fixed missing third bind parameter in
apy_series()call (runtime SQL error) - Fixed hardcoded annualisation exponent — non-24h lookbacks now produce correct APY
- Fixed
"1m"token collision in interval parser (was resolving to 30 days instead of 1 minute) - Fixed nullable mismatch in
last_day_apy_now()Diesel mapping — NULL is now correctly returned asNoneinstead of a deserialisation error - Eliminated
Box::leakmemory allocations in RPC argument resolution
Infrastructure
- relayer-core dependency updated to
risk-param-fix-haltbranch - Batch insert architecture with configurable capacity and flush timeout
- Kafka broker configuration supports multiple hosts
- Dotenv loading made non-fatal — service starts cleanly without a
.envfile - Header metadata extraction centralised in
src/rpc/headers.rs