Skip to content

[pull] main from MetaMask:main#827

Merged
pull[bot] merged 18 commits into
Reality2byte:mainfrom
MetaMask:main
Jun 11, 2026
Merged

[pull] main from MetaMask:main#827
pull[bot] merged 18 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Jun 11, 2026

Copy link
Copy Markdown

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

michalconsensys and others added 18 commits June 11, 2026 11:55
…s cp-7.81.0 (#31547)

## **Description**

The Perps "Learn the basics" tutorial carousel crashes on Android when
navigating through the screens.

**Root cause:** `ScrollableTabView` renders all child tabs
simultaneously, which means 4–5 `<Rive>` components (one per tutorial
screen with an animation) are all mounted with `autoplay={true}` at the
same time. On Android, the Rive native renderer cannot handle multiple
concurrent GPU-accelerated animation instances and crashes.

**Fix:** Only mount the `<Rive>` component for the currently visible tab
(`currentTab === index`). This ensures a single native Rive renderer
instance exists at any time. When the user swipes or taps Continue, the
previous instance is unmounted and the next one takes its place.

iOS is unaffected because its Metal rendering pipeline handles
concurrent Rive instances more gracefully.

## **Changelog**

CHANGELOG entry: Fixed a crash on Android when navigating through the
Perps tutorial carousel

## **Related issues**

Fixes: #31540

## **Manual testing steps**

```gherkin
Feature: Perps tutorial carousel stability on Android

  Scenario: user completes the full tutorial without crash
    Given the user has not completed the Perps tutorial
    When user taps Perps and goes through "Learn the Basics of Perps"
    Then the app does not crash
    And all tutorial screens display their Rive animations correctly

  Scenario: user re-enters tutorial from Perps home
    Given the user is on the Perps home screen
    When user scrolls down and taps "Learn the Basics of Perps"
    And user taps Continue through all screens
    Then the app does not crash
    And the user reaches the final screen successfully
```

## **Screenshots/Recordings**

N/A — no visual change; this is a crash fix. The tutorial screens render
identically, only one Rive animation is mounted at a time instead of all
simultaneously.

### **Before**

App crashes on Android when navigating through tutorial carousel
screens.

### **After**

Tutorial carousel completes without crash on Android.

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **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**
> Single conditional around Rive mounting in the tutorial carousel;
behavior is unchanged except avoiding concurrent animations on Android.
> 
> **Overview**
> Fixes an **Android crash** in the Perps “Learn the basics” tutorial by
ensuring only one native **Rive** animation is mounted at a time.
> 
> `ScrollableTabView` keeps every tab’s children in the tree, so every
screen with `riveArtboardName` used to mount `<Rive autoplay>` together.
The change adds `index` in the screen map and renders the animation only
when **`currentTab === index`**, so swiping or tapping Continue unmounts
the previous instance before the next one loads. No intended UI change
on iOS.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
17b73bc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…0, MUSD-861) (#30804)

## **Description**

Two small fixes for the Money tab, bundled because MUSD-861 is a pure
padding tweak.

**MUSD-860** — The `Add` button on the MetaMask USD row (Money home) now
skips the `Add funds` bottom sheet and routes directly: if the user has
mUSD balance it goes to MM Pay with mUSD pre-selected as the pay token;
if not, it goes to the Ramps Buy flow with the mUSD asset pre-selected.
The action-row `+` and footer `Add money` entry points still open the
bottom sheet (the multi-route choice is still meaningful there). The
routing logic is consolidated into a new `useMoneyAccountAddRouting`
hook so `MoneyAddMoneySheet` and `MoneyHomeView` share one source of
truth — no more duplicated chain-pick loop.

**MUSD-861** — On the Money `Add money` confirmation screen
(`MoneyAccountDepositInfo`), the `From / Pay with / Transaction fee /
Est. time / Total` rows were pressed against the footer button on
Android (Pixel 8a) and tall iPhones. Added an opt-in `compactSpacing`
prop to the shared `CustomAmountInfo` so only `MoneyAccountDepositInfo`
gets the extra bottom breathing room — Perps, Predict, musd-conversion,
and Withdrawal screens are unchanged.

## **Changelog**

CHANGELOG entry: Fixed the `Add` button on the Money tab to route
directly to the right funding flow based on your mUSD balance, and
adjusted spacing on the Money deposit screen so the rows no longer
overlap the footer button on Android and tall iPhones.

## **Related issues**

Fixes:
[MUSD-860](https://consensyssoftware.atlassian.net/browse/MUSD-860),
[MUSD-861](https://consensyssoftware.atlassian.net/browse/MUSD-861)

## **Manual testing steps**

```gherkin
Feature: MetaMask USD row Add button routing (MUSD-860)

  Scenario: User has mUSD balance
    Given I am on the Money tab
    And my MetaMask USD balance is greater than zero
    When I tap "Add" next to the MetaMask USD row
    Then I am taken to MM Pay with mUSD pre-selected as the pay token

  Scenario: User has no mUSD balance
    Given I am on the Money tab
    And my MetaMask USD balance is zero
    When I tap "Add" next to the MetaMask USD row
    Then I am taken to the Ramps Buy flow with mUSD pre-selected

  Scenario: Action-row and footer Add still open the bottom sheet
    Given I am on the Money tab
    When I tap the central "+" action button or the footer "Add money" button
    Then the Add funds bottom sheet appears with the existing options

Feature: Add money screen padding (MUSD-861)

  Scenario: Rows clear the footer
    Given I tap "Convert crypto" from the Add money bottom sheet
    When the Add money confirmation screen renders
    Then the From / Pay with / Transaction fee / Total rows have a clear gap above the "Add funds" footer button
    And no row overlaps the footer or the home indicator on Android Pixel 8a or tall iPhones
```

## **Screenshots/Recordings**

### **Before**

### **After**



https://github.com/user-attachments/assets/ca08cc77-8bc5-48ba-9fc6-116c78b91d28



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

#### Performance checks (if applicable)

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

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

[MUSD-860]:
https://consensyssoftware.atlassian.net/browse/MUSD-860?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes user navigation for add-money and deposit initiation paths
tied to balance and chain selection; shared confirmation UI padding
affects all CustomAmountInfo screens on Android.
> 
> **Overview**
> **Money home mUSD “Add”** no longer opens the Add funds sheet. It
calls **`useMoneyAccountAddRouting`**, which sends users with mUSD
balance into **`moveMusd`** (deposit with `addMusd` intent and the
highest-balance chain’s mUSD token) and users without balance into
**Ramps Buy** via **`depositFunds`**. Analytics on that button now
record **`redirect_target`** as `MONEY_DEPOSIT` vs **`RAMP_BUY`**
(`SCREEN_NAMES` extended). The hook also exposes **`convertCrypto`** and
is covered by unit tests; other Add entry points on the home screen
still use the bottom sheet.
> 
> **Confirmations `CustomAmountInfo`** drops the
**`hasExtraBottomPadding`** prop and always applies a **`bottomBlock`**
style: **16dp** bottom padding on Android (replacing the previous
**56dp** opt-in used from Perps withdraw). Perps withdraw no longer
passes the extra-padding flag.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3d1671c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Goktug Poyraz <omergoktugpoyraz@gmail.com>
… user has multiple wallets (#31538)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

Display wallet name nest to From/To labels in account picker, if user
has multiple wallets.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1125

## **Manual testing steps**
NA

## **Screenshots/Recordings**
<img width="397" height="847" alt="Screenshot 2026-06-11 at 1 46 41 PM"
src="https://github.com/user-attachments/assets/02e30963-37c5-4ed0-a913-4c94fd88208c"
/>

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [X] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [X] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [X] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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**
> Localized confirmation UI label logic with unit tests; no auth,
signing, or transaction flow changes.
> 
> **Overview**
> **Confirmation account picker** now shows which wallet the selected
account belongs to when the user has **more than one wallet**: the pill
text becomes something like `From Wallet 1` instead of plain `From`, by
resolving the wallet section title from `filteredAccountSections` for
the selected account group. With a single wallet, the label stays
unchanged.
> 
> Tests cover multi-wallet vs single-wallet label behavior.
> 
> The Predict search hook test that asserted **stale markets are
filtered on an empty query** was removed (active-query stale behavior
test remains).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1860ff1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
…components (#31465)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

This PR updates the homepage Predictions World Cup discovery row so the
“events in total” count comes from Polymarket’s lightweight pagination
endpoint instead of the loaded World Cup market list.
The row now uses:

`https://gamma-api.polymarket.com/events/pagination?tag_slug=fifa-world-cup&limit=1&active=true&closed=false&archived=false`
and reads `pagination.totalResults`.
This prevents the UI from showing partial loaded counts like `19+` or
`20+` when the real total is much higher. The `+` suffix is preserved.


## **Changelog**

<!-- mms-check: type=changelog required=true -->

<!--
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: Fixed the World Cup events count shown in the homepage
Predictions discovery row.

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes:

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Homepage Predictions World Cup event count

  Scenario: user views the World Cup discovery row in Predictions
    Given Predict is enabled
    And the homepage Predictions discovery layout is shown

    When the user views the FIFA World Cup 2026 row
    Then the row shows the total event count from the Polymarket pagination API
    And the count keeps the plus suffix
    And the row does not show a partial loaded market count such as "19+" or "20+"
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**
<img width="387" height="335" alt="Screenshot 2026-06-10 at 13 07 25"
src="https://github.com/user-attachments/assets/16df1441-1e94-4bd5-a395-ba56e9aceab6"
/>

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

### **After**
<img width="391" height="337" alt="Screenshot 2026-06-10 at 12 59 32"
src="https://github.com/user-attachments/assets/c163ed17-a4c7-4710-9cb5-f3ca1d2f404b"
/>

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

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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**
> Read-only UI and a lightweight external count API; no auth, payments,
or data writes.
> 
> **Overview**
> Fixes the homepage Predictions **FIFA World Cup 2026** row so “events
in total” reflects Polymarket’s full catalog instead of how many markets
are already loaded.
> 
> A new **`useHomepagePredictWorldCupEventCount`** hook calls Gamma
**`/events/pagination`** with `limit=1` and the remote-configured World
Cup tag, then surfaces **`pagination.totalResults`** via React Query
(with refetch on section pull-to-refresh). **`PredictionsSection`**
loads that count alongside existing World Cup/NBA discovery feeds and
treats event-count fetching as part of discovery loading.
> 
> **`HomepagePredictWorldCupDiscovery`** stops deriving the label from
`marketData.length` / `hasMore` and always formats the API total with
the overflow copy (e.g. `48+ events in total`). **`MensWorldCupRow`**
hides the subtitle until a count is available so partial loaded counts
are not shown while the pagination request is in flight.
> 
> Hook and section tests cover the pagination URL, invalid/missing
totals, disabled queries, and the new UI assertion.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8a68d99. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Bumps `@metamask/perps-controller` from `^8.0.0` to `^8.1.0` (now
published on npm).

`8.1.0` adds human-readable market names and keyword/ranked search
(TAT-2413 / TAT-3338). Searching a market by its **full name** now
resolves to the matching market. Previously `filterMarketsByQuery` only
matched the ticker **symbol**, so searching "bitcoin", "tesla", or
"spacex" returned **"No tokens found"** even though BTC, TSLA, and SPCX
exist.

This PR also adds a `perps-market-list-no-results` testID to the
market-search empty state so the search behaviour can be asserted
directly in e2e/recipes (empty-state present for a no-match query,
absent once results appear) instead of relying on screenshots.

## **Changelog**

CHANGELOG entry: Perps market search now matches full market names and
keywords — e.g. searching "bitcoin" finds BTC (and BCH), "tesla" finds
TSLA, "spacex" finds SPCX.

## **Related issues**

Refs: TAT-2413, TAT-3338

## **Manual testing steps**

```gherkin
Feature: Perps market search by name

  Scenario: user searches a market by its full name
    Given the user is unlocked and on the Perps Markets search screen

    When the user types "bitcoin"
    Then the BTC market (and BCH "Bitcoin Cash") are listed

    When the user clears and types "tesla"
    Then the TSLA market is listed

    When the user clears and types "spacex"
    Then the SPCX market is listed
```

## **Screenshots/Recordings**

Validated end-to-end on iOS (sim `mm-4`) with a recipe using testID
assertions: the `perps-market-list-no-results` empty state is
**present** for a no-match control query and **absent** once a name
query matches.

<table>
<tr><th>Before — <code>perps-controller@8.0.0</code></th><th>After —
<code>perps-controller@8.1.0</code></th></tr>
<tr>
<td><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/059ffb2d33f337b829f7648eef551362ff7f8f9f/fixes/31537/before-bitcoin-8.0.0.png"
width="260"><br/>"bitcoin" → <b>No tokens found</b> (only ticker "BTC"
matched)</td>
<td><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/059ffb2d33f337b829f7648eef551362ff7f8f9f/fixes/31537/after-bitcoin-8.1.0.png"
width="260"><br/>"bitcoin" → <b>BTC</b> + <b>BCH</b> (matched by
name)</td>
</tr>
</table>

The name search also works for stocks and pre-IPO markets:

<table>
<tr><th>"tesla" → TSLA</th><th>"spacex" → SPCX</th></tr>
<tr>
<td><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/059ffb2d33f337b829f7648eef551362ff7f8f9f/fixes/31537/after-tesla-8.1.0.png"
width="260"></td>
<td><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/059ffb2d33f337b829f7648eef551362ff7f8f9f/fixes/31537/after-spacex-8.1.0.png"
width="260"></td>
</tr>
</table>

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

#### Performance checks (if applicable)

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

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Dependency bump with localized UI/testID changes; search behavior
improves without touching auth or payments.
> 
> **Overview**
> **Upgrades `@metamask/perps-controller` to 8.1.0** so Perps market
search can match **full names and keywords**, not just tickers (e.g.
"bitcoin" → BTC/BCH). Displayed market **names** now come from the
controller’s asset name map (tests expect BTC → **Bitcoin**).
> 
> Adds **`perps-market-list-no-results`** on the market list
empty-search UI for e2e assertions, and a **`BACK_BUTTON`** testID alias
alongside existing list selectors. Lockfile also picks up
**`@metamask/controller-utils@12.2.0`** via the perps-controller
dependency.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ad85672. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ve backdrop overlay (#31550)

## **Description**

QuickBuy's bottom sheet previously used the full `BottomSheet` wrapper
from `@metamask/design-system-react-native`, which includes a
`BottomSheetOverlay` (dark backdrop) that was obscuring the asset
details chart underneath. This change swaps the wrapper for
`BottomSheetDialog` directly — the lower-level component that the Design
System team recommends for this use case.

`BottomSheetDialog` provides all the core sheet behaviour (slide-in/out
animation, swipe-to-dismiss gesture, drag handle, keyboard avoidance)
without rendering any backdrop overlay. The imperative ref API is
updated from `onOpenBottomSheet`/`onCloseBottomSheet` to
`onOpenDialog`/`onCloseDialog` accordingly.

The asset details chart now remains fully visible underneath the open
sheet.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: QuickBuy sheet without backdrop

  Scenario: User opens QuickBuy from the asset detail view
    Given the user is on the Asset detail view
      And the asset details chart is visible

    When the user taps the QuickBuy CTA
    Then the QuickBuy bottom sheet slides up without a dark overlay
      And the asset chart underneath remains visible

    When the user swipes the sheet down
    Then the sheet dismisses normally
```

## **Screenshots/Recordings**

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

### **Before**
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-06-11
at 10 55 20"
src="https://github.com/user-attachments/assets/ebd99ff5-b845-493a-99a0-424ea6a3511d"
/>

<!-- [screenshot showing dark backdrop over the chart] -->

### **After**

<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-06-11
at 10 51 43"
src="https://github.com/user-attachments/assets/898e87e6-3fdf-41b3-b03f-27f68093febc"
/>

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

## **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 wrapper swap in a single feature with equivalent sheet behavior;
tests updated and no auth, payment, or data-path changes.
> 
> **Overview**
> **QuickBuy** now uses **`BottomSheetDialog`** from the design system
instead of **`BottomSheet`**, so the sheet no longer renders the dark
**`BottomSheetOverlay`** backdrop and the asset chart stays visible
under the open sheet.
> 
> The imperative ref API is aligned with the dialog component:
**`onOpenDialog`** / **`onCloseDialog`** replace **`onOpenBottomSheet`**
/ **`onCloseBottomSheet`** for deferred content readiness and animated
dismiss. **`QuickBuyRoot.test.tsx`** and **`QuickBuySheet.test.tsx`**
mocks and assertions were updated to match.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7d1759a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

useComplianceGate had a race condition where switching wallets could
cause the previous wallet's compliance result to be applied to the new
one. Between a wallet switch and the useEffect firing, gate() would read
stale refs and either block a clean wallet or allow a blocked one
through.

The fix tags each prefetch with its address so gate can verify it
belongs to the current wallet before trusting it. A latest-value ref
(currentAddressKeyRef) is updated during render — before the effect
fires — letting gate detect a mid-flight wallet switch and abandon
silently rather than applying a stale result. A request ID counter
prevents slow in-flight checks from overwriting the result for a newer
address.

Three new tests cover the race scenarios: stale prefetch from a previous
address, silent abandon on mid-flight wallet switch, and correct
blocking for the newly-selected address.

## **Changelog**

<!-- mms-check: type=changelog required=true -->

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

<!-- mms-check: type=issue-link required=true -->

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

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Compliance gate respects wallet switch during pending check
    Scenario: user switches wallet while a compliance check is in progress
      Given the user has a blocked wallet and a clean wallet
      And the user is on the Perps screen with the blocked wallet selected
      And a compliance check is in flight

      When the user switches to the clean wallet
      And taps a Perps action before the check resolves

      Then the action is not blocked
      And the Access Restricted modal is not shown
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

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

### **After**

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



https://github.com/user-attachments/assets/ba4f234a-3c02-4224-bc70-3d9f39e4b73b



https://github.com/user-attachments/assets/aa72fb6c-f910-4943-bf0d-79334a816041



## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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 compliance gating for Perps and similar flows; incorrect logic
could wrongly block or allow actions, though behavior is heavily tested
and fail-open on errors is preserved.
> 
> **Overview**
> Fixes a **wallet-switch race** in `useComplianceGate` so OFAC prefetch
results from the previous account are not applied after the user changes
wallets.
> 
> **`useComplianceGate`** now tags each prefetch with its `addressKey`,
uses a **request ID** so late responses cannot overwrite the current
wallet’s blocked state, and updates **`currentAddressKeyRef` during
render** so `gate()` can detect a mid-flight switch and **abandon
silently** (no modal, action not run). If there is no matching prefetch
yet after a switch, `gate()` runs a one-off check via
`checkComplianceRef`. Empty/missing addresses are handled explicitly
(`filter(Boolean)` on split addresses; no prefetch when compliance is
disabled).
> 
> **Tests** add coverage for no-address behavior and three wallet-switch
scenarios (stale prefetch, abandon on switch, block on new blocked
address).
> 
> **Mock** `@metamask/compliance-controller` gets typed
`ComplianceService` options and **non-EVM address lookup** aligned with
the real package (no case-insensitive fallback for non-EVM).
> 
> **`compliance-service-init.test.ts`** restores `COMPLIANCE_API_URL` in
**`afterEach`** instead of `afterAll` so env isolation is per test.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3e4e39e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Nick Gambino <nicholas.gambino@consensys.net>
#31454)

## **Description**

<!-- mms-check: type=text required=true -->

The shared icon asset
`app/component-library/components/Icons/Icon/assets/error.svg` hardcodes
`fill="#121314"` on its path, which overrides the `currentColor`
mechanism the `Icon` component relies on. As a result `IconName.Error`
always rendered near-black at every call site (~24 across the app),
regardless of the color passed.

This PR removes the hardcoded fill (and the non-standard root
`fill`/`width`/`height` attributes) so `error.svg` matches the structure
of the other 283 icon assets and inherits the color passed to `Icon`.
Among all icon assets only `error.svg` and `hash-tag.svg` had hardcoded
hex fills; `hash-tag.svg` is left untouched as out of scope.

Jira: [TSA-662](https://consensyssoftware.atlassian.net/browse/TSA-662)

## **Changelog**

<!-- mms-check: type=changelog required=true -->

CHANGELOG entry: Fixed error icons rendering black instead of the error
color (e.g. in the Quick Buy failure toast)

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: [TSA-662](https://consensyssoftware.atlassian.net/browse/TSA-662)

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Error icon color

  Scenario: user sees a Quick Buy failure toast
    Given the user is on a token details page
    And a Quick Buy trade is going to fail terminally

    When the "Couldn't buy/sell" toast appears
    Then the leading error icon is tinted red (theme error color), matching the green icon of the success toast
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

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

<!-- Generated with the help of the pr-description AI skill -->


[TSA-662]:
https://consensyssoftware.atlassian.net/browse/TSA-662?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Single SVG asset change with no logic or API changes; only visual
tinting for an icon that was incorrectly fixed to black.
> 
> **Overview**
> **`error.svg`** no longer hardcodes `fill="#121314"` on its path or
redundant root `fill`/`width`/`height`, so it follows the same pattern
as the other icon assets and picks up **`Icon`**’s `currentColor`
styling.
> 
> **`IconName.Error`** call sites that pass theme error colors (e.g.
Quick Buy failure toasts, bridge banners) should now show red/error
tinting instead of always rendering near-black.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
be67024. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ltered market list (#30738)

## **Description**

Add a magnifying glass icon to the market detail screen header. Tapping
it navigates to the Market List pre-filtered to the category of the
market being viewed (e.g. BTC → Crypto tab, TSLA → Stocks tab).

Category mapping uses the market's `marketType` field: `equity` →
stocks, `commodity` → commodities, `forex` → forex, default → crypto,
`isNewMarket` → all.

Tracks `PERPS_UI_INTERACTION` with `button_clicked: magnifying_glass` on
tap, and Market List receives `source: magnifying_glass` for
`PERPS_SCREEN_VIEWED` attribution.

## **Changelog**

CHANGELOG entry: Added category-aware search shortcut to market detail
page

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Market detail category search shortcut

  Scenario: user taps magnifying glass on crypto market
    Given user is on the BTC market detail page

    When user taps the magnifying glass icon in the header
    Then the Market List opens with the Crypto tab pre-selected

  Scenario: user taps magnifying glass on equity market
    Given user is on the TSLA market detail page

    When user taps the magnifying glass icon in the header
    Then the Market List opens with the Stocks tab pre-selected

  Scenario: user navigates back from Market List
    Given user arrived on the Market List via the magnifying glass

    When user taps the back button
    Then user returns to the originating market detail page

  Scenario: new market defaults to All tab
    Given user is viewing a market with isNewMarket=true and no marketType

    When user taps the magnifying glass icon
    Then the Market List opens with the All tab selected
```

## **Screenshots/Recordings**

<table>
<tr><td align="center" width="50%"><strong>Recipe Manual/ac1 Btc Detail
Search Icon</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30738/recipe-manual/ac1-btc-detail-search-icon.png?sha=fd6ba732f091dab6"
alt="Recipe Manual/ac1 Btc Detail Search Icon" width="400" /></td><td
align="center" width="50%"><strong>Recipe Manual/ac2 Market List From
Shortcut</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30738/recipe-manual/ac2-market-list-from-shortcut.png?sha=6e052a30c5ac05df"
alt="Recipe Manual/ac2 Market List From Shortcut" width="400"
/></td></tr>
<tr><td align="center" width="50%"><strong>Recipe Manual/clean 1 Btc
Detail</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30738/recipe-manual/clean-1-btc-detail.png?sha=85b4edc4666f20be"
alt="Recipe Manual/clean 1 Btc Detail" width="400" /><br/><sub>caption
confidence: LOW — generic filename — no state-specific
suffix</sub></td><td align="center" width="50%"><strong>Recipe
Manual/clean 2 Market List</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30738/recipe-manual/clean-2-market-list.png?sha=44ef2c287fcbdb03"
alt="Recipe Manual/clean 2 Market List" width="400" /><br/><sub>caption
confidence: LOW — generic filename — no state-specific
suffix</sub></td></tr>
<tr><td align="center" width="50%"><strong>Recipe Manual/clean 3 Back To
Detail</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30738/recipe-manual/clean-3-back-to-detail.png?sha=5ccac78601608b27"
alt="Recipe Manual/clean 3 Back To Detail" width="400"
/><br/><sub>caption confidence: LOW — generic filename — no
state-specific suffix</sub></td><td></td></tr>
</table>

## **Validation Recipe**
<details><summary>recipe.json (11 steps — navigate to BTC detail, verify
search icon, tap, verify Market List with crypto tab, back
navigation)</summary>

```json
{
  "title": "TAT-3168: Market detail category search shortcut",
  "description": "Verifies magnifying glass icon on market detail navigates to Market List with correct category pre-selected",
  "validate": {
    "workflow": {
      "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"],
      "entry": "nav-to-market-detail",
      "nodes": {
        "nav-to-market-detail": {
          "action": "navigate",
          "target": "PerpsMarketDetails",
          "params": {
            "market": {
              "symbol": "BTC",
              "name": "BTC",
              "price": "0",
              "change24h": "0",
              "change24hPercent": "0",
              "volume": "0",
              "maxLeverage": 100
            }
          },
          "next": "wait-detail-loaded"
        },
        "wait-detail-loaded": {
          "action": "wait_for",
          "test_id": "perps-market-details-view",
          "timeout_ms": 10000,
          "next": "ac1-wait-search-icon"
        },
        "ac1-wait-search-icon": {
          "action": "wait_for",
          "test_id": "perps-market-header-category-search-button",
          "visibility": "viewport",
          "timeout_ms": 10000,
          "poll_ms": 500,
          "next": "ac1-screenshot"
        },
        "ac1-screenshot": {
          "action": "screenshot",
          "filename": "after-ac1-search-icon-visible.png",
          "note": "AC1: Magnifying glass icon visible in market detail header alongside expand and star icons",
          "claims": {
            "must_show": [{ "test_id": "perps-market-header-category-search-button", "visibility": "viewport" }],
            "must_not_show": [{ "text_contains": "Fund your wallet" }]
          },
          "next": "ac2-press-search-icon"
        },
        "ac2-press-search-icon": {
          "action": "press",
          "test_id": "perps-market-header-category-search-button",
          "next": "ac2-wait-market-list"
        },
        "ac2-wait-market-list": {
          "action": "wait_for",
          "test_id": "perps-market-list",
          "timeout_ms": 10000,
          "next": "ac2-verify-crypto-tab"
        },
        "ac2-verify-crypto-tab": {
          "action": "eval_sync",
          "expression": "(function(){ var route = globalThis.__AGENTIC__.getRoute(); return JSON.stringify({ onMarketList: route.name === 'PerpsTrendingView', params: route.params }); })()",
          "assert": {
            "operator": "eq",
            "field": "onMarketList",
            "value": true
          },
          "next": "ac2-screenshot"
        },
        "ac2-screenshot": {
          "action": "screenshot",
          "filename": "after-ac2-market-list-crypto-tab.png",
          "note": "AC2: Market List opened with Crypto tab pre-selected after tapping search on BTC detail",
          "claims": {
            "must_show": [{ "test_id": "perps-market-list", "visibility": "viewport" }]
          },
          "next": "ac4-press-back"
        },
        "ac4-press-back": {
          "action": "press",
          "test_id": "perps-market-header-back-button",
          "next": "ac4-wait-return"
        },
        "ac4-wait-return": {
          "action": "wait_for",
          "test_id": "perps-market-details-view",
          "timeout_ms": 10000,
          "next": "ac4-verify-return"
        },
        "ac4-verify-return": {
          "action": "eval_sync",
          "expression": "(function(){ var route = globalThis.__AGENTIC__.getRoute(); return JSON.stringify({ name: route.name, isMarketDetail: route.name === 'PerpsMarketDetails' }); })()",
          "assert": {
            "operator": "eq",
            "field": "isMarketDetail",
            "value": true
          },
          "next": "done"
        },
        "done": {
          "action": "end",
          "status": "pass"
        }
      }
    }
  }
}
```
</details>

## **Validation Logs**
Command:
```bash

```

<details><summary>Full output (11/11 passed)</summary>

```
Running recipe: TAT-3168: Market detail category search shortcut
Pre-conditions: wallet.unlocked, perps.feature_enabled
Workflow nodes: 12

Pre-conditions: PASS

[nav-to-market-detail] navigate to PerpsMarketDetails — PASS
[wait-detail-loaded] wait for perps-market-details-view — PASS
[ac1-wait-search-icon] wait for perps-market-header-category-search-button — PASS
[ac1-screenshot] AC1: Magnifying glass icon visible — PASS
[ac2-press-search-icon] press perps-market-header-category-search-button — PASS
[ac2-wait-market-list] wait for perps-market-list — PASS
[ac2-verify-crypto-tab] eval_sync: onMarketList=true, defaultMarketTypeFilter="crypto" — PASS
[ac2-screenshot] AC2: Market List with Crypto tab — PASS
[ac4-press-back] press perps-market-header-back-button — PASS
[ac4-wait-return] wait for perps-market-details-view — PASS
[ac4-verify-return] eval_sync: route=PerpsMarketDetails — PASS

Results: 11/11 passed
Recipe: PASS
```
</details>

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **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 Perps UI/navigation change with existing hooks and controller
helpers; no auth or payment logic touched.
> 
> **Overview**
> Adds a **search (magnifying glass) control** to the perps market
detail header so users can jump to the market list with the tab that
matches the current asset.
> 
> Tapping it resolves the category via `getMarketTypeFilter(market)`,
fires `PERPS_UI_INTERACTION` (`magnifying_glass` on market details), and
calls `navigateToMarketList` with `source: magnifying_glass` and
`defaultMarketTypeFilter` set to that category. A new header test ID,
accessibility string (`perps.market_details.category_search`), and a
unit test assert the navigation params.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b608cbf. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

Bumps `@metamask/money-account-upgrade-controller` to `2.0.5`

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes:

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```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]
```

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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**
> Money account upgrade flows depend on delegation, keyring, and
authenticated user storage; behavior may change via the upgraded
controller and its transitive packages despite no local code edits.
> 
> **Overview**
> Bumps **`@metamask/money-account-upgrade-controller`** from `^2.0.0`
to **`^2.0.5`** in `package.json` and refreshes **`yarn.lock`**
accordingly. There are **no application source changes** in this PR.
> 
> The resolved **`2.0.5`** tree pulls newer transitive versions than the
previous lock, including **`@metamask/authenticated-user-storage`**
`^2.0.0` (replacing `1.0.1`), **`@metamask/delegation-controller`**
`3.0.2`, **`@metamask/delegation-core`** `2.2.1`,
**`@metamask/delegation-deployments`** `1.4.0`,
**`@metamask/keyring-controller`** `^27.0.0`, and **`@metamask/utils`**
`^11.11.0` for that controller’s dependency graph.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
450052c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…31444)

## **Description**

The Perps home screen silently hid open positions and open orders beyond
the 10th. `usePerpsHomeData` sliced both lists to a hardcoded limit of
10, while `PerpsHomeView` renders them in a vertical `ScrollView` with
no carousel and no "see all" page — so a wallet with 11+ open
positions/orders could never reach the rest.

This change makes the home screen show **every** open position and
order: the cap is no longer applied by default.
`positionsLimit`/`ordersLimit` become optional opt-in parameters (slice
only when an explicit finite limit is passed), and the orphaned
`PositionsCarouselLimit`/`OrdersCarouselLimit` constants are removed.

## **Changelog**

CHANGELOG entry: Fixed the Perps home screen hiding open positions and
orders beyond the 10th — all open positions and orders are now shown.

## **Related issues**

Fixes:
[TAT-3294](https://consensyssoftware.atlassian.net/browse/TAT-3294)

## **Manual testing steps**

```gherkin
Feature: Perps home shows all open positions and orders

  Scenario: user with more than ten open positions/orders
    Given a wallet with 11 or more open perps positions and 11 or more open orders

    When the user opens the Perps home screen
    Then every open position is listed with no cut-off at 10
    And every open order is listed in the Orders section with no cut-off at 10
    And scrolling reaches the last entry with none hidden
```

## **Screenshots/Recordings**

| Perps home top | 11th position visible after scroll |
| --- | --- |
| ![Perps home
top](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/31444/screenshots/live-proof-home-top.png?sha=cd6a2b8053b86e3d)
| ![11th position
visible](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/31444/screenshots/live-11th-card.png?sha=ad181f2871dd0352)
|

| Scroll proof top | After proof: 11th card present |
| --- | --- |
| ![Scroll proof
top](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/31444/screenshots/proof-scroll-home-top.png?sha=fca21470c2d64490)
| ![After proof 11th card
present](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/31444/screenshots/after-11th-card-present.png?sha=ae84f2d0c64fe1b2)
|

- **Live Proof recording**:
[live-proof.mp4](https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/31444/video/live-proof.mp4?sha=ee31c1166cf8a323)

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

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

## **Validation Recipe**

Live, replayable end-to-end recipe (`artifacts/live-proof.json`) that
drives the real app on iOS: opens 11 real testnet positions, navigates
to the Perps home, scrolls the list, asserts the 11th card renders
(`perps-home-position-card-10` — the one the old cap hid), screenshots
top + tail, then closes all positions to restore the wallet. The
recording above is this recipe running.

<details>
<summary>live-proof.json (the 11 <code>setup-open-*</code> seed nodes
are collapsed for brevity — full file in artifacts)</summary>

```json
{
  "schema_version": 1,
  "title": "TAT-3294 live proof — Perps home shows all 11 open positions",
  "validate": {
    "workflow": {
      "entry": "gate-status",
      "nodes": {
        "gate-status":  { "action": "app.status", "next": "gate-unlock" },
        "gate-unlock":  { "action": "metamask.wallet.ensure_unlocked", "next": "setup-clean" },
        "setup-clean":  { "action": "metamask.perps.close_positions", "mode": "all", "next": "setup-open-BTC" },

        "setup-open-BTC": { "action": "metamask.perps.place_order", "market": "BTC", "side": "long", "amount": "10", "leverage": 10, "next": "setup-open-SOL" },
        "// ...":         "setup-open-{SOL,AVAX,BNB,LTC,ARB,DOGE,SUI,LINK,XRP} — same shape",
        "setup-open-ADA": { "action": "metamask.perps.place_order", "market": "ADA", "side": "long", "amount": "10", "leverage": 5, "next": "ac1-nav-home" },

        "ac1-nav-home":  { "action": "ui.navigate", "route": "PerpsMarketListView", "next": "ac1-wait-first" },
        "ac1-wait-first":{ "action": "ui.wait_for", "test_id": "perps-home-position-card-0", "timeout_ms": 15000, "next": "ac1-shot-top" },

        "ac1-scroll1":   { "action": "ui.scroll", "test_id": "scroll-content", "delta_y": 450, "animated": true, "next": "ac1-scroll2" },
        "ac1-scroll2":   { "action": "ui.scroll", "test_id": "scroll-content", "delta_y": 850, "animated": true, "next": "ac1-wait-11th" },
        "ac1-wait-11th": { "action": "ui.wait_for", "test_id": "perps-home-position-card-10", "timeout_ms": 15000, "intent": "PROOF: 11th card renders — the old slice(0,10) cap hid it", "next": "ac1-shot-tail" },

        "teardown-close":  { "action": "metamask.perps.close_positions", "mode": "all", "next": "teardown-verify" },
        "teardown-verify": { "action": "metamask.perps.read_positions", "mode": "all", "next": "done" },
        "done": { "action": "end", "status": "pass" }
      }
    }
  }
}
```

</details>

**Unit tests** (not a recipe — they live in the suite):
`usePerpsHomeData.test.ts` covers the hook at the layer of the cap —
"displays every open position/order when more than ten are open" feeds
12 → returns 12, and fails if the `slice` removal is reverted.

## **Recipe Workflow**

<details>
<summary>workflow.mmd</summary>

```mermaid
flowchart TD
  gate-status --> gate-unlock --> setup-clean
  setup-clean -->|"11x place_order: BTC…ADA"| ac1-nav-home
  ac1-nav-home --> ac1-wait-first --> ac1-shot-top --> ac1-scroll1 --> ac1-scroll2
  ac1-scroll2 --> ac1-wait-11th["ac1-wait-11th<br/>wait_for card-10 (PROOF)"]
  ac1-wait-11th --> ac1-shot-tail --> teardown-close --> teardown-verify --> done
  done["done<br/>end: pass"]
```

</details>


[TAT-3294]:
https://consensyssoftware.atlassian.net/browse/TAT-3294?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Display-only change on Perps home with optional limits preserved for
other callers; main risk is slightly longer scroll lists for power
users, not trading or auth logic.
> 
> **Overview**
> Fixes a bug where **Perps home** only showed the first 10 open
positions and orders because `usePerpsHomeData` applied a default
`slice(0, 10)` even though the screen lists everything in a vertical
scroll with no “see all” flow.
> 
> **Data behavior:** `positionsLimit` and `ordersLimit` no longer
default to 10; when omitted, the hook returns the full filtered lists.
Explicit numeric limits still slice for callers that need them.
`PositionsCarouselLimit` / `OrdersCarouselLimit` are removed from
`HOME_SCREEN_CONFIG` and documented as intentionally uncapped on home;
recent activity still uses `RecentActivityLimit`.
> 
> **UI / testing:** `PerpsHomeView` wires `testID`s on the main scroll
view and on each position/order card
(`perps-home-position-card-{index}`, `perps-home-order-card-{index}`) to
support scroll-and-assert E2E (e.g. proving the 11th card). Unit tests
in `usePerpsHomeData.test.ts` assert uncapped behavior for 12+ items and
keep opt-in limit coverage.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
76c72be. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…QA-1931) (#31543)

## **Description**

Adds a `run-performance` PR label so QA can force the performance E2E
workflow on demand, following the same pattern as `skip-e2e` and
`force-builds`.

When the label is present on an internal PR, `get-requirements.yml` sets
`run_performance=true`, CI re-runs via
`rerun-ci-on-skipped-e2e-labels.yml`, and the `Run Performance Tests
(PR)` job executes all performance tests on Android low-profile devices
— even when Smart E2E Selection would skip them (e.g. no
performance-relevant changes, `skip-e2e`, or `pr-not-ready-for-e2e`).
Without the label, the existing Smart E2E Selection behavior is
unchanged.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

Refs: MMQA-1931

## **Manual testing steps**

```gherkin
Feature: run-performance PR label

  Scenario: force performance tests on a PR without AI-selected tags
    Given an open internal PR where Smart E2E Selection returns no performance tags
    When the run-performance label is added to the PR
    Then CI is re-triggered and the Run Performance Tests (PR) job executes

  Scenario: default behavior without the label
    Given an open internal PR without the run-performance label
    When CI runs after a push
    Then performance tests only run when Smart E2E Selection selects performance tags
```

## **Screenshots/Recordings**

N/A — CI workflow change only; validation is via GitHub Actions job
execution.

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

## **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 limited to GitHub Actions workflow gating and
documentation; no app runtime or security-sensitive code paths are
modified.
> 
> **Overview**
> Adds a **`run-performance-tests`** PR label so QA can **force the PR
performance E2E workflow** to run the **full Android low-profile
performance suite**, even when Smart E2E Selection would skip perf tests
(e.g. `ai_performance_test_tags == '[]'`, `skip-e2e`, or
`pr-not-ready-for-e2e`).
> 
> **`get-requirements.yml`** detects the label on internal (non-fork)
PRs and exposes **`run_performance`**. **`ci.yml`** updates **`Run
Performance Tests (PR)`** to run when `run_performance` is true **or**
when Smart E2E Selection returns non-empty perf tags; a forced run
passes **blank `performance_tags`** (run all) and a fixed reasoning
string. **`rerun-ci-on-skipped-e2e-labels.yml`** re-triggers CI when the
label is added or removed. **`LABELING_GUIDELINES.md`** documents the
label and fork limitation.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0c47b4e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…"Link card" for cardholder users (#31520)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

When a user already holds a MetaMask card (i.e. `isCardholder === true`)
but has not yet authenticated or linked it to their Money account, the
Money onboarding stepper was incorrectly showing the "Get card" flow
(title and CTA) instead of the "Link card" flow. This happened because
the step-2 branch condition only checked `isCardAuthenticated &&
!isCardLinkedToMoneyAccount`, which evaluates to `false` for
unauthenticated cardholders — even though they should be prompted to
link, not to get a new card.

The fix introduces a single derived boolean `shouldShowLinkCardAction`
that combines both conditions:
- `isCardholder` — the user already owns a card (regardless of
authentication state), **or**
- `isCardAuthenticated && !isCardLinkedToMoneyAccount` — the user is
authenticated but the card is not linked yet.

Both the step-2 content (title, description, CTAs) and the analytics
`handleCardCtaPress` callback now branch on `shouldShowLinkCardAction`,
ensuring cardholder users are always directed to the correct "Link card"
flow.

## **Changelog**

<!-- mms-check: type=changelog required=true -->

<!--
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: Fixed a bug where the Money onboarding stepper showed
"Get card" instead of "Link card" for users who already hold a MetaMask
card

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: null

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Money onboarding stepper — cardholder sees "Link card" on step 2

  Scenario: Cardholder who has not authenticated their card
    Given the user has a MetaMask card (isCardholder = true)
    And the user has NOT yet authenticated their card (isCardAuthenticated = false)
    And the Money onboarding stepper is visible on step 2

    When the user reaches step 2 of the Money onboarding stepper
    Then the step 2 title reads "Link your card account" (unlinked_card_account.title)
    And the primary CTA reads "Link card" (unlinked_card_account.cta_primary)
    And pressing the CTA initiates the card link flow

  Scenario: Authenticated cardholder with card not linked to Money account
    Given the user has a MetaMask card (isCardholder = true)
    And the user has authenticated their card (isCardAuthenticated = true)
    And the card is NOT linked to the Money account (isCardLinkedToMoneyAccount = false)

    When the user reaches step 2 of the Money onboarding stepper
    Then the step 2 title reads "Link your card account"
    And the primary CTA reads "Link card"

  Scenario: Non-cardholder user on step 2
    Given the user does NOT have a MetaMask card (isCardholder = false)
    And isCardAuthenticated = false

    When the user reaches step 2 of the Money onboarding stepper
    Then the step 2 title reads "Get a card" (no_card_account.title)
    And the primary CTA reads "Get card" (no_card_account.cta_primary)
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

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

<!-- Generated with the help of the pr-description AI skill -->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Scoped UI and analytics branching in Money onboarding with unit test
coverage; no auth or payment logic changes.
> 
> **Overview**
> Fixes Money onboarding **step 2** so users who already hold a MetaMask
card see the **Link card** experience instead of **Get card** when they
are not authenticated or not linked yet.
> 
> The component now branches on **`shouldShowLinkCardAction`**
(`isCardholder` **or** authenticated with an unlinked card) for step-2
copy/CTAs and for onboarding analytics (`LINK_CARD` vs `GET_CARD`).
Tests mock **`selectIsCardholder`**, expect **`card_state:
'non_cardholder'`** where appropriate, and add coverage for cardholders
who are not authenticated.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d3f6862. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

Users can see generic transaction notifications while the swap screen or
post-trade bottom sheet is already presenting the transaction state.
Those notifications compete with the post-trade modal experience and can
make the flow feel noisy.

This change adds a post-trade notification suppression helper that
registers a notification skip predicate, tracks visible post-trade
surfaces, and suppresses tracked in-flight transaction notifications
while the relevant UI is visible. `BridgeView` and
`PostTradeBottomSheet` now increment/decrement the visible surface
count, and the confirm flow wraps `submitBridgeTx` with suppression when
the post-trade modal A/B treatment is enabled.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

CHANGELOG entry: Fixed duplicate Bridge transaction notifications while
post-trade screens are visible.

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Refs: N/A

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Bridge post-trade notification suppression

  Scenario: user submits a Bridge transaction with the post-trade modal treatment enabled
    Given the Bridge post-trade modal treatment is enabled
    And the user is on the Bridge screen with a valid quote

    When user submits the Bridge transaction
    Then the post-trade bottom sheet opens
    And the app does not show a competing generic transaction notification for the submitted Bridge transaction

  Scenario: user leaves Bridge post-trade UI
    Given the user submitted a Bridge transaction
    And the Bridge post-trade bottom sheet is visible

    When user dismisses the post-trade bottom sheet or navigates away from Bridge
    Then post-trade notification suppression is released for future non-Bridge surfaces
```

Additional validation:

- `yarn jest
app/components/UI/Bridge/hooks/useBridgeConfirm/useBridgeConfirm.test.ts
app/components/UI/Bridge/components/PostTradeBottomSheet/PostTradeBottomSheet.test.ts
--collectCoverage=false`
- `yarn prettier --check
app/components/UI/Bridge/utils/postTradeNotifications.ts
app/components/UI/Bridge/components/PostTradeBottomSheet/index.tsx
app/components/UI/Bridge/hooks/useBridgeConfirm/index.ts
app/components/UI/Bridge/Views/BridgeView/index.tsx`
- `git diff --check`

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

### **Before**

N/A - notification timing/state-management change; no screenshots or
recordings captured in this thread.

### **After**

N/A - notification timing/state-management change; no screenshots or
recordings captured in this thread.

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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**
> Hooks into global notification skip predicates for submitted
transactions; mis-scoping could hide legitimate toasts, though
suppression is gated on visible post-trade surfaces and tracked
bridge/batch txs.
> 
> **Overview**
> Adds **`postTradeNotifications`** helpers that register a global
notification skip predicate and only suppress generic transaction toasts
while Bridge post-trade UI is visible.
> 
> **BridgeView** and **PostTradeBottomSheet** increment/decrement a
ref-counted “visible surface” on focus/mount cleanup. When the
post-trade modal A/B variant is on, **`useBridgeConfirm`** wraps
**`submitBridgeTx`** in **`withPostTradeNotificationSuppression`**,
which tracks submitted tx ids and temporarily skips notifications for
in-flight bridge/batch txs until surfaces are dismissed. Unit tests
cover registration, ref-counting, and failure cleanup.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6a16760. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

- Bump of `@metamask/assets-controllers` dependency from `^108.4.0` to
`^109.0.0` after new [core
release](MetaMask/core#9078)
- Removed `TransactionController:incomingTransactionsReceived` from
`TokenBalancesController` since described as breaking change in the
[`@metamask/assets-controllers`
CHANGELOG](https://github.com/MetaMask/core/pull/9078/changes#diff-2f986b0c95bbc85106e03a1488e264023e3c500a078db85033a92e7b4da66f2fR10)

## **Changelog**

<!-- mms-check: type=changelog required=true -->

<!--
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: Bump `@metamask/assets-controllers` from 108.4.0 to
109.0.0

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: add support for assets detection on Arc network

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

1. Import SRP
2. Import private key funds account with Arc funds
3. Click on tokens
4. Add Arc network
5. Go to homepage tokens, verify the USDC on Arc network is displayed
6. Send USDC from imported account to account (with no funds)
7. Verify send transaction is confirmed
8. Go to other Account and verify the sent funds are listed on Tokens
page

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

N/A

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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**
> Token balance refresh timing after incoming transfers may differ
because TokenBalancesController no longer reacts to
incomingTransactionsReceived; verify Arc/USDC detection and post-receive
balances in manual testing.
> 
> **Overview**
> Upgrades **`@metamask/assets-controllers`** from **108.4.0** to
**109.0.0** (lockfile included) to pick up the latest core release,
including **Arc network** asset detection support referenced in the
ticket.
> 
> Aligns with a **breaking change** in v109:
**`TokenBalancesController`** no longer subscribes to
**`TransactionController:incomingTransactionsReceived`**, so that event
is removed from the token-balances controller messenger allowlist in
**`token-balances-controller-messenger.ts`**. Incoming-tx notifications
elsewhere (e.g. **`Engine`** → **`NotificationManager`**) are unchanged
in this diff.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
915a6e7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… Sentry (#31553)

## **Description**

Currently the performance E2E pipeline sends timer step durations (e.g.
login time, swap time) to Sentry after each test via
`publishPerformanceScenarioToSentry`. However, the BrowserStack App
Profiling v2 data — which includes UI rendering (slow/frozen frames,
ANRs), CPU, and memory — is fetched after all tests complete in
`PerformanceReporter.onEnd()` but never forwarded to Sentry.

This PR closes that gap by:

1. Extending `publishPerformanceScenarioToSentry` to accept an optional
`profilingSummary` and emit the following typed Sentry measurements when
present:
- `profiling_slow_frames_pct` (percent) — % of slow frames (<60 fps
equivalent)
- `profiling_frozen_frames_pct` (percent) — % of frozen frames (>700 ms)
   - `profiling_anrs` (none) — ANR count
   - `profiling_cpu_avg_pct` / `profiling_cpu_max_pct` (percent)
   - `profiling_memory_avg_mb` / `profiling_memory_max_mb` (megabyte)
2. Adding `publishProfilingDataToSentry` in `PerformanceReporter` that
is called after session enrichment (`mergeSessionDataIntoMetrics`) and
sends a Sentry transaction per test that has profiling data.

For non-BrowserStack runs (local/simulator), behaviour is unchanged —
only the existing timer-step transaction is sent. For BrowserStack runs,
each test also gets a profiling transaction with the above measurements.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: MMQA-1929

## **Manual testing steps**

```gherkin
Feature: BrowserStack profiling metrics in Sentry

  Scenario: Run performance E2E tests on BrowserStack and verify Sentry data
    Given a BrowserStack performance test run completes with profiling data available
    When the PerformanceReporter finishes and calls publishProfilingDataToSentry
    Then each test that has a profilingSummary emits a Sentry transaction
    And that transaction contains measurements for profiling_slow_frames_pct, profiling_frozen_frames_pct, profiling_anrs, profiling_cpu_avg_pct, profiling_cpu_max_pct, profiling_memory_avg_mb, profiling_memory_max_mb
    And tests without profilingSummary (local runs) are not affected
```

## **Screenshots/Recordings**

N/A — infrastructure/tooling change with no UI impact.

### **Before**

BrowserStack profiling data (FPS, CPU, memory) only in HTML/CSV/JSON
local reports, absent from Sentry.

### **After**

BrowserStack profiling data available as typed Sentry measurements on a
dedicated profiling transaction per test, queryable in Sentry
Performance.

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

#### Performance checks (if applicable)

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

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds post-run Sentry uploads for BrowserStack tests (possible
duplicate timer transactions alongside the existing fixture publish) and
expands the performance telemetry pipeline, but changes are gated on
profiling data and env-controlled Sentry settings.
> 
> **Overview**
> After BrowserStack session enrichment, **PerformanceReporter** now
publishes Sentry transactions for tests that have a valid
`profilingSummary`, so UI/CPU/memory profiling that previously only
appeared in local reports is also sent to Sentry.
> 
> **`publishPerformanceScenarioToSentry`** accepts optional
`profilingSummary` and `testEndTimestamp`, maps BrowserStack profiling
into typed Sentry measurements (`profiling_slow_frames_pct`,
`profiling_frozen_frames_pct`, `profiling_anrs`, CPU/memory metrics),
mirrors the summary in `extra.profiling_summary`, and anchors
transaction start/end to the test end time when provided. Runs without
profiling or with enrichment errors are skipped unchanged.
> 
> Unit tests cover profiling payload shape, absence of profiling fields,
and timestamp anchoring.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0060635. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

1. Empty state: When the watchlist is empty, suggests the top 5 markets
by 24h volume. Each row shows the asset's live price and 24h change
alongside a "+" button to add to the watchlist.
2. Expand/collapse: When the watchlist has more than 3 markets, only the
first 3 are shown with a "Show X more" toggle. A "Show less" button
collapses it back.
3. Watchlist filter badge: A star badge appears at the start of the
market list filter row (before Crypto/Stocks/etc.) when the user has
watchlist markets. Tapping it filters the list to watchlisted assets
only. Mutually exclusive with category filters. When empty, we show the
same default state as on perps home
4. Watchlist header chevron: The "Watchlist" section header on the home
screen now has an arrow that deep-links into the full market list with
the star filter pre-selected. Hidden when the watchlist is empty.

## **Changelog**

<!-- mms-check: type=changelog required=true -->

<!--
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: Add new empty state for Perps Watchlist

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

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

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Perps market list filter mutual exclusivity
  Scenario: Watchlist deep link clears active category filter
    Given the market list screen is already mounted
    And a category filter (e.g. "Stocks") is active
    When the user navigates from the home watchlist header with showWatchlistOnly
    Then the star (watchlist) filter is turned on
    And the category filter is reset to "All"
    And all watchlisted markets are visible regardless of category
  Scenario: Selecting a category deactivates the watchlist filter
    Given the watchlist filter is active
    When the user taps a category badge (e.g. "Crypto")
    Then the category filter is applied
    And the watchlist filter is turned off
    And all markets in that category are shown
  Scenario: Activating the watchlist filter clears an active category
    Given a category filter is active
    When the user taps the star badge to enable the watchlist filter
    Then the watchlist filter is turned on
    And the category filter is reset to "All"
Feature: Category badge screen reader labels
  Scenario: Screen reader announces correct category name
    Given a category badge is displayed (e.g. "Forex")
    When a screen reader focuses the badge
    Then it announces "Forex"
    And not a raw i18n key or empty string
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->


https://github.com/user-attachments/assets/00278952-9e7e-478a-a84f-3afec948bdf3

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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 watchlist persistence paths and navigation params across
several Perps screens; behavior is well covered by tests but scope is
broad for a user-facing feature.
> 
> **Overview**
> Adds a **Perps watchlist empty state and discovery flow** across home,
market list, wallet tab, and market details.
> 
> **Watchlist UI:** `PerpsWatchlistMarkets` now accepts **suggested
markets** (top volume via `getSuggestedWatchlistMarkets`), shows an
empty subtitle with **+ add** rows, **show more/less** when more than
three saved markets, and an optional **header chevron**
(`onSeeAllPress`) to open the full list with watchlist-only mode.
Suggested rows hide when the list hits **`WATCHLIST_LIMIT` (10)**.
> 
> **Market list:** A **star filter badge** on the category row toggles
watchlist-only view, **mutually exclusive** with category filters
(synced in `usePerpsMarketListView` and list handlers). Empty watchlist
filter reuses `PerpsWatchlistMarkets` instead of the old favorites empty
copy; sort row hides while the star filter is active.
> 
> **Actions & limits:** New **`usePerpsWatchlistActions`** centralizes
add/remove with analytics and toasts; **`PerpsMarketRowItem`** gains
optional **`onAddPress`**. Market details blocks favoriting at the cap
with a limit toast.
> 
> **Wallet Perps tab:** **`PerpsTabView`** (with styles/tests) shows
watchlist + explore markets when there are no positions/orders, wired
through **`usePerpsTabExploreData`**.
> 
> **Supporting:** New i18n strings, test IDs, trace name `PerpsTabView`,
category badge **icon mode** + required **`accessibilityLabel`**.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fe82a1e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ation cp-7.81.0 (#31566)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

<!--
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?
-->
Updates the World Cup homepage discovery overflow copy from “events in
total” to “markets in total”.
This matches the product language for the overflowing World Cup market
count while leaving the normal non-overflow event count unchanged.


## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
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: Updated World Cup discovery copy to say markets instead
of events for overflowing counts.

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes:

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: World Cup discovery card copy
  Scenario: user sees overflowing World Cup market count
    Given the Predictions homepage discovery card has more World Cup items than the display limit
    When the user views the World Cup discovery row
    Then the overflow count says "{{count}}+ markets in total"
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

<!-- mms-check: type=checklist required=true -->

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] 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**
> Copy-only English localization and test assertion change with no logic
or data-handling impact.
> 
> **Overview**
> Updates World Cup homepage discovery **overflow** copy from “events”
to **markets** so overflowing counts match product terminology.
> 
> The English string
`predict.homepage_discovery.events_in_total_overflow` now renders
`{{count}}+ markets in total` instead of `{{count}}+ events in total`.
The non-overflow key `events_in_total` is unchanged. The
`PredictionsSection` test expectation for the discovery row was aligned
with the new copy.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f19f028. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Jun 11, 2026
@pull pull Bot added the ⤵️ pull label Jun 11, 2026
@pull
pull Bot merged commit c101846 into Reality2byte:main Jun 11, 2026
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.