subscribeToEvents
Open a live WebSocket to the ZyFAI risk engine and get a callback the moment something changes: a stablecoin drifting off peg, a pool bleeding liquidity, or a new collateral type showing up in a vault. No wallet, no polling loop — just handlers.
Like simulateBestPositions, this only needs your API key. It's a good fit for dashboards, alerting, and monitoring that needs to run independently of any one user's session.
Signature
subscribeToEvents(handlers: ZyfaiEventHandlers, filters?: ZyfaiEventFilters): () => void
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
handlers | ZyfaiEventHandlers | ✅ | Callbacks for each event type you care about. |
filters | ZyfaiEventFilters | ❌ | Narrow the stream to specific chains/protocols/pools. Omit a field to receive everything for that dimension. |
interface ZyfaiEventHandlers {
onDepeg?: (data: DepegEvent) => void;
onLiquidityDrop?: (data: LiquidityDropEvent) => void;
onNewCollateralDetected?: (data: NewCollateralDetectedEvent) => void;
onError?: (error: unknown) => void;
}
interface ZyfaiEventFilters {
chains?: string[];
protocols?: string[];
pools?: string[];
}
Returns
An unsubscribe function.
subscribeToEvents opens a real WebSocket connection. Call the function it returns as soon as you no longer need the stream — on component unmount, on page leave, whenever the caller goes away — or you'll leak the connection.
Event types
onDepeg
interface DepegEvent {
token: string;
price: number;
deviation: number; // percent off peg
severity: "warning" | "critical";
previousSeverity?: string; // present when severity just changed
affectedPools: { protocol: string; pool: string; chain: string }[];
timestamp: string;
}
onLiquidityDrop
interface LiquidityDropEvent {
protocol: string;
pool: string;
chain: string;
asset: string;
previousLiquidityUsd: number;
currentLiquidityUsd: number;
dropPercent: number;
windowMinutes: number;
timestamp: string;
}
onNewCollateralDetected
interface NewCollateralDetectedEvent {
protocol: string;
pool: string;
chain: string;
asset: string;
exposureUsd: number;
percentOfTvl: number;
timestamp: string;
}
Good to know
A few behaviors worth knowing before you build against this, confirmed by connecting to the live socket directly:
- A quiet feed is a healthy feed. A 25-second subscription with real filters produced zero events — that's expected, not broken. Real depegs and liquidity crunches aren't hourly occurrences, so don't design your UI around "an event should have arrived by now."
- It reconnects on its own. Treat
onErroras "reconnecting…", not "the stream is dead." Don't tear your UI down on the first error. - Don't rely on
onErrorto validate your API key. Subscribing with a deliberately invalid key produced no error within 20 seconds in testing. If you need to confirm a key works, check it with a normal REST call (likesimulateBestPositions) first — don't wait on this socket to tell you. - All three
filtersfields are independent and optional — set only the ones you need.
Examples
Simplest subscription
const unsubscribe = sdk.subscribeToEvents({
onDepeg: (e) => console.log(`${e.token} depeg — ${e.deviation}% (${e.severity})`),
onLiquidityDrop: (e) => console.log(`${e.pool} liquidity -${e.dropPercent}%`),
onNewCollateralDetected: (e) => console.log(`New collateral: ${e.asset} in ${e.pool}`),
onError: (err) => console.error("stream error", err),
});
// later
unsubscribe();
Filtered to specific chains/protocols/pools
const unsubscribe = sdk.subscribeToEvents(
{ onDepeg: (e) => alertMyTeam(e) },
{
chains: ["Ethereum", "Base"],
protocols: ["morpho"],
pools: ["gauntlet usdc core"],
},
);
Cleaning up in React
useEffect(() => {
const unsubscribe = sdk.subscribeToEvents({ onDepeg: handleDepeg });
return unsubscribe; // runs on unmount
}, []);