Skip to content

[pull] main from MetaMask:main#517

Merged
pull[bot] merged 28 commits into
Reality2byte:mainfrom
MetaMask:main
Feb 12, 2026
Merged

[pull] main from MetaMask:main#517
pull[bot] merged 28 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Feb 12, 2026

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 : )

dawnseeker8 and others added 28 commits February 12, 2026 08:35
style: center button content in LedgerConnect and LedgerSelectAccount…
components

Updated styles in `Scan.tsx` and `index.styles.ts` to center the button
content by adding `justifyContent: 'center'` to the button styles,
enhancing the UI consistency across the Ledger components.

<!--
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?
-->

## **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: fix #25693 styling issue in for ledger devices

## **Related issues**

Fixes: #25693


## **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
- [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**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] 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**
> Style-only changes limited to Ledger selector layout plus a snapshot
update; no functional, security, or data-flow impact.
> 
> **Overview**
> Fixes a Ledger UI alignment issue by centering the contents of the
device/path selector containers.
> 
> Adds `justifyContent: 'center'` to the dropdown wrapper styles in
`LedgerConnect/Scan.tsx` and `LedgerSelectAccount/index.styles.ts`, and
updates the LedgerConnect Jest snapshot accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
70e5b96. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Long token names in the Send flow and MM Pay token picker were pushing
the balance display off the screen. This fix adds proper flex
constraints to allow the token name container to shrink while keeping
the balance visible.

1. **Reason for change:** Tokens with long names (e.g., DAI on Linea,
USDT on Base) push the balance completely off screen in the Send flow
token picker and MM Pay deposit confirmation.
2. **Solution:** Add flex constraints (`flex-1`, `min-w-0`) to the token
info container to allow proper shrinking, and change the balance
container to `shrink-0` to prevent it from being pushed off screen. This
matches the behavior of the home page token list.

## **Changelog**

CHANGELOG entry: Fixed long token names pushing balance off screen in
Send flow and MM Pay token picker

## **Related issues**

Fixes: MetaMask/MetaMask-planning#6940

## **Manual testing steps**

```gherkin
Feature: Token picker displays long token names correctly

  Scenario: User views token with long name in Send flow
    Given user has a token with a long name (e.g., DAI on Linea, USDT on Base)

    When user starts a Send flow and opens the token picker
    Then the long token name is truncated with ellipsis
    And the balance is visible on the right side of the screen

  Scenario: User views token with long name in MM Pay deposit
    Given user has a token with a long name

    When user starts a Perps or Predict deposit and views the token picker
    Then the long token name is truncated with ellipsis
    And the balance is visible on the right side of the screen
```

## **Screenshots/Recordings**

### **Before**

Long token names push the balance off the screen (see issue for
screenshots).

### **After**

Long token names truncate with ellipsis while the balance remains
visible.

## **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
- [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.
## **Description**

`@metamask/perps-controller` is a local path alias (not an npm package)
resolved via `tsconfig.json` paths and `metro.config.js`. ESLint's
`import/no-extraneous-dependencies` rule doesn't understand path aliases
and flags every import as missing from `package.json`.

This adds `import/internal-regex` to `.eslintrc.js` settings so imports
matching `^@metamask/perps-controller` are classified as internal
modules, skipping the `package.json` check.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: false positive ESLint errors on `@metamask/perps-controller`
imports.

## **Manual testing steps**

```gherkin
Feature: ESLint config for perps-controller path alias

  Scenario: Lint a file importing @metamask/perps-controller
    Given the developer has the current branch checked out

    When running `npx eslint app/components/UI/Perps/Views/PerpsTabView/PerpsTabView.tsx`
    Then no `import/no-extraneous-dependencies` error is reported for @metamask/perps-controller
```

## **Screenshots/Recordings**

N/A - config-only change.

## **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]
> **Low Risk**
> Config-only ESLint change affecting lint classification of a single
import prefix; no runtime behavior changes.
> 
> **Overview**
> Adjusts ESLint `import` settings to classify
`^@metamask/perps-controller` as an *internal* module via
`import/internal-regex`.
> 
> This prevents `import/no-extraneous-dependencies` from flagging the
`@metamask/perps-controller` path alias as missing from `package.json`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
52e11c4. 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?
-->
## Summary
- Adds bidirectional communication between E2E tests and the app via the
existing CommandQueueServer
- Tests can now request a snapshot of the app's Redux +
Engine/Controller state and assert on it
  - All app-side code is guarded by `isE2E` — zero production impact

  ## Changes
- **`tests/framework/types.ts`** — Added `exportState` to
`E2ECommandTypes` enum (renamed from `PerpsModifiersCommandTypes`)
- **`tests/framework/fixtures/CommandQueueServer.ts`** — Added `POST
/exported-state`, `GET /exported-state.json` routes,
  `requestStateExport()` and `getExportedState()` methods
- **`app/util/test/e2eStateExport.ts`** — New: captures app state
(`store.getState()`) and POSTs it to the server
- **`app/util/test/e2eCommandPolling.ts`** — New: polls `/queue.json`
for generic commands like `export-state`
- **`app/store/index.ts`** — Bootstraps generic command polling on store
init when `isE2E`
- **`tests/regression/wallet/state-export.spec.ts`** — E2E test:
onboards a new wallet, exports state, verifies accounts
- **Unit tests** for `e2eCommandPolling` and `e2eStateExport` confirming
no-op in production
## **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
- [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]
> **Low Risk**
> Changes are gated behind `isE2E` and primarily affect the test
harness, with minimal production impact; the main risk is E2E flakiness
from the new store-init polling timer and command server interactions.
> 
> **Overview**
> Enables **bidirectional E2E test ↔ app communication** by adding an
E2E-only command poller in the app that consumes `/queue.json` and
handles a new `export-state` command by serializing `store.getState()`
(Redux + engine background state) and POSTing it back to the
`CommandQueueServer`.
> 
> Updates the test harness `CommandQueueServer` to persist exported
state and expose `POST /exported-state` + `GET /exported-state.json`,
adds helper APIs (`requestStateExport`, `getExportedState`), and
introduces a regression spec asserting onboarding produces accounts via
the exported snapshot. Perps command handling is consolidated under a
shared `E2ECommandTypes` enum and moved out of the Perps UI bridge by
deleting the old perps-specific HTTP polling logic, while keeping the
deep-link handler for perps commands.
> 
> Separately, the `smart-e2e-selection` GitHub composite action now
checks the `skip-smart-e2e-selection` label up front and gates
subsequent setup steps on it, and fixture JSON imports are redirected to
`fixtures/json/*`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6230e51. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…balance (#25960)

<!--
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**

1. **What is the reason for the change?**  
The "Add funds to start trading perps" banner with "Add funds" CTA on
the Perps market details screen was removed by product. Users should
still be able to start a trade (Long/Short) even when their perps
balance is zero; they can add funds in the order/deposit flow if needed.

2. **What is the improvement/solution?**  
- Removed the add-funds banner and "Add funds" button from the fixed
actions footer on the Perps market details (asset) screen.
- Action footer now shows Long/Short (or Modify/Close when there is a
position) whenever position data is loaded, regardless of balance. Users
with zero perps balance can tap Long or Short and proceed to the order
flow.
- Removed unused logic: `hasZeroBalance`, `hasAddFundsButton`,
`handleAddFundsPress`, and hooks only used for that CTA
(`useConfirmNavigation`, `usePerpsTrading`, `usePerpsNetworkManagement`,
`usePerpsLiveAccount`).
- Updated unit tests to assert Long/Short buttons are shown with zero
balance and that the add-funds banner is no longer present.


## **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: Removed "Add funds to start trading perps" banner from
Perps market details and allow opening trades (Long/Short) when perps
balance is zero.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2530

## **Manual testing steps**

```gherkin
Feature: Perps market details – no add-funds banner, trade with zero balance

  Scenario: user opens a perps market with zero balance
    Given user is on a Perps market details screen and their perps balance is 0

    When the screen has finished loading
    Then the "Add funds to start trading perps" banner and "Add funds" button are not shown
    And Long and Short buttons are shown in the footer
    And user can tap Long or Short and proceed to the order flow

  Scenario: user opens a perps market with non-zero balance
    Given user is on a Perps market details screen and their perps balance is > 0

    When the screen has finished loading
    Then Long and Short (or Modify/Close if they have a position) are shown as before
    And no add-funds banner is shown

```

## **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="1206" height="2622"
alt="simulator_screenshot_27173437-1211-4E38-B9DD-D5CACE24AFD1"
src="https://github.com/user-attachments/assets/4f5acacb-9c25-41b1-89d0-fa531a530df6"
/>


## **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]
> **Low Risk**
> UI behavior change limited to the market details action footer and
corresponding tests; no changes to order placement or on-chain flows,
but it can affect user navigation expectations for zero-balance users.
> 
> **Overview**
> Removes the fixed-footer "Add funds to start trading perps" banner/CTA
from `PerpsMarketDetailsView` and no longer gates the Long/Short actions
on having a non-zero perps balance (buttons now render whenever position
loading is complete).
> 
> Deletes the associated deposit-navigation handler and related
hooks/imports used only for that CTA, and updates tests to assert
Long/Short buttons are visible at zero balance while the add-funds UI
and its navigation/geo-block test cases are removed.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fb8eba1. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description**
Bumps the STX controller to ^22.5.0.

## **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: null

## **Related issues**

Fixes:

## **Manual testing steps**
When a cancelled smart transaction happens, we will log this new prop in
the Transaction Finalized event, which will give us more granular reason
for cancellation

## **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**

- [ ] 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]
> **Low Risk**
> Dependency-only bump with no in-repo logic changes; risk is limited to
behavioral changes introduced by the upstream controller update.
> 
> **Overview**
> Updates the `@metamask/smart-transactions-controller` dependency from
`^22.4.0` to `^22.5.0`.
> 
> Regenerates `yarn.lock` to pin the new `22.5.0` resolution and
checksum for this package.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9573cfe. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com>
<!--
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**
This PR will fix #24546 regarding unknown error display in ledger
selection screen.
The root cause of this issue is due to mis match of error code returned
from ledger sdk. i have setup a constant array to cover all code
regarding `Eth not open` and also mapping the error code with
localisation string.

<!--
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: Fix #24546 with human readable message

## **Related issues**

Fixes: #24546 

## **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
- [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**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] 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**
> Touches hardware-wallet error classification and account
unlock/pagination paths, so misclassification could change user flows or
hide actionable errors; token-list CTA logic also changes gating
behavior for Earn CTAs.
> 
> **Overview**
> Fixes Ledger UX by introducing a dedicated `EthAppNotOpen` error
classification (status-code and message based) and mapping it to new
localized strings, so users see a clear “open the Ethereum app” prompt
instead of generic/unknown errors.
> 
> Plumbs this error through Ledger flows: `useLedgerBluetooth`, `Ledger`
core (`getLedgerAccountsByOperation`, `unlockLedgerWalletAccount`),
`LedgerConnect`, and the confirmation modal now render the new error
state and tests cover the new mappings and helpers.
> 
> Cleans up token list rendering by removing the
`shouldShowTokenListItemCta` prop from
`TokenList`/`TokenListItem`/`TokenListItemV2` and having items call
`useMusdCtaVisibility` internally; also loosens stablecoin lending CTA
gating to rely on the returned `earnToken` rather than an extra
BigNumber threshold check (and updates tests accordingly).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
372625a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…6000)

## **Description**

Apply the `ensureSubscriptionClient()` pattern consistently to all HIP-3
subscription methods.

`createClearinghouseSubscription` and `createOpenOrdersSubscription`
were missing `ensureSubscriptionClient()` calls before accessing the
subscription client. This creates a potential race condition during
WebSocket reconnection where the client could be destroyed between the
parent method's check and the child's `getSubscriptionClient()` call.

The fix adds the same `ensureSubscriptionClient()` guard already used by
`createUserDataSubscription` and `createAssetCtxsSubscription`, ensuring
all subscription creation methods follow the same defensive pattern.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: Sentry perps socket "Subscription client not available" errors

## **Manual testing steps**

```gherkin
Feature: Perps WebSocket subscription resilience

  Scenario: User reconnects to perps after network interruption
    Given user has perps positions open and is viewing the perps UI

    When user experiences a brief network disconnection and reconnects
    Then clearinghouse and open orders subscriptions resume without errors
```

## **Screenshots/Recordings**

N/A - internal WebSocket fix, no UI changes.

## **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.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…5943)

<!--
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**
We currently have E2E tests using skipReactNativeReload: true pass but
the test suite fails with Aborted errors from mockttp's streamToBuffer.
When mockServer.stop() calls destroy(), it immediately kills all TCP
connections. Any in-flight background requests (price polling, token
metadata, etc.) from the still-running app have their body-buffering
promises rejected as unhandled rejections, which Jest reports as "Test
suite failed to run."
Example:
https://github.com/MetaMask/metamask-mobile/actions/runs/21895017113/job/63209898359

### Solution
Add graceful shutdown to MockServerE2E:
- Shutdown flag (_shuttingDown): When set, request handlers consume the
body (preventing unhandled rejections) and return 503 immediately
instead of processing.
- Active request tracking (_activeRequests): Tracks in-flight handler
callbacks. stop() waits for them to drain before calling destroy(), so
connections are only killed when idle.
- Timeout safety net: 5s max wait to avoid hanging on slow CI, with
warning logs if requests don't drain in time.

<!--
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:

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MMQA-1420

## **Manual testing steps**
N/A

## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**
N/A
<!-- [screenshots/recordings] -->

### **After**
N/A
<!-- [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
- [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]
> **Medium Risk**
> Touches E2E request proxying and shutdown behavior; mistakes could
hang shutdowns or change which requests are forwarded vs
short-circuited, though changes are test-only and include a timeout
safety net.
> 
> **Overview**
> Prevents E2E failures during `MockServerE2E.stop()` by adding
**graceful shutdown**: a `_shuttingDown` gate returns `503` while safely
consuming request bodies, and `_activeRequests` tracking drains
in-flight handlers before calling `mockttp.stop()` (with a 5s timeout
and logging).
> 
> Updates `Gestures.scrollToElement` on iOS to pass `startPositionX/Y`
through to Detox scrolling, and adjusts `TrendingView` horizontal
quick-action scrolling to use a normalized `startPositionX` (`0.5`
instead of `50`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5e3358d. 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**

WalletConnect V1 has been fully deprecated. This PR removes leftover
codepaths from that integration.

<!--
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: remove WalletConnect V1 support

## **Related issues**

Fixes:
[WAPI-1033](https://consensyssoftware.atlassian.net/browse/WAPI-1033)

## **Manual testing steps**

There's no feature to test, this is removal of dead code.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **After**


https://github.com/user-attachments/assets/b8043868-13d1-4922-b2b5-ed8b30f74c38
(WC connections still work)

## **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.


[WAPI-1033]:
https://consensyssoftware.atlassian.net/browse/WAPI-1033?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it removes approval/UI and connection codepaths
that may still be referenced by edge flows (deeplinks/QR) and changes
session management behavior to v2-only, though changes are largely
deletions with updated tests.
> 
> **Overview**
> Removes the legacy WalletConnect v1 integration end-to-end: deletes
the `app/core/WalletConnect/WalletConnect.js` implementation, its tests,
the `WALLET_CONNECT` approval type, and the `WalletConnectApproval`
UI/modal wiring from `RootRPCMethodsUI`.
> 
> Updates the WalletConnect sessions screen to be **v2-only**, sourcing
sessions and disconnect actions exclusively via `WC2Manager` and
rendering v2 session fields (e.g., `topic`), with tests/snapshots
updated accordingly.
> 
> `WC2Manager.connect` now explicitly rejects v1 URIs by logging a
deprecation warning and returning early; invalid-URI warnings/tests were
adjusted, and v1 dependencies (`@walletconnect/client`, socket
transport) were removed from `package.json`/`yarn.lock`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d53d91b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…onGatedFeatureFlag (#25992)

## **Description**

Inlines the MYX provider feature flag check in `PerpsController`,
removing the dependency on `resolvePerpsMyxProviderEnabled` from the UI
selectors layer. Reuses the shared `isVersionGatedFeatureFlag` utility
and the controller's existing `featureFlags.validateVersionGated`
infrastructure instead.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

```gherkin
Feature: Perps MYX provider feature flag

  Scenario: MYX provider flag resolves correctly
    Given the app is running with perps enabled

    When the PerpsController checks the MYX provider flag
    Then it should resolve the version-gated remote flag via the controller's infrastructure
```

## **Screenshots/Recordings**

N/A — no UI changes.

### **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
- [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]
> **Low Risk**
> Scoped refactor of feature-flag resolution with test updates; primary
risk is behavior drift if remote flag shape/version validation differs
from the previous selector logic.
> 
> **Overview**
> MYX provider enablement is now resolved inside
`PerpsController.isMYXProviderEnabled()` instead of calling the UI
selector `resolvePerpsMyxProviderEnabled`, using the shared
`isVersionGatedFeatureFlag` + `featureFlags.validateVersionGated` path
and falling back to `MM_PERPS_MYX_PROVIDER_ENABLED`.
> 
> Tests were updated to stop mocking the selector and instead exercise
the new behavior by providing `perpsMyxProviderEnabled` in
`RemoteFeatureFlagController:getState` and mocking version validation
when switching to `myx`, while keeping the “MYX disabled”
fallback-to-`hyperliquid` case.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6ca1246. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… feature tags (#26004)

## **Description**

Sentry shows "Unknown error (no details provided)" events/week from
perps code because:
1. Most `ensureError()` calls lack the optional `context` parameter —
when the caught value is `undefined`/`null`, the error has no
identifying info.
2. Several `logger.error()` calls are missing the `feature` tag, making
them invisible in the Sentry perps dashboard.

### What changed
- Added `context` string (e.g. `'AccountService.withdraw'`) to ~35 bare
`ensureError()` calls across 21 files
- Added `tags: { feature: PERPS_CONSTANTS.FeatureName }` to ~14
`logger.error()` calls missing it
- Replaced 13 hardcoded `feature: 'perps'` with
`PERPS_CONSTANTS.FeatureName`

No functional behavior changes — only error metadata is enriched.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: Sentry "Unknown error (no details provided)" noise from perps
layer

## **Manual testing steps**

No user-facing changes. Verify existing perps flows (deposit, withdraw,
trade) still work. Error reporting improvements are observable only in
Sentry.

## **Screenshots/Recordings**

N/A — observability-only change.

## **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]
> **Low Risk**
> Logging/telemetry metadata-only changes; functional code paths are
unchanged aside from error object/message enrichment when errors are
`null`/`undefined`.
> 
> **Overview**
> Improves Perps observability by **adding explicit context strings to
many `ensureError(...)` calls** so Sentry errors are identifiable even
when the thrown value is `null`/`undefined`.
> 
> Standardizes Perps `Logger.error`/`deps.logger.error` payloads by
**using `tags: { feature: PERPS_CONSTANTS.FeatureName }` (and removing
ad-hoc `feature: 'perps'` fields / message+context strings)** across UI
views, hooks, connection/subscription management, controller/services,
and provider implementations; updates a few unit tests to match the new
logging shape.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
109672c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
)

## **Description**

Creates a new FF for token details v2 with min version

## **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: null

## **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**

- [ ] 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]
> **Low Risk**
> Feature-flag plumbing and selector behavior changes only; risk is
mainly incorrect gating if the new flag payload/override configuration
is wrong.
> 
> **Overview**
> Adds a new remote feature flag `tokenDetailsV2ButtonLayout` (default
`false`) and switches `selectTokenDetailsV2ButtonsEnabled` to evaluate
this flag via `validatedVersionGatedFeatureFlag`, including support for
override env vars.
> 
> Updates the `AssetOverviewContent` test to mock the feature-flag
selectors directly and removes reliance on
`RemoteFeatureFlagController.remoteFeatureFlags.tokenDetailsV2Buttons`
state.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
276d02c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#25971)

<!--
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**

Geolocation request failures were causing a cascade that reset
`userCardLocation` from `'us'` to `'international'` for authenticated US
users, breaking the `x-us-env` header required for US operations.

**Root cause:** The `useCardAuthenticationVerification` hook dispatched
`resetAuthenticatedData()` whenever `isBaanxLoginEnabled` was `false`.
Since `isBaanxLoginEnabled` depends on `cardGeoLocation` (IP-based
lookup), a transient network failure would set `cardGeoLocation` to
`'UNKNOWN'`, making `isBaanxLoginEnabled` evaluate to `false`, which
triggered the reset — wiping `userCardLocation` and causing the SDK to
re-instantiate with `x-us-env: false`.

**The fix has two parts:**

1. **Decouple `userCardLocation` from auth state resets:**
`resetAuthenticatedData`, `verifyCardAuthentication.fulfilled` (when no
location in payload), and `verifyCardAuthentication.rejected` no longer
reset `userCardLocation` to `'international'`. A user's
declared/registered region does not change when auth state changes.

2. **Guard session clearing against transient geo failures:**
`useCardAuthenticationVerification` now only clears sessions when
`isBaanxLoginEnabled` is `false` AND `cardGeoLocation` has been resolved
(i.e. is not `'UNKNOWN'`). When geo is `'UNKNOWN'` (initial state or
network failure), the session is preserved. Once geo resolves to an
unsupported country, the session is cleared as expected.

## **Changelog**

CHANGELOG entry: Fixed `x-us-env` header being incorrectly set to
`false` for US Card users when geolocation requests fail

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Card x-us-env header resilience to geolocation failures

  Scenario: US user retains correct x-us-env header when geolocation fails
    Given a US user is authenticated with the Card feature
    And userCardLocation is set to 'us'

    When the geolocation API request fails (e.g. network error)
    Then userCardLocation remains 'us'
    And the x-us-env header is 'true' on subsequent Card API calls
    And the user's session is not cleared

  Scenario: US user retains correct x-us-env header on app restart with geo failure
    Given a US user has a valid stored auth token with location 'us'

    When the app restarts and the geolocation API is unreachable
    Then the auth verification reads the location from the stored token
    And userCardLocation is set to 'us'
    And the x-us-env header is 'true' on subsequent Card API calls

  Scenario: Session is cleared when geo resolves to unsupported country
    Given a user is authenticated with the Card feature
    And the geolocation API resolves to an unsupported country (e.g. 'FR')

    When the isBaanxLoginEnabled check evaluates to false
    Then the user's session is cleared via resetAuthenticatedData
    And userCardLocation is preserved (not reset to 'international')

  Scenario: Session is not cleared when geo is unknown
    Given a user is authenticated with the Card feature
    And the geolocation API has not resolved yet or has failed (cardGeoLocation = 'UNKNOWN')

    When the isBaanxLoginEnabled check evaluates to false
    Then the user's session is NOT cleared
    And the user remains authenticated until the token naturally expires
```

## **Screenshots/Recordings**

<!-- Not applicable — no UI changes -->

### **Before**

<!-- N/A -->

### **After**

<!-- N/A -->

## **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]
> **Medium Risk**
> Touches Card authentication reset logic and Redux state persistence
(`userCardLocation`), which can affect session handling and regional
behavior if the new guards are incorrect; changes are contained and
covered by expanded unit tests.
> 
> **Overview**
> Prevents Card geolocation failures from cascading into
session/location resets by **preserving `userCardLocation`** when
clearing authenticated data and when `verifyCardAuthentication`
returns/rejects without a location, and by only dispatching
`resetAuthenticatedData()` when Baanx login is disabled *and*
geolocation has resolved (not `UNKNOWN`).
> 
> Updates Card Home analytics to wait for load even without a priority
token, adds a `state` property derived from auth/KYC/warnings/delegated
wallets, and avoids emitting priority-token balance properties when no
priority token exists.
> 
> Adds a `CARD_BUTTON_CLICKED` analytics event for the push provisioning
“Add to wallet” action (new `CardActions.ADD_TO_WALLET_BUTTON`), removes
the unused `CARD_ADD_TO_WALLET_CLICKED` event, and simplifies Card SDK
geolocation to always call the production endpoint; tests are updated to
cover these behaviors.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
17c8770. 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**
Following #24313 we're
looking to centralize all tools and test resources in one place. This
marks the final PR deprecating `e2e` by moving all page objects and test
specific selectors. A follow up PR will be created to remove all
references from scripts and other tools.


This PR:
- deprecates the `appwright` folder
- moves all `appwright/**` files into their appropriate folders inside
`tests`.
- Marks the first stage of unifying the frameworks

Previous related PRs:
- #24988
- #24313
- #25031
- #25095
- #25167
- #25198
- #25219
- #25263
- #25279
- #25520
- #25533
- #25598
- #25636
- #25638
- #25698
- #25706
- #25764
- #25785
- #25849


<!--
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:

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MMQA-1235

## **Manual testing steps**
N/A

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**
N/A
<!-- [screenshots/recordings] -->

### **After**
N/A
<!-- [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
- [x] 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]
> **Medium Risk**
> Moderate risk because it rewires CI workflows, artifact/report paths,
and many import paths for the performance test infrastructure; failures
would primarily impact performance E2E execution rather than app runtime
behavior.
> 
> **Overview**
> Consolidates Appwright performance testing under `tests/` by updating
GitHub Actions workflows, package scripts, and the aggregation pipeline
to use the new locations for the device matrix, config, reports, and
aggregated artifacts.
> 
> Refactors the performance test framework and suites to match the new
directory structure (updated `testMatch`, fixture/util/reporter imports,
and tag sources), adds the new `tests/tags.performance.js` + team
mapping, and introduces/relocates performance specs (including a new
`asset-view` test and moved launch-time tests). Updates several `wdio`
screen objects to pull shared helpers from `tests/framework/utils`
instead of `appwright`/Appwright-provided utility paths, and refreshes
docs to point to `tests/performance`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
91bab4a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Sentry issues
[5E7H](https://metamask.sentry.io/issues/METAMASK-MOBILE-5E7H) (Android)
and [5E7K](https://metamask.sentry.io/issues/METAMASK-MOBILE-5E7K) (iOS)
report `KeyringController - The operation cannot be completed while the
controller is locked.` errors from the Perps trading setup flow.

**Root cause**: When a user enters the Perps screen and the app
backgrounds or locks, the keyring locks. On the next trade attempt,
`ensureReadyForTrading()` runs automatic signing operations (referral
setup, builder fee approval, DEX abstraction) that fail because the
keyring is locked. These failures are expected but were being reported
to Sentry and unnecessarily cached as permanent failures.

**Fix**: Guard signing operations against keyring lock state by checking
`KeyringController:getState().isUnlocked` before attempting to sign.
When the keyring is locked:
- Throw a `KEYRING_LOCKED` error from
`HyperLiquidWalletService.signTypedMessage()`
- Don't cache the failure in the `ensure*` methods (so they can retry on
the next attempt)
- Don't report to Sentry (expected behavior, not a bug)
- Don't mark `tradingSetupComplete = true` (so `ensureReadyForTrading()`
re-runs next time)

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[METAMASK-MOBILE-5E7H](https://metamask.sentry.io/issues/METAMASK-MOBILE-5E7H),
[METAMASK-MOBILE-5E7K](https://metamask.sentry.io/issues/METAMASK-MOBILE-5E7K)

## **Manual testing steps**

```gherkin
Feature: Perps trading setup handles keyring lock gracefully

  Scenario: user trades after app was backgrounded
    Given user has navigated to the Perps trading screen
    And the app is backgrounded long enough for the keyring to lock

    When user returns to the app and attempts to place a trade
    Then the trading setup retries the signing operations
    And no KeyringController errors are reported to Sentry

  Scenario: user trades without keyring lock
    Given user has navigated to the Perps trading screen
    And the keyring is unlocked

    When user places a trade
    Then the trading setup completes normally (referral, builder fee, DEX abstraction)
    And the trade is placed successfully
```

## **Screenshots/Recordings**

N/A - Internal error handling change, no UI changes.

### **Before**

KeyringController locked errors sent to Sentry.

### **After**

Signing operations gracefully skip when keyring is locked, retry on next
trade attempt, no Sentry noise.

## **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]
> **Medium Risk**
> Touches Perps trading readiness/signing and cache behavior; mistakes
could cause repeated setup attempts or skipped initialization, but
changes are localized and covered by new tests.
> 
> **Overview**
> Prevents Perps trading setup from performing signature-required
operations when the keyring is locked by introducing a `KEYRING_LOCKED`
error path and checking `KeyringController:getState().isUnlocked` before
signing.
> 
> Updates HyperLiquid trading-readiness `ensure*` flows to treat
keyring-lock failures as *expected*: skip caching failure states (so
setup retries after unlock), avoid extra error reporting, and only set
`tradingSetupComplete` when the keyring is unlocked. Adds messenger
permissions for `KeyringController:getState`, updates UI error
translation to never surface the lock error, and extends mocks/tests to
cover these scenarios.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
110efc4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…fig (#25938)

<!--
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**

When users leave the Perps order screen (e.g. to check another tab or
the Pay-with modal) and return within the 5-minute pending config
window, their previously selected "Pay with" token was not restored; the
Pay row reverted to the default. This restores the selected pay-with
token from pending trade configuration so the Pay row and Pay-with flow
reflect the user’s last choice.


## **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: Restored the previously selected "Pay with" token when
returning to the Perps order view within 5 minutes.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2523

## **Manual testing steps**

```gherkin
Feature: Perps pending pay-with token restore

  Scenario: user returns to order view and sees previous pay-with token restored
    Given user is on the Perps order view for a market
    And user has selected a specific token in Pay with (e.g. USDC) or left it as Perps balance

    When user navigates away (e.g. to another tab or screen) and returns within 5 minutes
    Then the Pay row shows the same token (or Perps balance) that was selected before leaving
    And opening Pay with modal shows that option pre-selected

```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

No visible change

## **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]
> **Medium Risk**
> Touches Perps state persistence and token-selection synchronization
across UI hooks and `PerpsController`, which could cause incorrect token
selection or deposits if the pending config mapping is wrong; changes
are covered by new unit tests but span multiple layers.
> 
> **Overview**
> Restores the previously selected **Perps “Pay with” token** when
returning to the order screen by persisting it into the pending trade
configuration and syncing it back into the confirmation `payToken` and
`PerpsController.selectedPaymentToken`.
> 
> This wires `PerpsPayRow` to read
`selectPendingTradeConfiguration(state, initialAsset)` and apply/clear
the pending `selectedPaymentToken`, updates `usePerpsSavePendingConfig`
to save `selectedPaymentToken`, introduces `parsePayWithToken` +
`usePerpsPayWithToken`/`selectPerpsPayWithToken` for safer token
parsing, and adjusts controller/types to store an explicit
`PerpsSelectedPaymentToken` (incl. optional `description`). Tests are
expanded/added to cover the new sync + parsing behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
baeac8c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
<!--
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**

- Add selectPerpsPayWithAnyTokenAllowListAssets selector (env overrides
remote)
- Filter pay-with modal tokens by allowlist in
usePerpsBalanceTokenFilter
- Document PERPS_PAY_WITH_ANY_TOKEN_ALLOW_LIST_ASSETS in .js.env.example
and docs
- Add unit tests for allowlist parsing and env override


## **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: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2521

## **Manual testing steps**

```gherkin
Feature: Perps pay-with token allowlist

  Scenario: pay-with modal shows only allowlisted tokens when flag is set
    Given the app is running with PERPS_PAY_WITH_ANY_TOKEN_ALLOW_LIST_ASSETS set (e.g. "1.0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" for USDC on mainnet)
    When user opens Perps and triggers the pay-with modal (e.g. from order flow)
    Then only the Perps balance option and tokens matching the allowlist are shown

  Scenario: pay-with modal shows all tokens when allowlist is empty
    Given PERPS_PAY_WITH_ANY_TOKEN_ALLOW_LIST_ASSETS is unset or empty (and remote flag empty)
    When user opens the pay-with modal
    Then all eligible tokens appear as before (no filtering)
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->
No visible change

## **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]
> **Medium Risk**
> Changes which tokens can be presented for funding perps orders based
on a remotely configurable allowlist; misconfiguration could
unintentionally hide valid tokens, though parsing is designed to fail
open.
> 
> **Overview**
> Adds a new Perps configuration flag
`perpsPayWithAnyTokenAllowlistAssets` (env
`MM_PERPS_PAY_WITH_ANY_TOKEN_ALLOWLIST_ASSETS` overrides LaunchDarkly)
to define an allowlist of permitted pay-with assets as
`chainId.address`.
> 
> Updates `usePerpsBalanceTokenFilter` to filter pay-with modal tokens
to the allowlist (while still prepending the synthetic Perps balance
token), and introduces `parseAllowlistAssets` to safely parse/normalize
flag values (string or array) with a fail-open `[]` fallback. Tests and
docs are updated to cover env override, parsing behavior, and filtering.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
39e809c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description**

Three changes to the perps standalone mode:

1. **Rename `readOnly` → `standalone`** across the entire stack (types,
controller, provider, services, hooks, tests, docs). "Standalone" better
describes the intent: lightweight queries via a standalone `InfoClient`
without full initialization.

2. **HIP-3 multi-DEX support in standalone mode.** Standalone
`getPositions` and `getAccountState` now discover and query all
validated HIP-3 DEXs (same as the fully-initialized path), with DEX list
caching and graceful fallback to main DEX on errors.

3. **Store raw `returnOnEquity` — let UI handle formatting.** Removed
`.toFixed(1)` from `returnOnEquity` at the data layer so it stores raw
numeric strings like all other `AccountState` fields. The UI's
`formatPercentage()` handles display precision.

### Key changes

- New `getStandaloneValidatedDexs()` method — discovers DEXs via
standalone `InfoClient`, filters by allowlist, caches results
- `getPositions` standalone path queries all validated DEXs in parallel
and combines positions
- `getAccountState` standalone path aggregates balances and margin
across all validated DEXs
- Removed single-DEX `getStandaloneClearinghouseState` helper
(superseded)
- Added dedicated unit tests for `standaloneInfoClient.ts` (12 tests
covering transport creation, multi-DEX queries, error propagation)
- Updated `perps-architecture.md` to reflect HIP-3 support in standalone
mode
- Removed `.toFixed(1)` from `returnOnEquity` in adapter, accountUtils,
and HyperLiquidProvider (4 call sites)
- `returnOnEquity` now stores raw numeric strings like all other
`AccountState` fields
- Updated test assertions to match raw values (e.g. `'10'` instead of
`'10.0'`)

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Perps standalone mode

  Scenario: Standalone positions include HIP-3 DEXs
    Given a user with positions on both main DEX and a HIP-3 DEX
    When calling getPositions with standalone: true
    Then positions from all validated DEXs are returned

  Scenario: Standalone account state aggregates across DEXs
    Given a user with balances on multiple DEXs
    When calling getAccountState with standalone: true
    Then totalBalance and marginUsed are summed across DEXs

  Scenario: Graceful fallback
    Given the perpDexs() API call fails
    When calling getPositions with standalone: true
    Then only main DEX positions are returned (no error thrown)
```

## **Screenshots/Recordings**

N/A — internal changes only, no UI impact.

## **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]
> **Medium Risk**
> Touches core perps data-fetch paths (controller/provider) and changes
numeric formatting/aggregation behavior, which could subtly impact
balances/ROE display and discovery logic, though covered by expanded
tests and includes graceful fallbacks.
> 
> **Overview**
> Renames the perps lightweight query parameter from `readOnly` to
`standalone` end-to-end
(controller/types/provider/hooks/services/tests/docs), keeping the
behavior of bypassing full perps initialization for discovery-style
queries.
> 
> Extends standalone mode to support HIP-3 multi-DEX:
`HyperLiquidProvider` now discovers validated DEXs via the standalone
info client, queries `clearinghouseState` across DEXs in parallel (new
`queryStandaloneClearinghouseStates` helper), combines positions, and
aggregates account state totals.
> 
> Stops rounding `returnOnEquity` in the data layer by removing
`.toFixed(1)` and returning raw numeric strings; adds
`aggregateAccountStates` utility and updates/expands unit tests to match
the new semantics and fallback behavior when standalone queries fail.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3758398. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…Socket timeout failures (#26014)

## **Description**

Fixes the "Failed to fetch market data" error that is a top Sentry issue
for Perps.

`getMarketDataWithPrices()` uses the WebSocket-based `InfoClient` for
one-shot request/response calls (`metaAndAssetCtxs()`, `allMids()`).
When the WebSocket is reconnecting (after app backgrounding or network
transitions), messages get buffered and eventually time out — causing
all DEX fetches to fail.

The fix switches these calls to the existing HTTP-based `InfoClient`,
which uses `fetch()` and is independent of WebSocket state.

Additionally:
- Enriched the aggregate error message with diagnostic context
(failed/succeeded DEXs, WebSocket state)
- Downgraded per-DEX fetch errors from Sentry to local debug logs to
reduce duplicate reporting
- Added cache staleness context to `PerpsStreamManager` error reporting

## **Changelog**

CHANGELOG entry: Fixed intermittent "Failed to fetch market data" errors
on Perps by switching market data fetches from WebSocket to HTTP
transport

## **Related issues**

Fixes:
[METAMASK-MOBILE-521H](https://metamask.sentry.io/issues/METAMASK-MOBILE-521H)

## **Manual testing steps**

```gherkin
Feature: Perps market data loading

  Scenario: user opens Perps after app was backgrounded
    Given the app has been in the background for 30+ seconds
    And the WebSocket connection is in reconnecting state

    When user navigates to the Perps trading screen
    Then market data loads successfully via HTTP transport
    And no "Failed to fetch market data" error appears

  Scenario: user opens Perps on unstable network
    Given the device has intermittent network connectivity

    When user navigates to the Perps trading screen
    Then market data loads via HTTP even if WebSocket is disconnected
    And cached data is shown if HTTP fetch also fails
```

## **Screenshots/Recordings**

N/A - Backend transport change, no UI changes.

### **Before**

N/A

### **After**

N/A

## **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]
> **Medium Risk**
> Changes the transport path and error behavior for a critical
market-data fetch used during Perps initialization; mistakes could
impact data loading or error reporting, though the change is localized
and test-covered.
> 
> **Overview**
> Fixes intermittent Perps market-data load failures by forcing
`HyperLiquidProvider.getMarketDataWithPrices()` to use an HTTP
`InfoClient` instead of the WebSocket transport (which can
buffer/timeout during reconnect states).
> 
> Tightens observability by logging per-DEX fetch failures only to local
debug logs (reducing duplicate Sentry noise), enriching the aggregate
"no markets available" error with failed/succeeded DEX lists and
WebSocket state, and adding cache staleness + cached-market counts to
`PerpsStreamManager` error reporting when refreshes fail. Tests are
updated to cover the HTTP client usage and the new diagnostic error
message, and the client-service mock now includes
`getConnectionState()`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6191349. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
)

## **Description**

This PR implements the Continue button functionality in the unified
ramps BuildQuote screen to route users to the appropriate flow based on
provider type.

### What Changed

**Continue Button Routing Logic**:
- Native/whitelabel providers (e.g., Transak Native) → Navigate to
deposit flow with amount pre-filled
- Aggregator providers (e.g., Mercuryo, Banxa) → Fetch widget URL and
open Checkout webview
- Aggregator providers without URL → Log error (should not occur in
production)

**New Checkout Component** (`app/components/UI/Ramp/Views/Checkout/`):
- Lightweight webview component for aggregator provider widgets
- Uses BottomSheet + WebView pattern (consistent with existing
aggregator implementation)
- Basic error handling for HTTP errors with retry capability
- Includes close button with cancel callback hook for future analytics
- Order callback processing deferred to future work

**Provider Type Detection** (`app/components/UI/Ramp/types/index.ts`):
- Extended Quote type to include `providerInfo` metadata
- `isNativeProvider(quote)` - Uses `providerInfo.type` instead of suffix
pattern matching
- `getQuoteProviderName(quote)` - Uses canonical `providerInfo.name` for
display
- Ensures correct routing regardless of provider ID naming conventions

**Navigation Enhancements**:
- Wired Checkout screen into unified routes using `Routes.RAMP.CHECKOUT`
- Added navbar helper `getRampsNavbarOptions()` for consistent unified
flow headers
- Deposit flow now accepts and preserves `amount` and
`shouldRouteImmediately` params

**Controller Integration**:
- Added `getWidgetUrl()` method to RampsController hook surface
- Added `redirectUrl` parameter to `startQuotePolling()` for callback
handling
- Updated all test mocks to include new `getWidgetUrl` method

### Why These Changes

The unified ramps flow needed a way to handle the Continue button once
users select a quote. Different provider types require different
navigation paths:
- Native providers use our internal deposit flow
- Aggregator providers use external widget webviews

The implementation ensures type-safe provider detection using metadata
instead of string pattern matching, making it resilient to provider
naming changes.

### Dependencies

Requires updated `@metamask/ramps-controller` package with:
- Enhanced `Quote` type including `providerInfo` field
- `getWidgetUrl()` controller method

The controller changes are in MetaMask/core and bundled in this PR's
yarn.lock.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: [Add issue number if applicable]

## **Manual testing steps**

```gherkin
Feature: Unified Ramps Continue Button Flow

  Scenario: User continues with aggregator provider quote
    Given user is on the unified ramps BuildQuote screen
    And user has entered an amount of $100
    And user has selected an aggregator provider (Mercuryo/Banxa)
    And a quote is available and matches the amount

    When user taps the Continue button
    Then the app fetches the widget URL from the quote
    And the Checkout webview opens
    And the provider name appears in the navbar title
    And the webview loads the provider's widget

  Scenario: User continues with native provider quote
    Given user is on the unified ramps BuildQuote screen
    And user has entered an amount of $100
    And user has selected a native provider (Transak Native)
    And a quote is available and matches the amount

    When user taps the Continue button
    Then the app navigates to the Deposit flow
    And the amount ($100) is pre-filled in the Deposit BuildQuote screen
    And the deposit flow starts immediately

  Scenario: User taps Continue when no quote is available
    Given user is on the unified ramps BuildQuote screen
    And user has entered an amount of $100
    And quotes are still loading OR no quote is selected

    When user views the Continue button
    Then the Continue button is disabled
    And user cannot proceed

  Scenario: User closes Checkout webview
    Given user is in the Checkout webview for an aggregator provider

    When user taps the Close button in the navbar
    Then the webview closes
    And user returns to the BuildQuote screen
```

## **Screenshots/Recordings**

### **Before**

Continue button had no functionality (TODO comment).

### **After**

_(Will add after manual testing on device)_
- Screenshot: BuildQuote with Continue button enabled
- Recording: Full flow from BuildQuote → Continue → Checkout webview
- Recording: Full flow from BuildQuote → Continue → Deposit flow

## **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 new navigation paths and an embedded WebView checkout, plus new
controller surface (`getWidgetUrl`) and redirect URL handling; issues
could impact ramp purchase routing and quote/checkout correctness.
> 
> **Overview**
> Implements the unified ramps `BuildQuote` *Continue* flow: validates
the selected quote against the current amount/payment method, routes
**native/whitelabel** providers into the Deposit flow (passing `amount`
+ `shouldRouteImmediately`), and routes **aggregator** providers into a
new `Checkout` bottom-sheet WebView after fetching a resolved widget URL
via `getWidgetUrl`.
> 
> Adds the `Checkout` screen (navigation + tests) with close affordance,
optional provider-specific `userAgent`, and HTTP-error handling that
only blocks on initial-URL failures. Extends quote polling to pass a
`redirectUrl`, plumbs `RampsController.getWidgetUrl` through
`useRampsQuotes`/`useRampsController`, introduces quote metadata helpers
(`isNativeProvider`, `getQuoteProviderName`, `getQuoteBuyUserAgent`),
and updates Deposit `Root`/`BuildQuote` to preserve and initialize from
an `amount` param; updates affected tests/mocks accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
179c87f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: George Weiler <georgejweiler@gmail.com>
## **Description**

This PR adds analytics for the Perps “pay with any token” flow so we can
measure usage and payment method changes.

## **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: null

## **Related issues**

Jira issue:
https://consensyssoftware.atlassian.net/browse/TAT-2442?atlOrigin=eyJpIjoiZjg3YTQ2NTUyNjQzNDMxMjlkMTU3NzVhYmUxMDljYWYiLCJwIjoiaiJ9

## **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**
No visible change
<!-- [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
- [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]
> **Low Risk**
> Analytics-only changes that add/propagate new tracking fields and
events; primary risk is incorrect or inconsistent metric property values
rather than functional trading behavior.
> 
> **Overview**
> Adds end-to-end MetaMetrics coverage for the Perps “pay with any
token” flow.
> 
> Orders now include `trackingData` fields (`trade_with_token`,
`mm_pay_token_selected`, `mm_pay_network_selected`) from
`PerpsOrderView`, and both `TradingService` and `usePerpsOrderExecution`
attach these fields to `PERPS_TRADE_TRANSACTION` events for
executed/partially-filled/failed outcomes.
> 
> The pay-with UI now tracks a `PERPS_UI_INTERACTION` event when opening
the payment token selector, and
`PerpsController.setSelectedPaymentToken` tracks
`payment_method_changed` with
`initial_payment_method`/`new_payment_method`; event constants/types and
docs are updated accordingly, with tests added/updated to assert the new
tracking behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
23ad545. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
#25430)

…imal precision errors

## **Description**

We got a report of a user trying to unstake and getting the error:

```
View: root
Error: [number] while converting number 130.96926000000002 to token minimal util, too many decimal places 
```

## **Changelog**

CHANGELOG entry: Fixed decimal precision calculation for Tron's staked
balance

## **Related issues**

n/a

## **Manual testing steps**

```gherkin
Feature: Tron TRX Unstaking

  Scenario: User unstakes TRX when staked balance has decimal values
    Given the user has TRX staked across Energy and Bandwidth resources with decimal balances
    And the sum of staked balances would produce floating-point precision artifacts (e.g., 65.48463 + 65.48463 = 130.96926000000002)

    When user taps "Unstake" on the Tron staking screen
    Then the unstake flow proceeds without "too many decimal places" error
    And the staked balance is correctly calculated as 130.96926 TRX
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<img width="1290" height="2796" alt="image"
src="https://github.com/user-attachments/assets/ad83eaeb-9b35-4f8d-9c95-a5e6210ca898"
/>

### **After**

n/a

## **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]
> **Medium Risk**
> Touches TRON staking/earn calculation paths and changes the shape of
`selectTronResourcesBySelectedAccountGroup` from an array to an object,
so any missed call sites could break TRON-specific UI/flows; changes are
localized and backed by expanded tests.
> 
> **Overview**
> Fixes TRON staking precision bugs by switching staked-balance
arithmetic and token minimal-unit conversion to `BigNumber`, preventing
floating-point artifacts (e.g. `130.96926000000002`) from causing “too
many decimal places” errors.
> 
> Refactors `selectTronResourcesBySelectedAccountGroup` to return a
typed `TronResourcesMap` (named fields + precomputed `totalStakedTrx`)
and updates TRON UI consumers (`AssetOverview`, `useTokenBalance`,
`useTronResources`, Earn/TRON preview) to use the mapped fields instead
of scanning arrays. Adds `safeParseBigNumber` and broadens unit tests to
cover empty/invalid inputs, APY absence, and precision/rounding edge
cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a7004cb. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ing (#25396)

## **Description**

Updated the Cursor rules for unit testing guidelines to focus on
**testID-specific guidance** rather than prescribing general mocking
philosophy. This change addresses team feedback about respecting
MetaMask's support for both sociable and solitary unit testing
approaches.

**Key changes:**

1. **Focused on testID usage** - Guidelines now specifically address the
anti-pattern of mocking components just to inject testIDs
2. **Prefer data test IDs** - Added guidance to always use \`testID\`
props for element selection instead of fragile text-based queries
3. **Prefer \`toBeOnTheScreen()\`** - Discourage weak matchers like
\`toBeTruthy()\` and \`toBeDefined()\` for element assertions
4. **Child prop objects** - Document that ALL design system and
component library components support testID via child prop objects
(\`closeButtonProps\`, \`iconProps\`, etc.)
5. **Removed prescriptive mocking guidance** - No longer prescribes
"avoid over-mocking" or "prefer real implementations" to respect
different testing approaches

### Context from Team Discussion

From the Slack thread:
- **Joao**: MetaMask supports both sociable and solitary unit tests -
shouldn't prescribe one over the other
- **Brian**: The specific problem is Cursor mocking components just to
inject testIDs when components already support them
- **Nico**: Guidelines should be specific to testID usage, not general
mocking philosophy

### Research Findings
- **84 test files** currently mock
\`@metamask/design-system-react-native\` unnecessarily
- **3,394 uses** of \`toBeTruthy()\` (many should use
\`toBeOnTheScreen()\`)
- **2,601 uses** of \`toBeDefined()\` (many should use
\`toBeOnTheScreen()\`)

### Example Implementation

See **[PR
#25548](#25548 for a
concrete example of refactoring following these guidelines. That PR
demonstrates:

- Removed **133 lines of unnecessary mocks** from RegionSelectorModal
test
- Used \`closeButtonProps={{ testID: '...' }}\` instead of mocking
BottomSheetHeader
- Kept only justified mocks (external boundaries, imperative handles)
with clear documentation
- All 22 tests passing ✅

**Before (unnecessary mocking):**
\`\`\`tsx
// 30+ lines of mock code to inject a testID
jest.mock('BottomSheetHeader', () => {
  return ({ onClose }) => (
<TouchableOpacity testID="close-button"
onPress={onClose}>Close</TouchableOpacity>
  );
});
\`\`\`

**After (using child prop objects):**
\`\`\`tsx
// Zero mocking needed - use the component's API
<BottomSheetHeader
  onClose={handleClose}
  closeButtonProps={{ testID: 'region-selector-close-button' }}
/>
\`\`\`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Related: #25548 (example test refactoring)

## **Manual testing steps**

\`\`\`gherkin
Feature: Unit Testing Guidelines

  Scenario: Developer writes unit tests following guidelines
    Given the developer is writing a new unit test
    When they reference the unit-testing-guidelines.mdc Cursor rule
    Then they see guidance to use testID props instead of mocking
And they see guidance to use toBeOnTheScreen() instead of toBeTruthy()
And they see guidance to use child prop objects for internal element
testIDs
\`\`\`

## **Screenshots/Recordings**

### **Before**

N/A - Documentation changes only

### **After**

N/A - Documentation changes only

## **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.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only changes to testing guidelines with no runtime code
or behavior changes.
> 
> **Overview**
> Updates `.cursor/rules/unit-testing-guidelines.mdc` to push more
reliable UI testing practices: prefer selecting elements via
`testID`/`getByTestId` (with naming conventions) and prefer
`toBeOnTheScreen()` over weak presence matchers.
> 
> Adds explicit guidance and examples to avoid mocking
`@metamask/design-system-react-native` / `app/component-library`
components solely to inject test IDs, documenting the use of child prop
objects (e.g., `closeButtonProps`, `iconProps`) as the standard way to
target internal elements, and refreshes the reviewer checklist/common
mistakes accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d591bed. 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**
The import token flow is not polished enough, it has a couple of bugs:
- Import token screen has a network picker that is not on top o the
screen
- Import token screen shows chains that are not supported for an account
- Import token checkbox is not working onPress
- Removal of old deprecated code
<!--
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: multiple fixes on import token flow

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2653 &
https://consensyssoftware.atlassian.net/browse/ASSETS-2654 &
https://consensyssoftware.atlassian.net/browse/ASSETS-2655 &
https://consensyssoftware.atlassian.net/browse/ASSETS-2618

## **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**


https://github.com/user-attachments/assets/fb74c776-90f2-4a30-88fd-af84c98710c2



<!-- [screenshots/recordings] -->

### **After**


https://github.com/user-attachments/assets/63ebcd78-2d94-416b-be77-24c878132031


<!-- [screenshots/recordings] -->

## **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**
> Touches core navigation and asset-import UI flows; risk is mainly
regressions in header layout, network selection filtering, and tap
handling across multi-select rows.
> 
> **Overview**
> Improves the `AddAsset` (import token/NFT) screen by moving
safe-area/header rendering into the view (`HeaderCompactStandard` +
insets) and simplifying `MainNavigator`’s `AddAsset` route options.
> 
> Fixes selection UX by preventing the nested checkbox wrapper from
intercepting presses (`pointerEvents="none"`) across multi-select
list/cell usages, and filters the network picker to hide non‑EVM
networks unsupported by the current account scope.
> 
> Hardens token list rendering by providing placeholders when
fiat/secondary balance values are missing or non-finite, updates tests
accordingly, and removes legacy `Collectibles`/`Collectible` screens and
their snapshots/tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0cc4ff3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

SonarQube reported that we have 6 nested functions/layers here.
Decoupled and used curried funcs to reduce nesting to 2
functions/layers.

## **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: refactor: simplify section state management in
TrendingView

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2280

## **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
- [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]
> **Low Risk**
> Pure refactor of local React state update callbacks with no functional
or data-flow changes expected; risk is limited to potential mistakes in
the Set add/remove logic.
> 
> **Overview**
> Refactors `TrendingView.tsx`’s `useSectionStateTracker` by extracting
the per-section `setActiveSections` updater into a shared curried helper
(`curriedSetSectionState`), reducing callback nesting while keeping
behavior the same.
> 
> Each section’s `toggleSection*State` callback is now created by
partially applying `setActiveSections` and the `sectionId`, instead of
inlining the `setState`/`Set` mutation logic inside the `useMemo` loop.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a56f999. 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?
-->

## **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: Remove deeplink interstitial on dApp deeplinks

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/GE-117

## **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]
```
- Open deeplink:
https://metamask.app.link/dapp/https://payments.coinbase.com/sandbox/payment-links/pl_01kh61hxfcenvtctydzcwbrh1p?action=TO_DAPP_BROWSER_FLOW
- You should be directly redirected to the in-app browser tab

## **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**

- [ ] 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**
> Changes deep link security UX by allowing `dapp` links to bypass the
interstitial, which could increase exposure to unsafe links if the
whitelist is too broad or parsing differs from expectations.
> 
> **Overview**
> Removes the interstitial modal for `dapp` universal links by adding
`ACTIONS.DAPP` to the deep link interstitial whitelist in
`handleUniversalLink`.
> 
> Updates `handleUniversalLink` tests to assert `dapp` links no longer
trigger the modal, and shifts existing interstitial/signature/link-type
modal expectations to use `swap` URLs/titles instead.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8fa5273. 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**

Add deeplink capabilities to the asset overview page to allow direct
navigation to asset details via CAIP-19 addresses.

Url: https://link.metamask.io/asset?assetId=CAIP-19

Examples:
```
# PAXG ETH
xcrun simctl openurl booted https://link.metamask.io/asset?assetId=eip155:1/erc20:0x45804880De22913dAFE09f4980848ECE6EcbAf78
adb shell am start -W -a android.intent.action.VIEW -d "https://link.metamask.io/asset?assetId=eip155:1/erc20:0x45804880De22913dAFE09f4980848ECE6EcbAf78" io.metamask

# USDC BASE
xcrun simctl openurl booted https://link.metamask.io/asset?assetId=eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
adb shell am start -W -a android.intent.action.VIEW -d "https://link.metamask.io/asset?assetId=eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" io.metamask

# Native BASE
xcrun simctl openurl booted https://link.metamask.io/asset?assetId=eip155:8453/slip44:60
adb shell am start -W -a android.intent.action.VIEW -d "https://link.metamask.io/asset?assetId=eip155:8453/slip44:60" io.metamask

# PIPPIN Solana
xcrun simctl openurl booted https://link.metamask.io/asset?assetId=solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:Dfh5DzRgSvvCFDoYc2ciTkMrbDfRKybA4SoFbPmApump
adb shell am start -W -a android.intent.action.VIEW -d "https://link.metamask.io/asset?assetId=solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:Dfh5DzRgSvvCFDoYc2ciTkMrbDfRKybA4SoFbPmApump" io.metamask

# Native SOL
xcrun simctl openurl booted https://link.metamask.io/asset?assetId=solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501
adb shell am start -W -a android.intent.action.VIEW -d "https://link.metamask.io/asset?assetId=solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501" io.metamask

# You must make sure that the token you are trying to find is inside our token API
# https://tokens.api.cx.metamask.io/v3/assets?assetIds=eip155:1/erc20:0x45804880De22913dAFE09f4980848ECE6EcbAf78
# https://tokens.api.cx.metamask.io/v3/chains/solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/assets?first=50
```

## **Changelog**

CHANGELOG entry: feat: add asset overview deeplinks

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2208

## **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**

https://www.loom.com/share/6a9070f6df12464fbe309f0797e6917c

https://www.loom.com/share/c638bcd87d0540d7b8b68bcb832fe910

<!-- [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
- [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.

---
<a
href="https://cursor.com/background-agent?bcId=bc-9d82825e-357b-40ad-ab2e-07eb1e042fee"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/agents?id=bc-9d82825e-357b-40ad-ab2e-07eb1e042fee"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new deep link routing and navigation into the wallet’s Asset
screen plus new token-metadata fields (`iconUrl`/`rwaData`), which could
misroute users or show incorrect token details if CAIP parsing/metadata
lookups behave unexpectedly.
> 
> **Overview**
> Adds a new universal-link action `asset` (`ACTIONS.ASSET`) that routes
to `handleAssetUrl`, enabling
`https://link.metamask.io/asset?assetId=<CAIP-19>` to open the Asset
details view.
> 
> `handleAssetUrl` validates the `assetId` as CAIP-19, fetches token
metadata via `fetchAssetMetadata`, derives navigation params for EVM vs
non-EVM and native (`slip44`) vs token assets (including `rwaData`), and
falls back to `Routes.WALLET.HOME` when metadata is missing or errors
occur. Deep link analytics is extended with a new `DeepLinkRoute.ASSET`
and extracts `assetId` into sensitive props, and docs/tests are updated
accordingly.
> 
> Updates `fetchAssetMetadata` to request `includeIconUrl` and
`includeRwaData`, return `rwaData`, and fall back to the API-provided
`iconUrl` when a static icon URL can’t be derived; unit tests are
adjusted for the new query params and returned fields.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f1cdba1. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Feb 12, 2026
@pull pull Bot added the ⤵️ pull label Feb 12, 2026
@pull pull Bot merged commit cec13d8 into Reality2byte:main Feb 12, 2026
3 of 37 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.