WebSocket
The SDK provides real-time event subscriptions via WebSocket.
Connecting
import { createClient } from "@kaizen-core/sdk";
const client = createClient({
rpcUrl: "http://localhost:8546", // Via proxy (recommended)
wsUrl: "ws://localhost:8546/ws",
});
// Or connect directly to a node:
// rpcUrl: "http://localhost:8545", // write-node
// wsUrl: "ws://localhost:8545/ws",
// rpcUrl: "http://localhost:8547", // read-node-aggressive
// wsUrl: "ws://localhost:8547/ws",
// Connect to WebSocket
await client.connectWebSocket();
// Check connection status
if (client.isWebSocketConnected) {
console.log("WebSocket connected!");
}
// Disconnect when done
client.disconnectWebSocket();Subscriptions
All subscription methods return an unsubscribe function.
Subscribe to Blocks
const unsubscribe = client.subscribeBlocks((event) => {
if (event.type === "block") {
console.log({
height: event.block.height,
timestamp: event.block.timestamp,
txCount: event.block.txCount,
});
}
});
// Later: stop receiving updates
unsubscribe();Subscribe to User Theses
const unsubscribe = client.subscribeUserTheses("0xUserAddress...", (event) => {
if (event.type === "thesis") {
console.log({
thesisId: event.thesis.id,
status: event.thesis.status,
eventType: event.eventType, // "created" | "active" | "settled" | "cancelled"
});
}
});Subscribe to My Theses
Convenience method that uses the connected signer's address.
client.connectSigner("0x...");
const unsubscribe = client.subscribeMyTheses((event) => {
if (event.type === "thesis") {
console.log(`My thesis ${event.thesis.id}: ${event.eventType}`);
}
});Subscribe to Solver Theses
For solver implementations.
const unsubscribe = client.subscribeSolverTheses(
"0xSolverAddress...",
(event) => {
if (event.type === "thesis") {
// Handle theses where this solver is involved
}
}
);Subscribe to Oracle Prices
const unsubscribe = client.subscribeOraclePrices(
{
base: "0x0000000000000000000000000000000000000001", // BTC
quote: "0x0000000000000000000000000000000000000002", // USDC
},
(event) => {
if (event.type === "oraclePrice") {
console.log({
price: event.price.price,
timestamp: event.price.timestamp,
});
}
}
);Using WebSocketClient Directly
For more control, use WebSocketClient directly.
import { WebSocketClient } from "@kaizen-core/sdk";
const ws = new WebSocketClient("ws://localhost:8546/ws");
// Set event handlers
ws.setOnOpen(() => {
console.log("Connected!");
});
ws.setOnError((error) => {
console.error("WebSocket error:", error);
});
ws.setOnClose((code, reason) => {
console.log(`Disconnected: ${code} - ${reason}`);
});
// Connect
await ws.connect();
// Subscribe with custom channel/params
const unsubscribe = ws.subscribe("userTheses", (event) => console.log(event), {
address: "0x...",
});
// Check state
console.log(`Connected: ${ws.isConnected}`);
console.log(`Subscriptions: ${ws.subscriptionCount}`);
// Disconnect
ws.disconnect();Debug Mode
Enable debug logging to troubleshoot WebSocket issues:
import { WebSocketClient } from "@kaizen-core/sdk";
// Enable debug logging at construction
const ws = new WebSocketClient("ws://localhost:3030/ws", {
debug: "verbose", // "none" | "info" | "verbose"
});
// Or change at runtime
ws.setDebugLevel("info");
// Check connection stats
const stats = ws.getStats();
console.log(stats);
// {
// messagesReceived: 42,
// bytesReceived: 12345,
// deserializeErrors: 0,
// lastMessageAt: 1701234567890
// }
// Reset stats
ws.resetStats();Debug Levels
| Level | Description |
|---|---|
none | No logging (default) |
info | Connection events, subscriptions, errors |
verbose | All messages with hex dumps for troubleshooting |
Custom Logger
const ws = new WebSocketClient("ws://localhost:8546/ws", {
debug: "verbose",
logger: {
info: (msg, data) => myLogger.info(`[WS] ${msg}`, data),
verbose: (msg, data) => myLogger.debug(`[WS] ${msg}`, data),
error: (msg, error) => myLogger.error(`[WS] ${msg}`, error),
},
});Binary Protocol
WebSocket messages use Borsh binary encoding for efficient data transfer. The SDK handles serialization/deserialization automatically - you always work with typed JavaScript objects.
:::info Why Binary?
- Smaller payload: ~40-60% smaller than JSON for typical messages
- Faster parsing: No string parsing overhead
- Type-safe: Schema enforced at protocol level :::
If you need to inspect raw messages for debugging, use verbose debug mode which logs hex dumps.
Event Types
import type {
WebSocketEvent,
BlockEvent,
ThesisEvent,
OraclePriceEvent,
} from "@kaizen-core/sdk";
// Type guard for events
function handleEvent(event: WebSocketEvent) {
switch (event.type) {
case "block":
handleBlock(event);
break;
case "thesis":
handleThesis(event);
break;
case "oraclePrice":
handlePrice(event);
break;
}
}
function handleBlock(event: BlockEvent) {
const { height, timestamp, stateRoot, txCount, transactions } = event.block;
// ...
}
function handleThesis(event: ThesisEvent) {
const { id, user, solver, status, betAmount, payout } = event.thesis;
const eventType = event.eventType; // "created" | "active" | ...
// ...
}
function handlePrice(event: OraclePriceEvent) {
const { base, quote, price, timestamp } = event.price;
// ...
}Subscription Channels
| Channel | Parameters | Description |
|---|---|---|
newBlocks | None | New block notifications |
newTransactions | { address } (opt) | All or address-filtered TX updates |
userTheses | { address } | Theses for a specific user |
solverTheses | { address } | Theses for a specific solver |
oraclePrices | { base, quote } (opt) | All or pair-specific price updates |
allEvents | None | All events (use sparingly) |
Automatic Reconnection
The WebSocket client automatically handles reconnection with exponential backoff:
- Max reconnection attempts: 5
- Base delay: 1 second
- Backoff: 2^attempt seconds (1s, 2s, 4s, 8s, 16s)
Subscriptions are automatically restored after reconnection.
Example: Real-time Thesis Monitoring
import { createClient } from "@kaizen-core/sdk";
async function monitorTheses() {
const client = createClient({
rpcUrl: "http://localhost:8546",
wsUrl: "ws://localhost:8546/ws",
});
client.connectSigner("0x...");
await client.connectWebSocket();
// Track thesis states
const thesisStates = new Map<bigint, string>();
client.subscribeMyTheses((event) => {
if (event.type === "thesis") {
const { id, status } = event.thesis;
const prevStatus = thesisStates.get(id);
if (prevStatus !== status) {
console.log(`Thesis ${id}: ${prevStatus ?? "new"} -> ${status}`);
thesisStates.set(id, status);
// Take action based on status change
if (status === "active") {
console.log("Thesis is now active, monitoring price...");
} else if (status === "settled") {
console.log("Thesis settled!");
}
}
}
});
// Keep running
process.on("SIGINT", () => {
client.disconnectWebSocket();
process.exit(0);
});
}
monitorTheses();Example: Price Alert
import { createClient, parsePrice, formatPrice } from "@kaizen-core/sdk";
async function priceAlert(targetPrice: bigint) {
const client = createClient({
rpcUrl: "http://localhost:8546",
wsUrl: "ws://localhost:8546/ws",
});
await client.connectWebSocket();
const BTC = "0x0000000000000000000000000000000000000001";
const USDC = "0x0000000000000000000000000000000000000002";
const unsubscribe = client.subscribeOraclePrices(
{ base: BTC, quote: USDC },
(event) => {
if (event.type === "oraclePrice") {
const currentPrice = event.price.price;
if (currentPrice >= targetPrice) {
console.log(
`🎯 Price alert! BTC reached ${formatPrice(currentPrice)}`
);
unsubscribe();
client.disconnectWebSocket();
}
}
}
);
console.log(`Waiting for BTC to reach ${formatPrice(targetPrice)}...`);
}
priceAlert(parsePrice("100000.00"));