FEDEV-3973: WebSocket price + candle streaming (UI + SDK)#2611
Conversation
Phase 2 (FEDEV-3973): stream prices and live candles into the UI and SDK, behind off-by-default flags with the existing REST/poll as fallback. - sdk: WsStreamClient transport (isomorphic-ws, reconnect+backoff, snapshot- then-stream); v2 watchTokenPrices / watchCandles raw Subscriptions and a fetchTokenPrices REST snapshot, all serving normalized TokenPricesData over one shared connection - prices: useTokenRecentPricesRequest overlays the WS set behind the abWebsocket flag, throttled, with an originTs staleness fallback to the REST poll; useWsPriceOverlay emits freshness metrics - candles: DataFeed streams the forming bar into TradingView behind wsCandles; the poll stays the backstop and a monotonic onTick guard prevents rollover rewrites - fix weekly/monthly CHART_PERIODS NaN and guard empty stream frames; unit + e2e tests
Deploying gmx-interface-home with
|
| Latest commit: |
1ca4a55
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1158ba88.gmx-interface-home.pages.dev |
| Branch Preview URL: | https://phase-2-ws-prices-2.gmx-interface-home.pages.dev |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.
| wsStatus === "live" && | ||
| wsPrices !== undefined && | ||
| wsOriginTs !== undefined && | ||
| Date.now() - wsOriginTs < WS_PRICES_STALE_MS; |
There was a problem hiding this comment.
Stale WS prices without rerenders
Medium Severity
The WebSocket freshness gate uses Date.now() - wsOriginTs only during render, so when frames stop and nothing else updates state, wsFresh can stay true long after the 10s threshold. On leaderboard/competition routes the REST poll runs every 60s, so stale streamed prices may keep displaying for up to roughly a minute.
Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.
| pricesData: data?.pricesData, | ||
| updatedAt: data?.updatedAt, | ||
| pricesData: wsFresh ? wsPrices : data?.pricesData, | ||
| updatedAt: wsFresh ? wsOriginTs : data?.updatedAt, |
There was a problem hiding this comment.
Loading flag ignores WebSocket prices
Medium Severity
When wsFresh is true and pricesData comes from the WebSocket overlay, isPriceDataLoading still mirrors the REST/SWR isLoading flag only. UI that waits on isPriceDataLoading can stay blocked even though live ticker data is already available from the stream.
Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.
| pricesData: data?.pricesData, | ||
| updatedAt: data?.updatedAt, | ||
| pricesData: wsFresh ? wsPrices : data?.pricesData, | ||
| updatedAt: wsFresh ? wsOriginTs : data?.updatedAt, |
There was a problem hiding this comment.
WS prices skip native alias
Medium Severity
Fresh WebSocket ticker maps are returned directly as pricesData, but the REST fetcher always copies wrapped-token prices onto NATIVE_TOKEN_ADDRESS. If the stream/API map lacks that zero-address entry, native-token rows in useTokensDataRequest lose prices whenever the WS overlay is active.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.
Deploying gmx-interface with
|
| Latest commit: |
1ca4a55
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://50ddfe96.gmx-interface.pages.dev |
| Branch Preview URL: | https://phase-2-ws-prices-2.gmx-interface.pages.dev |


Phase 2 — Prices & candles over WebSocket (UI + SDK)
Streams normalized prices and live candles into the trading UI and the @gmx-io/sdk v2 client, behind off-by-default flags with the existing REST/poll as the fallback. Consumes the gmx-api WS gateway (gmx-io/gmx-api#102).
Linear: https://linear.app/gmx-io/issue/FEDEV-3973
SDK (
@gmx-io/sdkv2)WsStreamClienttransport inutils/stream— isomorphic-ws, reconnect with backoff, snapshot-then-stream, ref-counted single connection.watchTokenPrices()/watchCandles()— rawSubscriptions;fetchTokenPrices()— REST snapshot companion. All serve normalizedTokenPricesData.UI
useTokenRecentPricesRequestoverlays the WS set behind theabWebsocketflag, throttled (~250ms), with anoriginTsstaleness fallback to the REST poll (which never stops polling).useWsPriceOverlayemits freshness metrics.DataFeedstreams the forming bar into TradingView behindwsCandles; the 1s poll stays the backstop, and a monotoniconTickguard prevents series rewrites at a period rollover.CHART_PERIODSNaN; guard empty stream frames.Tests
Unit (conversion, staleness, DataFeed overlay) + in-process SDK e2e (real socket).
Notes
abWebsocket/wsPrices/wsCandles(off by default).pr-tests.yml) is omitted from this push (token lacks theworkflowscope) — to be added separately.