Relay Connection
Makers connect to the HyperQuote relay via a persistent WebSocket connection. The relay is the message broker that delivers RFQ broadcasts to makers and forwards signed quotes back to takers.
Relay URL
The relay WebSocket endpoint defaults to:
ws://127.0.0.1:8080Set via the RELAY_WS_URL environment variable in production. The relay also exposes REST endpoints on the same port for polling (GET /rfqs, GET /quotes?rfqId=..., GET /health).
WebSocket Handshake
Open a standard WebSocket connection to the relay URL. No special handshake headers or subscription messages are required — all connected clients immediately receive RFQ_BROADCAST messages.
import WebSocket from "ws";
const ws = new WebSocket("ws://127.0.0.1:8080");
ws.on("open", () => {
console.log("Connected to relay");
});Upon connection, the relay logs the client and begins forwarding all active RFQ broadcasts. There is no authentication step in V1 — any WebSocket client that connects will receive broadcasts.
In production, the relay enforces rate limiting (default: 30 messages per minute per IP). Exceeding this limit will result in an ERROR message from the relay.
Message Protocol
All messages are JSON objects with a type field and a data field:
interface RelayMessage {
type: "RFQ_SUBMIT" | "RFQ_BROADCAST" | "QUOTE_SUBMIT"
| "QUOTE_BROADCAST" | "PING" | "PONG" | "ERROR";
data: unknown;
}Makers primarily interact with three message types:
| Message Type | Direction | Purpose |
|---|---|---|
RFQ_BROADCAST | Relay -> Maker | New RFQ available for quoting |
QUOTE_SUBMIT | Maker -> Relay | Submit a signed quote for an RFQ |
QUOTE_BROADCAST | Relay -> Maker | A quote was submitted (by any maker) |
PING | Relay -> Maker | Keepalive check |
PONG | Maker -> Relay | Keepalive response |
ERROR | Relay -> Maker | Validation or rate limit error |
Ping/Pong Heartbeat
The maker bot should send a PING message every 30 seconds to keep the connection alive. The relay responds to PING with PONG, and the relay also sends its own PING messages that the maker must respond to with PONG.
// Send keepalive PING every 30 seconds
const pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: "PING", data: {} }));
}
}, 30_000);
// Respond to relay PING with PONG
ws.on("message", (raw) => {
const msg = JSON.parse(raw.toString());
if (msg.type === "PING") {
ws.send(JSON.stringify({ type: "PONG", data: {} }));
}
});
// Clean up on disconnect
ws.on("close", () => clearInterval(pingInterval));Error Handling
The relay sends ERROR messages when validation fails or rate limits are exceeded:
ws.on("message", (raw) => {
const msg = JSON.parse(raw.toString());
if (msg.type === "ERROR") {
console.error("Relay error:", msg.data.message);
}
});Common error messages include:
"Rate limit exceeded"— Too many messages in the current window."RFQ not found or expired"— The referenced RFQ is no longer active."Invalid Quote EIP-712 signature"— Signature verification failed on the relay."Duplicate quote from this maker for this RFQ"— Only one quote per maker per RFQ is allowed.
Auto-Reconnect with Exponential Backoff
The relay connection can drop due to network issues or relay restarts. Implement auto-reconnect with exponential backoff to recover gracefully:
const MAX_RECONNECT_ATTEMPTS = 5;
const BASE_DELAY_MS = 1000;
let attempt = 0;
function connect() {
const ws = new WebSocket("ws://127.0.0.1:8080");
ws.on("open", () => {
console.log("Connected to relay");
attempt = 0; // Reset on successful connection
});
ws.on("close", () => {
if (attempt >= MAX_RECONNECT_ATTEMPTS) {
console.error("Max reconnect attempts reached. Exiting.");
process.exit(1);
}
const delay = BASE_DELAY_MS * Math.pow(2, attempt);
attempt++;
console.log(`Disconnected. Reconnecting in ${delay}ms (attempt ${attempt}/${MAX_RECONNECT_ATTEMPTS})...`);
setTimeout(connect, delay);
});
ws.on("error", (err) => {
console.error("WebSocket error:", err.message);
});
// ... message handlers
}
connect();The default maker relay bot (makerRelay.ts) uses a simpler fixed 3-second reconnect delay. For production, exponential backoff with jitter is recommended.
Connection Status
Monitor relay health via the REST endpoint:
curl http://127.0.0.1:8080/healthReturns:
{
"status": "ok",
"chainId": 31337,
"engineAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
"activeRfqs": 2,
"totalQuotes": 5,
"connectedClients": 3,
"uptime": 1234
}This is useful for monitoring dashboards and alerting on relay downtime.