Skip to Content
Symmio Frontier — the SDK surface for builders on HyperEVM
CoreNotifications

Notifications

Notifications come from a shared notification service (Defilytics protocol). Multiple parties — the solver, the TP/SL conditional-order handler, and any future producer — publish their state transitions into this one service, each under its own appName. Consumers (this SDK included) subscribe to whichever appNames they care about and receive the matching stream.

Today the SDK exposes two of those channels:

  • Solver notifications (appName: "Hyper-EVM_Solver-Low-Cap_Production") — quote lifecycle events: instant open accepted, price filled, quote anchored, close requested, close filled, failures. This page covers them via watchNotifications + searchNotifications.
  • TP/SL notifications (appName: "Hyper-EVM_COH-Low-Cap_Production") — conditional-order state transitions. Same underlying service, different appName, so it lives on its own page — see TP/SL.

Two access modes for each channel:

  • Live WebSocket stream — real-time updates as they happen. The SDK maintains one pooled connection per (wsUrl, appName, account) triple; every subscriber on the same triple shares that socket.
  • REST search — paginated history for backfill, replay, or audit.

Both surfaces on this page (the solver channel) return the same normalized Notification shape, so a UI can consume live + history with one code path.

The appName for each channel lives in the chain config — you never pass it directly:

const chain = config.getChainConfig(); chain.notifications.channel; // solver appName chain.solver.tpsl?.appName; // TP/SL appName

Import

import { watchNotifications, searchNotifications, normalizeNotification, classifyQuoteNotificationAction, NotificationType, type Notification, type SocketStatus, } from "@symmio/trading-core";

watchNotifications — live stream

Subscribe to the solver’s notifications WebSocket for one account. Reuses the SDK’s shared socket pool — many watchers on the same (wsUrl, appName, account) triple share one connection.

const unwatch = watchNotifications(config, { account: subAccount, onNotification: (notification) => { console.log(notification.type, notification.quoteId, notification.lastSeenAction); }, onStatusChange: (status) => console.log(status), onError: (err) => console.error(err), }); // dispose (idempotent): unwatch();

Parameters

NameTypeDefaultNotes
accountAddressrequiredSubAccount to subscribe for.
chainIdnumber?config defaultOptional chain override.
onNotification(n: Notification) => voidrequiredFires per parsed frame.
onStatusChange(s: SocketStatus) => void?undefinedConnection status changes.
onError(e: SymmError) => void?undefinedTransport / parse errors; does not stop the sub.

Returns

() => void — idempotent disposer. Call to unsubscribe.

searchNotifications — REST history

Paginated search of past notifications. Filter by action, quote id, temp id, action-status, or time range.

const page = await searchNotifications(config, { account: subAccount, filter: { quoteId: "42" }, page: 0, size: 20, }); for (const notification of page.data) { console.log(notification.quoteId, notification.type); }

Parameters

NameTypeNotes
accountAddressSubAccount to scope the search to.
filterNotificationSearchFilter?quoteId / tempQuoteId / lastSeenAction / date range.
pagenumber0-indexed.
sizenumberRows per page.
chainIdnumber?Optional chain override.

Returns

NotificationSearchResult{ data: Notification[], total: number }.

Also exposes getNotificationSearchQueryOptions / getNotificationSearchQueryKey for TanStack integration.

Notification shape

Normalized frame — camelCase, with quoteId resolved to the on-chain id when known (falling back to the temp id) and type classified from actionStatus.

interface Notification { id: string; quoteId: string; // on-chain id (string) or temp id when not yet anchored tempQuoteId: number; // negative pre-chain type: NotificationType; // "success" | "failed" | "seen" | "other" actionStatus: string | null; // raw wire value lastSeenAction: string | null; account: string | null; vaAddress: string | null; counterpartyAddress: string; filledAmountOpen: string | null; filledAmountClose: string | null; avgPriceOpen: string; avgPriceClose: string; failureType: string | null; failureMessage: string | null; errorCode: number | null; stateType: string | null; createTime: string; raw: RawNotification; }

The pair (tempQuoteId, quoteId) is the temp ↔ on-chain link. A frame with both set is the anchor frame — it’s how the reconciler learns which temp row is now which on-chain row.

NotificationType

Broad classification derived from actionStatus. Enumerated so consumers can switch on it without knowing the wire tags:

enum NotificationType { SUCCESS = "success", FAILED = "failed", SEEN = "seen", OTHER = "other", }

classifyQuoteNotificationAction

Turn a lastSeenAction into an “open” / “close” / “other” bucket. Used by higher layers to decide which query slice to invalidate on a notification burst.

const kind = classifyQuoteNotificationAction(notification.lastSeenAction); // "open" | "close" | "other"

normalizeNotification

Pure helper that turns the raw wire frame into a Notification. watchNotifications and searchNotifications call it internally; expose it directly when consuming the raw feed elsewhere (e.g. replaying a fixture in tests).

const notification = normalizeNotification(rawFrame);
Last updated on