Skip to content

Conversation

@abretonc7s
Copy link
Contributor

@abretonc7s abretonc7s commented Nov 1, 2025

Description

This PR fixes a performance regression in the Perps feature introduced in PR #21428 (October 21, 2025) where L2 order book WebSocket subscriptions were created for 100+ markets globally, despite only 2 views needing this data.

What is the reason for the change?

Performance Regression: PR #21428 added includeOrderBook: true to ALL price subscriptions (including the prewarm system) to support maker/taker fee calculations. This created unnecessary L2 order book WebSocket subscriptions for 100+ markets on every screen, even though only PerpsOrderView and PerpsClosePositionView actually use bestBid/bestAsk data.

Critical Context: This issue is present in release/7.58.0 (about to be submitted). It wasn't detected earlier because it was masked by:

  1. React Native patch performance issues (October 2025) - caused general app slowness
  2. HIP-3 new markets (October 2025) - added 3-10 markets which multiplied the problem
  3. All three issues hit simultaneously, making attribution extremely difficult

The order book issue would have been obvious in isolation, but was effectively "lost in the noise" of other performance problems.

What is the improvement/solution?

Architectural Fix: Separate order book subscriptions from basic price subscriptions using a dedicated channel:

  1. Keep prewarm efficient: Basic price data (price, %change, funding, OI, volume) remains in prewarm for 100+ markets
  2. Separate top of book channel: New TopOfBookStreamChannel and usePerpsTopOfBook() hook
  3. Explicit subscriptions: Only PerpsOrderView and PerpsClosePositionView subscribe to top of book data for their 1 active token

Note: Renamed to "TopOfBook" (from "OrderBook") to clarify that it provides only best bid/ask (1 level), not full L2 order book with multiple levels. Full L2 order book subscriptions would be a separate feature if needed.

Result: Reduces L2 order book WebSocket subscriptions from 100+ (global) to 2 maximum (on-demand).

Implementation Details

Phase 1: Infrastructure

  • Created TopOfBookStreamChannel class in PerpsStreamManager.tsx
  • Created usePerpsTopOfBook hook in hooks/stream/
  • Added TypeScript types for TopOfBookData

Phase 2: View Updates

  • Updated PerpsOrderView.tsx to use usePerpsTopOfBook
  • Updated PerpsClosePositionView.tsx to use usePerpsTopOfBook
  • Both views now explicitly request top of book data for their active asset only

Phase 3: Cleanup

  • Removed includeOrderBook: true from prewarm subscription (line 357)
  • Removed includeOrderBook: true from regular subscriptions (line 250)

Phase 4: Testing

  • Updated test mocks to include topOfBook channel
  • All Perps Views tests pass (19/19)
  • All Perps Hooks tests pass (68/68)

Changelog

CHANGELOG entry: Fixed Perps performance issue by optimizing order book subscriptions

Related issues

Fixes: Performance regression from PR #21428
Related: Issue present in release/7.58.0

Manual testing steps

Feature: Perps Order Book Subscription Optimization

  Scenario: HomeView performance - no unnecessary order book subscriptions
    Given user opens Perps HomeView
    When the view loads with positions, watchlist, and trending markets
    Then only basic price data should be subscribed (no order book)
    And the view should render without performance issues

  Scenario: MarketListView performance - no unnecessary order book subscriptions
    Given user opens Perps MarketListView with 100+ markets
    When the list renders
    Then only basic price data should be subscribed (no order book)
    And scrolling should be smooth

  Scenario: OrderView fee calculation - top of book works correctly
    Given user opens PerpsOrderView for a market
    When user enters a limit order
    Then top of book data should be fetched for that 1 market only
    And maker/taker fee should be calculated correctly based on bestBid/bestAsk
    And fee should update when limit price changes relative to top of book

  Scenario: ClosePositionView fee calculation - top of book works correctly
    Given user opens PerpsClosePositionView for a position
    When user enters close details
    Then top of book data should be fetched for that 1 market only
    And closing fee should be calculated correctly based on bestBid/bestAsk

  Scenario: Multiple views - independent subscriptions
    Given user has OrderView open for BTC
    When user navigates to ClosePositionView for ETH
    Then BTC top of book subscription should clean up
    And ETH top of book subscription should be created
    And only 1 top of book subscription should be active at a time

Screenshots/Recordings

Before

Video extracted from clean install on release/7.58.0

android_7.58_unusable.mp4

Architecture:

Connection → Prewarm (includeOrderBook: true)
  ├─ Subscribe to 100+ markets with L2 order book
  ↓
All Views (HomeView, MarketListView, OrderView, etc.)
  ├─ Receive order book data for 100+ markets
  └─ Process bestBid/bestAsk for 100+ markets (98% unused)

WebSocket Subscriptions: 100+ L2 order book subscriptions created on connection

Performance: Views processing unnecessary order book data for markets they don't display

After

android_fix_performance.mp4

Architecture:

Connection → Prewarm (basic prices only)
  ├─ Subscribe to 100+ markets for price/change/funding/OI/volume
  ↓
HomeView/MarketListView/etc.
  ├─ Receive basic price data only
  └─ No order book processing

OrderView/ClosePositionView
  ├─ usePerpsLivePrices(['BTC']) → basic price data
  ├─ usePerpsTopOfBook(['BTC']) → top of book for 1 market
  └─ Process top of book only for active trading asset

WebSocket Subscriptions: Max 2 L2 order book subscriptions (only when OrderView or ClosePositionView is active)

Performance: Views only process data they actually need

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

Introduces a dedicated top-of-book stream/hook used by order/close views, removes global L2 order book from price subscriptions, and optimizes price/throttle handling.

  • Streams/Infrastructure:
    • Top of Book: Add TopOfBookStreamChannel in PerpsStreamManager and usePerpsTopOfBook hook; subscribes per-symbol with includeOrderBook: true, caches best bid/ask, and cleans up on unmount.
    • Price Subscriptions: Remove includeOrderBook from prices subscriptions and prewarm; keep basic price data only.
    • Performance: Improve throttling/timer cleanup in StreamChannel; memoize usePerpsLivePrices dependencies; optimize HyperLiquidSubscriptionService.allMids to process only subscribed symbols and skip unchanged prices before notifying.
  • Views:
    • Update PerpsOrderView.tsx and PerpsClosePositionView.tsx to use usePerpsTopOfBook for maker/taker fee inputs (currentBidPrice/currentAskPrice).
  • Tests:
    • Add usePerpsTopOfBook tests and TopOfBookStreamChannel tests; update mocks (defaultPerpsTopOfBookMock) and view tests to wire new hook; mark perps-add-funds.spec.ts test as it.skip.

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

@abretonc7s abretonc7s requested a review from a team as a code owner November 1, 2025 08:06
@github-actions
Copy link
Contributor

github-actions bot commented Nov 1, 2025

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.

cursor[bot]

This comment was marked as outdated.

@abretonc7s abretonc7s added team-perps Perps team and removed team-earn labels Nov 1, 2025
@github-actions github-actions bot added size-M and removed size-S labels Nov 1, 2025
cursor[bot]

This comment was marked as outdated.

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 78.31325% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.02%. Comparing base (744b8ce) to head (bece15f).
⚠️ Report is 46 commits behind head on main.

Files with missing lines Patch % Lines
...mponents/UI/Perps/providers/PerpsStreamManager.tsx 69.56% 9 Missing and 5 partials ⚠️
...ponents/UI/Perps/hooks/stream/usePerpsOrderBook.ts 83.33% 1 Missing and 1 partial ⚠️
...I/Perps/services/HyperLiquidSubscriptionService.ts 88.23% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #22038      +/-   ##
==========================================
- Coverage   77.04%   77.02%   -0.03%     
==========================================
  Files        3765     3805      +40     
  Lines       95826    97096    +1270     
  Branches    18616    18928     +312     
==========================================
+ Hits        73833    74792     +959     
- Misses      16918    17165     +247     
- Partials     5075     5139      +64     

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

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

gambinish
gambinish previously approved these changes Nov 2, 2025
cursor[bot]

This comment was marked as outdated.

@abretonc7s abretonc7s enabled auto-merge November 2, 2025 00:23
gambinish
gambinish previously approved these changes Nov 2, 2025
@gambinish gambinish changed the title fix(perps): price caching performance issues fix(perps): price caching performance issues cp-7.58.0 Nov 2, 2025
cursor[bot]

This comment was marked as outdated.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 2, 2025

@abretonc7s abretonc7s added this pull request to the merge queue Nov 2, 2025
Merged via the queue into main with commit d3e8361 Nov 2, 2025
87 checks passed
@abretonc7s abretonc7s deleted the feat/perps/price-caching branch November 2, 2025 18:11
@github-actions github-actions bot locked and limited conversation to collaborators Nov 2, 2025
@metamaskbot metamaskbot added the release-7.59.0 Issue or pull request that will be included in release 7.59.0 label Nov 2, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.59.0 Issue or pull request that will be included in release 7.59.0 size-M team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants