fix(perps): restore MYX webpackIgnore sync guard#28871
Conversation
Restore the myxModulePath workaround in PerpsController so the synced core build keeps the webpackIgnore safeguard, and harden the perps core-sync workflow to validate built publish artifacts for this regression before syncing forward. Constraint: Mobile remains the source of truth for perps-controller syncs into core Constraint: Core package publish excludes MYXProvider files, so the built dist must preserve the webpackIgnore-based dynamic import safeguard for extension consumers Rejected: Fix only in core | would be overwritten by the next mobile-to-core sync Confidence: high Scope-risk: narrow Directive: Keep the publish-artifact verification in sync tooling until ts-bridge or the package layout guarantees this invariant automatically Tested: validate-core-sync.sh through build/artifact verification against local core checkout Not-tested: full mobile app runtime behavior (source-of-truth fix is bundler/sync oriented)
Switch the perps core-sync build step to build:all so the validator can run against a fresh core checkout with project references, and update the sync skill documentation to match. Constraint: validate-core-sync must be reproducible from a clean core worktree, not depend on previously built dist outputs Rejected: Keep using the package-local build command | fails on clean core checkouts with missing referenced dist artifacts Confidence: high Scope-risk: narrow Directive: Keep the sync script aligned with the actual core workspace build requirements whenever perps-controller project references change Tested: validate-core-sync.sh against a clean core worktree through the build step Not-tested: full mobile app runtime behavior (tooling-only change)
Ensure the sync validator reports step failures deterministically and keeps its step count accurate when build steps are skipped. Constraint: The validator must keep running after a failed step so sync diagnostics are complete. Rejected: Rely on set -e for step handling | exits early and hides downstream validation results Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep step execution wrapped so future checks can fail without aborting the whole validation report Tested: bash -n scripts/perps/validate-core-sync.sh; prettier check; validate-core-sync against core-myx-sync through artifact gate Not-tested: Full clean-core build still fails upstream in @metamask/perps-controller typing
|
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. |
Store the successful parity workflow on the branch so reviewers can rerun the same mobile screens that were used to compare extension formatting against mobile. Constraint: Review evidence needs a branch-local recipe path, not a temp file or prose-only instructions Rejected: Keep the recipe only under /tmp | reviewers cannot rerun the exact workflow from the PR branch Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep this recipe focused on review parity surfaces unless a broader mobile smoke suite explicitly adopts it Tested: validate-recipe.sh scripts/perps/agentic/teams/perps/recipes/mobile-decimal-parity.json --dry-run; live mobile recipe run 26/26 pass using equivalent content Not-tested: Additional mobile markets beyond ETH
…avigation (#28865) ## **Description** Historical candlestick chart data (`candleSnapshot`) was being fetched through the WebSocket-backed `InfoClient`. On extension, rapid market navigation causes an abort race condition — the UI unmount message arrives too late to cancel in-flight WebSocket requests, leading to bursty candleSnapshot traffic and 429 rate limit errors from Hyperliquid. This PR switches `fetchHistoricalCandles()` to use the HTTP `InfoClient` instead. Live candle streaming remains on WebSocket. This is the source-of-truth fix in the controller/client-service layer, so both mobile and extension benefit. Transport split after this change: - Initial chart history load → **HTTP** - Load-more historical candles → **HTTP** - Live candle updates → **WebSocket** (unchanged) ## **Changelog** CHANGELOG entry: Fixed candlestick chart 429 rate limiting during rapid market navigation by routing historical candle fetches over HTTP ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2954 ## **Manual testing steps** ```gherkin Feature: Candlestick chart loads during rapid market switching Scenario: User rapidly switches between 5+ market detail pages Given the user is on the Perps trending markets list When user taps BTC, then back, then ETH, then back, then SOL, then back, then HYPE, then back, then BTC again, then back, then ETH again Then each market detail page loads successfully with chart visible And no candleSnapshot errors appear in Metro logs ``` ## **Screenshots/Recordings** ### Video _Uploaded artifact links below; replace with manual GitHub video attachments if you want inline playback._ - After video: [after.mp4](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/features/28865/after.mp4) ## **Validation Recipe** <details><summary>recipe.json (27 nodes — rapid market switching validation)</summary> ```json { "title": "Validate candlestick chart loads correctly during rapid market switching (TAT-2954)", "initial_conditions": { "testnet": false }, "validate": { "workflow": { "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"], "entry": "setup-nav-perps", "nodes": { "setup-nav-perps": { "action": "navigate", "target": "PerpsTrendingView", "next": "setup-wait-list" }, "setup-wait-list": { "action": "wait_for", "test_id": "perps-market-row-item-BTC", "timeout": 10000, "next": "ac1-open-btc" }, "ac1-open-btc": { "action": "press", "test_id": "perps-market-row-item-BTC", "next": "ac1-wait-detail-btc" }, "ac1-wait-detail-btc": { "action": "wait_for", "test_id": "perps-market-details-view", "timeout": 8000, "next": "ac1-back-1" }, "ac1-back-1": { "action": "press", "test_id": "perps-market-header-back-button", "next": "ac1-wait-list-1" }, "ac1-wait-list-1": { "action": "wait_for", "test_id": "perps-market-row-item-ETH", "timeout": 5000, "next": "ac1-open-eth" }, "ac1-open-eth": { "action": "press", "test_id": "perps-market-row-item-ETH", "next": "ac1-wait-detail-eth" }, "ac1-wait-detail-eth": { "action": "wait_for", "test_id": "perps-market-details-view", "timeout": 8000, "next": "ac1-back-2" }, "ac1-back-2": { "action": "press", "test_id": "perps-market-header-back-button", "next": "ac1-wait-list-2" }, "ac1-wait-list-2": { "action": "wait_for", "test_id": "perps-market-row-item-SOL", "timeout": 5000, "next": "ac1-open-sol" }, "ac1-open-sol": { "action": "press", "test_id": "perps-market-row-item-SOL", "next": "ac1-wait-detail-sol" }, "ac1-wait-detail-sol": { "action": "wait_for", "test_id": "perps-market-details-view", "timeout": 8000, "next": "ac1-back-3" }, "ac1-back-3": { "action": "press", "test_id": "perps-market-header-back-button", "next": "ac1-wait-list-3" }, "ac1-wait-list-3": { "action": "wait_for", "test_id": "perps-market-row-item-HYPE", "timeout": 5000, "next": "ac1-open-hype" }, "ac1-open-hype": { "action": "press", "test_id": "perps-market-row-item-HYPE", "next": "ac1-wait-detail-hype" }, "ac1-wait-detail-hype": { "action": "wait_for", "test_id": "perps-market-details-view", "timeout": 8000, "next": "ac1-back-4" }, "ac1-back-4": { "action": "press", "test_id": "perps-market-header-back-button", "next": "ac1-wait-list-4" }, "ac1-wait-list-4": { "action": "wait_for", "test_id": "perps-market-row-item-BTC", "timeout": 5000, "next": "ac1-open-btc2" }, "ac1-open-btc2": { "action": "press", "test_id": "perps-market-row-item-BTC", "next": "ac1-wait-detail-btc2" }, "ac1-wait-detail-btc2": { "action": "wait_for", "test_id": "perps-market-details-view", "timeout": 8000, "next": "ac1-back-5" }, "ac1-back-5": { "action": "press", "test_id": "perps-market-header-back-button", "next": "ac1-wait-list-5" }, "ac1-wait-list-5": { "action": "wait_for", "test_id": "perps-market-row-item-ETH", "timeout": 5000, "next": "ac1-open-eth2" }, "ac1-open-eth2": { "action": "press", "test_id": "perps-market-row-item-ETH", "next": "ac1-wait-detail-eth2" }, "ac1-wait-detail-eth2": { "action": "wait_for", "test_id": "perps-market-details-view", "timeout": 8000, "next": "ac1-screenshot-final" }, "ac1-screenshot-final": { "action": "screenshot", "filename": "evidence-rapid-switch-chart-loaded.png", "next": "ac1-back-6" }, "ac1-back-6": { "action": "press", "test_id": "perps-market-header-back-button", "next": "ac2-check-no-rate-limit" }, "ac2-check-no-rate-limit": { "action": "log_watch", "window_seconds": 45, "must_not_appear": ["candleSnapshot error", "historical_candles_api", "candle_subscription_async", "initial_candles_fetch"], "watch_for": ["candleSnapshot", "fetchHistoricalCandles", "historical_candles"], "next": "ac2-done" }, "ac2-done": { "action": "end", "status": "pass" } } } } } ``` </details> ## **Validation Logs** Command: ```bash bash scripts/perps/agentic/validate-recipe.sh .task/feat/tat-2954-0415-2218/artifacts/ --skip-manual ``` <details><summary>Full output (27/27 passed)</summary> ``` Running recipe: Validate candlestick chart loads correctly during rapid market switching (TAT-2954) Pre-conditions: wallet.unlocked, perps.feature_enabled Workflow nodes: 28 Pre-conditions: PASS [setup-nav-perps] navigate to PerpsTrendingView — PASS [setup-wait-list] wait for perps-market-row-item-BTC — PASS [ac1-open-btc] press perps-market-row-item-BTC — PASS [ac1-wait-detail-btc] wait for perps-market-details-view — PASS [ac1-back-1] press perps-market-header-back-button — PASS [ac1-wait-list-1] wait for perps-market-row-item-ETH — PASS [ac1-open-eth] press perps-market-row-item-ETH — PASS [ac1-wait-detail-eth] wait for perps-market-details-view — PASS [ac1-back-2] press perps-market-header-back-button — PASS [ac1-wait-list-2] wait for perps-market-row-item-SOL — PASS [ac1-open-sol] press perps-market-row-item-SOL — PASS [ac1-wait-detail-sol] wait for perps-market-details-view — PASS [ac1-back-3] press perps-market-header-back-button — PASS [ac1-wait-list-3] wait for perps-market-row-item-HYPE — PASS [ac1-open-hype] press perps-market-row-item-HYPE — PASS [ac1-wait-detail-hype] wait for perps-market-details-view — PASS [ac1-back-4] press perps-market-header-back-button — PASS [ac1-wait-list-4] wait for perps-market-row-item-BTC — PASS [ac1-open-btc2] press perps-market-row-item-BTC — PASS [ac1-wait-detail-btc2] wait for perps-market-details-view — PASS [ac1-back-5] press perps-market-header-back-button — PASS [ac1-wait-list-5] wait for perps-market-row-item-ETH — PASS [ac1-open-eth2] press perps-market-row-item-ETH — PASS [ac1-wait-detail-eth2] wait for perps-market-details-view — PASS [ac1-screenshot-final] capture screenshot — PASS [ac1-back-6] press perps-market-header-back-button — PASS [ac2-check-no-rate-limit] scan metro log — PASS Results: 27/27 passed Recipe: PASS ``` </details> ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a summary for commit de043e1. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> (cherry picked from commit 351ead7)
## Explanation This restores the `myxModulePath` workaround for the `MYXProvider` dynamic import in `@metamask/perps-controller` so the built package preserves `webpackIgnore` and consumers do not statically resolve the intentionally-unpublished MYX provider files. This is the narrow publish fix that matches mobile source-of-truth follow-up `MetaMask/metamask-mobile#28871` and unblocks a corrected controller publication for the extension decimal-format adoption in `MetaMask/metamask-extension#41558`. ## References - Related to #8424 - Related to #8460 - Related to MetaMask/metamask-mobile#28871 - Related to MetaMask/metamask-extension#41558 ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches HyperLiquid market discovery caching and WebSocket subscription teardown logic, which can affect market availability and live data stability. Also adjusts the MYX dynamic import path handling to influence bundling behavior in downstream consumers. > > **Overview** > Restores the MYX provider dynamic import workaround by moving the module path into a variable so built dist output preserves the `/* webpackIgnore: true */` comment and extension consumers don’t statically resolve the unpublished MYX module. > > Refactors HyperLiquid DEX discovery into a new unified `DexDiscoveryCacheManager` (with a `DexDiscoveryState` type) and updates call sites to use the shared state for raw/validated DEX lists and TTL behavior, reducing cache desync and avoiding rapid market-switching 429s. > > Switches HyperLiquid candle snapshots to use an HTTP `InfoClient` transport, and updates subscription teardown to explicitly `unsubscribe()` all active subscriptions during `clearAll` to prevent orphaned-unsubscribe `SOCKET_NOT_CONNECTED` errors during disconnect. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3430560. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Keep the MYX sync guard branch focused on source-of-truth controller and sync-validator changes by removing the review recipe, which now lives on its own branch for dedicated recipe iteration. Constraint: Separate recipe/evidence work from controller sync work so each PR stays narrowly reviewable Rejected: Leave the recipe on the sync branch | mixes validation tooling concerns into the controller portability fix Confidence: high Scope-risk: narrow Reversibility: clean Directive: Future recipe expansion should happen on the dedicated recipe branch instead of being folded back into the sync branch Tested: file move only Not-tested: no runtime behavior changed
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
Tag selection rationale:
No other tags are warranted as the changes are isolated to the perps controller and developer tooling. Performance Test Selection: |
|
✅ E2E Fixture Validation — Schema is up to date |
|



Description
This restores the
myxModulePathworkaround in mobilePerpsControllerso the mobile source of truth matches the safe Core pattern fromcore#8424, and it hardensscripts/perps/validate-core-sync.shplus theperps-core-syncskill so future syncs fail if the built Core publish artifact loses thewebpackIgnoresafeguard again.This branch has been refreshed onto a
mainthat already includes #28865, so no separate follow-up is still pending for the historical candle transport fix.Changelog
CHANGELOG entry: null
Related issues
Fixes:
mainafter feat(perps): Fix candlestick chart 429 rate limiting on rapid asset navigation #28865 mergedManual testing steps
Screenshots/Recordings
Before
N/A - controller/source-sync change only.
After
N/A - controller/source-sync change only.
Pre-merge author checklist
Performance checks (if applicable)
Pre-merge reviewer checklist