Commit 6f8e8e8
chore(runway): cherry-pick fix(perps): reduce WebSocket subscription overhead and prevent leaks cp-7.63.0 cp-7.64.0 (#25504)
- fix(perps): reduce WebSocket subscription overhead and prevent leaks
cp-7.63.0 cp-7.64.0 (#25496)
## **Description**
This PR addresses WebSocket subscription issues identified during the
rate limiting incident investigation. The fixes reduce subscription
message volume by ~75% and prevent subscription leaks.
### Root Causes Identified
1. **Subscriptions to unregistered DEXs** - System subscribed to ALL 8
DEXs from API instead of only the 2 in our allowlist (main + xyz)
2. **Duplicate DEX subscriptions from race conditions** - Concurrent
calls created 2× subscriptions per DEX
3. **Candle subscription leaks** - Cleanup failed when component
unmounted before async subscription resolved
### Fixes Implemented
#### 1. Filter DEXs by Allowlist on Mainnet (HIGH PRIORITY)
**Files:** `hyperLiquidConfig.ts`, `HyperLiquidProvider.ts`
- Added `MAINNET_HIP3_CONFIG` with `AutoDiscoverAll: false`
- DEX filtering is now dynamic - extracts DEX names from the
`allowlistMarkets` feature flag patterns
- Added `extractDexsFromAllowlist()` method that parses patterns like
`xyz:*`, `xyz:TSLA`, or `xyz`
- **Impact:** Reduces from 8 DEXs to 2 (main + xyz), ~75% reduction in
subscription messages
#### 2. Prevent Duplicate DEX Subscriptions (HIGH PRIORITY)
**File:** `HyperLiquidSubscriptionService.ts`
- Added `pendingClearinghouseSubscriptions` and
`pendingOpenOrdersSubscriptions` Maps
- Refactored `ensureClearinghouseStateSubscription()` and
`ensureOpenOrdersSubscription()` to check for pending promises
- Concurrent calls now wait for the pending promise instead of creating
duplicate subscriptions
- **Impact:** Prevents 50% redundant subscriptions from race conditions
#### 3. Fix Candle Subscription Cleanup (HIGH PRIORITY)
**File:** `HyperLiquidClientService.ts`
- Store subscription promise to enable cleanup even when pending
- Updated cleanup function to wait for pending promise and unsubscribe
- **Impact:** Prevents WebSocket subscription leaks when component
unmounts before subscription resolves
### Test Results
| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| DEXs subscribed | 8 | 2 | 75% reduction |
| clearinghouseState subscriptions | 16 | 2 | 87% reduction |
| openOrders subscriptions | 16 | 2 | 87% reduction |
| Candle subscription leaks | Yes | No | Fixed |
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: Rate limiting incident from WebSocket over-subscription
Related: [WebSocket Subscription Investigation
Report](docs/perps/perps-websocket-subscription-investigation.md)
## **Manual testing steps**
```gherkin
Feature: WebSocket subscription optimization
Scenario: User connects to perps and only allowlisted DEXs are subscribed
Given user has the app installed with perps feature enabled
And WebSocket logging is enabled in dev mode
When user navigates to Perps home screen
Then WebSocket logs show subscriptions only for main and xyz DEXs
And no subscriptions for flx, vntl, hyna, km, abcd, cash DEXs
Scenario: User navigates between markets without duplicate subscriptions
Given user is connected to perps
And WebSocket logging is enabled
When user navigates from Home to xyz:XYZ100 market details
And user returns to Home
And user navigates back to xyz:XYZ100
Then WebSocket logs show no duplicate clearinghouseState subscriptions
And WebSocket logs show no duplicate openOrders subscriptions
Scenario: User views candle chart and subscriptions are properly cleaned up
Given user is on a market details screen with chart visible
When user quickly navigates away from the screen
And user waits for 2 seconds
Then candle subscriptions are properly unsubscribed
And no orphaned candle subscriptions exist
```
## **Screenshots/Recordings**
### **Before**
WebSocket subscription breakdown (full trading flow):
- clearinghouseState: 16 subscriptions (8 DEXs × 2 duplicates)
- openOrders: 16 subscriptions (8 DEXs × 2 duplicates)
- candle: 4 subscriptions, 0 unsubscriptions (leak)
### **After**
WebSocket subscription breakdown (full trading flow):
- clearinghouseState: 2 subscriptions (main + xyz only)
- openOrders: 2 subscriptions (main + xyz only)
- candle: 2 subscriptions, 2 unsubscriptions (balanced)
**Total outgoing messages:** 44
**Total incoming messages:** 402 (down from ~750)
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **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.
---
### Subscription Breakdown
- `clearinghouseState`: 2 (main + xyz)
- `openOrders`: 2 (main + xyz)
- `userFills`: 1
- `webData3`: 1
- `allMids`: 1
- `assetCtxs`: 2 (xyz only, subscribed/unsubscribed on navigation)
- `activeAssetCtx`: 2 (xyz:XYZ100, subscribed/unsubscribed on
navigation)
- `candle`: 2 (1h + 15m intervals)
- `bbo`: 2 (subscribed/unsubscribed during order flow)
### Future Optimization Opportunity
Trading operations (order placement, cancellation, modification)
currently use **HTTP transport**:
- `ExchangeClient` is configured with `httpTransport` to avoid 429 rate
limiting
- `InfoClient` uses `wsTransport` for info queries (multiplexed over
single WS connection)
Now that subscription volume is reduced by 75%, we could consider moving
`ExchangeClient` to WebSocket transport (see follow-up investigation).
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches core perps WebSocket subscription logic (DEX
discovery/filtering and subscription lifecycle), so mistakes could drop
market/user updates or leave subscriptions running. Changes are targeted
and add guards against race conditions and cleanup failures.
>
> **Overview**
> Reduces HyperLiquid HIP-3 WebSocket load by **filtering mainnet DEX
discovery** based on the `allowlistMarkets` patterns, falling back to
*main DEX only* when no HIP-3 DEXs are implied. Adds
`MAINNET_HIP3_CONFIG` and an allowlist parser
(`extractDexsFromAllowlist`) to avoid subscribing to non-allowlisted
HIP-3 DEXs.
>
> Prevents **duplicate per-DEX subscriptions** by deduplicating
concurrent `clearinghouseState` and `openOrders` subscription attempts
via pending-promise tracking, and ensures these pending entries are
cleared during teardown.
>
> Fixes a **candle subscription leak** by tracking the pending
subscription promise and unsubscribing even if cleanup happens before
the async subscription resolves.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9fcf758. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude <noreply@anthropic.com>
[7a0c2a1](7a0c2a1)
Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0cf3191 commit 6f8e8e8
4 files changed
Lines changed: 205 additions & 9 deletions
File tree
- app/components/UI/Perps
- constants
- controllers/providers
- services
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
370 | 370 | | |
371 | 371 | | |
372 | 372 | | |
373 | | - | |
374 | | - | |
375 | 373 | | |
376 | 374 | | |
377 | 375 | | |
| |||
388 | 386 | | |
389 | 387 | | |
390 | 388 | | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
391 | 408 | | |
392 | 409 | | |
393 | 410 | | |
| |||
Lines changed: 81 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
1025 | 1026 | | |
1026 | 1027 | | |
1027 | 1028 | | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
1028 | 1073 | | |
1029 | 1074 | | |
1030 | | - | |
| 1075 | + | |
1031 | 1076 | | |
1032 | 1077 | | |
1033 | 1078 | | |
| |||
1041 | 1086 | | |
1042 | 1087 | | |
1043 | 1088 | | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
1044 | 1124 | | |
1045 | 1125 | | |
1046 | 1126 | | |
| |||
Lines changed: 19 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
526 | 526 | | |
527 | 527 | | |
528 | 528 | | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
529 | 532 | | |
530 | 533 | | |
531 | 534 | | |
| |||
548 | 551 | | |
549 | 552 | | |
550 | 553 | | |
551 | | - | |
| 554 | + | |
| 555 | + | |
552 | 556 | | |
553 | 557 | | |
554 | 558 | | |
| |||
598 | 602 | | |
599 | 603 | | |
600 | 604 | | |
601 | | - | |
602 | | - | |
| 605 | + | |
| 606 | + | |
603 | 607 | | |
604 | 608 | | |
605 | 609 | | |
606 | | - | |
| 610 | + | |
607 | 611 | | |
608 | 612 | | |
609 | 613 | | |
| |||
663 | 667 | | |
664 | 668 | | |
665 | 669 | | |
| 670 | + | |
666 | 671 | | |
667 | 672 | | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
668 | 683 | | |
669 | 684 | | |
670 | 685 | | |
| |||
Lines changed: 86 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
158 | 158 | | |
159 | 159 | | |
160 | 160 | | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
161 | 173 | | |
162 | 174 | | |
163 | 175 | | |
| |||
1258 | 1270 | | |
1259 | 1271 | | |
1260 | 1272 | | |
| 1273 | + | |
| 1274 | + | |
1261 | 1275 | | |
1262 | 1276 | | |
1263 | 1277 | | |
1264 | 1278 | | |
1265 | 1279 | | |
| 1280 | + | |
1266 | 1281 | | |
1267 | | - | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
| 1285 | + | |
| 1286 | + | |
| 1287 | + | |
| 1288 | + | |
| 1289 | + | |
| 1290 | + | |
| 1291 | + | |
1268 | 1292 | | |
1269 | 1293 | | |
| 1294 | + | |
| 1295 | + | |
| 1296 | + | |
| 1297 | + | |
| 1298 | + | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
1270 | 1316 | | |
1271 | 1317 | | |
1272 | 1318 | | |
| |||
1351 | 1397 | | |
1352 | 1398 | | |
1353 | 1399 | | |
| 1400 | + | |
| 1401 | + | |
1354 | 1402 | | |
1355 | 1403 | | |
1356 | 1404 | | |
1357 | 1405 | | |
1358 | 1406 | | |
| 1407 | + | |
1359 | 1408 | | |
1360 | | - | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
1361 | 1432 | | |
| 1433 | + | |
1362 | 1434 | | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
1363 | 1443 | | |
1364 | 1444 | | |
1365 | 1445 | | |
| |||
1569 | 1649 | | |
1570 | 1650 | | |
1571 | 1651 | | |
| 1652 | + | |
| 1653 | + | |
| 1654 | + | |
| 1655 | + | |
1572 | 1656 | | |
1573 | 1657 | | |
1574 | 1658 | | |
| |||
0 commit comments