Skip to main content
The api process exposes a WebSocket at /ws (default ws://localhost:8081/ws). It fans out Redis pubsub messages from the quote-worker to subscribed clients.

Protocol

Client → server messages:
// Subscribe to a channel
{ "type": "sub", "channel": "quotes:v1:<oracleId>:<strike>" }

// Unsubscribe
{ "type": "unsub", "channel": "quotes:v1:<oracleId>:<strike>" }
Server → client messages:
// Quote update
{
  "type": "quote",
  "channel": "quotes:v1:<oracleId>:<strike>",
  "data": {
    "oracleId": "0x...",
    "strike": 65000,
    "yes_ask": 27.3,
    "no_ask": 11.4,
    "fairPerToken": 0.27,
    "asOf": 1718425600000
  }
}

Lifecycle

  1. Client subscribes → hub joins it to the Redis pubsub channel.
  2. Quote-worker polls predict::get_trade_amounts for hot strikes (default 2s interval via QUOTE_POLL_MS).
  3. On change, worker PUBLISHes to quotes:v1:<oracle>:<strike>.
  4. Hub fans out to all subscribed sockets.
  5. After 30s idle (no subscribers), the channel closes.

Frontend integration

packages/frontend/src/lib/realtime.ts is a singleton WS client with:
  • Per-channel subscribe / unsubscribe (useQuoteSubscription hook)
  • Linear-backoff reconnect on disconnect
  • Idle-close after 30s with no active subscribers
React components use the typed useQuoteSubscription hook. It auto-subscribes on mount and cleans up on unmount.

Other deferred upgrades

The current realtime stack is poll-based: 5s client devInspect for event-market books, 2s server poll for Predict quotes. The designed-but-deferred upgrade (1s server-side book poll → Redis → WS; oracle-event-triggered strike requotes; DeepBook order-event tape) is documented in the 2026-06-12 decision log but won’t ship before the hackathon submission.

Channel naming

  • quotes:v1:<oracleId>:<strike>. Per-strike quote
  • (future) book:v1:<poolId>. DeepBook V3 level-2 ticks
  • (future) fills:v1:<oracleId>. Per-oracle fill tape