Skip to content

chore: add ohlcv websocket streaming#29739

Open
sahar-fehri wants to merge 16 commits into
mainfrom
chore/ohlcv-ws-streaming-integration
Open

chore: add ohlcv websocket streaming#29739
sahar-fehri wants to merge 16 commits into
mainfrom
chore/ohlcv-ws-streaming-integration

Conversation

@sahar-fehri
Copy link
Copy Markdown
Contributor

@sahar-fehri sahar-fehri commented May 5, 2026

Description

Related to: https://www.notion.so/metamask-consensys/OHLCV-WebSocket-Integration-UI-Implementation-Guide-346f86d67d6880b6a70fc3be0f0c34b9

Wires OHLCVService from @metamask/core-backend into the Engine and creates a useOHLCVRealtime hook that streams live candlestick updates to the advanced chart via the existing realtimeBar prop on AdvancedChart.

Why: The advanced chart currently only renders historical data fetched via the REST OHLCV API. Users see stale candles until they navigate away and back. Real-time streaming via WebSocket keeps the chart live with 5-second heartbeat updates.

How: Follows the exact same Engine wiring pattern as AccountActivityService — messenger, init function, Engine registration. The new useOHLCVRealtime hook subscribes to OHLCVService:barUpdated events, filters by channel, and converts the WS bar format (timestamp in Unix seconds) to the chart's expected format (time in milliseconds).

Manual Test Plan

Prerequisites

  • MetaMask Mobile connected to a wallet with tokens
  • backendWebSocketConnection feature flag enabled

Adding console.log statements to the mobile hook

1. Inside handleBarUpdated — after the channel guard:

const handleBarUpdated = (payload: { channel: string; bar: WSOHLCVBar }) => {
  if (payload.channel === channelRef.current) {
    console.log(                                                        // ← ADD
      `[OHLCV-WS] Bar received — channel=${payload.channel}, close=${payload.bar.close}, ts=${payload.bar.timestamp}`,
    );
    lastMessageTimeRef.current = Date.now();
    ...

2. Inside handleSubscriptionError — first line of the callback:

const handleSubscriptionError = (payload: { channel: string; error: string; operation: string }) => {
  console.log(                                                          // ← ADD
    `[OHLCV-WS] Subscription error on ${payload.channel}: ${payload.error} (${payload.operation})`,
  );
};

3. Inside handleChainStatusChanged — after the chainIds.includes guard:

if (payload.chainIds.includes(chainId)) {
  console.log(                                                          // ← ADD
    `[OHLCV-WS] Chain status changed — chainId=${chainId}, status=${payload.status}`,
  );
  chainDownRef.current = payload.status === 'down';
}

4. Inside pollLatest — first line of the function:

const pollLatest = async () => {
  pollingAbortRef.current?.abort();
  const controller = new AbortController();
  pollingAbortRef.current = controller;

  console.log('[OHLCV-WS] Polling /latest via REST fallback');          // ← ADD
  ...

5. Inside the staleness setInterval — when isStale || chainDown:

if (isStale || chainDownRef.current) {
  console.log(                                                          // ← ADD
    `[OHLCV-WS] Stream stale or chain down — isStale=${isStale}, chainDown=${chainDownRef.current}, elapsed=${elapsed}ms`,
  );
  pollLatest();
}

6. Inside the debounce setTimeout — first line:

debounceTimerRef.current = setTimeout(async () => {
  console.log(                                                          // ← ADD
    `[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for ${channel}`,
  );
  try {
    await Engine.controllerMessenger.call('OHLCVService:subscribe', { ... });
    ...

7. In the cleanup return function — first line:

return () => {
  console.log(                                                          // ← ADD
    `[OHLCV-WS] Cleanup — channel=${channel}, wasSubscribed=${subscribedRef.current}`,
  );
  cancelledRef.current = true;
  ...

Enabling core logs in the debugger

By default, core OHLCVService logs use projectLogger (the debug package) and won't appear in the React Native debugger. To make them visible, open:

node_modules/@metamask/core-backend/dist/ws/ohlcv/OHLCVService.cjs

Find this line (near the top, around line 30):

const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, SERVICE_NAME);

Replace with:

const log = (...args) => console.log('[OHLCV-WS]', ...args);

Now all core logs will appear in the debugger with the [OHLCV-WS] prefix, alongside the mobile hook logs. Revert with yarn install when done.


Group A — No Code Changes (Just Tap and Observe)


Scenario 1: Basic WebSocket Subscription

Steps:

  1. Open Token Details for a supported token (e.g., ETH on Base)
  2. Wait for historical chart to load
  3. Observe logs

Expected logs:

[OHLCV-WS] OHLCV-WS: Initializing — registering system-notifications callback
[OHLCV-WS] OHLCV-WS: Resubscribing active channels after reconnect {count: 0}
[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, close=1986.69, ts=1778538600

Note: Resubscribing active channels after reconnect {count: 0} appears at app boot because AccountActivityService opened the shared WebSocket first. OHLCVService hears the CONNECTED event and checks for channels to restore — finds zero since no subscription exists yet. This is normal.

Verify: Bars continue arriving every ~5s with updating close prices.


Scenario 2: Navigate Away (Unsubscribe + Grace Period)

Steps:

  1. From Scenario 1, press back to leave Token Details
  2. Wait 3+ seconds
  3. Observe logs

Expected logs:

[OHLCV-WS] Cleanup — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, wasSubscribed=true
[OHLCV-WS] OHLCV-WS: Grace period expired — performing actual WS unsubscribe {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] OHLCV-WS: WS unsubscribe completed {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}

Verify: No more bar updates after grace period expires.


Scenario 3: Rapid Navigation (Grace Period Cancel)

Steps:

  1. Open Token Details for Token A, wait for subscription
  2. Navigate back
  3. Immediately re-open Token A (within 3 seconds)

Expected logs:

[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Cleanup — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, wasSubscribed=true
[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Cancelled grace-period unsubscribe, bumped refCount {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur', refCount: 1}

Verify: Cancelled grace-period unsubscribe, bumped refCount appears — subscription was reused without a server roundtrip.


Scenario 4: Switch Between Tokens

Steps:

  1. Open Token Details for Token A (e.g. ETH on Base), wait for subscription
  2. Navigate back to token list
  3. Open Token B (e.g. MNT on Ethereum)

Expected logs:

[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, close=1988.32, ts=1778539500
[OHLCV-WS] Cleanup — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, wasSubscribed=true
[OHLCV-WS] OHLCV-WS: Grace period expired — performing actual WS unsubscribe {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] OHLCV-WS: WS unsubscribe completed {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:1/erc20:0x3c3a...15m.eur
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: 'market-data.v1.eip155:1/erc20:0x3c3a...15m.eur'}
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:1/erc20:0x3c3a...15m.eur, close=0.59, ts=1778539500

Verify: Token A fully unsubscribes (grace period expires). Token B gets its own subscription and bars flow.


Scenario 5: Rapid Time Range Switching

Steps:

  1. Open Token Details, wait for bars on default time range (15m)
  2. Rapidly switch between time ranges (e.g. 1H → 1D → 1W → 1H)

Expected logs (showing one switch cycle: 15m → 1h):

[OHLCV-WS] Cleanup — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, wasSubscribed=true
[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.1h.eur
[OHLCV-WS] OHLCV-WS: Flushing grace-period channel before new subscribe {flushedChannel: '...15m.eur', newChannel: '...1h.eur'}
[OHLCV-WS] OHLCV-WS: Grace period expired — performing actual WS unsubscribe {channel: '...15m.eur'}
[OHLCV-WS] OHLCV-WS: WS unsubscribe completed {channel: '...15m.eur'}
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: '...1h.eur'}

This pattern repeats for each switch (1h → 1d → 1h → 15m → 1m). Each time, the old channel is flushed immediately before the new subscribe — no accumulation, no server rejections.

Verify: Every subscribe succeeds (Subscribe succeeded). Flushing grace-period channel appears before each new subscribe. Bars flow on the final time range.


Scenario 6: App Background / Foreground

Steps:

  1. Open Token Details for a supported token, wait for bars to flow
  2. Press home button (send app to background)
  3. Wait ~10 seconds
  4. Bring app back to foreground

Expected logs:

[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, close=1987.42, ts=1778540400
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, close=1987.37, ts=1778540400
— app sent to background, then brought back —
[OHLCV-WS] OHLCV-WS: Resubscribing active channels after reconnect {count: 1}
[OHLCV-WS] OHLCV-WS: Resubscription succeeded {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, close=1987.18, ts=1778540400

Verify: Resubscribing active channels after reconnect {count: 1} appears after foregrounding. Bars resume automatically without user interaction.


Scenario 7: Unsupported Token (No OHLCV Data)

Steps:

  1. Open Token Details for a token with no OHLCV API data

Expected: No WS subscription, falls back to legacy line chart.


Group B — Requires Changing DEV Constants in useOHLCVRealtime.ts

After testing, set both constants back to 0 before committing.


Scenario 8: WebSocket Disconnect → REST Polling Fallback

What this tests: The WebSocket connection drops and stays disconnected. After the staleness threshold (30s) is exceeded, the hook falls back to polling REST.

Code to add

In useOHLCVRealtime.ts, set the DEV constants:

const DEV_SIMULATE_WS_DISCONNECT_AFTER_MS = 10000; // ← ACTIVE

How it works

After 10s, calls BackendWebSocketService:disconnect (clean shutdown, no auto-reconnect). The WS stays dead. After 30s with no bars, staleness triggers REST polling every 15s.

Steps to test

  1. Set the constants as shown above
  2. Rebuild / hot-reload the app
  3. Open Token Details for a supported token
  4. Wait for bars to start flowing (~5s)
  5. At 10s, the simulated disconnect fires automatically
  6. Wait ~30s for the staleness threshold
  7. Observe REST fallback polling in logs

Expected logs:

[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Subscribe succeeded — new WS subscription created {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur'}
[OHLCV-WS] Bar received — channel=market-data.v1.eip155:8453/slip44:60.15m.eur, close=1985.08, ts=1778540400
[OHLCV-WS] DEV: Simulating WS disconnect (no reconnect) after 10000ms
[OHLCV-WS] Stream stale or chain down — isStale=true, chainDown=false, elapsed=38975ms
[OHLCV-WS] Polling /latest via REST fallback
[OHLCV-WS] Stream stale or chain down — isStale=true, chainDown=false, elapsed=44886ms
[OHLCV-WS] Polling /latest via REST fallback

Verify: After the simulated disconnect, no more Bar received logs. REST polling kicks in every 15s once staleness threshold (30s) is exceeded.


Group C — Requires Editing .cjs in node_modules

After testing, run yarn install in the mobile repo to restore the original file.


Scenario 10: Subscribe Failure / Error Recovery

What this tests: OHLCVService.subscribe() fails. The service catches the error, publishes OHLCVService:subscriptionError, forces reconnection, and REST fallback keeps the chart alive.

Code to add

1. Disable dev simulation constant in useOHLCVRealtime.ts:

const DEV_SIMULATE_WS_DISCONNECT_AFTER_MS = 0;

2. Simulate subscribe failure — open node_modules/@metamask/core-backend/dist/ws/ohlcv/OHLCVService.cjs.

Find the subscribe call (look for BackendWebSocketService:subscribe) and comment it out, then add a throw:

// await __classPrivateFieldGet(this, _OHLCVService_messenger, "f").call('BackendWebSocketService:subscribe', {
//     channels: [channel],
//     channelType: SUBSCRIPTION_NAMESPACE,
//     callback: (notification) => {
//         __classPrivateFieldGet(this, _OHLCVService_instances, "m", _OHLCVService_handleBarUpdate).call(this, channel, notification);
//     },
// });
throw new Error('DEV: Simulated subscribe failure — invalid channel');

Steps to test

  1. Apply both code changes above
  2. Reload the app
  3. Open Token Details for a supported token
  4. Observe logs
  5. Revert: run yarn install to restore the original .cjs

Expected — look for these key logs:

[OHLCV-WS] OHLCV-WS: Resubscribing active channels after reconnect {count: 0}
[OHLCV-WS] Debounce fired — calling OHLCVService:subscribe for market-data.v1.eip155:8453/slip44:60.15m.eur
[OHLCV-WS] OHLCV-WS: Subscription failed, forcing reconnection {channel: 'market-data.v1.eip155:8453/slip44:60.15m.eur', error: Error: Test error ...}
[OHLCV-WS] Subscription error on market-data.v1.eip155:8453/slip44:60.15m.eur: Error: Test error (subscribe)
[OHLCV-WS] OHLCV-WS: Forcing WebSocket reconnection
[OHLCV-WS] OHLCV-WS: Resubscribing active channels after reconnect {count: 0}
[OHLCV-WS] Stream stale or chain down — isStale=true, chainDown=false, elapsed=44219ms
[OHLCV-WS] Polling /latest via REST fallback

Verify: Error is caught, reconnection attempted (Forcing WebSocket reconnection), and REST fallback keeps chart alive after staleness is detected.


Log Reference

All logs use the OHLCV-WS prefix. Filter by OHLCV-WS in Flipper / debugger.

Changelog

CHANGELOG entry: Adds websocket streaming integration for ohlcv data

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3194?atlOrigin=eyJpIjoiYmQ4N2E3MTlmZTFlNGYyNGFiODUxNzA2YThmM2FkYTkiLCJwIjoiaiJ9
Related: MetaMask/core#8695

Manual testing steps

Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]

Screenshots/Recordings

Before

After

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Adds a new Engine-integrated OHLCVService plus a realtime hook that subscribes to WebSocket events and falls back to REST polling, which can impact chart correctness, network usage, and Engine lifecycle if miswired. Change is gated behind a new remote feature flag but also updates the @metamask/core-backend dependency to a preview build.

Overview
Enables real-time candlestick updates on the token details advanced chart by wiring OHLCVService into the Engine (new init + messenger + type registrations) and feeding AdvancedChart a computed realtimeBar.

Adds useOHLCVRealtime with a 500ms subscribe debounce, channel-filtered OHLCVService:barUpdated handling, and a staleness/chain-down REST /latest polling fallback, gated by the new remote flag selector selectTokenDetailsOhlcvWsEnabled (registry + CI-known constant updates) and covered by new unit tests.

Updates @metamask/core-backend to a preview version to pick up the OHLCV service implementation.

Reviewed by Cursor Bugbot for commit d5c404b. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 11, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​metamask/​core-backend@​6.2.1 ⏵ 6.2.2-preview-094d56fb3100 +25100100100 +6100

View full report

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.35294% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.83%. Comparing base (3751d9a) to head (caefeb6).
⚠️ Report is 15 commits behind head on main.

Files with missing lines Patch % Lines
...onents/UI/Charts/AdvancedChart/useOHLCVRealtime.ts 91.76% 2 Missing and 5 partials ⚠️
...ine/controllers/core-backend/ohlcv-service-init.ts 16.66% 5 Missing ⚠️
...messengers/core-backend/ohlcv-service-messenger.ts 0.00% 3 Missing ⚠️
...mponents/UI/AssetOverview/Price/Price.advanced.tsx 71.42% 1 Missing and 1 partial ⚠️
app/core/Engine/Engine.ts 0.00% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (3751d9a) and HEAD (caefeb6). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (3751d9a) HEAD (caefeb6)
2 1
Additional details and impacted files
@@             Coverage Diff             @@
##             main   #29739       +/-   ##
===========================================
- Coverage   81.54%   55.83%   -25.72%     
===========================================
  Files        5343     5350        +7     
  Lines      142128   142350      +222     
  Branches    32411    32463       +52     
===========================================
- Hits       115899    79478    -36421     
- Misses      18299    56212    +37913     
+ Partials     7930     6660     -1270     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread package.json
"@metamask/connectivity-controller": "^0.1.0",
"@metamask/controller-utils": "^11.18.0",
"@metamask/core-backend": "^6.2.0",
"@metamask/core-backend": "npm:@metamask-previews/core-backend@6.2.2-preview-094d56fb3",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: to be removed after release

@sahar-fehri sahar-fehri marked this pull request as ready for review May 12, 2026 01:15
@sahar-fehri sahar-fehri requested review from a team as code owners May 12, 2026 01:15
Comment thread app/components/UI/Charts/AdvancedChart/useOHLCVRealtime.ts
});

const wsInterval = WS_INTERVAL_BY_TIME_RANGE[timeRange];
// TODO: Check if we want to add a feature flag to gate the WS OHLCV feature
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be a followup

Comment thread app/components/UI/Charts/AdvancedChart/useOHLCVRealtime.ts
@github-actions github-actions Bot added size-XL and removed size-L labels May 12, 2026
@sahar-fehri sahar-fehri requested a review from a team as a code owner May 12, 2026 12:23
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeWalletPlatform
  • Selected Performance tags: @PerformanceAssetLoading
  • Risk Level: medium
  • AI Confidence: 78%
click to see 🤖 AI reasoning details

E2E Test Selection:

The PR introduces a new OHLCVService (real-time OHLCV candlestick WebSocket streaming) integrated into the Engine, along with a new useOHLCVRealtime hook and updates to the Price.advanced.tsx component.

Key findings:

  1. Engine.ts changes are additive: OHLCVService is added as a stateless non-controller service (listed in STATELESS_NON_CONTROLLER_NAMES), following the same pattern as AccountActivityService. No existing controllers are modified, no initialization order changes, no Redux state sync changes.

  2. Feature flag gated: The new real-time chart feature is behind tokenDetailsOhlcvWsIntegration which is disabled by default in production (inProd: false). This significantly reduces risk of breaking existing functionality.

  3. Preview package: @metamask/core-backend is updated to a preview version (6.2.2-preview-094d56fb3), which introduces some risk around the new OHLCVService API.

  4. UI impact: Changes affect the advanced price chart in the asset overview/token details screen. This is part of the wallet platform feature set.

  5. No E2E tests exist for OHLCV/advanced charts: No existing E2E tests directly test the advanced chart or OHLCV functionality, so there's no risk of breaking existing E2E tests.

  6. SmokeWalletPlatform is the most relevant tag as it covers core wallet platform features including asset display and transaction history. The account-activity WebSocket connection test (under SmokeWalletPlatform) is also relevant since the OHLCVService uses the same BackendWebSocketService infrastructure.

No other tags are needed since:

  • No confirmation flows are affected
  • No account management changes
  • No network/chain permission changes
  • No swap/stake/bridge flows affected
  • The feature is gated behind a disabled-by-default feature flag

Performance Test Selection:
The PR adds real-time WebSocket streaming (OHLCVService) to the asset overview/token details price chart via useOHLCVRealtime hook. This introduces new data loading patterns (WebSocket subscriptions, debounced subscriptions, staleness polling with HTTP fallback every 15s) that could impact asset loading performance. The @PerformanceAssetLoading tag covers token list rendering, balance fetching, and portfolio value calculation - which is the closest match to the asset overview screen where these changes appear. The staleness check interval (15s) and debounce (500ms) could affect perceived responsiveness of the chart component.

View GitHub Actions results

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d5c404b. Configure here.

});
subscribedRef.current = false;
};
}, [assetId, interval, currency, timePeriod, enabled, buildChannel]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary WS teardown when only REST fallback param changes

Medium Severity

timePeriod is in the useEffect dependency array, but it's only consumed by the REST fallback pollLatest function — the WebSocket channel is built solely from assetId, interval, and currency. When switching between time ranges that share the same WS interval (e.g. '1M''1Y', both mapped to '1d' in WS_INTERVAL_BY_TIME_RANGE), the effect tears down and re-establishes the identical WS subscription. This causes a ~500ms real-time data gap (debounce) and unnecessary unsubscribe/resubscribe churn on every such switch. Storing timePeriod in a ref that pollLatest reads would avoid triggering the effect on timePeriod-only changes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d5c404b. Configure here.

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants