Skip to content

feat(perps): sync PerpsController implementation for npm publishing#7941

Open
abretonc7s wants to merge 12 commits intomainfrom
feat/perps/controller-migration-sync
Open

feat(perps): sync PerpsController implementation for npm publishing#7941
abretonc7s wants to merge 12 commits intomainfrom
feat/perps/controller-migration-sync

Conversation

@abretonc7s
Copy link
Contributor

@abretonc7s abretonc7s commented Feb 16, 2026

Explanation

Syncs the full PerpsController implementation from Mobile into Core for npm publishing as @metamask/perps-controller.

This builds on #7654 (initial package scaffolding) by adding the complete controller implementation: 59 source files covering the controller, providers (HyperLiquid, MYX), services, types, and utilities. Notably, Core's strict ESLint rules were adopted directly on the perps code in Mobile via metamask-mobile#26064 — this was initially thought to be impossible (one of the original blockers in the ADR-42 debate), but the result is a clean 1:1 file sync: source files are copied verbatim with zero modifications and no linting suppression needed.

Approach: Mobile remains the source of truth for active perps development. Core acts as the publishing vehicle — receiving synced source files and publishing them to npm via Core's existing release infrastructure. This is a pragmatic interim approach (~2 months) that avoids cross-repo DX friction while the controller and UI are being iterated on together rapidly. See `PERPS_CONTROLLER_CONTEXT.md` for full background on the ADR-42 debate and why this approach was chosen.

Key components added:

  • `PerpsController` — main controller with state management, messenger integration, and multi-provider orchestration
  • `HyperLiquidProvider` / `MYXProvider` — DEX-specific provider implementations
  • `AggregatedPerpsProvider` — multi-provider aggregation layer
  • `ProviderRouter` — routes operations to the appropriate provider
  • `SubscriptionMultiplexer` — real-time WebSocket data aggregation
  • 13 services: Trading, MarketData, Account, Deposit, Eligibility, FeatureFlagConfiguration, HyperLiquidClient, HyperLiquidSubscription, HyperLiquidWallet, MYXClient, DataLake, RewardsIntegration, TradingReadinessCache
  • Comprehensive type definitions, constants, and utility functions
  • Platform-agnostic via `PerpsPlatformDependencies` injection interface

CI / Testing: The real unit tests live in Mobile alongside the source of truth. A minimal placeholder test (`tests/placeholder.test.ts`) is included to satisfy Core's CI requirement that every package has at least one test file. It lives in `tests/` (outside `src/`) so the Mobile sync script (`rsync --delete` on `src/`) does not remove it. Coverage collection is scoped to the placeholder file only, preventing 0% coverage failures on the synced source. Tests will be migrated when development moves fully to Core.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
    • Placeholder test included for CI. Full unit tests remain in Mobile (source of truth) and will be migrated when development moves fully to Core.
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

High Risk
Very large drop-in of trading/controller logic with new provider orchestration, transaction submission, and remote feature-flag/eligibility handling; high surface area means higher chance of integration or runtime regressions despite being largely a sync.

Overview
Syncs @metamask/perps-controller from scaffolding to a full, publishable Perps implementation. The PR replaces the placeholder PerpsController with a large, feature-complete controller exposing many messenger actions/events, a substantial persisted state shape (eligibility, deposits/withdrawals, watchlists, trade prefs), provider initialization/reinit logic, background preloading/caching, and live WebSocket subscription APIs.

It adds the multi-provider surface area (e.g. aggregation utilities like SubscriptionMultiplexer, portable constants like chartConfig/eventNames, plus numerous new deps) and adjusts package test/coverage setup by removing the old src/PerpsController.test.ts and scoping Jest coverage collection to tests/placeholder.test.ts only.

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

Add all required dependencies to perps-controller package.json
(account-tree-controller, bridge-controller, keyring-controller,
network-controller, transaction-controller, etc.) and corresponding
tsconfig.build.json project references so the package builds correctly
when source files are synced from mobile.
@abretonc7s abretonc7s requested review from a team as code owners February 16, 2026 11:05
@socket-security
Copy link

socket-security bot commented Feb 16, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​myx-trade/​sdk@​0.1.265801007698100
Added@​nktkas/​hyperliquid@​0.30.39810010096100

View full report

@socket-security
Copy link

socket-security bot commented Feb 16, 2026

Warning

MetaMask internal reviewing guidelines:

  • Do not ignore-all
  • Each alert has instructions on how to review if you don't know what it means. If lost, ask your Security Liaison or the supply-chain group
  • Copy-paste ignore lines for specific packages or a group of one kind with a note on what research you did to deem it safe.
    @SocketSecurity ignore npm/PACKAGE@VERSION
Action Severity Alert  (click "▶" to expand/collapse)
Warn Low
Potential code anomaly (AI signal): npm crypto-js is 100.0% likely to have a medium risk anomaly

Notes: This module implements the RC4 and RC4Drop stream ciphers from CryptoJS. RC4 is known to suffer from key-stream biases and other cryptographic weaknesses and is deprecated for modern use. There is no evidence of malware, network activity, hidden backdoors, or data exfiltration in this code—only the inclusion of an outdated cipher that may lead to weak confidentiality if used.

Confidence: 1.00

Severity: 0.60

From: ?npm/@myx-trade/sdk@0.1.265npm/crypto-js@4.2.0

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/crypto-js@4.2.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Ignoring alerts on:

  • @myx-trade/sdk@0.1.265
  • @nktkas/hyperliquid@0.30.3
  • viem@2.45.3
  • wretch@2.11.1
  • rxjs@7.8.2
  • ox@0.12.1
  • @inquirer/external-editor@2.0.3
  • @noble/curves@2.0.1
  • @scure/bip39@1.6.0

View full report

Synced from mobile PR #26110:
- toggleTestnet: check InitializationState.Failed after init() and
  rollback isTestnet on failure (matching switchProvider pattern)
- depositWithConfirmation: replace never-resolving promise with
  Promise.resolve(transactionMeta.id) when placeOrder=true
Hoist currentDepositId before try block so it is accessible in the
outer catch. When a pre-submission error occurs (e.g. missing
networkClientId), the deposit request is now marked as 'failed'
instead of staying permanently 'pending' in state.
Prevent standalone preload from leaking WebSocket providers by caching
the HyperLiquidProvider instance across standalone calls and cleaning
it up at lifecycle boundaries (init, disconnect, toggleTestnet, etc.).

Reorder switchProvider() to check "already active" before validating
the providers map, so it returns a no-op success before init().
Add uuidv4() fallback for currentDepositId which TypeScript cannot
narrow inside the update() callback after the variable was hoisted
to let binding with string | undefined type.
The base tsconfig.json was missing project references that
tsconfig.build.json already had, causing TS2345 errors for imports
like @metamask/account-tree-controller during type checking.
Jest exits with code 1 when no test files exist. Add a minimal
placeholder test in tests/ (outside src/ so the Mobile sync script
does not delete it) and scope collectCoverageFrom to that file only,
preventing 0% coverage failures on the synced source.
…cription

Register all 34 PerpsControllerActions via registerMethodActionHandlers()
so inter-controller communication works through the messenger in core.
Store the RemoteFeatureFlagController:stateChange subscription handle
and clean it up in disconnect() to prevent leaks.
… and account switch

- Remove feature-flag unsubscribe from disconnect() so geo-blocking and
  HIP-3 flag changes keep propagating after reconnect cycles
- Add deposit request lifecycle tracking for the deposit+order flow so
  requests transition from pending to completed/failed/cancelled
- Clear cached user data when switching to a non-EVM account group to
  prevent stale positions/orders from the previous EVM account
@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/@nktkas/hyperliquid@0.30.3

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/@inquirer/external-editor@2.0.3

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/@myx-trade/sdk@0.1.265

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/@noble/curves@2.0.1

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/ox@0.12.1

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/viem@2.45.3

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/@scure/bip39@1.6.0

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/rxjs@7.8.2

@abretonc7s
Copy link
Contributor Author

@SocketSecurity ignore npm/wretch@2.11.1

Add a type import and use it in the test to satisfy both
import-x/unambiguous (requires ES module syntax) and
@typescript-eslint/no-unused-vars.
Copy link

@cursor cursor bot left a comment

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.

@Gudahtt
Copy link
Member

Gudahtt commented Feb 16, 2026

The lint job seems to be failing (you need to run yarn dedupe)

Also:

Mobile remains the source of truth for active perps development. Core acts as the publishing vehicle

I thought we had discussed how this was a bad idea, and that we should migrate the controller fully to core instead? I'm not following what the plan is here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants