Skip to content

Spike: Performance Audit for Perps #23696

@gambinish

Description

@gambinish

What is this about?

This is a performance audit spike for the Perps feature, identifying optimization opportunities across three key areas:

  • API audit: Duplicate geolocation calls, redundant HyperLiquid API requests
  • Controller state analysis: Dead Redux state fields, selector memoization issues
  • UI rendering performance: MarketList triple-rendering, Activity tab unbounded transactions

The audit identifies 7 actionable improvements that will reduce API calls by ~50%, eliminate unnecessary re-renders, and improve perceived performance.

Scenario

User flows audited:

  1. App cold start → Excessive geolocation API calls (4x instead of 1x)
  2. Opening Perps Home Page → ~25+ HyperLiquid API calls (should be ~12)
  3. Opening Market Details → 7 API calls (should be 3)
  4. Opening Activity tab, switching between other Activity tabs → Unbounded transaction list causes slow rendering
  5. App backgrounded >60s then foregrounded → Stale WebSocket connections

Design

N/A - No design changes required except for MarketList tab removal (requires designer input for filter button style).

Technical Details

1. Cap Perps Activity Tab Transaction Count

Jira issue: https://consensyssoftware.atlassian.net/browse/TAT-2212

Problem: No limit on transactions loaded into UI causes slow rendering.

Solution: Add TRANSACTIONS_HISTORY_LIMIT: 100 constant and apply .slice() after deduplication in usePerpsTransactionHistory.ts.

Files:

  • app/components/UI/Perps/constants/transactionsHistoryConfig.ts
  • app/components/UI/Perps/hooks/usePerpsTransactionHistory.ts

2. Selector Memoization Issues in PerpsMarketBalanceActions

Jira issue: https://consensyssoftware.atlassian.net/browse/TAT-2213

Problem: Inline selector creates new array reference every render, triggering Redux warning and unnecessary re-renders.

Solution: Create memoized selector using createSelector that filters withdrawal requests by account address.

Files:

  • app/components/UI/Perps/screens/HomeView/PerpsMarketBalanceActions.tsx

3. Fix WebSocket Connection Stale After Background (more investigation needed)

Jira issue: https://consensyssoftware.atlassian.net/browse/TAT-2214

Problem: HyperLiquid closes WebSocket after 60s inactivity, but app thinks it's still connected when foregrounded.

Solution:

  • Fix keepAlive config property name (should be keepAliveInterval)
  • Add validateAndReconnectIfNeeded() method with ping health check
  • Track background duration and validate connection on foreground

Files:

  • app/components/UI/Perps/types/config.ts
  • app/components/UI/Perps/constants/hyperLiquidConfig.ts
  • app/components/UI/Perps/constants/perpsConfig.ts
  • app/components/UI/Perps/services/PerpsConnectionManager.ts
  • app/components/UI/Perps/hooks/usePerpsConnectionLifecycle.ts
  • app/components/UI/Perps/providers/PerpsConnectionProvider.tsx

4. Coalesce Geolocation API Calls

Jira Issue: https://consensyssoftware.atlassian.net/browse/TAT-2210

Problem: Same geolocation endpoint called by 4 separate features (Ramp, Perps, Rewards, Card) with no shared caching.

API Call Evidence:

https://on-ramp.dev-api.cx.metamask.io/geolocation - 1858ms
https://on-ramp.dev-api.cx.metamask.io/geolocation - 3127ms
https://on-ramp.uat-api.cx.metamask.io/geolocation - 1856ms
https://polymarket.com/api/geoblock - 1807ms

Solution: Create centralized GeolocationController with TTL caching and promise deduplication.

Files:

  • Create: app/core/Engine/controllers/geolocation-controller/GeolocationController.ts
  • Modify: app/components/UI/Perps/controllers/services/EligibilityService.ts
  • Modify: app/components/UI/Ramp/hooks/useDetectGeolocation.ts
  • Modify: app/core/Engine/controllers/rewards-controller/services/rewards-data-service.ts
  • Modify: app/components/UI/Card/sdk/CardSDK.ts

5. Remove Dead PerpsController State Fields

Jira issue: https://consensyssoftware.atlassian.net/browse/TAT-2215

Problem: connectionStatus and positions fields never properly used - live data flows through React Context instead of Redux.

Solution: Remove both fields from type, defaults, and metadata.

Files:

  • app/components/UI/Perps/controllers/PerpsController.ts
  • app/components/UI/Perps/controllers/PerpsController.test.ts
  • app/components/UI/Perps/__mocks__/serviceMocks.ts

6. Optimize Perps API Calls

Jira issue: https://consensyssoftware.atlassian.net/browse/TAT-2211

Problem: ~25+ API calls on Home Page load with significant duplication.

API Call Before After
perpDexs 2 1
meta per DEX 2+ 1
metaAndAssetCtxs 6 5
allMids 5 5
Total ~25+ ~12

Solution:

  • Share meta cache between Provider and SubscriptionService
  • Remove redundant meta() call in getMarketDataWithPrices() (extract from metaAndAssetCtxs)
  • Consolidate perpDexs caching

Files:

  • app/components/UI/Perps/services/HyperLiquidSubscriptionService.ts
  • app/components/UI/Perps/controllers/providers/HyperLiquidProvider.ts
  • app/components/UI/Perps/services/HyperLiquidClientService.ts (optional: request deduplication)

7. MarketList Performance: Replace Swipeable Tabs with Filter Buttons

Jira issue: https://consensyssoftware.atlassian.net/browse/TAT-2216

Problem: Swipeable tabs create 3 simultaneous PerpsMarketList instances with complex scroll synchronization.

Metric Before After
FlashList instances 3 1
Scroll event handlers 2 0
Animation overhead Fade + scroll sync None

Solution: Replace TabsBar + swipeable ScrollView with ButtonFilter pills + single PerpsMarketList.

Files:

  • Create: app/components/UI/Perps/Views/PerpsMarketListView/components/PerpsMarketCategoryFilter/
  • Modify: app/components/UI/Perps/Views/PerpsMarketListView/PerpsMarketFiltersBar.tsx
  • Modify: app/components/UI/Perps/Views/PerpsMarketListView/PerpsMarketListView.tsx
  • Modify: app/components/UI/Perps/Views/PerpsMarketListView/PerpsMarketListView.styles.ts

Functions:

  • transformOrdersToTransactions
  • transformFillsToTransactions
  • transformFundingToTransactions

Design Required: Filter button style, responsive behavior, layout spacing

Threat Modeling Framework

N/A - Performance optimizations only, no security-sensitive changes.

Acceptance Criteria

  • Activity tab renders in <500ms with 100+ transactions
  • No Redux selector warnings in console
  • WebSocket reconnects successfully after 60s+ background
  • Geolocation API called maximum 1x per 5-minute window
  • PerpsController state does not contain connectionStatus or positions fields
  • Home Page makes ≤12 HyperLiquid API calls (down from ~25)
  • Market Details makes ≤3 API calls (down from 7)
  • MarketList renders single FlashList instance (down from 3)
  • Implementation tickets created for all 7 findings

Stakeholder review needed before the work gets merged

  • Engineering (needed in most cases)
  • Design (for MarketList filter button style)
  • Product
  • QA (automation tests are required to pass before merging PRs but not all changes are covered by automation tests - please review if QA is needed beyond automation tests)
  • Security
  • Legal
  • Marketing
  • Management (please specify)
  • Other (please specify)

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions