Skip to content

feat(perps): sdk reconnect on native socket event#25022

Merged
abretonc7s merged 45 commits intomainfrom
feat/perps/ws-sdk-terminate-event
Jan 26, 2026
Merged

feat(perps): sdk reconnect on native socket event#25022
abretonc7s merged 45 commits intomainfrom
feat/perps/ws-sdk-terminate-event

Conversation

@abretonc7s
Copy link
Contributor

@abretonc7s abretonc7s commented Jan 22, 2026

Description

This PR implements an event-based WebSocket connection health monitoring system for Perps with visual toast notifications.

What is the reason for the change?

The previous WebSocket connection monitoring used polling (5-second intervals) to check connection state, which caused:

  • Delayed detection of disconnection events
  • Unnecessary resource usage from constant polling
  • Poor user experience when connection issues occurred

What is the improvement/solution?

This PR implements a layered architecture with event-driven connection monitoring:

  1. UI Layer: Custom PerpsWebSocketHealthToast component with animated slide-in/out notifications showing connection states (connected/connecting/disconnected) with retry functionality

  2. Bridge Layer: useWebSocketHealthToast hook that subscribes to connection state changes and translates them into toast notifications

  3. Controller Layer: PerpsController facade exposing subscribeToConnectionState() and reconnect() methods

  4. Service Layer: HyperLiquidClientService now listens to the SDK's terminate event (fired when all reconnection attempts are exhausted) for instant detection

Key improvements:

  • Event-driven: Uses SDK's terminate event instead of polling for instant feedback
  • User feedback: Toast shows connection status with contextual messages and reconnection attempt count
  • Manual retry: Users can tap "Retry" button when disconnected to manually trigger reconnection
  • Auto-retry: Automatically attempts reconnection after 10 seconds if still disconnected (invisible recovery for temporary HyperLiquid outages)
  • Auto-hide: Success toast auto-hides after 3 seconds
  • Decoupled architecture: Each layer only knows about its immediate neighbors via well-defined contracts

Changelog

CHANGELOG entry: Added WebSocket connection health toast notification for Perps trading to show real-time connection status with manual retry option

Related issues

Fixes:

Manual testing steps

Feature: WebSocket Health Toast

  Scenario: User sees disconnection toast when WebSocket terminates
    Given user is on the Perps trading screen
    And WebSocket connection is active

    When WebSocket connection fails and exhausts all reconnection attempts
    Then user sees a red "Disconnected" toast at the top of the screen
    And toast shows "Retry" button

  Scenario: User manually retries connection
    Given user sees the disconnection toast with Retry button

    When user taps the "Retry" button
    Then toast changes to yellow "Connecting" state showing reconnection attempt
    And when connection succeeds, toast shows green "Connected" message
    And toast auto-hides after 3 seconds

  Scenario: Auto-retry recovers connection after temporary outage
    Given user sees the disconnection toast
    And HyperLiquid service was temporarily unavailable

    When 10 seconds pass without user interaction
    Then system automatically attempts reconnection
    And if HyperLiquid is back online, connection recovers silently
    And user sees green "Connected" toast briefly before it auto-hides

  Scenario: User navigates away and back during outage
    Given WebSocket is disconnected

    When user navigates away from Perps screen and returns
    Then disconnection toast is shown again (not hidden due to remount)

Screenshots/Recordings

Before

No visual feedback when WebSocket connection fails - users only notice when data stops updating.

After

auto-reconnect.mp4

Pre-merge author checklist

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

Implements event-driven WebSocket health monitoring for Perps with user-visible status and retry.

  • Add PerpsWebSocketHealthToast + context/provider rendered at App level; slide-in states for DISCONNECTED/CONNECTING/CONNECTED, auto-hide on success, manual Retry, and test IDs
  • New useWebSocketHealthToast hook bridges stream context to global toast; auto-retry after 10s, cleans up on unmount
  • Controller/Provider: expose getWebSocketConnectionState(), subscribeToConnectionState(), and reconnect(); propagate to HyperLiquidProvider
  • HyperLiquidClientService: replace polling with SDK terminate event listening; connection state listeners, manual/auto reconnection with capped attempts and retry delay; cleanup on disconnect; ensure transports/clients recreated safely
  • Stream reconnection: PerpsStreamManager.clearAllChannels() now reconnects active channels; CandleStreamChannel.reconnect() fixes hyphenated symbols parsing
  • Config/strings: add RECONNECTION_RETRY_DELAY_MS and i18n copy for toast
  • Extensive unit tests added for context, toast UI, hook, client/service, provider, stream manager, and controller

Written by Cursor Bugbot for commit f8c2166. This will update automatically on new commits. Configure here.

michalconsensys and others added 26 commits January 8, 2026 14:34
- Create PerpsWebSocketHealthToast component with slide-from-top animation
- Show connection states: disconnected (error), connecting (warning), connected (success)
- Position toast at top of screen (74px from top) with solid background and shadow
- Update useWebSocketHealthToast hook to return state for custom toast rendering
- Remove websocketHealth options from usePerpsToasts (no longer needed)
- Update PerpsStreamBridge to render the custom toast component
- Add reconnect() method to HyperLiquidClientService, Provider, and Controller
- Show Retry button on toast when connection is disconnected
- Update toast positioning to 12px from left/right edges
- Update copy: title, description, and button text per design specs
- Limit auto-reconnection to 10 attempts before marking as disconnected
- Reset attempt counter when user manually clicks Retry button
- Allows user to always retry even after max attempts reached
…sitioning

- Create WebSocketHealthToastContext for managing toast state globally
- Render PerpsWebSocketHealthToast at App level next to existing Toast
- Update useWebSocketHealthToast hook to use context instead of local state
- Remove toast rendering from PerpsStreamBridge (now uses context)
- Ensures toast appears on top of all content regardless of where useWebSocketHealthToast is called
…ached

- Update condition to show disconnected toast when transitioning from
  CONNECTING to DISCONNECTED (max attempts reached case)
- Previously only showed toast for direct CONNECTED to DISCONNECTED transition
- Update CandleStreamChannel.reconnect() to call disconnect() instead of
  disconnectAll() directly so the spy in tests can detect the call
- Update reconnect test to verify reconnection happened without relying
  on exact call count (more resilient to implementation changes)
- Use advanceTimersByTimeAsync for proper async promise handling
- Add await to initialize() calls since it's an async method
- Add mock cleanup in afterEach to prevent leakage between tests
- Use rejects.toThrow() for async error assertions
…ptionClient

- Add await before initialize() in toggleTestnet to ensure SDK clients are ready before returning
- Change ensureSubscriptionClient from sync to async and await initialize() call
- Update all callers in HyperLiquidSubscriptionService to await ensureSubscriptionClient
- Fix Jest open handles by using fake timers globally and proper cleanup in afterEach
- Update test mocks to use mockResolvedValue for async ensureSubscriptionClient
…nnect

The reconnect() method was using split('-') which incorrectly parsed cache
keys when coin symbols contained hyphens (e.g., 'ETH-USD'). This would
cause 'ETH-USD-1h' to be parsed as coin='ETH' and interval='USD' instead
of coin='ETH-USD' and interval='1h'.

Fixed by using lastIndexOf('-') to split from the right, ensuring the
interval (always the last segment) is correctly identified while preserving
the full coin symbol including any hyphens.

Added tests to verify the fix works for coins with and without hyphens.
Wrap initial listener call in try-catch to match notifyConnectionStateListeners behavior. This ensures the unsubscribe function is always returned even if the listener throws during the initial call, preventing zombie listeners from remaining in the Set.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

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.

@metamaskbot metamaskbot added the team-perps Perps team label Jan 22, 2026
Resolve merge conflicts preserving WebSocket terminate event detection:
- HyperLiquidProvider: Combined initialization promise caching from main
  with terminate callback from HEAD for robust connection handling
- HyperLiquidClientService: Used HEAD's simpler transport.ready() approach,
  terminate events handle connection failures
- Tests: Updated to use main's naming convention while keeping all
  terminate event tests from HEAD
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

Copy link

@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.

@github-actions
Copy link
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePerps
  • Risk Level: medium
  • AI Confidence: 85%
click to see 🤖 AI reasoning details

This PR introduces WebSocket connection health monitoring and toast notifications for the Perps (perpetuals trading) feature. The changes include:

  1. App.tsx modification: Adds a new WebSocketHealthToastProvider context wrapper around the entire app and a PerpsWebSocketHealthToast component. While this wraps the whole app, the context is lightweight (simple state management) and the toast only renders when visible. The provider is passive and doesn't affect other app functionality.

  2. PerpsController.ts (CRITICAL): Adds new methods for WebSocket state management (getWebSocketConnectionState, subscribeToConnectionState, reconnect). These are additive changes that don't modify existing behavior.

  3. HyperLiquidClientService.ts: Major refactoring of WebSocket connection handling - replaces polling-based health checks with event-based state notifications, adds reconnection retry logic with max attempts. This is the most significant change affecting real-time data streaming.

  4. New UI components: Toast component and context for displaying connection status to users.

  5. PerpsStreamManager and CandleStreamChannel: Adds reconnect() methods for re-establishing subscriptions after WebSocket reconnection.

All changes except the App.tsx wrapper are isolated to the Perps module (app/components/UI/Perps/). The SmokePerps tests cover the Perps Add Funds flow which relies on WebSocket connections for real-time data, making them appropriate for validating these changes.

The risk is medium because:

  • The App.tsx change adds a context provider but it's passive and lightweight
  • The WebSocket connection handling changes are significant but isolated to Perps
  • No changes to core wallet functionality, confirmations, navigation, or other features
  • Unit tests are included for the new functionality

View GitHub Actions results

@sonarqubecloud
Copy link

@abretonc7s abretonc7s added this pull request to the merge queue Jan 26, 2026
Merged via the queue into main with commit 91ad46f Jan 26, 2026
82 of 83 checks passed
@abretonc7s abretonc7s deleted the feat/perps/ws-sdk-terminate-event branch January 26, 2026 15:42
@github-actions github-actions bot locked and limited conversation to collaborators Jan 26, 2026
@metamaskbot metamaskbot added the release-7.65.0 Issue or pull request that will be included in release 7.65.0 label Jan 26, 2026
@metamaskbot metamaskbot added release-7.64.0 Issue or pull request that will be included in release 7.64.0 and removed release-7.65.0 Issue or pull request that will be included in release 7.65.0 labels Feb 3, 2026
@metamaskbot
Copy link
Collaborator

No release label on PR. Adding release label release-7.64.0 on PR, as PR was added to branch 7.64.0 when release was cut.

@metamaskbot
Copy link
Collaborator

No release label on PR. Adding release label release-7.63.1 on PR, as PR was cherry-picked in branch 7.63.1.

@metamaskbot metamaskbot added release-7.63.1 Issue or pull request that will be included in release 7.63.1 and removed release-7.64.0 Issue or pull request that will be included in release 7.64.0 labels Feb 5, 2026
@metamaskbot
Copy link
Collaborator

Missing release label release-7.63.1 on PR. Adding release label release-7.63.1 on PR and removing other release labels(release-7.64.0), as PR was cherry-picked in branch 7.63.1.

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

Labels

release-7.63.1 Issue or pull request that will be included in release 7.63.1 size-XL team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants