Skip to content

fix(perps): restore MYX webpackIgnore sync guard#28871

Merged
abretonc7s merged 7 commits into
mainfrom
fix/perps/myx-webpack-ignore-restore
Apr 16, 2026
Merged

fix(perps): restore MYX webpackIgnore sync guard#28871
abretonc7s merged 7 commits into
mainfrom
fix/perps/myx-webpack-ignore-restore

Conversation

@abretonc7s

@abretonc7s abretonc7s commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Description

This restores the myxModulePath workaround in mobile PerpsController so the mobile source of truth matches the safe Core pattern from core#8424, and it hardens scripts/perps/validate-core-sync.sh plus the perps-core-sync skill so future syncs fail if the built Core publish artifact loses the webpackIgnore safeguard again.

This branch has been refreshed onto a main that already includes #28865, so no separate follow-up is still pending for the historical candle transport fix.

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

Feature: preserve MYX publish safety during mobile-to-core sync

  Scenario: validate the sync guard on a clean Core checkout
    Given mobile is on this branch and Core is checked out locally
    When I run `bash scripts/perps/validate-core-sync.sh --core-path <core-path> --skip-test`
    Then the copied-source validation reaches the publish-artifact gate
    And the run fails if the built Core artifact does not preserve the MYX webpackIgnore safeguard

  Scenario: validate the perps historical candle transport coverage that is already present on main
    When I run `yarn jest app/controllers/perps/services/HyperLiquidClientService.test.ts --no-coverage`
    Then the TAT-2954 historical candle HTTP transport coverage passes

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)

  • I've tested on Android
  • I've tested with a power user scenario
  • I've instrumented key operations with Sentry traces for production performance metrics

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.

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
@github-actions

Copy link
Copy Markdown
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.

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
@abretonc7s abretonc7s changed the title Restore MYX webpackIgnore sync guard for core publish parity fix(perps): restore MYX webpackIgnore sync guard Apr 15, 2026
abretonc7s and others added 2 commits April 16, 2026 00:38
…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)
@abretonc7s abretonc7s changed the title fix(perps): restore MYX webpackIgnore sync guard fix(perps): restore MYX sync guard and include candle transport fix Apr 15, 2026
@abretonc7s abretonc7s changed the title fix(perps): restore MYX sync guard and include candle transport fix fix(perps): restore MYX webpackIgnore sync guard Apr 15, 2026
@abretonc7s abretonc7s marked this pull request as ready for review April 15, 2026 16:48
@abretonc7s abretonc7s requested a review from a team as a code owner April 15, 2026 16:48
@abretonc7s abretonc7s enabled auto-merge April 15, 2026 17:02
github-merge-queue Bot pushed a commit to MetaMask/core that referenced this pull request Apr 15, 2026
## 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
@github-actions github-actions Bot added the risk-medium Moderate testing recommended · Possible bug introduction risk label Apr 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePerps, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 88%
click to see 🤖 AI reasoning details

E2E Test Selection:
The PR makes three changes:

  1. PerpsController.ts — A targeted bundling fix: the dynamic import('./providers/MYXProvider') now stores the path in a const myxModulePath variable before passing it to import(). This preserves the /* webpackIgnore: true */ magic comment in the Core monorepo's built dist artifacts (ts-bridge was stripping it when the path was a string literal). The runtime behavior of the mobile app is unchanged — the MYX provider is still loaded dynamically the same way. However, since this touches the PerpsController (a critical file), running SmokePerps is warranted to confirm the controller still initializes and functions correctly.

  2. validate-core-sync.sh — Adds a new step_verify_publish_artifact step (step 9 of 13) that checks built Core dist files contain webpackIgnore: true, changes build to build:all, and adds set +e/set -e around the step runner. This is developer tooling only — no mobile app runtime impact.

  3. SKILL.md — Documentation update for the AI agent skill, updating step counts and adding the new verification step description. No runtime impact.

Tag selection rationale:

  • SmokePerps: The PerpsController.ts change, while a bundling fix, touches the critical perps controller initialization path (specifically the MYX provider registration promise). Running perps E2E tests validates the controller still works correctly in the mobile app.
  • SmokeWalletPlatform: Required per SmokePerps tag description — Perps is a section inside the Trending tab.
  • SmokeConfirmations: Required per SmokePerps tag description — Add Funds deposits are on-chain transactions.

No other tags are warranted as the changes are isolated to the perps controller and developer tooling.

Performance Test Selection:
The PerpsController.ts change is a bundling/import path fix that does not affect runtime performance. The dynamic import path is stored in a variable instead of a literal — this has no impact on rendering, data loading, state management, or any measurable performance metric. The script and documentation changes are developer tooling only. No performance tests are needed.

View GitHub Actions results

@github-actions

Copy link
Copy Markdown
Contributor

E2E Fixture Validation — Schema is up to date
11 value mismatches detected (expected — fixture represents an existing user).
View details

@sonarqubecloud

Copy link
Copy Markdown

@abretonc7s abretonc7s added this pull request to the merge queue Apr 16, 2026
Merged via the queue into main with commit 7103a2c Apr 16, 2026
107 checks passed
@abretonc7s abretonc7s deleted the fix/perps/myx-webpack-ignore-restore branch April 16, 2026 23:20
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 16, 2026
@metamaskbotv2 metamaskbotv2 Bot added the release-7.75.0 Issue or pull request that will be included in release 7.75.0 label Apr 16, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.75.0 Issue or pull request that will be included in release 7.75.0 risk-medium Moderate testing recommended · Possible bug introduction risk size-M team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants