Skip to content

feat(perps): core resolver — providerCredentials, builder fee injection, env var centralization#27899

Merged
abretonc7s merged 14 commits into
mainfrom
feat/perps/core-resolver
Mar 25, 2026
Merged

feat(perps): core resolver — providerCredentials, builder fee injection, env var centralization#27899
abretonc7s merged 14 commits into
mainfrom
feat/perps/core-resolver

Conversation

@abretonc7s

@abretonc7s abretonc7s commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Description

Resolves several core-parity and architecture concerns for the perps controller:

1. Backport core-only changes (existing)

  • stopEligibilityMonitoring() — Disables geo-blocking eligibility checks when useExternalServices is toggled off.
  • Dynamic MYX importawait import().then()/.catch() to avoid bundling heavy MYX dependencies in extension.

2. Nested providerCredentials on PerpsControllerConfig

  • Restructures flat MYX config fields (myxAppIdTestnet, myxProviderEnabled, etc.) into providerCredentials.myx.*.
  • Adds providerCredentials.hyperliquid.* for builder fee wallet addresses.
  • New types: PerpsProviderCredentials, HyperLiquidCredentials, MYXCredentials.

3. Builder fee address injection

  • HyperLiquidProvider accepts optional builderAddressTestnet/builderAddressMainnet via constructor.
  • Falls back to hardcoded BUILDER_FEE_CONFIG defaults when env vars are empty.
  • New env vars in .js.env.example: MM_PERPS_HL_BUILDER_ADDRESS_TESTNET, MM_PERPS_HL_BUILDER_ADDRESS_MAINNET.

4. Env var centralization in mobile adapter

  • New createMobileClientConfig() in mobileInfrastructure.ts — all process.env.* reads in one place.
  • Engine init (perps-controller/index.ts) reduced from ~73 to ~37 lines — pure controller wiring, no env var reads.

5. MYX dynamic import race condition fix

  • await import() inside non-async #createProviders(): void.then()/.catch() chain.
  • Removes @ts-expect-error suppression. Fixes provider setup race condition flagged by bugbot.

Changelog

CHANGELOG entry: null

Related issues

Fixes: N/A — architecture cleanup + core parity

Manual testing steps

Feature: Provider credentials and builder fee injection

  Scenario: HyperLiquid uses env-var builder address when set
    Given MM_PERPS_HL_BUILDER_ADDRESS_TESTNET is set in .js.env
    When a trade is placed on testnet
    Then the builder fee uses the env-var address (not hardcoded default)

  Scenario: HyperLiquid falls back to default when env var is empty
    Given MM_PERPS_HL_BUILDER_ADDRESS_TESTNET is empty
    When a trade is placed on testnet
    Then the builder fee uses BUILDER_FEE_CONFIG.TestnetBuilder

  Scenario: MYX provider registers via dynamic import
    Given MYX provider is enabled
    When PerpsController initializes
    Then MYX registers asynchronously via .then()/.catch()
    And initialization completes without waiting for MYX

  Scenario: Engine init uses adapter for config
    Given the app starts
    When PerpsController is initialized
    Then clientConfig comes from createMobileClientConfig()
    And no process.env reads exist in the Engine init file

Screenshots/Recordings

N/A — no UI changes

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

Medium Risk
Touches Perps provider initialization/selection and geo-eligibility monitoring, which can impact trading availability and protocol routing if misconfigured. Changes are largely additive but include async/dynamic-import ordering and new config wiring that should be validated across networks/providers.

Overview
Refactors Perps controller configuration to use a nested providerCredentials structure and centralizes all Perps process.env reads into createMobileClientConfig(), simplifying perpsControllerInit to pure wiring.

Adds HyperLiquid builder-fee address injection via new env vars and passes these through PerpsController into HyperLiquidProvider, falling back to hardcoded defaults when env values are empty.

Hardens MYX provider registration and eligibility controls by switching MYX to a dynamic import() flow with explicit error handling/awaiting during initialization, adding stopEligibilityMonitoring() (and messenger action typing) to defer geolocation checks, and extending tests to cover these behaviors.

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

…dynamic MYX import)

Backport two commits made directly in core since the last mobile→core sync:
- Add stopEligibilityMonitoring() method to disable geo-blocking checks
  when useExternalServices is toggled off (core 902236dba)
- Dynamic import for MYXProvider to avoid bundling heavy MYX dependencies
  in extension until MYX fixes their package (core ee7281491)
@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.

@metamaskbot metamaskbot added the team-perps Perps team label Mar 25, 2026
@abretonc7s abretonc7s marked this pull request as ready for review March 25, 2026 00:47
@abretonc7s abretonc7s requested a review from a team as a code owner March 25, 2026 00:47
Comment thread app/controllers/perps/PerpsController.ts Outdated
…ar centralization

- Restructure PerpsControllerConfig: flat MYX fields → nested providerCredentials.{hyperliquid,myx}
- Inject HL builder fee addresses via config instead of hardcoded constants
- Move all process.env reads from Engine init to createMobileClientConfig() in mobileInfrastructure adapter
- Fix MYX dynamic import race condition: await in non-async → .then()/.catch()
@abretonc7s abretonc7s changed the title feat(perps): backport core-only changes (stopEligibilityMonitoring + dynamic MYX import) feat(perps): core resolver — providerCredentials, builder fee injection, env var centralization Mar 25, 2026
- Extract #assignActiveProvider from #createProviders, called after
  await Promise.all([wait, myxRegistrationPromise]) so MYX has
  registered before active provider is assigned
- Extract firstNonEmpty and resolveMyxAuthConfig as exported pure
  functions (testable without --experimental-vm-modules)
- Fix switchProvider test: mock init on reinit call since import()
  rejects in Jest
- 100% new code coverage (15/15 lines)
@github-actions github-actions Bot added the risk-medium Moderate testing recommended · Possible bug introduction risk label Mar 25, 2026
Comment thread app/controllers/perps/PerpsController.ts Outdated
- Add createMobileClientConfig to test mock factory (CI fix)
- Distinguish module-not-found from runtime errors in MYX .catch()
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
…g, builder address

- Test MYX dynamic import catch: module-not-found → debug log
- Test stopEligibilityMonitoring defers refreshEligibility
- Test testnet builder address selection in HyperLiquidProvider
- Test createMobileClientConfig default config shape
- Harden catch handler for cross-realm errors (instanceof fails)
@github-actions github-actions Bot added size-L risk-medium Moderate testing recommended · Possible bug introduction risk and removed size-M risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
Comment thread app/controllers/perps/PerpsController.ts Outdated
Comment thread app/controllers/perps/PerpsController.test.ts
…lity

Extract .then()/.catch() callbacks from the MYX dynamic import into
protected methods (registerMYXProvider, handleMYXImportError) so they
can be tested directly. Jest rejects dynamic import() without
--experimental-vm-modules, making inline callbacks untestable.

New code coverage: 97% (33/34 changed lines).
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
Switch from import() to require() for MYX provider dynamic loading.
Both achieve lazy loading; require() works with Jest module mocking.
Add integration test covering the full init → MYX registration path.

New code coverage: 96% (26/27 changed lines).
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
Replace broad regex /cannot find|not found|module/ with precise
error.code === 'MODULE_NOT_FOUND' check. Only Node's actual module
resolution failures are treated as expected; constructor/config
errors now correctly route to Sentry via logError.
@github-actions github-actions Bot removed the risk-medium Moderate testing recommended · Possible bug introduction risk label Mar 25, 2026
@github-actions github-actions Bot added the risk-medium Moderate testing recommended · Possible bug introduction risk label Mar 25, 2026
…iles

Investigation of PerpsController.ts growth (3,343 → 4,689 lines in 6 weeks)
and HyperLiquidProvider.ts (8,342 lines). Documents root causes, phased
extraction plan, and CI guardrails to prevent re-growth.
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
Comment thread app/components/UI/Perps/adapters/mobileInfrastructure.test.ts
…shaking

require() defeats webpack code splitting — only import() enables true
tree-shaking so MYX is excluded from the extension bundle. Remove the
integration test that depended on require() resolution (Jest can't
resolve dynamic import() without --experimental-vm-modules); unit tests
for registerMYXProvider and handleMYXImportError remain.
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
step_eslint_fix was backing up eslint-suppressions.json before running
--prune-suppressions, then restoring the original — undoing the prune.
Step 8 (Lint) then failed on the stale entries. Remove the backup/restore
so pruned suppressions persist for lint and the eventual commit.
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread scripts/perps/validate-core-sync.sh

@aganglada aganglada left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@abretonc7s abretonc7s enabled auto-merge March 25, 2026 09:56
@github-actions github-actions Bot added risk-medium Moderate testing recommended · Possible bug introduction risk and removed risk-medium Moderate testing recommended · Possible bug introduction risk labels Mar 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePerps, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: @PerformancePreps
  • Risk Level: medium
  • AI Confidence: 82%
click to see 🤖 AI reasoning details

E2E Test Selection:
The PR refactors the PerpsController with several architectural changes:

  1. PerpsController initialization flow changed: The #createProviders() method now uses dynamic import() for MYXProvider instead of a static import, and a new #assignActiveProvider() method is separated out. The initialization now awaits #myxRegistrationPromise alongside the WebSocket delay. This changes the timing/order of provider setup which could affect perps functionality.

  2. Config type restructuring: The flat clientConfig fields (myxAppIdTestnet, myxProviderEnabled, etc.) are now nested under providerCredentials.myx and providerCredentials.hyperliquid. The Engine init now uses createMobileClientConfig() from mobileInfrastructure. This is a breaking change in the config shape that could cause misconfiguration if not properly wired.

  3. New stopEligibilityMonitoring() method: Added as a messenger-exposed action, which affects geo-blocking behavior.

  4. HyperLiquidProvider builder address: Now configurable via env vars, with fallback to hardcoded defaults. This affects transaction fee routing.

  5. SmokePerps is the primary tag since all changes are in the perps domain (PerpsController, HyperLiquidProvider, mobileInfrastructure adapter).

  6. SmokeWalletPlatform is included because Perps is a section inside the Trending tab, and changes to the PerpsController initialization could affect how Perps appears in Trending.

  7. SmokeConfirmations is included per the SmokePerps tag description: 'When selecting SmokePerps, also select SmokeConfirmations (Add Funds deposits are on-chain transactions).'

The changes are internal refactoring (no new user-facing features), but the initialization flow changes and config restructuring warrant running perps-related E2E tests to verify the controller still initializes correctly and perps flows work end-to-end.

Performance Test Selection:
The PerpsController initialization flow has been refactored with async MYX provider registration (dynamic import) and a new provider assignment step. The initialization now uses Promise.all() to await both WebSocket readiness and MYX registration. These changes could affect the time it takes for the perps controller to become ready, which would impact perps market loading and the add funds flow measured by @PerformancePreps.

View GitHub Actions results

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ E2E Fixture Validation — Structural changes detected

Category Count
New keys 46
Missing keys 0
Type mismatches 0
Value mismatches 12 (informational)

The committed fixture schema is out of date. To update, comment:

@metamaskbot update-mobile-fixture

View full details | Download diff report

@sonarqubecloud

Copy link
Copy Markdown

@abretonc7s abretonc7s added this pull request to the merge queue Mar 25, 2026
Merged via the queue into main with commit 62f6136 Mar 25, 2026
97 of 100 checks passed
@abretonc7s abretonc7s deleted the feat/perps/core-resolver branch March 25, 2026 10:55
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 25, 2026
@metamaskbot metamaskbot added the release-7.72.0 Issue or pull request that will be included in release 7.72.0 label Mar 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants