[pull] main from MetaMask:main#507
Merged
Merged
Conversation
…25685) ## **Description** This PR optimizes the token details page by implementing a lightweight way to display open perps positions without requiring full PerpsController initialization, and adds one-click Long/Short trading buttons that navigate directly to the order confirmation flow. **Problem:** Previously, checking if a user had an open position on a token required initializing the entire PerpsController with WebSocket subscriptions, causing slow page loads. Additionally, cached position data could become stale when users closed positions in the perps environment. There was also no way to initiate a perps trade directly from the token details page. **Solution:** Added a `readOnly` mode pattern that allows querying perps data (positions, account state, markets) via lightweight HTTP API calls without WebSocket, wallet, or full controller initialization. Combined with a `PerpsCacheInvalidator` service that ensures cached data is refreshed when positions change. Added Long/Short buttons on token details that navigate through a new `PerpsOrderRedirect` screen to handle WebSocket initialization and order creation seamlessly. ### Key Changes **New Hook:** - `usePerpsPositionForAsset` - Fetches position data via single HTTP API call with 30-second client-side cache, subscribes to cache invalidation events **ReadOnly Mode (Controller/Provider):** - `getPositions({ readOnly: true, userAddress })` - Query positions without full init - `getAccountState({ readOnly: true, userAddress })` - Query account state without full init - Uses `createStandaloneInfoClient` for lightweight HTTP-only queries **Cache Invalidation Service:** - `PerpsCacheInvalidator` - Singleton service for loosely-coupled cache invalidation - Hooks subscribe to invalidation events (`positions`, `accountState`) - Services (TradingService, AccountService) call `invalidate()` after successful operations - Ensures position display is always accurate even after user actions in perps **One-Click Trade from Token Details:** - New `PerpsOrderRedirect` screen - a redirect/loader that initializes the WebSocket connection inside the Perps stack, calls `depositWithOrder()`, then navigates to the confirmation screen - `usePerpsActions` hook - provides `handlePerpsAction(direction)` callback for Long/Short buttons, navigates to `PerpsOrderRedirect` with direction and asset params - `AssetOverviewContent` integrates Long/Short buttons via `usePerpsActions` when a perps market exists for the token **Dynamic Button Layout:** - Token details action buttons (Buy, Sell, Swap, Bridge, etc.) now include Long/Short when a perps market exists - Buttons dynamically overflow into a "More" menu when there are too many actions **Documentation:** - Added "ReadOnly Mode (Lightweight Queries)" section to `docs/perps/perps-architecture.md` - Added "Cache Invalidation" subsection documenting the pattern ### Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ PerpsCacheInvalidator │ │ (Singleton service) │ ├─────────────────────────────────────────────────────────────────┤ │ - invalidate('positions') → notifies position subscribers │ │ - invalidate('accountState') → notifies account subscribers │ │ - subscribe(type, callback) → returns unsubscribe function │ └─────────────────────────────────────────────────────────────────┘ ▲ ▲ │ subscribe │ invalidate │ │ ┌─────────┴─────────┐ ┌──────────┴──────────┐ │ usePerpsPosition │ │ TradingService │ │ ForAsset │ │ (closePosition, │ │ │ │ placeOrder) │ │ (30s cache + │ │ │ │ invalidation) │ │ AccountService │ └───────────────────┘ │ (withdraw) │ └─────────────────────┘ Order Redirect Flow (Long/Short buttons): ┌────────────────┐ navigate ┌──────────────────┐ WS ready ┌─────────────────┐ │ Token Details │ ──────────────→ │PerpsOrderRedirect│ ────────────→ │ Confirmation │ │ (Long/Short) │ │ (Perps stack) │ depositWith │ Screen │ │ │ │ - init WebSocket │ Order() │ │ └────────────────┘ │ - show loader │ └─────────────────┘ └──────────────────┘ │ on error ▼ goBack() + toast ``` ## **Changelog** CHANGELOG entry: Added lightweight position display and one-click Long/Short trading on token details page for perps-enabled assets ## **Related issues** Fixes: [TAT-2427](https://consensyssoftware.atlassian.net/browse/TAT-2427) ## **Manual testing steps** ```gherkin Feature: Perps position display on token details Scenario: User views token with open perps position Given user has an open perps position for ETH And user is on the wallet home screen When user navigates to ETH token details page Then user should see their open position displayed And the page should load quickly without full perps initialization Scenario: User taps on position to view details Given user is viewing token details with an open position displayed When user taps on the position card Then user should be navigated to the perps market detail page And the full perps environment should load Scenario: User with no perps position Given user does not have any perps positions When user navigates to any token details page Then no perps position card should be displayed And no perps API calls should be made (if user is not eligible) Scenario: Position display updates after closing position Given user has an open perps position for ETH And user is viewing the ETH token details page And user sees their open position displayed When user navigates to perps and closes their ETH position And user navigates back to the ETH token details page Then the position card should no longer be displayed And the cache should have been invalidated automatically Scenario: User taps Long button on token with perps market Given user is viewing ETH token details And ETH has a perps market available When user taps the "Long" button Then a loader screen should appear ("Preparing order...") And the WebSocket connection should initialize And depositWithOrder should be called And user should be navigated to the order confirmation screen Scenario: User taps Short button on token with perps market Given user is viewing ETH token details And ETH has a perps market available When user taps the "Short" button Then a loader screen should appear ("Preparing order...") And the WebSocket connection should initialize And depositWithOrder should be called And user should be navigated to the order confirmation screen Scenario: Long/Short buttons not shown for token without perps market Given user is viewing a token details page for a token without a perps market (e.g. USDC) Then no Long or Short buttons should be displayed in the action bar Scenario: Order redirect handles error gracefully Given user taps Long or Short on a perps-enabled token And the depositWithOrder call fails Then user should see an error toast notification And user should be navigated back to the token details page ``` ## **Screenshots/Recordings** ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/245b905f-e9ab-4b65-a96b-49f81fe51afe ## **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 - [ ] 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. [TAT-2427]: https://consensyssoftware.atlassian.net/browse/TAT-2427?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Introduces new read-only provider/controller code paths and cache invalidation wiring, plus a new navigation redirect that triggers `depositWithOrder`; mistakes could lead to stale UI or incorrect trade/confirmation routing, but changes are scoped and covered by new tests. > > **Overview** > Adds a *read-only perps discovery path* so token details can query perps `markets`/`positions`/`accountState` via lightweight HTTP (no full controller/WebSocket init) by extending `PerpsController`/`HyperLiquidProvider` with `readOnly` + `userAddress` params and a standalone info client. > > Introduces `PerpsCacheInvalidator` (and platform dependency plumbing) and wires it into `TradingService` and `AccountService` to invalidate read-only caches after successful state-changing actions, enabling hooks like the new `usePerpsPositionForAsset` (30s TTL + invalidation subscriptions) to stay fresh. > > Updates token details (`AssetOverviewContent`) to display either a compact `PerpsPositionCard` or a `PerpsDiscoveryBanner` based on the read-only position lookup, adds geo-eligibility modal handling for Long/Short, and implements a one-click trade flow via new `PerpsOrderRedirect` route/screen that waits for perps connection, calls `depositWithOrder`, then `StackActions.replace`s into redesigned confirmations (or toasts + goes back on failure). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 4a032ad. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: sahar-fehri <sahar.fehri@consensys.net>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
- Adds HyperEVM as selectable network for Bridge/Swap.
- Adds Bridge/Swap feature for HyperEVM (behind feature flags).
- Switches from `CHAIN_IDS` (transactions-controller) to
`NETWORK_CHAIN_ID` (internal, extends `CHAIN_IDS`) in bridge-related
files mapping [chain.id]: { data }. @reviewers happy to discuss about
that and where CHAIN_IDS could be located in the future. I used
`NETWORK_CHAIN_ID` because it already existed and was an extension of
the first one.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: Adds Bridge and Swap feature to HyperEVM
## **Related issues**
Jira task: https://consensyssoftware.atlassian.net/browse/NEB-103
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
<img width="300" alt="image"
src="https://github.com/user-attachments/assets/4989e0aa-3f21-424e-9f84-0ddede78f698"
/>
<img width="300" alt="image"
src="https://github.com/user-attachments/assets/e1ea34c3-7aca-4d24-b88b-030cfc230408"
/>
<img width="300" alt="image"
src="https://github.com/user-attachments/assets/8310e5f8-8472-4fc8-b0f6-b532f4d04aef"
/>
<img width="300" alt="image"
src="https://github.com/user-attachments/assets/09d2f5af-e791-4799-9927-64a86f2c89e1"
/>
## **Pre-merge author checklist**
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] 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]
> **Medium Risk**
> Adds a new chain into bridge/swap routing via multiple constant maps
and supported-chain allowlists, so incorrect ids/addresses could break
swaps/bridges or mislabel activity. Dependency bumps to
bridge/transaction controllers add some integration risk.
>
> **Overview**
> Enables Bridge/Swaps flows to recognize **HyperEVM** by adding its
chain id to supported network lists, display-name mappings, and
first‑party `Bridge`/`Swaps` contract address maps.
>
> Updates bridge UI defaults by adding a HyperEVM default destination
token (USDC) and treating HyperEVM USDC as a stablecoin for default
slippage logic, while also standardizing several bridge constants to use
`NETWORK_CHAIN_ID` (from `customNetworks`) instead of `CHAIN_IDS`.
>
> Bumps `@metamask/bridge-controller` and
`@metamask/transaction-controller` versions and adjusts unit tests/mocks
accordingly (including using a clearly invalid chain id in a
transaction-history test).
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
225aa56. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
### Root Causes
**Flask Snap tests (Android + iOS):**
The invalid-entropy-source and past-date-scheduling error tests were
failing on **both** platforms but for different reasons:
- **iOS**: errors appear as native WebView alert dialogs —
`Assertions.expectTextDisplayed()` works.
- **Android**: errors render inside the web-view result span as JSON
with escaped quotes — `checkResultSpanIncludes()` is needed, matching a
quote-free substring to avoid `\"invalid\"` vs `"invalid"` mismatches.
The fix uses `device.getPlatform()` to pick the correct assertion per
platform.
**Identity multi-SRP test:**
- `profile-sync-controller@27.1.0` bumped `snaps-controllers` from `^14`
to `^17.2.0`, slowing down the initial full sync enough that
`enqueueSingleGroupSync` silently drops subsequent sync requests while
`isAccountTreeSyncingInProgress` is still `true`.
- The "Discovering accounts..." spinner was still active when the test
tried to tap the Wallet 2 "Add account" button, which is disabled during
discovery — so the tap silently did nothing and the 4th account was
never created.
### Changes
**Flask Snap tests** (`test-snap-bip-32`, `test-snap-bip-44`,
`test-snap-get-entropy`, `test-snap-background-events`):
- Platform-conditional error assertions: native dialog check on iOS,
web-view result span check on Android
- Increased assertion timeouts to 30s for slow CI emulators
**Identity sync tests** (`multi-srp.spec.ts`):
- Wait for initial full sync via
`waitUntilSyncedAccountsNumberEquals(1)` before mutating accounts
- Wait for "Discovering accounts..." to disappear before tapping "Add
account" on Wallet 2
- Set up PUT event counter after initial sync completes to only track
subsequent mutations
**Identity sync helpers** (`helpers.ts`):
- Increased `BASE_TIMEOUT` from 12s to 30s
- Improved error messages to include actual vs expected counts
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **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
- [ ] I've included tests if applicable
- [ ] 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]
> **Low Risk**
> Test-only changes (timeouts, waits, and assertions) with no impact on
production logic; main risk is slightly longer CI runtime if failures
occur.
>
> **Overview**
> Reduces flakiness in identity account-sync smoke coverage by **waiting
for the initial full sync to complete** before mutating accounts in
`multi-srp.spec.ts`, and by increasing the shared helper `BASE_TIMEOUT`
to 30s.
>
> Improves debuggability of identity sync helpers by including *actual
vs expected* counts in timeout errors.
>
> Stabilizes multiple Snap smoke tests by making error assertions
**platform-aware** (native alert on iOS vs web-view result on Android)
and by increasing assertion timeouts to 30s; also increases the optional
delay when tapping the V2 “Add Account” button (1.5s � 5s) to avoid UI
timing issues.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
92ac3cf. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Curtis David <Curtis.David7@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )