Skip to content

release: 7.78.0#30207

Draft
metamaskbotv2[bot] wants to merge 377 commits into
stablefrom
release/7.78.0
Draft

release: 7.78.0#30207
metamaskbotv2[bot] wants to merge 377 commits into
stablefrom
release/7.78.0

Conversation

@metamaskbotv2
Copy link
Copy Markdown
Contributor

@metamaskbotv2 metamaskbotv2 Bot commented May 14, 2026

🚀 v7.78.0 Testing & Release Quality Process

Hi Team,
As part of our new MetaMask Release Quality Process, here’s a quick overview of the key processes, testing strategies, and milestones to ensure a smooth and high-quality deployment.


📋 Key Processes

Testing Strategy

  • Developer Teams:
    Conduct regression and exploratory testing for your functional areas, including automated and manual tests for critical workflows.
  • QA Team:
    Focus on exploratory testing across the wallet, prioritize high-impact areas, and triage any Sentry errors found during testing.
  • Customer Success Team:
    Validate new functionalities and provide feedback to support release monitoring.

GitHub Signoff

  • Each team must sign off on the Release Candidate (RC) via GitHub by the end of the validation timeline (Tuesday EOD PT).
  • Ensure all tests outlined in the Testing Plan are executed, and any identified issues are addressed.

Issue Resolution

  • Resolve all Release Blockers (Sev0 and Sev1) by Tuesday EOD PT.
  • For unresolved blockers, PRs may be reverted, or feature flags disabled to maintain release quality and timelines.

Cherry-Picking Criteria

  • Only critical fixes meeting outlined criteria will be cherry-picked.
  • Developers must ensure these fixes are thoroughly reviewed, tested, and merged by Tuesday EOD PT.

🗓️ Timeline and Milestones

  1. Today (Friday): Begin Release Candidate validation.
  2. Tuesday EOD PT: Finalize RC with all fixes and cherry-picks.
  3. Wednesday: Buffer day for final checks.
  4. Thursday: Submit release to app stores and begin rollout to 1% of users.
  5. Monday: Scale deployment to 10%.
  6. Tuesday: Full rollout to 100%.

✅ Signoff Checklist

Each team is responsible for signing off via GitHub. Use the checkbox below to track signoff completion:

Team sign-off checklist

  • Accounts
  • Assets
  • BE Trade
  • Bots Team
  • Card
  • Confirmations
  • Core Platform
  • Delegation
  • Design System
  • Earn
  • LavaMoat
  • Mobile Platform
  • Mobile UX
  • Money Movement
  • Networks
  • Onboarding
  • Perps
  • Predict
  • Rewards
  • Social & AI
  • Swaps and Bridge
  • team-mobile-delivery
  • Transactions

This process is a major step forward in ensuring release stability and quality. Let’s stay aligned and make this release a success! 🚀

Feel free to reach out if you have questions or need clarification.

Many thanks in advance

Reference

Prithpal-Sooriya and others added 30 commits May 6, 2026 19:20
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## **Description**

This change updates the DeFi empty-state `Explore DeFi` CTA behavior so
it no longer opens the external MetaMask Portfolio explore tokens URL in
the in-app browser.

Instead, pressing the CTA now navigates users to the in-app Explore flow
and opens the Explore **Sites** section (`TrendingView ->
SitesFullView`), matching the requested product direction and avoiding
the blank page issue.

## **Changelog**

CHANGELOG entry: Fixed the DeFi empty-state Explore button to open the
in-app Explore sites screen instead of an external portfolio page.

## **Related issues**

Fixes: #29471
https://consensyssoftware.atlassian.net/browse/ASSETS-3133

## **Manual testing steps**

```gherkin
Feature: DeFi empty-state Explore CTA navigation

  Scenario: user opens Explore from empty DeFi tab
    Given the user is on the DeFi tab with no open positions
    When user taps the "Explore DeFi" button
    Then the app navigates to the Explore Sites screen
    And the app does not open portfolio.metamask.io/explore/tokens
```

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

https://www.loom.com/share/04b68f115a2c44a190bd7049b5ee323e

https://www.loom.com/share/88e42d07ee06480a90abde1d4771add2

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

<div><a
href="https://cursor.com/agents/bc-9cac285f-d4ce-4156-a35e-004942245eb2"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-9cac285f-d4ce-4156-a35e-004942245eb2"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Prithpal Sooriya <prithpal@example.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.
-->

## **Description**

This cleans up some unintentional text issues when displaying Ondo
assets in the Rewards tab. This makes the Rewards tab match how Ondo
assets are displayed elsewhere in the app.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: n/a

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-05-06 at 15 10 33"
src="https://github.com/user-attachments/assets/6b266c71-e1db-4e72-a30c-d8bcaab36fee"
/>

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

## **Pre-merge author checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI/text-only changes in Rewards Ondo views plus removal of a
now-unused formatting helper; primary risk is minor regressions in how
token names/units are displayed and in i18n key usage.
> 
> **Overview**
> Rewards Ondo screens now **preserve backend-provided token display
names** (including the `(Ondo Tokenized)` suffix) instead of
stripping/truncating branding via `sanitizeOndoTokenName`, and
navigation to swaps passes the same unmodified name.
> 
> Ondo portfolio rows adjust layout to truncate long names and change
the units subtext from a localized `"{{units}} shares"` string to a
direct `${units} ${TOKEN_SYMBOL}` format (uppercased), removing the
`position_units` i18n key and associated tests.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
60550e0. 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.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

This updates the direct MetaMask design system dependencies used by
mobile to the latest published releases:

- `@metamask/design-system-react-native`: `^0.22.0` -> `^0.23.0`
- `@metamask/design-tokens`: `^8.3.0` -> `^8.4.0`
- `@metamask/design-system-twrnc-preset` remains at `^0.4.2` because it
is already current

I reviewed the upstream changelog and migration docs before upgrading.
The main breaking change in the new React Native package is the `Toast`
static API redesign, plus `Input` readonly naming alignment and shared
`AvatarGroup` contract updates. No mobile code changes were required in
this branch because the app does not directly consume those changed
design-system APIs today.

Release notes and migration references:

- MMDS releases:
https://github.com/MetaMask/metamask-design-system/releases
- React Native 0.23.0 notes:
https://github.com/MetaMask/metamask-design-system/releases/tag/v38.0.0
- React Native changelog:
https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/CHANGELOG.md#0230
- React Native migration guide:
https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/MIGRATION.md#from-version-0220-to-0230
- Design tokens changelog:
https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-tokens/CHANGELOG.md#840
- Design tokens migration guide:
https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-tokens/MIGRATION.md

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

No issue: dependency maintenance upgrade for the latest MetaMask design
system releases.

## **Manual testing steps**

N/A

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

<!--
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**
> Low risk dependency-only change, but it may introduce subtle
UI/behavior differences if any screens consume updated design-system
components indirectly.
> 
> **Overview**
> Upgrades design-system dependencies used by the app:
`@metamask/design-system-react-native` to `^0.23.0` and
`@metamask/design-tokens` to `^8.4.0`.
> 
> Updates `yarn.lock` accordingly, including bumping transitive
`@metamask/design-system-shared` to `^0.16.0`, with no app code changes
beyond dependency versions.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
03812e9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR syncs the stable branch to main for version 7.75.1.

*Synchronization Process:*

- Fetches the latest changes from the remote repository
- Resets the branch to match the stable branch
- Attempts to merge changes from main into the branch
- Handles merge conflicts if they occur

*File Preservation:*

Preserves specific files from the stable branch:
  - CHANGELOG.md
  - bitrise.yml
  - android/app/build.gradle
  - ios/MetaMask.xcodeproj/project.pbxproj
  - package.json

  Indicates the next version candidate of main to 7.75.1
…9298)

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

## **Description**

Phase 2 cleanup of the Runway workflow split. Removes the legacy
per-platform Runway entry workflows now that Runway has been flipped to
dispatch the combined OTA-only and build-only workflows introduced in
phase 1, and `release/7.73.x` / `release/7.74.x` are no longer actively
maintained.

### Context

Phase 1 (previous PR) added 5 new workflow files without touching
anything existing:

- `runway-ota-resolve-context.yml`
- `runway-production-builds.yml`
- `runway-rc-builds.yml`
- `runway-ota-production.yml`
- `runway-ota-rc.yml`

That PR intentionally deferred the cleanup so Runway could keep
dispatching the old per-platform workflow names against `release/7.73.x`
and `release/7.74.x` (which cannot receive cherry-picks).

### What this PR does

- **Deletes** the 4 legacy per-platform Runway entry workflows:
  - `runway-ios-production-workflow.yml`
  - `runway-android-production-workflow.yml`
  - `runway-ios-rc-workflow.yml`
  - `runway-android-rc-workflow.yml`
- **Renames** `runway-ota-build-core.yml` → `auto-rc-ota-build-core.yml`
to reflect that its only remaining caller is `build-rc-auto.yml`
(auto-RC on push), not Runway.
- **Refactors** the renamed core to call the reusable
`runway-ota-resolve-context.yml` from phase 1 instead of keeping the
`decide` + `resolve-pr` logic inline. Behaviour is identical; the logic
is now shared with the OTA-only Runway workflows.
- **Updates** `build-rc-auto.yml` `uses:` paths (two call sites) and the
header comment to point at the renamed core.

### What this PR does NOT change

- No behaviour change for `build-rc-auto.yml` — same OTA-vs-build
auto-detection, same parallel platform dispatch, same Slack
notification.
- No behaviour change for the 4 phase-1 Runway workflows.

### Precondition for merge

Before merging this PR, verify that:

1. Runway has been reconfigured to dispatch the 4 new workflow names
(`runway-production-builds.yml`, `runway-rc-builds.yml`,
`runway-ota-production.yml`, `runway-ota-rc.yml`).
2. `release/7.73.x` and `release/7.74.x` are no longer being hotfixed
via Runway dispatch (they can still receive direct pushes —
`build-rc-auto.yml` on those branches uses the files present on that
ref, which still include the legacy core until those branches are fully
retired).

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes GitHub Actions workflow entry points
and reusable workflow wiring for OTA-vs-build detection, which could
break release/RC automation if references or outputs diverge.
> 
> **Overview**
> Refactors the auto-RC release flow by replacing the legacy reusable
`runway-ota-build-core.yml` with a new `auto-rc-ota-build-core.yml` that
delegates OTA bump/PR resolution to `runway-ota-resolve-context.yml`,
while keeping the same OTA-vs-build branching behavior.
> 
> Cleans up CI by deleting the four per-platform Runway
`workflow_dispatch` entry workflows (iOS/Android, RC/production) and
updating `build-rc-auto.yml` to call the renamed core workflow for both
iOS and Android RC triggers.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
54fc5ee. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ar (#29645)

## **Description**

Bundle of polish items on the Money Home screen.

- **MUSD-741** migrates the "X% APY" pill in the Money Home header from
a hand-rolled `Box + Text` to the MMDS `Tag` component (severity =
success), and bumps the inner text from `BodySm` (14px) to `BodyMd`
(16px) so yield reads as a primary value prop.
- **MUSD-743** removes the back chevron from the Money Home header. With
Money now a top-level tab destination, the back button was misleading;
the kebab on the right naturally aligns with the title via
`HeaderStandard`'s built-in layout.
- **MUSD-744** renders the global wallet action bar at the bottom of
Money Home so the screen functions as a proper tab destination instead
of a dead-end. Concretely:
- The Money `Tab.Screen` is registered as `Routes.MONEY.ROOT` (instead
of `Routes.MONEY.HOME`) and wired to `MoneyScreenStack`. This matches
the existing `TabBar` handler which navigates to `Routes.MONEY.ROOT, {
screen: Routes.MONEY.HOME }` — so the tab mounts with its inner stack
and the global tab bar stays visible.
- The outer `Stack.Screen` for `Routes.MONEY.ROOT` (which was pushing
above `HomeTabs` and hiding the tab bar) is removed from
`MainNavigator`.
- All changes are inside `app/components/Nav/Main/MainNavigator.js` — no
design-system-owned files are touched.
- `MoneyFooter` ("Add money" CTA) was unpinned from its sticky-bottom
position and now flows inside the `ScrollView` content as a normal
section (`px-4 py-3`), with a single Divider above it (matching the
section rhythm) and `paddingBottom: 40` on the scroll content. MUSD-747
will reintroduce sticky behaviour with peek-and-hide based on the
onboarding stepper's viewport state.

No analytics changes, no copy changes, no behavioural changes outside
the navigation rewiring described above.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
- https://consensyssoftware.atlassian.net/browse/MUSD-741
- https://consensyssoftware.atlassian.net/browse/MUSD-743
- https://consensyssoftware.atlassian.net/browse/MUSD-744

## **Manual testing steps**

```gherkin
Feature: Money Home header polish + tab bar visibility

  Scenario: user opens Money Home via the bottom tab
    Given the Money Account feature flag is enabled
    When the user taps the Money tab in the bottom navigation
    Then Money Home renders with the global tab bar visible at the bottom
    And the "Money" tab is shown as active
    And no back chevron is rendered in the Money Home header
    And the options (kebab) icon sits in the top-right
    And the "X% APY" pill is rendered as an MMDS Tag at 16px text

  Scenario: Add money button placement
    Given Money Home is open
    When the user scrolls to the bottom of the page
    Then the "Add money" button renders inside the scroll content as the last section
    And it is preceded by the standard section divider
    And it has visible breathing room before the global tab bar
```

## **Screenshots/Recordings**

### **Before**

<!-- to be added -->

### **After**

<!-- to be added -->

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk due to navigation rewiring (Money tab now routes to
`Routes.MONEY.ROOT`/`MoneyScreenStack` and a stack-level screen is
removed), which could affect tab routing and back-stack behavior.
UI/layout changes are otherwise straightforward and covered by updated
tests.
> 
> **Overview**
> Makes Money a first-class bottom-tab destination by switching the
conditional tab registration from `Routes.MONEY.HOME` to
`Routes.MONEY.ROOT` and mounting `MoneyScreenStack` directly, while
removing the extra `Routes.MONEY.ROOT` stack screen that previously sat
above `HomeTabs` (keeping the global tab bar visible).
> 
> Polishes Money Home UI: replaces the APY pill with the design-system
`Tag`, updates the header to a title+menu-only `HeaderBase` (removing
the back button), and simplifies the “Add money” footer from an
animated/sticky overlay to a normal scroll section with fixed bottom
padding; associated peek/hide stepper logic and its unit tests are
deleted and component tests are updated accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a742e0d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Adds a new **Money balance card** to the wallet home screen, slotted
between the
wallet action bar (Buy/Swap/Send/Receive) and the Carousel/Tokens block.
The
card surfaces the user's Money Account balance, current vault APY, and a
direct CTA to add funds — replacing the chevron-style "Money" section
pattern
described in the Money Home Review (April 30, 2026) for users on the new
wallet home.

The card has two visual states sharing one component:

- **Empty** (MUSD-431) — balance `$0.00`, **Secondary** "Add" button.
- **Funded** (MUSD-752) — live `totalFiatFormatted` from
`useMoneyAccountBalance`,
  **Secondary** "Add" button. Switches as soon as `totalFiatRaw > 0`.

Other behaviour:
- Tap card body → navigates to Money home (`Routes.MONEY.ROOT`)
- Tap "Add" → `Routes.MONEY.MODALS.ADD_MONEY_SHEET` (same flow as the
existing
  Money home Add pill)
- Tap info icon → new `MoneyBalanceInfoSheet` modal (registered
alongside the
  existing APY/Earnings info sheets)
- Skeleton placeholders while balance/APY are loading
- Render-gated by `selectMoneyHomeScreenEnabledFlag &&
isHomepageSectionsV1Enabled`

The legacy `MoneyAccountHomeRow` and `CashSection` are intentionally
untouched
in this PR — they continue to serve users without the Money home flag.

## **Changelog**

CHANGELOG entry: Added a new Money balance card to the wallet home
screen showing the user's Money Account balance, vault APY, and a quick
action to add funds.

## **Related issues**

Fixes: MUSD-431, MUSD-752

## **Manual testing steps**

```gherkin
Feature: Money balance card on wallet home

  Scenario: user with no Money balance sees the empty state
    Given the Money home feature flag is enabled
    And the homepage sections v1 flag is enabled
    And the user has no Money Account balance

    When the user opens the wallet home screen
    Then the Money balance card is visible between the action bar and the tokens
    And the balance shows "$0.00"
    And the "Add" button uses the Secondary variant
    And the "4% APY" tag is visible

  Scenario: user with a Money balance sees the funded state
    Given the Money home feature flag is enabled
    And the homepage sections v1 flag is enabled
    And the user has a Money Account balance greater than $0.00

    When the user opens the wallet home screen
    Then the Money balance card shows the live USD balance
    And the "Add" button uses the Secondary variant

  Scenario: user taps the Money balance card body
    Given the Money balance card is visible

    When the user taps anywhere on the card outside of the Add button or info icon
    Then the app navigates to the Money home screen

  Scenario: user taps the info icon on the Money balance card
    Given the Money balance card is visible

    When the user taps the info icon next to "Money balance"
    Then the Money balance info sheet opens

  Scenario: feature flag is off
    Given the Money home feature flag is disabled

    When the user opens the wallet home screen
    Then the Money balance card is not rendered
```

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

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

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new wallet-home UI and navigation paths (including a new modal
route) gated by feature flags; risk is mainly around routing/press
handlers and empty-state logic but is localized and well-covered by
tests.
> 
> **Overview**
> Adds a new `MoneyBalanceCard` on the wallet home header area (shown
only when `selectMoneyHomeScreenEnabledFlag` is on) that displays Money
balance + APY with loading skeletons, and provides CTAs to open the Add
Money sheet, navigate to Money Home, or start the mUSD conversion
education flow for new users.
> 
> Introduces a new `MoneyBalanceInfoSheet` bottom-sheet modal and
registers it in the Money modal stack via new route
`Routes.MONEY.MODALS.MONEY_BALANCE_INFO_SHEET`, along with new i18n
strings for the card label and sheet copy.
> 
> Removes the legacy `MoneyAccountHomeRow` component/tests and updates
`CashSection` so the entire Cash section is not rendered when the Money
home flag is enabled; updates/extends unit tests (Wallet flag-gated
rendering, Cash section null behavior, Money modal registration)
accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
dea4013. 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.
-->

## **Description**

Four small UI/UX fixes for the What's Happening feature:

1. Home carousel card date visibility 
2. Detail-view header size
3. Expanded card height consistency
4. in Tokens row the Buy button switched to Trade button, and now users
should always be directed to Perps trade. When a token asset has an
hlPerpsMarket entry the row now shows a Trade button navigating to Perps
market details; otherwise it falls back to the existing Buy/Ramp flow.

<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-06
at 12 23 11"
src="https://github.com/user-attachments/assets/d3a91506-e9d0-4182-a9ea-47732834268a"
/>
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-06
at 12 23 02"
src="https://github.com/user-attachments/assets/2c40b688-b91b-4da5-9e10-d69bfc8b6844"
/>
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-06
at 12 01 23"
src="https://github.com/user-attachments/assets/9b7371c3-4306-4794-be88-2671d0e01836"
/>


## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

#### 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**
> Medium risk because it changes navigation behavior for token action
buttons (routing some assets to Perps) and alters carousel/card layout
rendering based on runtime measurement, which could affect
visibility/scroll positioning across devices.
> 
> **Overview**
> Polishes What’s Happening UI by slightly increasing home carousel card
heights, reducing card title lines to preserve footer/date visibility,
and resizing the “View more” card to match.
> 
> Updates the detail view header to a custom, smaller layout and makes
the expanded-card carousel use a fixed measured `cardHeight`, gating
card rendering and initial scroll positioning until layout is known;
tests now simulate `onLayout` to validate rendering.
> 
> Changes related-asset actions so token rows show **Trade** (navigating
to Perps market details) when `hlPerpsMarket` is present, via new
`useTradeNavigation`; `PerpsRow` is simplified to reuse the same hook,
and `AssetRow` migrates to the design-system `Button` component.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7edb172. 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.
-->

## **Description**

- Replaces confirmed EVM Activity transactions with data from accounts
v4 API via React Query
- Adds infinite pagination for confirmed EVM history
- Keep local pending EVM transactions and existing non-EVM activity
unchanged

Note: Due to the API requesting a bearer token, there is a current
bottleneck in that token retrieval, in particular in
`AuthenticationController.getPrimaryEntropySourceId`

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: feat: use accounts API v4 for transactions

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Accounts API v4 Transactions

  Scenario: user views EVM activity
    Given the wallet has EVM confirmed on-chain activity

    When user visits the Activity tab
    Then confirmed onchain transactions returned by the Accounts v4 API is displayed on screen.
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

#### 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**
> Moderate risk because it rewires the Activity/UnifiedTransactionsView
data source and filtering/deduping logic, which can change what
transactions appear and when pagination/refresh occurs.
> 
> **Overview**
> **Confirmed EVM Activity now comes from the Accounts v4 API** via a
new React Query `useTransactionsQuery` hook, while local pending EVM
transactions continue to come from controller state and are
merged/deduped with the API results.
> 
> Adds a small transformation layer (`helpers/adapters` +
`helpers/transformations`) to normalize API responses into
`TransactionMeta`-compatible view models, filter out unwanted items
(e.g. spam/incoming transfers/zero-value self-sends), and handle
bridge-history matching/deduping (including case-insensitive hash
matching).
> 
> Updates `UnifiedTransactionsView` to support infinite scrolling
pagination (prefetch near the end of confirmed EVM items), show
initial/next-page loading indicators, and refresh both local polling and
the query. Related selector additions (`selectLocalTransactions`,
`selectRequiredTransactionHashes/Ids`) support filtering required child
txs and nonce/hash collisions, and tests/smoke mocks were updated
accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a3e6592. 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 Agent <cursoragent@cursor.com>
Co-authored-by: Copilot <copilot@github.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.
-->

## **Description**

> Removes the WDIO `generateTestId` helper and updates many UI
components to pass `testID` directly (dropping `Platform`-dependent
spreading) across buttons, toggles, list items, and modals.
> 
> Introduces/standardizes colocated `*.testIds.ts` selector constants
for several screens/components (e.g., `Navbar`, `EthereumAddress`,
`AccountSelector`, `BrowserTab` options, `PhishingModal`,
`WebviewError`, `TermsAndConditions`, `ConnectQRHardware`) and updates
unit tests/components to import selectors from the new
`tests/selectors`/local testId modules instead of `wdio` paths.
> 

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

#### 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**
> Low risk refactor focused on test selectors: changes only how
`testID`s are assigned and referenced, with minimal runtime impact
beyond potential selector/name mismatches in tests/automation.
> 
> **Overview**
> Removes the WDIO `generateTestId` utility and updates multiple UI
components to pass `testID` directly (dropping `Platform`-dependent
spreading) across buttons, toggles, list items, and modals.
> 
> Introduces/standardizes co-located `*.testIds.ts` selector constants
(e.g., `Navbar`, `EthereumAddress`, `AccountSelector`, browser options,
phishing/webview error modals, terms, QR hardware connect) and updates
unit tests/components to import selectors from these modules (and from
`tests/selectors`) instead of `wdio` paths.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7d696af. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29548)

## **Description**

Bundles six small Money Hub UX changes:

- **MUSD-728** — Drop the inline **Learn more** CTA from
`MoneyConvertStablecoins`. The Convert section ends after the feature
tags / per-token rows; only the primary action remains.
- **MUSD-729** — Money Hub balance heading reads **Your balance**
(replacing the duplicate "Money" inline title; the page header still
shows "Money"). Standalone "3% bonus" label removed from mUSD rows in
the homepage token list — the row falls back to the standard percentage
rail when there's no Convert CTA.
- **MUSD-730** — `AssetOverviewClaimBonus` claim button switches from
primary to **secondary** styling (no logic change).
- **MUSD-731** — No code change required: the existing
`MUSD_CONVERSION_APY` constant already drives every "3%" surface
consistently. No outdated/conflicting variants remain.
- **MUSD-732** — Five-item checklist (`Dollar-backed`, `No lockups`,
`Daily bonus`, `MetaMask stablecoins`, `No MetaMask fee`) added to the
**Get 3% on stablecoins** education splash with green checkmarks.
- **MUSD-733** — Mounts the Convert section on the mUSD asset detail
page via a new `AssetOverviewConvertSection` wrapper that reuses
`MoneyConvertStablecoins`. The component already supports the three
target states (no-mUSD informational, has-mUSD with stablecoins
per-token rows, has-mUSD without stablecoins informational). The
secondary claim CTA from MUSD-730 covers the claim-styling requirement.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[MUSD-728](https://consensyssoftware.atlassian.net/browse/MUSD-728),
[MUSD-729](https://consensyssoftware.atlassian.net/browse/MUSD-729),
[MUSD-730](https://consensyssoftware.atlassian.net/browse/MUSD-730),
[MUSD-731](https://consensyssoftware.atlassian.net/browse/MUSD-731),
[MUSD-732](https://consensyssoftware.atlassian.net/browse/MUSD-732),
[MUSD-733](https://consensyssoftware.atlassian.net/browse/MUSD-733)

## **Manual testing steps**

```gherkin
Feature: Money Hub polish

  Scenario: Money Hub Convert section (MUSD-728)
    Given I open the Money Hub
    Then the Convert to mUSD section ends after the feature tags or per-token rows
    And no "Learn more" button is rendered

  Scenario: Money Hub balance heading (MUSD-729)
    Given I open the Money Hub
    Then the balance section heading reads "Your balance"

  Scenario: mUSD token row label (MUSD-729)
    Given I view the wallet token list with mUSD on Mainnet/Linea
    Then the mUSD row no longer renders the green "3% bonus" label
    And the row falls back to the standard percentage rail when no Convert CTA applies

  Scenario: Asset detail claim button (MUSD-730)
    Given I open the mUSD asset detail page with a claimable bonus
    Then the "Claim" button uses secondary button styling

  Scenario: Education splash checklist (MUSD-732)
    Given I view the "Get 3% on stablecoins" education splash
    Then I see a checklist with: Dollar-backed, No lockups, Daily bonus, MetaMask stablecoins, No MetaMask fee
    And each item shows a green check icon

  Scenario: Asset detail Convert module (MUSD-733)
    Given I open the mUSD asset detail page
    And mUSD conversion is enabled and I am geo-eligible
    Then a Convert section renders below the claim card
    And it shows per-token rows for any eligible stablecoins, or the empty/info layout otherwise
```

## **Screenshots/Recordings**

<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/474cfcf1-d538-43c7-b798-4ca060fa1a88"
/>
<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/82ee004e-40c1-4972-bf93-f6ca44822150"
/>
<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/c7ae2bd0-cf04-4475-826a-806498a33a92"
/>


## **Pre-merge author checklist**

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

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

- [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-728]:
https://consensyssoftware.atlassian.net/browse/MUSD-728?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk: refactors conversion UI wiring and token list rendering
paths (including a new compact mUSD layout and new analytics
events/locations), which could affect navigation and tracking if
misconfigured.
> 
> **Overview**
> **Money Hub UX polish for mUSD conversion and balances.** The Convert
section (`MoneyConvertStablecoins`) is simplified by removing the inline
*Learn more* CTA and now self-manages token fetching plus conversion
initiation, emitting `MONEY_HUB_TOKEN_ROW_CONVERT_CLICKED` analytics
with a passed-in `location`.
> 
> **mUSD balance presentation is adjusted across Money surfaces.**
`CashTokensFullView` adds a **"Your balance"** heading when Money Hub is
enabled, introduces a new `MoneyMusdEmptyBalanceRow` for the
zero-balance state, and passes a new `hideSecondaryPriceRow` flag
through `Tokens`/`TokenList` to render a compact mUSD row without the
price/percentage rail. Separately, mUSD token list items no longer show
the standalone green `"3% bonus"` secondary label.
> 
> **Other small UI/text tweaks.** `AssetOverviewClaimBonus` switches its
CTA button to `Secondary` styling and removes the leading `+` from the
estimated annual bonus display; the mUSD education screen is redesigned
to use design-system components, adds a 5-item checklist, and removes
the external “Terms apply” link while updating the education copy and
i18n keys (cash → money, new checklist strings, new
`money.your_balance`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6696fdc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This change replaces the temporary `HeaderCompactStandard` component
with `HeaderStandard` from `@metamask/design-system-react-native` on
Earn-related surfaces.

**Reason:** Align Earn UI with the MetaMask design system and reduce
reliance on `component-library/components-temp` for standard headers.

**What changed:** `HeaderStandard` is used for the Lending “How it
works” bottom sheet, the Earn input screen header (back button and end
actions), and the Earn token list bottom sheet. Behavior is intended to
match the previous header (title, back/close, analytics-related tests
unchanged aside from naming). Unit test comments and a `describe` block
name were updated to reference `HeaderStandard`.

## **Changelog**

CHANGELOG entry: null 

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-699

## **Manual testing steps**

```gherkin
Feature: Earn headers use design system HeaderStandard

  Scenario: Earn input screen header matches prior behavior
    Given the user is on the Earn flow and opens the amount/input screen (e.g. stake or supply)
    When the user views the screen header and uses the back control
    Then the header shows the expected title and navigation behaves as before

  Scenario: Lending “How it works” modal
    Given the user opens the Lending learn-more / “How it works” bottom sheet from Earn
    When the user views the header and taps close
    Then the sheet dismisses as before

  Scenario: Earn token selection bottom sheet
    Given the user opens the token list bottom sheet (e.g. select token to supply or withdraw)
    When the user views the header title and uses the close control
    Then the sheet closes as before and titles match the prior copy for the flow
```

## **Screenshots/Recordings**

### **Before**


### **After**


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

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**
> Low risk refactor that swaps a temporary header component for the
design-system header on a few Earn screens; main regression risk is
minor UI/interaction differences in back/close and end-icon rendering.
> 
> **Overview**
> Updates Earn surfaces to use the design-system `HeaderStandard`
instead of the temporary `HeaderCompactStandard`, including the Lending
“How it works” bottom sheet, the `EarnInputView` screen header (back +
optional info icon), and the Earn token list bottom sheet (close button
+ title).
> 
> Adjusts imports accordingly (including `IconName` usage from the
design system) and updates unit test descriptions/comments to reference
`HeaderStandard` while keeping behavioral assertions the same.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c517a2e. 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>
<!--
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.
-->

## **Description**
This PR introduces two shared `NativeStackNavigationOptions` presets in
`clearStackNavigatorOptions.ts`:

Perps already uses `createNativeStackNavigator`, but several screens
repeated the same option blobs (`presentation: 'transparentModal'`,
transparent `contentStyle`, `animation: 'none'`, `headerShown: false`)
inline. That duplicated the JS-stack `clearStackNavigatorOptions` idea
without a typed, reusable native-stack equivalent.



## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes React Navigation option presets for
native stacks, which can affect modal presentation, animations, and
header behavior across Perps flows.
> 
> **Overview**
> Standardizes Perps native-stack overlay behavior by replacing inline
`presentation: 'transparentModal'`/transparent styling with shared
presets (`transparentModalScreenOptions`,
`clearNativeStackNavigatorOptions`).
> 
> Adds native-stack equivalents of the existing clear JS-stack options
in `clearStackNavigatorOptions.ts`, and updates Perps screens (TP/SL,
close-position/bottom-sheet stacks, and pay-with modal) to use these
presets for consistent transparent modals without unwanted animations.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3a0cec5. 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.
-->

## **Description**
https://consensyssoftware.atlassian.net/browse/RWDS-1267
The Rewards crash likely came from an older persisted Rewards Redux
state that did not have newer array fields, especially campaigns. On
affected devices, selectCampaigns could return undefined.

It was account/device dependent because persisted state differs per
user/install.

Fix Applied: hardened both the restore path and selector path to
fallback to initial state (empty array or object instead of undefined)

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/RWDS-1267

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are defensive fallbacks for missing/undefined
persisted state and selector inputs, with added tests; behavior should
only differ for legacy/partial states.
> 
> **Overview**
> Prevents Rewards tab crashes caused by older/partial persisted
Redux/controller state by **defaulting missing fields to safe empty
values**.
> 
> Selectors and rehydrate logic now coalesce `undefined` arrays/objects
(e.g., `campaigns`, season arrays, `benefits`, dismissed-toasts map,
controller `accounts`/`subscriptions`) to empty defaults, and
`RewardsController` default state was extracted into `defaultState.ts`
and reused. Test coverage was expanded to lock in these
upgrade/undefined-state behaviors.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d7b351d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29813)

## **Description**

Replaces the legacy `Bank` icon used by the Money tab in the bottom
navigation bar with the new Dollar glyph from the Figma spec (MUSD-773),
in both selected (filled) and unselected (outline) states.

- Adds two new SVG assets: `dollar.svg` (outlined circle + dollar sign)
and `dollar-filled.svg` (solid circle with dollar-sign cutout).
- Both SVGs use `currentColor` for stroke and fill so the Icon component
can tint them per theme — they pick up the correct active/inactive color
in both light and dark mode, matching the convention used by the other
tab bar icons (`Home`/`HomeFilled`,
`MetamaskFoxOutline`/`MetamaskFoxFilled`).
- The filled variant uses `fill-rule="evenodd"` so the dollar sign is a
transparent cutout through the colored circle, showing the tab-bar
background through it (avoids hardcoded light/dark color pairs).
- Wires the new icons in `TabBar.constants.ts` (inactive →
`IconName.Dollar`) and `TabBar.tsx` (`FILLED_ICONS` map →
`IconName.DollarFilled`).
- Adds `Dollar` and `DollarFilled` to the local `IconName` enum and
asset map by hand to avoid the side-effect rewrite that `yarn
generate-icons` would have done to the rest of the enum.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[MUSD-773](https://consensyssoftware.atlassian.net/browse/MUSD-773)

## **Manual testing steps**

```gherkin
Feature: Money tab uses the new Dollar icon in both states and themes

  Scenario: Money tab is unselected in light mode
    Given the app is in light mode
    And the user is not on the Money tab
    Then the Money tab icon is the outlined Dollar glyph
    And its stroke and dollar sign use the inactive icon tint

  Scenario: Money tab is unselected in dark mode
    Given the app is in dark mode
    And the user is not on the Money tab
    Then the Money tab icon is the outlined Dollar glyph
    And its stroke and dollar sign use the inactive icon tint

  Scenario: Money tab is selected in light mode
    Given the app is in light mode
    When the user taps the Money tab
    Then the Money tab icon switches to the filled Dollar glyph
    And the circle paints in the active icon tint
    And the dollar sign is transparent, showing the tab-bar background through it

  Scenario: Money tab is selected in dark mode
    Given the app is in dark mode
    When the user taps the Money tab
    Then the Money tab icon switches to the filled Dollar glyph
    And the circle paints in the active icon tint
    And the dollar sign is transparent, showing the tab-bar background through it
```

## **Screenshots/Recordings**

### **Before**

### **After**

<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/74c25f60-fd6e-4b98-8645-aa7a1b907c92"
/>


<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/2d54975e-87db-49ee-876a-266f60682deb"
/>


## **Pre-merge author checklist**

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

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only change that swaps icon assets and enum entries; main
risk is any missed references to the removed/renamed `IconName` values
causing build-time errors.
> 
> **Overview**
> Updates the bottom navigation **Money** tab to use new
`Musd`/`MusdFilled` icon assets instead of the legacy bank glyph, wiring
them through the tab bar icon maps.
> 
> Extends the icon system with new `IconName` entries and SVG assets,
and updates Portfolio-related tab UI/tests to use `IconName.PieChart` in
place of the removed `IconName.Portfolio` (including
`HomepageDiscoveryTabs`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ee491bb. 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 Agent <cursoragent@cursor.com>
Co-authored-by: Brian August Nguyen <brianacnguyen@gmail.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.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
OAuth client IDs for Google and Apple sign-in (`IOS_GOOGLE_CLIENT_ID`,
`IOS_GOOGLE_REDIRECT_URI`, `ANDROID_GOOGLE_CLIENT_ID`,
`ANDROID_GOOGLE_SERVER_CLIENT_ID`, `ANDROID_APPLE_CLIENT_ID`) were
previously sourced from `process.env`, requiring manual environment
variable configuration and risking misconfiguration across different
build types.

This PR moves those client IDs into the existing `OAUTH_CONFIG` object
in `config.ts`, keyed by build type (development, main_prod, main_uat,
main_dev, flask_prod, flask_uat, flask_dev). The constants in
`constants.ts` now read from `CURRENT_OAUTH_CONFIG` instead of
`process.env`, ensuring the correct client IDs are automatically
selected based on the build type. The corresponding environment variable
entries have been removed from `.js.env.example`.


## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Seedless onboarding OAuth login

  Scenario: user signs in with Google on iOS
    Given the app is built with a main production build type
    When user taps "Sign in with Google" during onboarding
    Then the Google OAuth flow uses the correct production client ID
    And the user is authenticated successfully

  Scenario: user signs in with Google on Android
    Given the app is built with a main production build type
    When user taps "Sign in with Google" during onboarding
    Then the Google OAuth flow uses the correct production server client ID
    And the user is authenticated successfully

  Scenario: user signs in with Apple on Android
    Given the app is built with a main production build type
    When user taps "Sign in with Apple" during onboarding
    Then the Apple OAuth flow uses the correct production Apple client ID
    And the user is authenticated successfully
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

#### 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**
> Touches OAuth configuration used for Google/Apple login; incorrect
client IDs/redirect URIs could break authentication in specific build
targets despite being mostly a config refactor.
> 
> **Overview**
> OAuth client IDs/redirect URIs are now **defined per build type** in
`OAuthLoginHandlers/config.ts` and consumed via `CURRENT_OAUTH_CONFIG`
in `constants.ts`, instead of being read from `process.env`.
> 
> The example env file removes the seedless-onboarding client ID
entries, and unit tests are updated to assert against
`OAUTH_CONFIG.main_prod` values for Android and legacy iOS Google config
selection.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fd46114. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

The iOS production build in `build.yml` runs `pod install` without
caching `~/.cocoapods/repos` (the CocoaPods specs repository). Every run
downloads the full specs catalog from CDN, taking ~1m 36s.

This PR adds an `actions/cache@v4` step before `pod install` that caches
`~/.cocoapods/repos` keyed on `ios/Podfile.lock`. On cache hit, `pod
install` resolves specs locally instead of fetching from CDN. Uses
`continue-on-error: true` so cache failures never block the build.

This matches the existing pattern in
`.github/actions/setup-e2e-env/action.yml` (lines 382-391).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: MCWP-574

## **Manual testing steps**

```gherkin
Feature: CocoaPods specs caching in iOS production build

  Scenario: First run populates the cache (cache miss)
    Given a production iOS build is triggered via workflow_dispatch
    And no prior CocoaPods specs cache exists for the current Podfile.lock

    When the "Restore CocoaPods specs cache (iOS)" step runs
    Then the step logs show "Cache not found"
    And "Install CocoaPods dependencies (iOS)" completes successfully at baseline timing (~1m 36s)

  Scenario: Subsequent run restores the cache (cache hit)
    Given a production iOS build is triggered via workflow_dispatch
    And a CocoaPods specs cache exists from a previous run

    When the "Restore CocoaPods specs cache (iOS)" step runs
    Then the step logs show "Cache restored"
    And "Install CocoaPods dependencies (iOS)" completes faster (~30s-1m less)
    And the build produces a valid IPA artifact

  Scenario: Cache failure does not block the build
    Given the cache action encounters an error (network issue, quota exceeded)

    When the "Restore CocoaPods specs cache (iOS)" step fails
    Then the step is marked as successful due to continue-on-error: true
    And "Install CocoaPods dependencies (iOS)" proceeds normally with a full CDN fetch
```

## **Screenshots/Recordings**

N/A - CI workflow change only, no UI impact.

### **Before**

### **After**

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

The `prepare` and `emit-build-metadata` jobs in `build.yml` use
`fetch-depth: 0` (full git history clone), which takes ~1m 10s each
(median, n=21). Neither job performs any git history operations:

- `prepare`: reads `builds.yml` via `fs.readFileSync` and runs
`validate-build-config.js` (zero git commands)
- `emit-build-metadata`: runs `git rev-parse HEAD` (works on shallow
clones) and `get-build-metadata.sh` which only reads files (zero git
commands)

Removing `fetch-depth: 0` defaults to `fetch-depth: 1` (shallow clone),
reducing checkout from ~70s to ~10-15s per job.

**Expected saving:** ~1m 50s - 2m 10s per pipeline run across both jobs.
Also eliminates a tail-risk outlier where `emit-build-metadata` checkout
took 6m 45s.

Part of MCWP-574 (pipeline optimization series: PR 3 of 4).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: MCWP-574

## **Manual testing steps**

```gherkin
Feature: Shallow clone in build pipeline

  Scenario: prepare job completes with shallow clone
    Given a production build is triggered via workflow_dispatch on build.yml
      And skip_version_bump is true

    When the prepare job runs
    Then the actions/checkout step completes in ~10-15s (down from ~70s)
      And the prepare job outputs are identical to a full-clone run

  Scenario: emit-build-metadata job completes with shallow clone
    Given a production build completes successfully

    When the emit-build-metadata job runs
    Then the actions/checkout step completes in ~10-15s
      And built_commit_sha, semantic_version, and version codes are output correctly

  Scenario: version-bump commit ref works with shallow clone
    Given a production build is triggered with skip_version_bump false

    When the prepare job checks out the version-bump commit hash
    Then actions/checkout fetches the specific commit successfully
      And the prepare job completes without errors
```

## **Screenshots/Recordings**

### **Before**

Not applicable (CI pipeline change, no UI).

### **After**

Not applicable (CI pipeline change, no UI).

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This PR adds **component view tests (CVT)** for flows that were
previously covered by **smoke E2E** only, and **skips** those E2E cases
(eventually delete them). Smoke specs keep the original test bodies and
point to the CV file with `// Moved to cv tests (...)`.

Example: In network abstraction shard 1 we see a 4m reduction time
(android).

### E2E → component view test mapping

| File | Test Name | QA Comment | CV test file |
| --- | --- | --- | --- |
| view-defi-details.spec.ts | view DeFi position details | just checking
some data in the screen |
`app/components/UI/DeFiPositions/DeFiProtocolPositionDetails.view.test.tsx`
|
| view-market-insights.spec.ts | displays market insights content and
navigates to swap | |
`app/components/UI/MarketInsights/Views/MarketInsightsView/MarketInsightsView.view.test.tsx`
|
| view-market-insights.spec.ts | does not display entry card when API
returns no data | |
`app/components/UI/TokenDetails/components/AssetOverviewContent.view.test.tsx`
|
| view-market-insights.spec.ts | does not display entry card when
feature flag is disabled | |
`app/components/UI/TokenDetails/components/AssetOverviewContent.view.test.tsx`
|
| view-market-insights.spec.ts | navigates to buy screen when tapping
Buy button | |
`app/components/UI/MarketInsights/Views/MarketInsightsView/MarketInsightsView.view.test.tsx`
|
| view-market-insights.spec.ts | can tap thumbs up feedback button | |
`app/components/UI/MarketInsights/Views/MarketInsightsView/MarketInsightsView.view.test.tsx`
|
| send-btc-token.spec.ts | shows insufficient funds | This only does
validation on the input |
`app/components/Views/confirmations/components/send/send.non-evm.view.test.tsx`
|
| send-tron-token.spec.ts | shows insufficient funds | This only does
validation on the input |
`app/components/Views/confirmations/components/send/send.non-evm.view.test.tsx`
|
| send-erc20-token.spec.ts | should send USDC amount 50% to an address |
CV tests will handle these combinations |
`app/components/Views/confirmations/components/send/send.view.test.tsx`
|
| send-erc20-token.spec.ts | should send USDC send max to an address |
CV tests will handle these combinations |
`app/components/Views/confirmations/components/send/send.view.test.tsx`
|
| send-native-token.spec.ts | should send ETH to an address | PARTIALLY:
We should only cover ETH send, no need to cover 50% and Max |
`app/components/Views/confirmations/components/send/send.view.test.tsx`
|
| send-solana-token.spec.ts | should send solana to an address | This is
not actually sending anything, just checking that the text matches |
`app/components/Views/confirmations/components/send/send.non-evm.view.test.tsx`
|
| alert-system.spec.ts | should sign typed message | Moved to yes as per
team review |
`app/components/Views/confirmations/components/alert-banner/alert-system-typed-sign-blockaid.view.test.tsx`
|
| alert-system.spec.ts | should show security alert for malicious
request, acknowledge and confirm the signature | Moved to yes as per
team review |
`app/components/Views/confirmations/components/alert-banner/alert-system-typed-sign-blockaid.view.test.tsx`
|
| alert-system.spec.ts | should show security alert for error when
validating request fails | |
`app/components/Views/confirmations/components/alert-banner/alert-system-security-failed.view.test.tsx`
|
| alert-system.spec.ts | should show mismatch field alert, click the
alert, acknowledge and confirm the signature | As long as the component
is the same we can do this via CV test |
`app/components/Views/confirmations/components/alert-banner/alert-system-siwe-inline-mismatch.view.test.tsx`
|
| gas-fee-tokens-eip-7702-sponsored.spec.ts | fails transaction if error
occurs on API | |
`app/components/Views/confirmations/components/activity/eip-7702-sponsored-relay-api-failure.view.test.tsx`
|
| enable-notifications-after-onboarding.spec.ts | should enable
notifications and view feature announcements and wallet notifications |
Test is not doing what its title implies; skipped pending owner
discussion |
`app/components/Views/Notifications/NotificationsView.view.test.tsx` |
| notification-settings-flow.spec.ts | should enable notifications and
toggle feature announcements and account notifications | UI-only
validation, suitable for CV |
`app/components/Views/Settings/NotificationsSettings/NotificationsSettings.view.test.tsx`
|
| add-popular-networks.spec.ts | adds a popular network directly without
confirmation modal | This is not in prod anymore | *No matching
`*.view.test.tsx` on this branch* |


## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: N/A

  Scenario: Automated tests only
    Given developer checks out this branch
    When they run yarn test:view for the touched view test files
    Then tests pass
```

## **Screenshots/Recordings**

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

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**
> Low product risk since changes are test-only, but moderate test-suite
risk due to new integration-style view tests, new engine/nock mocks, and
`jest.config.view.js` forcing `IS_TEST=true` for feature-gated code
paths.
> 
> **Overview**
> Adds **component-view (CV) test coverage** for several flows
previously validated only by smoke E2E: DeFi protocol position details,
token Market Insights (including entry card gating + swap/buy navigation
+ sources sheet + feedback), notifications list/details and notification
settings toggles, confirmation alert-system (typed-sign Blockaid
benign/malicious + SIWE domain mismatch inline + validation-failed
banner), and EIP-7702 sponsored send (failed activity status + “Paid by
MetaMask” fee row).
> 
> Extends CV test infrastructure with new presets/helpers and mocks
(notifications state seeding, Market Insights navigation
renderer/preset, SnapController request interceptor, Sentinel
`/networks` nock mock), adds/normalizes several `testId` constants (send
50% button, confirmation transfer loader, status-icon tooltip), and sets
`process.env.IS_TEST=true` at view-jest config load time to satisfy
env-inlined feature gates.
> 
> Removes or skips corresponding smoke E2E specs (or individual cases)
and updates fixtures/assertions (e.g., SIWE signer address) to align
with the new CV coverage.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6098045. 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>
…liquidation and bonus messages (#29779)

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

## **Description**

Turkish copy used `%{{variable}}` so a literal percent could sit before
the interpolated value. **i18n-js** (used by `react-native-i18n`) treats
`%` followed by `{` as the start of a `%{name}` placeholder, so
`%{{...}}` was parsed as one invalid token and users saw messages like
`[missing %{{apy}} value]` instead of the real value.

All affected `tr.json` strings were updated to **`%%{variable}`**: a
literal `%` plus the supported `%{variable}` interpolation, preserving
“percent before number” wording while matching the same interpolation
keys the app already passes (`apy`, `percentage`, `fee`, `distance`,
etc.). No application code changes.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fixed Turkish strings that showed broken i18n
placeholders when a percent sign appeared before an interpolated value.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Turkish locale i18n placeholders

  Scenario: APY and bonus copy interpolate with a leading percent
    Given the app language is set to Türkçe (tr)
    And the user opens a surface that shows Money APY label, MetaMask Card APY bullet, earn/mUSD bonus copy, bridge fee disclaimer, swap slippage errors, or perps liquidation distance strings

    When those screens render

    Then no string should contain a substring like "[missing" or "value]"
    And percent-prefixed values should show as "%" immediately followed by the numeric or formatted value (e.g. "%4" for APY), not a raw placeholder token
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

<!--
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**
> Low risk translation-only change that adjusts placeholder formatting;
main risk is minor copy/interpolation regressions if any key names are
mismatched.
> 
> **Overview**
> Fixes broken Turkish (`tr.json`) interpolations where a leading
percent sign caused i18n placeholders like `%{{percentage}}` to be
parsed incorrectly.
> 
> Updates affected strings (perps liquidation/fees, swap/bridge fee and
slippage messages, earn/mUSD bonus and APY/cashback labels) to use
`%%{...}` so the UI shows a literal `%` followed by the interpolated
value.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4a6b57e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

### Problem

Android E2E runs are crashing with `Error: kill EPERM` in the "Set up
E2E environment" step
([example](https://github.com/MetaMask/metamask-mobile/actions/runs/25337405885/job/74288509502?pr=29670)).
This was introduced by #29236, which wrapped `sudo apt-get` inside
`nick-fields/retry` with `timeout_minutes: 3`.

**Root cause:** When the 3-minute timeout fires, `nick-fields/retry`
calls `process.kill()` on the child process. But `sudo apt-get` runs as
**root** while the Cirrus runner process runs as **admin** — Node.js
gets `EPERM` (permission denied) on the kill syscall. This is a [known
upstream bug](nick-fields/retry#124) (open
since Oct 2023, 11 upvotes, unpatched).

**Why the timeout fires:** `DPkg::Lock::Timeout=120` means `apt-get` can
legitimately wait up to 120s for the dpkg lock on each of the two `sudo`
calls (`update` + `install`). With slow Ubuntu mirrors on top, total
time can approach or exceed 180s (3 min), triggering the timeout. The
3-minute value was tightened from the original 5-minute design in a
follow-up commit on #29236, which didn't account for the double
lock-wait scenario.

### Fix

1. **Restore `timeout_minutes` from 3 to 5** — gives 300s per attempt.
Even worst-case (120s lock on update + 120s lock on install + 30s actual
install = 270s) fits with 30s headroom. `apt-get` resolves on its own
(success or dpkg lock timeout error) before the retry timeout fires, so
the `process.kill()` path — and the EPERM bug — is never hit.

2. **Add `retry_on: error`** — only retry when `apt-get` exits with a
non-zero code (mirror desync, lock timeout), not when
`nick-fields/retry`'s own timeout fires. A timeout-triggered retry would
crash with EPERM anyway, so this avoids a wasted attempt.

### Timing analysis

| Scenario | Duration | Fits in 5 min? |
|----------|----------|----------------|
| Happy path (no lock, fast mirror) | 5-15s | Yes (295s margin) |
| Lock on one call + normal mirror | 120s + 15s = 135s | Yes (165s
margin) |
| Lock on both calls + slow mirror | 240s + 30s = 270s | Yes (30s
margin) |
| Lock on both + very slow mirror | 240s + 60s = 300s | Boundary — but
this is extremely unlikely |

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: INFRA-3580
Fixes regression from #29236

## **Manual testing steps**

N/A — CI infrastructure fix. Validated by any Android E2E workflow run.
The timeout increase is transparent in the happy path (apt-get takes
5-15s).

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

Made with [Cursor](https://cursor.com)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk CI-only change that adjusts retry behavior for Linux
`apt-get` during Android E2E setup; primary impact is longer waits
before failing and fewer timeout-triggered retries.
> 
> **Overview**
> Reduces flaky Android E2E setup failures by updating the
`setup-e2e-env` composite action to **increase** the `nick-fields/retry`
`apt-get` wrapper timeout from 3 to 5 minutes.
> 
> The retry wrapper is also configured with `retry_on: error` so retries
only happen on non-zero exits, avoiding retries triggered by the
action's own timeout.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8bcc995. 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>
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## **Description**

This PR fixes token logo rendering for non-native assets when
`asset.image` is empty (the issue affecting mUSD/Money integration).

The `AssetLogo` component now:
- computes a fallback icon URL via `getAssetImageUrl` when the primary
image is missing,
- only attempts fallback generation for valid CAIP or strict-hex chain
IDs,
- passes `imageSource={{ uri: imageUri }}` so undefined URI values are
handled directly by `AvatarToken`.

It also adds unit tests to cover fallback behavior and unsupported
chain-id behavior.

## **Changelog**

CHANGELOG entry: fix: fixed token list items to use a fallback icon when
token image URLs are missing

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Token list item image fallback

  Scenario: Token with missing image URL still shows an icon
    Given a token list item where asset.image is empty
    When the token list item renders
    Then AssetLogo resolves and uses a fallback image URL for valid chain IDs
    And the token icon is shown instead of an empty image

  Scenario: Unsupported chain id does not crash icon rendering
    Given a token list item where asset.image is empty and chainId is unsupported
    When the token list item renders
    Then AssetLogo does not attempt invalid fallback URL generation
    And AvatarToken renders safely when uri is undefined
```

## **Screenshots/Recordings**

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

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_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-9a3458e2-b19c-40ef-b02b-feb8b7c2fa93"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-9a3458e2-b19c-40ef-b02b-feb8b7c2fa93"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…res that were disabled due to feature flag updates (#29154)

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

## **Description**

Brings Predict E2E test feature flag mocks into parity with production
values.

Two remote feature flag overrides in predict smoke tests diverged from
production after a feature flag registry sync ([PR
#28444](#28444)). This
PR aligns the mocks:

- **`exploreSectionsOrder`**: Replaced the explicit section ordering
arrays with `{}` in 4 predict smoke specs. On production this flag is
empty; the app falls back to hardcoded defaults which produce the same
layout. The Homepage component does not consume this flag at all — it
only affects TrendingView/Explore, which these tests don't exercise.
- **`predictLiveSports`**: Added `'nba'` to the leagues list (now
`['nfl', 'nba']`) to match production. This causes NBA markets (Spurs
vs. Pelicans) to render via `PredictGameDetailsContent`, which uses a
different cash-out button test ID
(`predict-picks-cash-out-button-{positionId}`). Updated the
`PredictDetailsPage` page object with a new
`tapGameCashOutButton(positionId)` method and updated
`predict-cash-out.spec.ts` to use it.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[MMQA-1711](https://consensyssoftware.atlassian.net/browse/MMQA-1711)

## **Manual testing steps**

<!-- Gherkin scenarios for this change -->

**Feature: Predict E2E prod parity**

**Scenario: Cash out on NBA game market uses correct button**
- Given the predict smoke tests use production-parity feature flag mocks
- When the predict-cash-out test runs against Spurs vs. Pelicans
- Then the test taps the game-details cash-out button (PredictPickItem
testID)
- And the cash-out flow completes successfully

**Scenario: Predict tests work without explicit exploreSectionsOrder**
- Given exploreSectionsOrder is set to `{}` in all predict smoke specs
- When any predict smoke test runs (cash-out, open-position,
geo-restriction, withdraw)
- Then the Homepage renders with the default section order
- And the test navigates to predictions by test ID without issue

## **Screenshots/Recordings**

### **Before**

N/A — test-only changes, no UI impact.

### **After**

N/A — test-only changes, no UI impact.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

[MMQA-1711]:
https://consensyssoftware.atlassian.net/browse/MMQA-1711?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Test-only changes that adjust feature-flag mocks and E2E selectors;
low product risk, but could affect Predict smoke test stability if
testIDs/position IDs drift.
> 
> **Overview**
> Aligns Predict E2E remote feature-flag mocks with current production
defaults by removing the `predictLiveSports` override from
`remoteFeatureFlagPredictEnabled`.
> 
> Updates Predict smoke specs to interact with the *game-details* UI:
adds a shared `SPURS_PELICANS_POSITION_ID`, introduces
`PredictDetailsPage.tapGameCashOutButton(positionId)` and
`tapGameBetYesButton()`, and switches cash-out/position-opening tests to
use the new testIDs for NBA/game markets.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f452736. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## **Description**

Adds the missing collection name field to the NFT details screen. The
data already existed on `collectible.collection.name`, but the screen
did not render it.

## **Changelog**

CHANGELOG entry: fix: NFT details did not show the collection name

## **Related issues**

Fixes: #29362
https://consensyssoftware.atlassian.net/browse/ASSETS-3125

## **Manual testing steps**

```gherkin
Feature: NFT details collection metadata

  Scenario: User views an NFT details page
    Given the user has imported NFTs from a collection
    When user opens the details screen for one NFT
    Then the screen displays the collection name in the Collection section
```

## **Screenshots/Recordings**

### **Before**

### **After**

<img width="318" height="102" alt="Screenshot 2026-05-07 at 10 49 53"
src="https://github.com/user-attachments/assets/6e3bd63d-e2db-46ab-990f-2e6d9f5193b7"
/>

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

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

<div><a
href="https://cursor.com/agents/bc-2131bb9a-ffff-464e-9da8-8a287e0d8b37"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-2131bb9a-ffff-464e-9da8-8a287e0d8b37"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

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

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Updated money account deposit.

## **Related issues**

Depends on: #29561
Depends on: MetaMask/core#8687

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

#### 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**
> Updates Money Account deposit transaction construction and
confirmation re-encoding, which can affect on-chain calldata and Pay
gating via `requiredAssets`, though it is still using a zero-amount
placeholder by default.
> 
> **Overview**
> Adds a Money Account deposit initiation path that submits an
`addTransactionBatch` for approve+deposit with a **zero-amount
placeholder**, navigates to the `CustomAmount` confirmation screen, and
declares Pay `requiredAssets` using a shared deposit-asset helper.
> 
> Implements real `updateMoneyAccountDepositTokenAmount` re-encoding:
converts the user-entered human amount to USDC base units, calls
`previewDeposit` to compute `minimumMint` (with slippage), and returns
updated calldata for the nested approve/deposit calls; it no-ops when
vault config/provider is unavailable.
> 
> Refactors deposit asset handling into
`getMoneyAccountDepositAssetAddress` (currently hardcoded USDC), skips
the `previewDeposit` RPC for 0 amounts, updates/extends unit tests and
confirmation mocks, and bumps `@metamask/transaction-controller` to
`65.1.0`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5ef8804. 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: Jyoti Puri <jyotipuri@gmail.com>
## **Description**

INFRA-3592 Phase 0 — adds a `runner_provider` control input (`current` |
`namespace`, default `current`) to the Phase 1-4 entry-point and
reusable workflows, threads forwarding through every in-scope caller,
and wraps each in-scope `runs-on:` in an additive ternary that selects
between the existing runner and the matching `namespace-profile-*`
label.

**No job is migrated. No default is changed.** With `runner_provider:
current` (the default on every existing trigger) every ternary collapses
to its prior literal/expression, so behavior is byte-identical to
`main`. The `namespace` branch is reachable only via manual
`workflow_dispatch`.

Branch is the long-lived working surface for Phases 1-4; do not merge.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[INFRA-3592](https://consensyssoftware.atlassian.net/browse/INFRA-3592)
(parent epic INFRA-3511)

## **Manual testing steps**

```gherkin
Feature: runner_provider trial control plane

  Scenario: dispatch on the current default — byte-identical
    Given the trial branch namespace-runner-trial
    When user runs `gh workflow run ci.yml --ref namespace-runner-trial -f runner_provider=current`
    Then every job runs on its existing GitHub-hosted / Cirrus runner
    And required-check context names match origin/main exactly

  Scenario: dispatch on namespace — plumbing reaches Namespace
    Given the trial branch and the MetaMask Actions allowlist already updated
    When user runs `gh workflow run ci.yml --ref namespace-runner-trial -f runner_provider=namespace`
    Then jobs are picked up by the namespace-profile-metamask-* runner that maps to each existing class
    And end-to-end success is not required at Phase 0 — composite-action assumptions land in Phase 2-4
```

## **Verification evidence (already executed)**

Both scenarios above were dispatched against this branch — results
recorded:

| Scenario | Run | Result |
| --- | --- | --- |
| `runner_provider=namespace` (Namespace path) |
[25319648133](https://github.com/MetaMask/metamask-mobile/actions/runs/25319648133)
| Linux, iOS, Android jobs all picked up by the matching
`namespace-profile-metamask-*` runner; secrets resolved end-to-end
(`secrets: inherit` flowing); job names + required-check contexts
unchanged |
| `runner_provider=current` (existing runners) |
[25320925061](https://github.com/MetaMask/metamask-mobile/actions/runs/25320925061)
| 0 Namespace instances spawned in the dispatch window; every job ran on
its prior GitHub-hosted / Cirrus runner |
| Implicit `current` via PR-trigger (no input) |
[25174041735](https://github.com/MetaMask/metamask-mobile/actions/runs/25174041735),
[25162883313](https://github.com/MetaMask/metamask-mobile/actions/runs/25162883313)
| Both `pull_request` runs on the branch completed successfully on
existing runners — proves the byte-identical contract holds without a
manual dispatch |

Required-check parity verified statically against the 3 contexts on
`main`'s branch protection (`check-template-and-add-labels`, `Check all
jobs pass`, `CLABot`) — none renamed in this diff. Detailed
cross-reference in INFRA-3592 [comment 417866
§5](https://consensyssoftware.atlassian.net/browse/INFRA-3592).

## **Screenshots/Recordings**

N/A — CI infrastructure PR, no UI surface.

## **Notes for reviewers**

- 6 commits, organised so each is independently reviewable: actionlint
label registration → `workflow_dispatch` inputs → `workflow_call` inputs
→ caller forwarding → `runs-on` ternary → placeholder→canonical-label
replacement.
- Phase 7 callers (`runway-*`, `nightly-build`,
`build-and-upload-to-testflight`, `push-eas-update`, `build-rc-auto`)
are intentionally **not** modified — they continue to call without
forwarding, callees default to `current`.
- Composite actions are inventoried only — Phase 2/3/4/5/7 own their
migration.
- `actionlint -config-file .github/actionlint.yaml` produces
byte-identical output to `origin/main` (84 lines, exit 1 from
pre-existing warnings only — no new findings introduced by this PR).
- Inventories captured (composite actions, caller graph,
secrets/environments, concurrency groups, required-check contexts) —
full tables in INFRA-3592 [comment
417866](https://consensyssoftware.atlassian.net/browse/INFRA-3592).
- Branch was rebased onto current `main` after a conflict with
[#29431](#29431) (e2e
label rename). Conflict resolution was mechanical — main's renamed jobs
(swap-, stake-, money-) had `runner_provider:` re-applied; no semantic
decision involved.

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (`team-dev-ops`, `size-M`)

#### Performance checks (if applicable)

N/A — workflow YAML only, no app code.

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


[INFRA-3592]:
https://consensyssoftware.atlassian.net/browse/INFRA-3592?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches many GitHub Actions workflows and `runs-on` expressions, so
miswiring could break CI execution or route jobs to the wrong runner.
Default behavior remains `current`, but the new `namespace` path changes
execution environment when manually dispatched.
> 
> **Overview**
> Introduces a new `runner_provider` input (default `current`, optional
`namespace`) across in-scope entrypoint and reusable workflows, and
forwards it through callers.
> 
> Updates `runs-on` in `ci.yml`, `build.yml`, `setup-node-modules.yml`,
and E2E build/test workflows to conditionally select between existing
GitHub-hosted/Cirrus runners and new `namespace-profile-metamask-*`
runner labels.
> 
> Registers the new `namespace-profile-*` labels in
`.github/actionlint.yaml`, and adds `workflow_dispatch` inputs to enable
manual trial runs using the namespace provider.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fffcc88. 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.
-->

## **Description**

Wires 5 events for Whats Happening analytics:

Card Scrolled to View, emitted via `useViewportTracking` in
WhatsHappeningCard
Opened — emitted in `WhatsHappeningSection` on card press and View All
Viewed — emitted in `WhatsHappeningDetailView` on initial mount and on
each carousel scroll
Interaction — emitted in `TokenRow` 
Closed — emitted in `WhatsHappeningDetailView` on back press

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

#### 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**
> Adds new analytics instrumentation across the Whats Happening homepage
section and detail flow, including new component props and
scroll/visibility hooks that could subtly affect rendering or event
duplication if indices/items drift.
> 
> **Overview**
> Adds a full set of **MetaMetrics Whats Happening** events (new
constants in `MetaMetrics.events.ts`) and wires them through the
homepage section and detail experience.
> 
> Homepage now tracks `WHATS_HAPPENING_OPENED` with an `entry_point` for
both card taps and *View more*, and cards emit
`WHATS_HAPPENING_CARD_SCROLLED_TO_VIEW` via `useViewportTracking`
(introducing a required `cardIndex` prop).
> 
> Detail view now tracks `WHATS_HAPPENING_VIEWED` once on initial mount
and again when the carousel settles on a new index, and tracks
`WHATS_HAPPENING_CLOSED` on back. Token/perps CTAs and source link
presses now emit `WHATS_HAPPENING_INTERACTION` with standardized
properties via the new shared helper `getWhatsHappeningEventProps` (plus
`interaction_type` and asset/source fields).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9d3ed1a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

INFRA-3593 Phase 1 — adds Namespace Cache Volumes integration to the
Linux CI jobs on the `namespace-runner-trial` branch.

When `runner_provider: namespace` is dispatched, the 8 Linux CI jobs
that install dependencies now:
1. Mount a Namespace Cache Volume via `nscloud-cache-action` covering
`~/.cache/yarn`, `.metamask`, `node_modules`, `.yarn/cache`, and
`.yarn/install-state.gz`
2. Skip `actions/setup-node` Yarn caching (set to empty string) to avoid
duplicate network-backed cache traffic
3. Skip `actions/cache` for `node_modules` in `component-view-tests` and
`merge-unit-and-component-view-tests` (Namespace cache already covers
it)

When `runner_provider: current` (the default on every existing trigger),
all ternaries collapse to their prior values and behavior is
byte-identical to the base branch.

**No job is renamed. No default is changed.** This is an additive,
opt-in change activated only via manual `workflow_dispatch` with
`runner_provider: namespace`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: INFRA-3593 (parent epic INFRA-3511)
Refs: INFRA-3592 (Phase 0, PR #29557)

## **Manual testing steps**

```gherkin
Feature: Namespace Cache Volumes on Linux CI

  Scenario: dispatch with namespace provider — cache volumes active
    Given the branch phase1-namespace-linux-cache
    When user runs `gh workflow run ci.yml --ref phase1-namespace-linux-cache -f runner_provider=namespace`
    Then all 8 Linux CI jobs with dependencies use nscloud-cache-action
    And actions/setup-node Yarn caching is disabled (no duplicate cache traffic)
    And all jobs pass across every matrix shard (unit-tests x10, component-view-tests x2, scripts x6)

  Scenario: dispatch with current provider — byte-identical to base
    Given the branch phase1-namespace-linux-cache
    When user runs `gh workflow run ci.yml --ref phase1-namespace-linux-cache -f runner_provider=current`
    Then nscloud-cache-action steps are skipped (if condition is false)
    And actions/setup-node uses cache: yarn as before
    And actions/cache for node_modules runs as before
    And all jobs pass on GitHub-hosted runners

  Scenario: implicit current via PR/push trigger
    Given a push or pull_request event (no workflow_dispatch)
    Then inputs.runner_provider is undefined/empty
    And all ternaries collapse to existing behavior
```

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

N/A — CI infrastructure PR, no UI surface.

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

N/A — workflow YAML only, no app code.

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

Made with [Cursor](https://cursor.com)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches many GitHub Actions workflows to optionally switch runner
labels and caching behavior, which could break CI execution or cause
cache-related flakiness when enabled. Default behavior remains unchanged
unless `runner_provider=namespace` is explicitly selected.
> 
> **Overview**
> Introduces a `runner_provider` input (with `workflow_dispatch` choices
where relevant) to route jobs between existing runners and new
`namespace-profile-*` runner labels across `ci.yml`, reusable build
workflows, and E2E smoke/regression workflows.
> 
> When `runner_provider=namespace`, Linux CI jobs that install
dependencies mount Namespace cache volumes via
`namespacelabs/nscloud-cache-action`, disable `actions/setup-node` Yarn
caching, and skip `actions/cache`-based `node_modules` restores in
coverage-merge/component-view jobs; Node memory limits are also reduced
on Namespace runners.
> 
> Updates `actionlint` configuration to allow the new Namespace runner
profile labels.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3a52111. 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: Jose Luque <jose.luque@consensys.net>
Co-authored-by: José Manuel <6741785+jluque0101@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…r Android build (#29777)

## **Description**

INFRA-3595 Phase 3 — adds Namespace Cache Volumes integration to the
Android build and setup workflows, and fixes the GRADLE_USER_HOME path
mismatch that blocked Android builds on Namespace runners.

**Changes:**

1. **`build-android-e2e.yml`**: Make `GRADLE_USER_HOME` conditional on
`runner_provider` (`/home/runner/_work/.gradle` on Namespace vs
`/home/admin/_work/.gradle` on Cirrus). Add `nscloud-cache-action`
covering yarn, .metamask, node_modules, .yarn/cache, and Gradle
caches/wrapper. Gate all 4 `cirruslabs/cache` steps on `runner_provider
!= 'namespace'`. On Namespace, always run full build (no APK fingerprint
cache since cirruslabs/cache is skipped).

2. **`setup-node-modules.yml`**: Add `nscloud-cache-action` before
dependency install. Make `setup-node` `cache:` conditional (disabled on
Namespace). Gate `.metamask` `actions/cache` on current path.

**Both cache paths coexist for rollback safety.** When `runner_provider:
current` (default on all triggers), all ternaries collapse to prior
values — cirruslabs/cache runs, nscloud-cache-action is skipped.
Behavior is byte-identical to the base branch.

Builds on Phase 1 (PR #29716) and Phase 0 (PR #29557).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: INFRA-3595 (parent epic INFRA-3511)
Refs: INFRA-3592 (Phase 0, PR #29557), INFRA-3593 (Phase 1, PR #29716)

## **Manual testing steps**

```gherkin
Feature: Android build on Namespace runners

  Scenario: dispatch with namespace provider — Android build succeeds
    Given the branch phase3-namespace-android
    When user runs `gh workflow run ci.yml --ref phase3-namespace-android -f runner_provider=namespace`
    Then Build Android E2E APKs succeeds on namespace-profile-metamask-android-build
    And GRADLE_USER_HOME resolves to /home/runner/_work/.gradle
    And nscloud-cache-action caches Gradle deps and yarn/node_modules
    And cirruslabs/cache steps are skipped

  Scenario: dispatch with current provider — byte-identical to base
    Given the branch phase3-namespace-android
    When user runs `gh workflow run ci.yml --ref phase3-namespace-android -f runner_provider=current`
    Then Build Android E2E APKs succeeds on Cirrus ubuntu-runner-amd64
    And GRADLE_USER_HOME resolves to /home/admin/_work/.gradle
    And cirruslabs/cache steps run as before
    And nscloud-cache-action steps are skipped

  Scenario: implicit current via PR/push trigger
    Given a push or pull_request event (no workflow_dispatch)
    Then inputs.runner_provider is undefined/empty
    And all ternaries collapse to existing behavior
```

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

N/A — CI infrastructure PR, no UI surface.

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

N/A — workflow YAML only, no app code.

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

Made with [Cursor](https://cursor.com)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes runner selection and caching behavior
across core CI/build/E2E workflows, which can impact build determinism
and job reliability. Default behavior remains `current`, but the new
`namespace` path introduces new cache tooling and environment
differences (e.g., Gradle home).
> 
> **Overview**
> Adds an opt-in `runner_provider` switch across CI, build, and E2E
workflows to route jobs to Namespace runner profiles (new labels added
to `actionlint.yaml`) instead of the existing GitHub/Cirrus runners.
> 
> When `runner_provider=namespace`, enables
`namespacelabs/nscloud-cache-action` for Yarn/`node_modules`/`.metamask`
(and Gradle caches for Android), disables existing
`actions/cache`/`cirruslabs/cache` steps where incompatible, and adjusts
Android `GRADLE_USER_HOME` to the Namespace filesystem layout. Manual
dispatch workflows (e.g., `ci.yml`, `build.yml`, Expo dev build, and E2E
regression runs) now expose `runner_provider` as an input and forward it
through reusable workflows.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
207bf39. 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: Jose Luque <jose.luque@consensys.net>
Co-authored-by: José Manuel <6741785+jluque0101@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description**

Add sort direction indicators to trending token filter buttons to
improve UX by making the current sort order immediately visible.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Adds sort icons on filter bar in trending list

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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



https://github.com/user-attachments/assets/2b7ac0c1-fe27-4ec8-bcd3-2bcd459ce306



## **Pre-merge author checklist**

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

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

#### 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**
> Low risk UI enhancement that only adds derived state and icon
rendering for the sort button; minimal chance of regressions outside the
Trending filter bar layout.
> 
> **Overview**
> Adds a sort-direction indicator to the Trending token list
price-change filter.
> 
> `FilterButton`/`FilterBar` now accept an optional
`iconName`/`priceChangeIconName` and render that icon before the label.
`useTokenListFilters` exposes a new `priceChangeSortDirectionIcon`
(up/down) derived from `priceChangeSortDirection`, `TokenListPageLayout`
wires it into the `FilterBar`, and tests cover the new icon mapping.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0c6e926. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-bots Bot team (for MetaMask Bot, Runway Bot, etc.) label May 14, 2026
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 14, 2026

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

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​metamask/​snaps-rpc-methods@​16.0.099100769550
Updatednpm/​@​metamask/​snaps-controllers@​20.0.3 ⏵ 20.0.56610076 +198 +150
Updatednpm/​@​metamask/​eth-snap-keyring@​20.0.0 ⏵ 22.0.19810091 -196 +250
Updatednpm/​@​metamask/​assets-controller@​6.2.1 ⏵ 6.4.06910080 +198 +1100
Updatednpm/​@​metamask/​assets-controllers@​104.3.0 ⏵ 106.0.072 +110091 +198100
Updatednpm/​@​react-native/​metro-config@​0.76.9 ⏵ 0.81.5100 +110073 +197100
Updatednpm/​@​metamask/​keyring-internal-api@​10.1.1 ⏵ 11.0.11001007395100
Updatednpm/​@​metamask/​eth-money-keyring@​2.0.0 ⏵ 2.0.473 +11008194 +3100
Addednpm/​@​metamask/​chomp-api-service@​3.1.0731007594100
Updatednpm/​@​metamask/​authenticated-user-storage@​1.0.0 ⏵ 1.0.17310010091 +2100
Updatednpm/​@​metamask/​money-account-controller@​0.1.0 ⏵ 0.2.0741007391 +2100
Updatednpm/​react-native-mmkv@​3.2.0 ⏵ 4.3.1100 +11007490 -1100
Updatednpm/​expo-splash-screen@​0.29.24 ⏵ 31.0.1374 +1100100 +1100 +1100
Updatednpm/​expo-haptics@​14.0.1 ⏵ 15.0.874 +210084 +2100 +1100
Updatednpm/​@​metamask/​keyring-utils@​3.2.0 ⏵ 3.3.1100 +110074 +191 +6100
Updatednpm/​@​metamask/​ai-controllers@​0.6.0 ⏵ 0.6.374 +110074 +196 +2100
Updatednpm/​@​metamask/​multichain-transactions-controller@​7.0.4 ⏵ 7.1.09810074 +196 -1100
Updatednpm/​@​metamask/​money-account-balance-service@​0.2.0 ⏵ 1.0.074 +110075 +292 +1100
Updatednpm/​@​react-native-community/​cli@​15.0.1 ⏵ 20.0.098 +110075 +191100
Updatednpm/​@​metamask/​keyring-sdk@​1.2.0 ⏵ 2.0.275 +110085 +194 +2100
Addednpm/​@​metamask/​money-account-upgrade-controller@​2.0.1751007695100
Updatednpm/​@​metamask/​eth-qr-keyring@​1.1.0 ⏵ 2.0.299 +2510075 +793 +2100
Updatednpm/​@​metamask/​keyring-snap-client@​9.0.1 ⏵ 9.0.2991007594 -1100
Updatednpm/​@​metamask/​gas-fee-controller@​26.1.1 ⏵ 26.2.19910076 +195 +3100
Updatednpm/​@​metamask/​remote-feature-flag-controller@​4.2.0 ⏵ 4.2.1991007694 +2100
Updatednpm/​@​metamask/​account-api@​1.0.3 ⏵ 1.0.41001007696 +2100
Updatednpm/​@​metamask/​multichain-network-controller@​3.0.6 ⏵ 3.1.19810076 +196 -1100
Updatednpm/​expo-screen-orientation@​8.0.4 ⏵ 9.0.87610086 +1100100
Updatednpm/​@​segment/​analytics-react-native@​2.20.3 ⏵ 2.22.098 -110076 +195 +5100
Updatednpm/​@​metamask/​multichain-api-middleware@​2.0.0 ⏵ 3.1.19910076 +196 +2100
Updatednpm/​@​metamask/​earn-controller@​12.0.0 ⏵ 12.1.0971007797100
Updatednpm/​@​metamask/​core-backend@​6.2.1 ⏵ 6.3.077 +110010096 +2100
See 63 more rows in the dashboard

View full report

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 14, 2026

Caution

MetaMask internal reviewing guidelines:

  • Do not ignore-all
  • Each alert has instructions on how to review if you don't know what it means. If lost, ask your Security Liaison or the supply-chain group
  • Copy-paste ignore lines for specific packages or a group of one kind with a note on what research you did to deem it safe.
    @SocketSecurity ignore npm/PACKAGE@VERSION
Action Severity Alert  (click "▶" to expand/collapse)
Block Medium
System shell access: gem benchmark

Location: Package overview

From: ios/Gemfile.lockgem/benchmark@0.5.0

ℹ Read more on: This package | This alert | What is shell access?

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

Suggestion: Packages should avoid accessing the shell which can reduce portability, and make it easier for malicious shell access to be introduced.

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

Block Medium
Network access: npm @expo/metro-config in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: ?npm/expo@54.0.33npm/@expo/metro-config@54.0.14

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
System shell access: npm @expo/sudo-prompt in module child_process

Module: child_process

Location: Package overview

From: ?npm/expo@54.0.33npm/@expo/sudo-prompt@9.3.2

ℹ Read more on: This package | This alert | What is shell access?

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

Suggestion: Packages should avoid accessing the shell which can reduce portability, and make it easier for malicious shell access to be introduced.

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

Block Medium
Network access: npm @metamask/chomp-api-service in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: package.jsonnpm/@metamask/chomp-api-service@3.1.0

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
Network access: npm @metamask/design-system-react-native in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: package.jsonnpm/@metamask/design-system-react-native@0.23.0

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
Network access: npm @sentry/react-native in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: package.jsonnpm/@sentry/react-native@7.2.0

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
Network access: npm glob in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: ?npm/expo-auth-session@7.0.10npm/expo-dev-client@6.0.20npm/expo-asset@12.0.12npm/expo-splash-screen@31.0.13npm/expo-updates@29.0.16npm/expo@54.0.33npm/glob@13.0.6

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
Network access: npm lan-network in module dgram

Module: dgram

Location: Package overview

From: ?npm/expo@54.0.33npm/lan-network@0.1.7

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
System shell access: npm lan-network in module child_process

Module: child_process

Location: Package overview

From: ?npm/expo@54.0.33npm/lan-network@0.1.7

ℹ Read more on: This package | This alert | What is shell access?

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

Suggestion: Packages should avoid accessing the shell which can reduce portability, and make it easier for malicious shell access to be introduced.

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

Block Medium
Network access: npm react-devtools-core in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: ?npm/react-native@0.81.5npm/react-devtools-core@6.1.5

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
Network access: npm react-native-mmkv in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: package.jsonnpm/react-native-mmkv@4.3.1

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Medium
Network access: npm react-native-video in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: package.jsonnpm/react-native-video@6.19.1

ℹ Read more on: This package | This alert | What is network access?

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

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

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

Block Low
Publisher changed: npm @expo/devcert is now published by kudochien instead of philpl

New Author: kudochien

Previous Author: philpl

From: ?npm/expo@54.0.33npm/@expo/devcert@1.2.1

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm @expo/plist is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo-auth-session@7.0.10npm/expo-dev-client@6.0.20npm/expo-asset@12.0.12npm/expo-splash-screen@31.0.13npm/expo-updates@29.0.16npm/expo@54.0.33npm/@expo/plist@0.4.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm @expo/schema-utils is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo@54.0.33npm/@expo/schema-utils@0.1.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-apple-authentication is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: package.jsonnpm/expo-apple-authentication@8.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-crypto is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo-auth-session@7.0.10npm/expo-crypto@15.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-eas-client is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo-updates@29.0.16npm/expo-eas-client@1.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-haptics is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: package.jsonnpm/expo-haptics@15.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-keep-awake is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo@54.0.33npm/expo-keep-awake@15.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-screen-orientation is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: package.jsonnpm/expo-screen-orientation@9.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-sensors is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: package.jsonnpm/expo-sensors@15.0.8

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-server is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo@54.0.33npm/expo-server@1.0.5

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Block Low
Publisher changed: npm expo-web-browser is now published by kudochien instead of expo-bot

New Author: kudochien

Previous Author: expo-bot

From: ?npm/expo-auth-session@7.0.10npm/expo-web-browser@15.0.10

ℹ Read more on: This package | This alert | What is new author?

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

Suggestion: Scrutinize new collaborator additions to packages because they now have the ability to publish code into your dependency tree. Packages should avoid frequent or unnecessary additions or changes to publishing rights.

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

Warn Medium
Deprecated by its maintainer: npm text-encoding with reason "no longer maintained"

Reason: no longer maintained

From: ?npm/react-native-qrcode-svg@6.3.21npm/text-encoding@0.7.0

ℹ Read more on: This package | This alert | What is a deprecated package?

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

Suggestion: Research the state of the package and determine if there are non-deprecated versions that can be used, or if it should be replaced with a new, supported solution.

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

Warn Low
Potential code anomaly (AI signal): npm @expo/cli is 100.0% likely to have a medium risk anomaly

Notes: The module implements conventional authentication flows (password login and SSO) with session management and a small in-memory cache for the current user. There is no explicit malicious behavior identified. The primary security considerations include secure handling of session secrets in headers, sanitization of logs to avoid leaking sensitive data, and careful management of filesystem cleanup to ensure it cannot affect unintended files. While the overall approach is typical and reasonable, the in-memory currentUser caching and logout-side effects warrant review to avoid stale data, accidental exposure, or misconfiguration in the code signing directory cleanup.

Confidence: 1.00

Severity: 0.60

From: ?npm/expo@54.0.33npm/@expo/cli@54.0.23

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

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

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

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

See 8 more rows in the dashboard

View full report

@chloeYue chloeYue added the skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. label May 15, 2026
runway-github Bot and others added 3 commits May 15, 2026 10:46
…or available count cp-7.78.0 (#30211)

- feat(rewards): benefits preview uses Tag for available count (#30196)

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

## **Description**

> **Section header spacing alignment:**

[`CampaignsPreview.tsx`](app/components/UI/Rewards/components/Campaigns/CampaignsPreview.tsx)
— the campaigns preview **header row** now uses **`gap-1`** instead of
**`gap-2`** between the title row items (spinner when shown, heading,
chevron), matching the **Benefits** preview header spacing on the
Rewards dashboard.

The Rewards dashboard **Benefits** preview header previously used a
numeric `BadgeCount` beside the section title. This change replaces it
with a design-system **`Tag`** (`TagSeverity.Neutral`) that shows how
many benefits are available using the localized string
`rewards.benefits.available_count` (e.g. `%{count} available` in
English). Counts above 99 display as `99+`.

The header row is full width with **`justifyContent: space-between`**:
the title and chevron stay on the leading side; the tag sits on the
**trailing** edge so it matches the intended layout. Spacing uses
`gap-1` between the title and chevron. The empty-state header no longer
renders a redundant null badge slot.

**Motivation:** Align with design (muted pill copy and alignment) and
keep copy in i18n for the translation pipeline (English source string
only in `en.json`).

**Automated tests:** `yarn jest
app/components/UI/Rewards/components/Benefits/BenefitsPreview.test.tsx`

## **Changelog**

CHANGELOG entry: Updated the Rewards benefits preview header to show how
many benefits are available using a tag label next to the section title;
aligned campaigns preview section header spacing with the benefits
preview (`gap-1`).

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Rewards benefits preview header

  Scenario: User sees benefits count when they have benefits
    Given the user is opted into Rewards and the benefits API returns at least one benefit

    When user opens the Rewards dashboard (home) and scrolls to the Benefits preview
    Then a neutral tag shows the correct count and available wording for the current locale
    And the tag is aligned to the far right of the header row with the title and chevron grouped on the left
    And tapping the header row still navigates to the full benefits view

  Scenario: User has no benefits
    Given the user has no benefits in the list

    When user opens the Rewards dashboard and views the Benefits preview
    Then the count tag is not shown and the empty state behaves as before

  Feature: Rewards campaigns preview header spacing

  Scenario: User compares section headers on Rewards home
    Given the user is on the Rewards dashboard home tab

    When user views the Campaigns preview section header
    Then the title row uses gap-1 between the title row elements, matching the Benefits preview header spacing
```

## **Screenshots/Recordings**

### **Before**

Numeric badge style (`BadgeCount`) adjacent to the Benefits title
(previous implementation).

### **After**

<img width="413" height="827" alt="image"

src="https://github.com/user-attachments/assets/bd00ee97-2ae3-4ccb-b924-51ba6d0ca677"
/>

Neutral `Tag` with “{count} available” (per locale), title + chevron on
the left, tag aligned to the trailing edge. (Screenshot also attached in
an earlier PR update.)

## **Pre-merge author checklist**

<!--
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**
> Low risk UI/i18n change with unit test updates; primary risk is minor
layout/regression in rewards preview headers and count formatting around
the 99/99+ boundary.
> 
> **Overview**
> The Benefits preview header now replaces the numeric `BadgeCount` with
a neutral design-system `Tag` that shows a localized
`rewards.benefits.available_count` label (capped to `99+`), and adjusts
header layout to keep the title+chevron grouped left with the tag
right-aligned.
> 
> Campaigns preview header spacing is tightened (`gap-1`), and tests
were expanded to cover the new benefits count behavior (including empty
state and 99/99+ cases) plus treating `undefined` campaigns as an empty
list. Adds the new English i18n key `rewards.benefits.available_count`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5ece706. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[f8f126d](f8f126d)

Co-authored-by: Andrew Cohen <imandrewcohen@gmail.com>
…running perf builds (#30224)

- fix: cp-7.78.0 add correct permissions to running perf builds (#30223)

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

## **Description**

> Updates the `run-performance-e2e-experimental.yml` and
`run-performance-e2e-release.yml` GitHub Actions workflows to grant
`permissions.contents: write` (instead of read-only) so they are at
least as permissive as the reusable `run-performance-e2e.yml` workflow
they call.
> 
> Adds an inline comment documenting the transitive requirement (via the
BrowserStack upload workflows).
> 
## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### 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**
> Low risk workflow-only change that broadens GitHub token permissions
to match the called reusable workflow; main risk is over-permissioning
if not actually required.
> 
> **Overview**
> Updates the `run-performance-e2e-experimental.yml` and
`run-performance-e2e-release.yml` GitHub Actions workflows to grant
`permissions.contents: write` (instead of read-only) so they are at
least as permissive as the reusable `run-performance-e2e.yml` workflow
they call.
> 
> Adds an inline comment documenting the transitive requirement (via the
BrowserStack upload workflows).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
54b2260. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[8fbb9a4](8fbb9a4)

Co-authored-by: Curtis David <Curtis.David7@gmail.com>
@github-actions

This comment has been minimized.

runway-github Bot and others added 4 commits May 15, 2026 12:52
…pay transactions in activity (#30217)

- fix: cp-7.77.0 cp-7.78.0 missing metamask pay transactions in activity
(#30145)

## **Description**

The Activity tab had several bugs causing MetaMask Pay transactions to
be missing, duplicated, or unreachable from the source chain. This PR
addresses four root causes in production code plus a test alignment for
the bridge smoke E2E:

1. **Source-chain visibility.** Submitted EVM transactions were filtered
strictly by `tx.chainId`, so a MetaMask Pay parent was only visible on
its destination chain. The source chain is recorded on
`metamaskPay.chainId` (for gasless flows) or on linked child
transactions via `requiredTransactionIds` (for non-gasless flows). A new
`selectRelatedChainIdsByTransactionId` selector returns the full set of
chain IDs a transaction relates to, and the Activity list now matches
against that set.

2. **Dedupe fallback collapsed internal MetaMask Pay transactions.**
When a transaction had no nonce, `selectLocalTransactions` fell back to
`txParams.actionId` as the dedupe key. `actionId` is a top-level field
on `TransactionMeta`, not on `txParams`, so for MetaMask Pay internal
transactions (which have no nonce) every entry collapsed onto the same
`undefined` key and all but one were dropped. The fallback now uses the
top-level `id`, which is always present.

3. **Local transactions were scoped to the wrong account.**
`selectLocalTransactions` gated on `selectEvmAddress` — the EVM address
of the **currently selected internal account**. When the user picked a
non-EVM account (e.g. Solana), this was `undefined` and the selector
returned an empty list. Switching to "All popular networks" did not
restore the address because that toggle changes enabled networks, not
the selected account. It now uses
`selectSelectedAccountGroupEvmInternalAccount`, the same source already
used by the Activity tab's API query.

4. **Incoming-transaction duplicates.** The `TransactionController`
incoming-transactions feature stores incoming transfers as separate
`TransactionMeta` entries marked with `isTransfer !== undefined`. The
accounts API also returns these transactions in its confirmed history,
producing duplicate rows in the Activity tab. The dedupe step now skips
entries with `isTransfer !== undefined`, leaving the accounts-API row as
the canonical source.

5. **Bridge smoke E2E row alignment.** The Activity list merges pending
smart transactions in alongside the real `TransactionMeta` row,
producing a stale shell entry that lands at row 0. `bridge-action-smoke`
was asserting on row 0 and timing out. The test now asserts on row 1,
with a TODO to remove the STX-state merge from the Activity selectors
and restore row 0.

## **Changelog**

CHANGELOG entry: Fixed MetaMask Pay transactions appearing duplicated or
missing from the Activity tab, including on the source chain and when
the selected account is non-EVM.

## **Related issues**

Fixes:
[#30066](#30066)

## **Manual testing steps**

```gherkin
Feature: MetaMask Pay Activity visibility

  Scenario: User views Activity on the chain that funded a MetaMask Pay transaction
    Given the user has completed a MetaMask Pay transaction funded by a token on chain X with destination chain Y
    And both chains X and Y are enabled networks

    When the user opens the Activity tab with chain X selected
    Then the MetaMask Pay transaction is visible in the list

    When the user opens the Activity tab with chain Y selected
    Then the MetaMask Pay transaction is also visible in the list

  Scenario: User views Activity after switching to a non-EVM account
    Given the user has pending MetaMask Pay transactions visible in the Activity tab

    When the user switches to a non-EVM account in the same account group
    And switches back to "All popular networks"
    Then the pending MetaMask Pay transactions remain visible

  Scenario: User views a single on-chain MetaMask Pay transaction
    Given the user has completed a single-chain MetaMask Pay transaction (for example an mUSD conversion)

    When the user opens the Activity tab
    Then the transaction appears exactly once
```

## **Screenshots/Recordings**

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### 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]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit f45d17e. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[ff95f16](ff95f16)

Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
…essibility cp-7.78.0 (#30233)

- chore: align carousel card heights for accessibility (#30201)

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

## **Description**

Use fluid heights on cards so large system text doesn’t clip.

Problem before: fixed heights + large accessibility text scaling =
content clipping inside cards.
Now: cards and skeletons are fully fluid (no height prop needed). Only
ViewMoreCard keeps a height, and only as a min-h directly inline in
WhatsHappeningSection, so it sits at the same height as a typical card
at normal font scale.

How it looks now with huge font:

<img height="800" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-14
at 18 39 46"

src="https://github.com/user-attachments/assets/9097c9eb-c49a-45c4-b998-2392c06676dc"
/>

And normal/default font size:
<img height="800" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-14
at 18 50 02"

src="https://github.com/user-attachments/assets/e4a61f2b-425a-44d4-b650-677f288304e0"
/>


## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### 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**
> Low risk UI/layout change to remove fixed card heights; main risk is
minor visual regression in carousel alignment across devices/font
scales.
> 
> **Overview**
> Makes the What’s Happening carousel cards and loading skeletons
**fluid-height** by removing the fixed Tailwind height prop
(`twHeightClassName`) from `WhatsHappeningCard` and
`WhatsHappeningCardSkeleton`, preventing content clipping with large
accessibility text.
> 
> Keeps the “View more” tile visually aligned by switching it to a
`min-h-[230px]` constraint, and updates the skeleton test to assert the
expected 2-line title and 3-line description placeholder configuration.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
00186c9. 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: Devin Stewart
<49423028+Bigshmow@users.noreply.github.com>
[a55aeb3](a55aeb3)

Co-authored-by: António Regadas <antonio.regadas@consensys.net>
Co-authored-by: Devin Stewart <49423028+Bigshmow@users.noreply.github.com>
@github-actions

This comment has been minimized.

runway-github Bot and others added 4 commits May 15, 2026 17:56
…ymarket withdraw (#30250)

- feat: cp-7.78.0 support deposit-wallet polymarket withdraw (#29953)

## **Description**

Adopts the new Polymarket deposit-wallet support landed in

[@metamask/transaction-pay-controller@22.5.0](MetaMask/core#8754)
so Polymarket users whose pUSD lives in a deposit wallet (a per-user
batch contract on Polygon) can withdraw cross-chain through MetaMask
Pay.

Highlights:

- Lets Polymarket deposit-wallet users withdraw cross-chain through
MetaMask Pay.
- Gated behind a new remote feature flag, with the existing "withdraw
unavailable" sheet preserved when off.
- Polishes Predict withdraw activity rendering.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

<!-- Internal -->

## **Manual testing steps**

```gherkin
Feature: Polymarket deposit-wallet withdraw

  Scenario: deposit-wallet user with the flag on
    Given enableDepositWalletWithdraw is on
    And the user has a Polymarket deposit wallet with pUSD balance on Polygon
    When the user taps Withdraw on the Predict balance
    Then the standard Pay confirmation opens
    And confirming submits via the Polymarket strategy with no Polygon gas

  Scenario: deposit-wallet user with the flag off
    Given enableDepositWalletWithdraw is off
    When the user taps Withdraw on the Predict balance
    Then the existing "Withdraw unavailable" sheet is shown
```

## **Screenshots/Recordings**

### **Before**

### **After**

<img width="300" alt="Activity"

src="https://github.com/user-attachments/assets/13d5a0e9-a39d-4c0a-9fde-468c5a0a7743"
/>

## **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
- [ ] 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**
> Changes withdrawal behavior and MetaMask Pay transaction configuration
for Polymarket `predictWithdraw`, including new controller callbacks and
retry logic; mistakes could impact withdraw routing/fees for affected
users. Gated by a remote feature flag, limiting blast radius.
> 
> **Overview**
> Enables Polymarket *deposit-wallet* users to run `predictWithdraw`
through MetaMask Pay when the new
`confirmations_pay_extended.enableDepositWalletWithdraw` flag is on;
when off, the existing “withdraw unavailable” handling remains.
> 
> Updates Predict/Pay plumbing for deposit-wallet withdraws:
`PredictController.prepareWithdraw` now omits `gasFeeToken` for
deposit-wallet accounts, `useTransactionPayPostQuote` skips `refundTo`
and marks `isPolymarketDepositWallet`, and Transaction Pay
initialization wires new Polymarket callbacks that can derive
deposit-wallet addresses and submit deposit-wallet batches (with “wallet
busy” retries + keyring signing support).
> 
> Polishes confirmations activity rendering for `predictWithdraw` by
adding a dedicated `predict_withdraw` title and treating it as a
receive-summary type using the source token/network metadata. Tests are
added/updated accordingly, and `@metamask/transaction-pay-controller` is
bumped to `22.5.0`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
054697c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[4997055](4997055)

Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
…ase branch (#30262)

- fix: cp-7.78.0 ensure perf e2e run on release branch (#30258)

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

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### 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**
> Low risk: only adjusts GitHub Actions gating logic for when the
performance E2E workflow runs, without touching app/runtime code.
> 
> **Overview**
> Ensures the `run-performance-e2e-release.yml` workflow runs for
**all** pushes to `release/*` branches (in addition to
`workflow_dispatch`), instead of only running on push when the commit
was a `metamaskbot` version bump.
> 
> Keeps the scheduled trigger behavior (checking for recent
`metamaskbot` version bumps) but updates comments/logging to reflect the
new push trigger conditions.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3cdedbe. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[c1071c4](c1071c4)

Co-authored-by: Curtis David <Curtis.David7@gmail.com>
@github-actions

This comment has been minimized.

runway-github Bot and others added 2 commits May 15, 2026 23:40
…ake it theme-aware cp-7.78.0 (#30273)

- fix(Rewards): Update theMiracle logo and make it theme-aware cp-7.78.0
(#30213)

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

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

The logo for theMiracle displayed at the bottom of the Benefits screen
was incorrect and was hard to see in dark theme

This uses the updated, correct logo as an SVG and swaps the color when
in dark mode.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/RWDS-1302

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

<img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e -
2026-05-15 at 11 03 13"

src="https://github.com/user-attachments/assets/9de0b304-234c-43b7-9cff-a20786909548"
/>

## **Pre-merge author checklist**

<!--
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**
> Low risk UI-only change: swaps an SVG asset and passes a theme-derived
`color` prop to improve contrast; minimal logic impact covered by unit
test updates.
> 
> **Overview**
> Updates the Rewards Benefits footer to render the TheMiracle logo
using the current theme text color by wiring `useTheme()` into
`TheMiracleFooter` and passing a `color` prop to the SVG component.
> 
> Replaces `themiracle-logo.svg` with the corrected artwork and adjusts
the unit test to mock/verify the new `color` prop is set to
`colors.text.default`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0ee0184. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[ea0f772](ea0f772)

Co-authored-by: Christian Montoya <christian.montoya@consensys.net>
@github-actions

This comment has been minimized.

runway-github Bot and others added 2 commits May 16, 2026 10:49
…e on first deposit cp-7.77.0 cp-7.78.0 (#30277)

- fix(predict): fix unregistered wallet issue on first deposit cp-7.77.0
cp-7.78.0 (#30267)

## **Description**

Fixes the first-deposit flow for new Predict users whose Polymarket
deposit wallet has been created but is not fully registered yet.

Polymarket advised that `STATE_MINED` can happen before the wallet is
usable on their side, so the deposit wallet relayer polling now treats
only `STATE_CONFIRMED` as a successful completion state. This keeps
polling through mined responses until Polymarket confirms the wallet,
preventing the follow-up batch transaction from failing with "wallet is
not registered".

## **Changelog**

CHANGELOG entry: Fixed a bug that caused a user's first Predict deposit
to fail while their deposit wallet was still registering.

## **Related issues**

Fixes: PRED-886

## **Manual testing steps**

```gherkin
Feature: Predict first deposit wallet registration

  Scenario: user makes their first Predict deposit
    Given a new Predict user does not have a registered Polymarket deposit wallet

    When user starts their first deposit
    Then the app creates the deposit wallet
    And waits until the relayer reports STATE_CONFIRMED
    And proceeds with the wallet batch transaction without a "wallet is not registered" error
```

## **Screenshots/Recordings**

N/A - logic-only relayer polling change.

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

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

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

## Testing

- `yarn jest
app/components/UI/Predict/providers/polymarket/depositWallet.test.ts
--runInBand`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes deposit-wallet relayer polling completion criteria, which can
affect first-deposit transaction flow timing and success. Low code
surface area but touches user-critical deposit execution behavior.
> 
> **Overview**
> Fixes Predict first-deposit failures by tightening Polymarket relayer
success detection: `waitForDepositWalletTransaction` now treats only
`STATE_CONFIRMED` (not `STATE_MINED`) as a completion state before
proceeding.
> 
> Updates the related unit test to expect continued polling through
`STATE_MINED`/no-hash responses until a `STATE_CONFIRMED` transaction
hash is returned.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a36ba27. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[dafc42c](dafc42c)

Co-authored-by: Luis Taniça <matallui@gmail.com>
@github-actions
Copy link
Copy Markdown
Contributor

🚀 RC Builds Ready for Testing

Platform Link Version
iOS TestFlight Go to TestFlight and download build 5027
Android Download from CI RC 7.78.0 (5027) — download APK artifact from the linked run
More Info
  • Version: 7.78.0
  • iOS Build Number: 5027
  • Android Build Number: 5027
  • Build Pipeline: View Pipeline

🛡️ Build Environment

Setting Value
Environment rc
Build Type main
Remote Feature Flag Env rc
Remote Feature Flag Distribution main
Ramps Environment production
API URLs & Details
API URL
Rewards API https://rewards.api.cx.metamask.io
Portfolio API https://portfolio.api.cx.metamask.io
Portfolio API (alt) https://portfolio.api.cx.metamask.io
Security Alerts API https://security-alerts.api.cx.metamask.io

Build Flags:

  • Build Name: main-rc
  • IS_TEST: false
  • RAMP_DEV_BUILD: false
  • BRIDGE_USE_DEV_APIS: false
---

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Teams Signed Off
65/100 9 6 2,720 0/23
Executive Summary

Release Focus: MetaMask Mobile 7.78.0 is a large-scale release introducing major architectural refactors across Bridge/Swaps, Money account, Predict (World Cup), QR hardware wallet scanning, and advanced charting, alongside significant dependency and native layer upgrades.

Key Changes:

  • Bridge/Swaps view refactored into BridgeViewContent with a new BridgeQuoteDataContext provider, new InsufficientNativeReserveError hook, and a new BatchSellTokenSelect screen for multi-token sell flows
  • Money account overhauled with new onboarding view, potential earnings view, balance card, transfer sheet, APY info sheet, and MoneyMetaMaskCard 'manage' mode with card-linking improvements
  • QR Hardware Wallet scanner (AnimatedQRScanner) significantly reworked with structured error states, analytics instrumentation, staleness detection, and a new error UI overlay
  • Advanced charting gains a real-time OHLCV WebSocket hook (useOHLCVRealtime) with HTTP polling fallback and staleness detection; LivelineChart refactored with forwardRef and imperative handle
  • React Native upgraded to 0.81.5 (from 0.76.9), Yarn upgraded to 4.14.1, and numerous native Android/iOS dependency patches updated including new yarn patches for react-native-acm, react-native-button, react-native-payments, and react-native-webview

Critical Areas: Bridge/Swaps: BridgeView architectural refactor with new context provider, insufficient native reserve error, and batch sell token selection, QR Hardware Wallet: Completely reworked scanner error handling and analytics, Money Account: New onboarding, balance card, transfer sheet, and card linkage flows, React Native 0.81.5 upgrade: Native rendering, gesture handling, and third-party library compatibility, Ramp/Checkout: New headless session integration, analytics instrumentation, and URL history tracking

Overall Risk: HIGH

Recommendation: Conditional go — the breadth of architectural changes across Bridge, Money, QR Hardware, and the React Native upgrade introduces substantial regression risk. Full regression coverage of Bridge/Swaps, QR hardware wallet pairing, Money account flows, and Ramp checkout is required before release. All critical-path transaction flows must pass on both iOS and Android with the new RN 0.81.5 runtime.

Release Scenarios (15)

High Risk Scenarios (9)

1. Bridge/Swaps

Risk Level: HIGH

Why This Matters: BridgeView was refactored into BridgeViewContent with latestSourceBalance passed as a prop, quote data moved to BridgeQuoteDataContext (breaking the previous direct useBridgeQuoteData call), and the loading state condition was changed. The InsufficientNativeReserveError is a new hook that can block submission. Any regression in context wiring or the new loading condition logic could silently prevent users from bridging or show incorrect error states.

Preconditions:

  • User has a wallet with ETH balance on Ethereum mainnet (at least 0.05 ETH)
  • User has at least one ERC-20 token with balance (e.g., USDC on Ethereum)
  • App is on a network where Bridge is supported
  • User is NOT in a low-gas/zero-balance state on the source chain

Test Steps:

  1. Navigate to the Bridge/Swap screen via the main navigation — verify the screen loads without crash and the new BridgeViewContent renders correctly with source and destination token selectors visible
  2. Select ETH as the source token and enter an amount equal to 99% of the ETH balance — verify the InsufficientNativeReserveError banner appears warning the user they need to keep ETH for gas, and the confirm button is disabled
  3. Reduce the source amount to 50% of ETH balance — verify the InsufficientNativeReserveError banner disappears and the confirm button becomes enabled when a valid quote is available
  4. Switch the bridge view mode between Bridge and Swap using navigation — verify the header title updates correctly ('Bridge' vs 'Swap') and the UI state is preserved
  5. Select a destination chain different from the source chain — verify quote fetching begins, loading state is shown, and a quote card appears with fee breakdown
  6. Simulate no available quotes by selecting an unsupported token pair — verify the 'no quotes available' state is shown (not a loading spinner) and the error is surfaced correctly from the new context-based quote data
  7. Tap the confirm/swap button with a valid quote — verify the transaction confirmation screen appears with correct amounts, fees, and the swap proceeds to signing
  8. Complete the swap and verify the transaction appears in the activity feed with correct status

Expected Outcomes:

  • BridgeViewContent renders without crash after the architectural refactor from BridgeView
  • InsufficientNativeReserveError correctly blocks submission when native token reserve would be depleted
  • Quote loading/error/no-quotes states are correctly differentiated (the loading condition logic changed from 'isLoading && !activeQuote && !needsNewQuote' to a multi-condition check)
  • Header title reflects the correct bridge view mode
  • Successful swap transaction is submitted and tracked

2. Bridge/Swaps - Batch Sell Token Select

Risk Level: HIGH

Why This Matters: BatchSellTokenSelect is an entirely new screen (395 lines) with complex token filtering (removeStablecoinsFromSourceTokens), chain-based filtering, sort direction toggling, and multi-select with a cap. It integrates with new redux selectors (selectBatchSellDestStablecoinsByChain) and the useTokensWithBalance hook. As a new flow with no prior test coverage in production, any wiring issue could silently fail or crash.

Preconditions:

  • User has multiple ERC-20 tokens with balances across at least 2 supported chains (e.g., USDC on Ethereum and Polygon)
  • User has no stablecoin tokens that would be filtered out as destination tokens
  • App is connected to a supported batch sell chain

Test Steps:

  1. Navigate to the Bridge screen and locate the batch sell entry point — verify the BatchSellTokenSelect screen can be opened without crash
  2. Verify the token list loads and displays eligible source tokens (non-stablecoins) with correct balances and network badges
  3. Tap the chain filter pills at the top — verify switching between chains filters the token list to only show tokens on the selected chain
  4. Toggle the sort direction button — verify tokens re-sort between ascending and descending balance order
  5. Select up to the maximum allowed tokens (MAX_BATCH_SELL_SOURCE_TOKENS) — verify each selected token shows a checked state and the selection count updates
  6. Attempt to select one more token beyond the maximum — verify the UI prevents additional selection or shows an appropriate limit message
  7. Tap the confirm/proceed button with selected tokens — verify the selected tokens are dispatched to the bridge redux slice via setBatchSellSourceTokens and navigation proceeds correctly
  8. Navigate back without confirming — verify no tokens are committed to state and the bridge view is in its previous state

Expected Outcomes:

  • BatchSellTokenSelect screen renders and loads token list correctly
  • Stablecoins are correctly filtered from source token options
  • Chain filtering and sort direction work correctly
  • Token selection respects MAX_BATCH_SELL_SOURCE_TOKENS limit
  • Redux state is correctly updated on confirmation

3. QR Hardware Wallet - Scanner Error Handling

Risk Level: HIGH

Why This Matters: AnimatedQRScanner was substantially rewritten (284 lines added, 44 removed) with new error state management (scanError, scanErrorActiveRef, lastForwardedScanErrorRef), a new error UI overlay with multiple button actions, analytics instrumentation via buildQrHardwareWalletErrorAnalyticsProperties, and the URRegistryDecoder initialization changed from 'new URRegistryDecoder()' to '() => new URRegistryDecoder()'. Any regression could leave users unable to pair or sign with QR hardware wallets.

Preconditions:

  • User has a QR-based hardware wallet (e.g., Keystone, AirGap) paired or in the process of pairing
  • Camera permissions are granted
  • Device has a working camera

Test Steps:

  1. Navigate to the QR hardware wallet pairing/signing flow and open the QR scanner — verify the scanner opens without crash and the camera preview is visible
  2. Present a QR code with an incorrect UR type (e.g., a UR for a different operation than expected) — verify the new error overlay appears with a title from getQRHardwareScanErrorTitle and a descriptive body message, not a generic crash
  3. Verify the error overlay shows two buttons: a primary action (e.g., 'Try Again') and a secondary action (e.g., 'Learn More' linking to the support URL) — tap 'Learn More' and verify it opens the correct support URL
  4. Tap 'Try Again' on the error overlay — verify the scanner resets (new URRegistryDecoder instantiated) and the camera preview resumes scanning
  5. Present a completely invalid/non-UR QR code — verify the error state correctly identifies it as non-UR format (is_ur_format: false) and shows an appropriate error message
  6. Present a valid UR QR code for the correct operation — verify the error overlay dismisses and the scan completes successfully
  7. Close and reopen the scanner modal — verify the error state is cleared (previousVisible ref logic) and the scanner starts fresh
  8. Verify that scan errors are reported to analytics with correct properties (error, error_category, is_ur_format, received_ur_type for wrong UR type errors)

Expected Outcomes:

  • New structured error overlay renders correctly for all QRHardwareScanErrorType values
  • Error state does not persist across modal open/close cycles
  • URRegistryDecoder is correctly reset on retry (now initialized with arrow function to avoid stale closure)
  • Analytics events fire with correct properties for each error category
  • Valid QR codes still scan successfully after the refactor

4. Ramp/Checkout - Headless Session and Analytics

Risk Level: HIGH

Why This Matters: Checkout.tsx was significantly expanded (295 lines added) with a new headless session integration (getSession, closeSession, failSession), comprehensive analytics instrumentation (RAMPS_CHECKOUT_OPENED event with new properties), URL history tracking via urlHistoryRef, step index tracking, and a new checkoutSessionId via uuidv4. The previousUrlRef was replaced with a more complex urlHistoryRef object. Regressions here could break the buy flow or cause session leaks.

Preconditions:

  • User has completed KYC/onboarding for the Ramp feature
  • User has a valid payment method configured
  • App is on a supported network for buying crypto

Test Steps:

  1. Navigate to the Buy crypto flow and proceed to the Checkout screen — verify the screen loads without crash and the WebView renders the provider checkout page
  2. Verify the RAMPS_CHECKOUT_OPENED analytics event fires on screen load with correct properties (checkoutSessionId, providerName, initial_url_path, has_callback_flow, order_id)
  3. Navigate through the checkout WebView (e.g., enter payment details, proceed to confirmation) — verify URL history tracking works and step index increments correctly
  4. Complete a purchase successfully — verify the order is created, the success state is shown, and navigation returns to the correct screen (RAMPS_ORDER_DETAILS for standard flow)
  5. Initiate a checkout and then close/cancel it — verify the closeSourceRef is set correctly and the session is properly cleaned up via closeSession
  6. Simulate a checkout failure (e.g., payment declined) — verify failSession is called, the error is surfaced to the user, and navigation pops correctly
  7. Verify that URL changes in the WebView are tracked via recordUrlChange and that redacted URLs (no PII) appear in analytics
  8. Test the checkout flow on both iOS and Android to verify WebView behavior is consistent with the new RN 0.81.5 runtime and updated react-native-webview patch

Expected Outcomes:

  • Checkout screen loads and WebView renders provider content correctly
  • Analytics events fire with correct properties at each checkout stage
  • Session lifecycle (open, close, fail) is correctly managed
  • URL history tracking does not expose PII in analytics
  • Purchase completion navigates to the correct post-purchase screen

5. Money Account - Onboarding and Balance Card

Risk Level: HIGH

Why This Matters: MoneyPotentialEarnings.tsx was completely rewritten (229 lines removed, 105 added) replacing the gradient/masked view with a simpler layout using PotentialEarningsTokenRow and useProjectedEarnings. MoneyMetaMaskCard gained a new 'manage' mode and changed the cashback display from Text to Tag. Multiple new components were added (MoneyBalanceCard, MoneyApyInfoSheet, MoneyBalanceInfoSheet, MoneyEarnCryptoInfoSheet, MoneyTransferSheet, MoneyMoreSheet). Any wiring issue in the refactored components could break the Money home screen.

Preconditions:

  • User does NOT have an existing Money account (new user state)
  • User has a wallet with USDC or mUSD balance on a supported chain
  • moneyEnableMoneyAccount feature flag is DISABLED — test only the UI components that are accessible without the flag

Test Steps:

  1. Navigate to the Money section of the app — verify the MoneyHomeView renders without crash and displays the correct state for a user without a Money account
  2. If the MoneyOnboardingView is accessible, verify it renders the onboarding animation (money_account_onboarding_animation.riv) and the 'How It Works' content correctly
  3. Navigate to the MoneyHowItWorksView — verify the updated layout renders correctly with the new testId structure and the content is accurate
  4. Verify the MoneyPotentialEarningsView renders correctly — check that the PotentialEarningsTokenRow components display token logos, projected earnings amounts, and network badges
  5. Verify the MoneyBalanceCard renders in its initial/empty state — check that all testIds (MoneyBalanceCard.testIds.ts) are present and the card layout is correct
  6. Tap the APY info button — verify the MoneyApyInfoSheet bottom sheet opens with correct APY information and closes on dismiss
  7. Verify the MoneyMetaMaskCard renders in 'upsell' mode — check that the card image, cashback percentage tag (now using Tag component instead of Text), and CTA button are displayed correctly
  8. Verify the MoneyMoreSheet opens and displays the correct menu options without crash

Expected Outcomes:

  • MoneyHomeView and all sub-components render without crash after the major refactor
  • MoneyPotentialEarnings correctly uses useProjectedEarnings hook and moneyFormatFiat utility instead of the removed gradient/masked view implementation
  • MoneyMetaMaskCard 'upsell' mode shows correct cashback percentage via Tag component
  • All new bottom sheets (APY info, balance info, earnings info, transfer, more) open and close correctly
  • MoneyOnboardingView animation plays without crash

6. Money Account - Deposit Transaction Building

Risk Level: HIGH

Why This Matters: moneyAccountTransactions.ts removed the hardcoded USDC address ('0xaf88d065e77c8cC2239327C5EDb3A432268e5831') and replaced it with getMoneyAccountDepositAssetAddress using MUSD_TOKEN_ADDRESS_BY_CHAIN. The minimumMint calculation now skips the RPC call for zero amounts. A regression here could cause deposits to fail silently or use the wrong token address, resulting in lost funds.

Preconditions:

  • User has mUSD or USDC balance on a supported chain (Ethereum mainnet or a chain where mUSD is deployed)
  • User has a Money account configured (or test with mock state)
  • User has sufficient ETH for gas

Test Steps:

  1. Initiate a Money account deposit flow — verify the deposit transaction batch is built without error using the new getMoneyAccountDepositAssetAddress function
  2. Verify that the mUSD address is correctly resolved from MUSD_TOKEN_ADDRESS_BY_CHAIN for the current chain — if mUSD is not deployed on the chain, verify an appropriate error is shown (not a silent failure with the old hardcoded USDC address)
  3. Enter a deposit amount of 0 (zero-amount placeholder) — verify the batch is built with minimumMint of 0n without making an RPC call for expected shares
  4. Enter a valid non-zero deposit amount — verify the RPC call for expected deposit shares is made and slippage is applied correctly
  5. Verify the approve transaction data is correctly encoded for the mUSD token (not the previously hardcoded USDC address '0xaf88d065e77c8cC2239327C5EDb3A432268e5831')
  6. Verify the deposit transaction data is correctly encoded with the minimumMint value after slippage
  7. Submit the deposit batch — verify both the approve and deposit transactions are submitted in the correct order and the activity feed shows the pending transactions
  8. Verify the new ERC20 transfer function encoding (buildErc20TransferData) works correctly for any transfer-based flows

Expected Outcomes:

  • Deposit batch uses the correct mUSD address from MUSD_TOKEN_ADDRESS_BY_CHAIN (not the hardcoded USDC address that was removed)
  • Zero-amount batches skip the RPC call for expected shares
  • Non-zero amounts correctly apply slippage to the expected shares
  • Approve and deposit transactions are correctly encoded and submitted
  • Error is surfaced if mUSD is not deployed on the selected chain

7. React Native 0.81.5 Upgrade - Core Navigation and Rendering

Risk Level: HIGH

Why This Matters: React Native was upgraded from 0.76.9 to 0.81.5 (a major version jump), the old react-native patch (564 lines) was removed and replaced with a new 35-line patch. Yarn was upgraded from 4.10.3 to 4.14.1. Multiple native dependency patches were added or replaced (react-native-webview, react-native-payments, react-native-acm, react-native-button, react-native-sensors, react-native-fast-crypto, react-native-aes-crypto). This is the highest-risk change in the release as it affects the entire app runtime.

Preconditions:

  • Fresh install of the app (not an upgrade) on both iOS and Android
  • Test on at least one older device (iOS 15, Android API 29) and one newer device
  • User has an existing wallet with multiple accounts and tokens

Test Steps:

  1. Launch the app from a cold start — verify the splash screen displays correctly and the app navigates to the wallet home screen without crash
  2. Navigate through all main tab bar items (Wallet, Activity, Browser, Settings) — verify each tab renders correctly and tab switching is smooth
  3. Open and close multiple bottom sheets in sequence (e.g., send flow, network selector, account selector) — verify no rendering artifacts or gesture handler conflicts
  4. Perform a send transaction end-to-end — verify the send flow, gas estimation, confirmation, and success screens all render correctly
  5. Switch between light and dark mode — verify the LivelineChart WebView reloads correctly (htmlContent change triggers reset of isChartReady and webViewError) and all screens re-render with correct theme
  6. Navigate to a token detail screen with a chart — verify the LivelineChart renders without crash and the forwardRef/useImperativeHandle changes don't break chart interactions
  7. Test deep link handling by opening a metamask:// deep link — verify the app handles it correctly with the updated MainNavigator
  8. Verify the Android app icon renders correctly at all densities (mipmap resources were updated)

Expected Outcomes:

  • App launches and navigates correctly on RN 0.81.5
  • All navigation flows work without gesture handler conflicts from the new react-native patch
  • Theme switching correctly resets WebView chart state
  • Deep links are handled correctly
  • No visual regressions in icons or splash screen

8. Perps - Home View and Market List

Risk Level: HIGH

Why This Matters: PerpsHomeView gained 88 lines of new logic, PerpsMarketRowItem was completely restructured (60 lines in/out), PerpsRowSkeleton was simplified (55→33 lines), PerpsStreamManager gained 42 lines of new provider logic, and multiple hooks were refactored (usePerpsOrderForm +190 lines, usePerpsCloseAllCalculations +44 lines, usePerpsDepositStatus refactored). These changes affect the core trading UI and data streaming.

Preconditions:

  • User has a Perps account with some balance
  • App is connected to a supported Perps network
  • perpsMyxProviderEnabled is DISABLED — test only with the default provider
  • perpsPerpGtmOnboardingModalEnabled is DISABLED — onboarding modal should NOT appear

Test Steps:

  1. Navigate to the Perps home screen — verify PerpsHomeView renders without crash and the market list loads correctly
  2. Verify the PerpsMarketRowItem renders correctly with the refactored component (60 lines changed) — check that market name, price, 24h change, and volume are displayed correctly
  3. Verify the PerpsRowSkeleton renders correctly during loading (refactored from 55 lines to 33 lines) — check that the skeleton placeholder has the correct dimensions
  4. Tap on a market row — verify navigation to PerpsMarketDetailsView works and the market details render correctly
  5. Verify the PerpsMarketBalanceActions component renders the correct action buttons and tapping them navigates to the correct screens
  6. Open a position and verify the PerpsPositionCard renders correctly (styles refactored)
  7. Navigate to PerpsTransactionsView — verify the transaction history loads and the funding/order/position transaction views render correctly
  8. Verify the PerpsStreamManager correctly manages WebSocket connections (42 lines added to provider) and the PerpsWebSocketHealthToast appears when connection is unhealthy

Expected Outcomes:

  • PerpsHomeView loads and displays market list without crash
  • PerpsMarketRowItem displays correct market data after refactor
  • PerpsRowSkeleton shows correct loading placeholder
  • Navigation between Perps screens works correctly
  • WebSocket health monitoring works and toast appears on connection issues

9. App Navigation - MainNavigator and App.tsx

Risk Level: HIGH

Why This Matters: App.tsx and MainNavigator.js both had significant changes (47+43 lines added respectively), new TabsIconBar and TabsIconList components were added (183+117 lines), TabBar gained new constants and types, and the useTabsBarLayout hook was added (254 lines). Navigation is the backbone of the app — any regression here affects all user flows.

Preconditions:

  • Fresh app state (no pending transactions or modals)
  • User is logged in with an existing wallet
  • Test on both iOS and Android

Test Steps:

  1. Launch the app and verify the main navigation stack renders correctly — check that App.tsx changes (47 lines added, 11 removed) don't cause any navigation initialization errors
  2. Navigate to each main section of the app (Wallet, Browser, Settings, Activity) — verify all routes defined in MainNavigator.js (43 lines added, 10 removed) are accessible
  3. Verify the TabBar renders correctly with the new constants (2 added to TabBar.constants.ts) and the new TabBar.types.ts property
  4. Test the new TabsIconBar component by navigating to any screen that uses it — verify tabs render with correct icons and the animated underline moves correctly between tabs
  5. Test the new TabsIconList component — verify it renders the correct list of icon tabs and selection state is maintained
  6. Navigate back and forward through the navigation stack multiple times — verify no navigation state corruption
  7. Test the OptinMetrics navigation flow (324 lines added to OptinMetrics.navigation.test.tsx indicates new navigation paths) — verify the metrics opt-in screen navigates correctly
  8. Verify deep link navigation works correctly for all supported metamask:// schemes

Expected Outcomes:

  • All navigation routes are accessible and render correctly
  • TabBar renders with correct icons and selection state
  • New TabsIconBar and TabsIconList components render without crash
  • Navigation stack does not corrupt state on back/forward navigation
  • OptinMetrics navigation flows work correctly

Medium Risk Scenarios (6)

1. Predict - World Cup Feature (UI Rendering Only)

Risk Level: MEDIUM

Why This Matters: The Predict section received extensive changes for World Cup support (402-line usePredictWorldCup hook, 327-line PredictWorldCup view, new queries, services, and utils) even though the flag is disabled. The existing Predict components (PredictFeed, PredictMarketDetails, PredictBuyWithAnyToken) were also refactored. The usePredictBuyError hook was significantly rewritten with new error source tracking and payment token key logic that could affect existing buy flows.

Preconditions:

  • predictWorldCup feature flag is DISABLED — do NOT test the World Cup screen as a user-accessible feature
  • Test only that the existing Predict feed and market flows are not broken by the new code
  • User has a Polymarket account or can access the Predict section

Test Steps:

  1. Navigate to the Predict section — verify the PredictFeed renders correctly after the refactor (52 lines added, 34 removed) without crash
  2. Verify the PredictHomeFeaturedCarousel renders correctly (23 lines added, 16 removed) and carousel items are displayed
  3. Tap on a market in the feed — verify PredictMarketDetails renders correctly after the refactor (23 lines added, 26 removed)
  4. Verify PredictMarketDetailsActions renders correctly (85 lines added, 90 removed) with the correct action buttons
  5. Verify PredictMarketDetailsStatus renders correctly (55 lines added, 59 removed) with correct market status information
  6. Verify PredictPositionsHeader renders correctly (14 lines added, 7 removed) with correct position summary
  7. Verify the PredictBuyWithAnyToken flow works correctly — check that the refactored usePredictBuyError hook (183 lines added, 81 removed) correctly surfaces errors for insufficient balance and order failures
  8. Verify the Polymarket WebSocket connection (WebSocketManager +22 lines) maintains connectivity and market data updates in real-time

Expected Outcomes:

  • Predict feed loads and displays markets without crash
  • Market details screen renders correctly after component refactors
  • Buy flow error handling works correctly with the new usePredictBuyError logic
  • WebSocket connection is maintained and market data updates
  • No regressions in existing Predict functionality from World Cup code additions

2. Advanced Chart - LivelineChart and OHLCV

Risk Level: MEDIUM

Why This Matters: LivelineChart.tsx was significantly refactored (235 lines added, 163 removed) with forwardRef and useImperativeHandle added, Logger imported, and the component signature changed. The theme-switch reset logic comment explicitly warns about a potential deadlock if only isChartReady is reset. The LivelineChartTemplate.ts also gained 92 lines. Any regression in the WebView message handling or state reset could break price charts for all tokens.

Preconditions:

  • User has a token with price chart data available (e.g., ETH, BTC)
  • tokenDetailsOhlcvWsIntegration feature flag is DISABLED — test only the existing chart functionality
  • App is connected to the internet

Test Steps:

  1. Navigate to a token detail screen with a price chart — verify the LivelineChart WebView renders without crash after the forwardRef/useImperativeHandle refactor
  2. Switch between light and dark mode — verify the chart correctly resets (isChartReady and webViewError both reset to false/null) and re-renders with the new theme
  3. Verify the chart loads data and displays the price line correctly
  4. Interact with the chart (hover/scrub) — verify the onHover callback fires correctly and the price display updates
  5. Switch between time windows (1H, 1D, 1W, 1M) — verify the onWindowChange callback fires and the chart updates
  6. Simulate a chart error (e.g., by disconnecting network briefly) — verify the error state is handled gracefully and the chart can recover
  7. Navigate away from the token detail screen and back — verify the chart re-initializes correctly without memory leaks
  8. Verify the Logger import (added to LivelineChart.tsx) does not cause any import errors

Expected Outcomes:

  • LivelineChart renders correctly after forwardRef refactor
  • Theme switching correctly resets chart state without deadlock
  • Chart interactions (hover, window change, mode change, series toggle) work correctly
  • Error states are handled gracefully
  • No memory leaks on navigation away and back

3. Card - MoneyAccountCardLinkage and Spending Limit

Risk Level: MEDIUM

Why This Matters: useCardDelegation.ts was significantly simplified (97 lines removed, 46 added), useAssetBalances.tsx was refactored (28 lines removed, 19 added), SpendingLimitProgressBar gained new logic (27 lines), and the new useMoneyAccountCardLinkage hook (217 lines) was added. The card delegation simplification is particularly risky as it could remove important state management logic.

Preconditions:

  • User has a MetaMask Card (virtual or physical)
  • User has a Money account or is in the process of linking one
  • User is in a supported region for the Card feature

Test Steps:

  1. Navigate to the Card section — verify CardHome renders correctly after the refactor (4 lines added, 2 removed)
  2. Navigate to the card management screen — verify the new useMoneyAccountCardLinkage hook (217 lines) correctly determines the card linkage state
  3. Verify the SpendingLimitProgressBar renders correctly with the new implementation (27 lines added, 5 removed) — check that the progress bar fills correctly based on spending limit usage
  4. Verify the spending limit percentage is displayed correctly at various usage levels (0%, 50%, 100%)
  5. Navigate to CardAuthentication — verify the refactored component (39 lines added, 34 removed) renders correctly and authentication flow works
  6. Verify the useCardDelegation hook (46 lines added, 97 removed — significant simplification) still correctly manages card delegation state
  7. Verify the useAssetBalances hook (19 lines added, 28 removed) correctly fetches and displays card-related asset balances
  8. Test the card onboarding flow steps — verify PhysicalAddress and OnboardingStep components render correctly

Expected Outcomes:

  • Card home and management screens render correctly
  • SpendingLimitProgressBar displays correct progress at all usage levels
  • CardAuthentication flow works correctly after refactor
  • useCardDelegation correctly manages delegation state after significant simplification
  • useMoneyAccountCardLinkage correctly determines linkage state

4. Earn - mUSD Conversion Flow

Risk Level: MEDIUM

Why This Matters: The MusdQuickConvertView (385 lines) was completely removed along with ConvertTokenRow (172 lines), MusdBalanceCard (83 lines), and related components. The new MusdConversionAssetRow (175 lines) replaces ConvertTokenRow. useMusdConversion.ts was significantly simplified (39 lines removed). The removal of MusdQuickConvertView and its replacement with new components could break the mUSD conversion user journey if any navigation routes or state management was missed.

Preconditions:

  • earnMusdConversionRewardsUiEnabled is DISABLED
  • rewardsEnableMusdDeposit is DISABLED
  • User has USDC or eligible stablecoin balance on a supported chain
  • User has accessed the Earn section previously

Test Steps:

  1. Navigate to the Earn section — verify EarnTokenList renders correctly after the minor refactor
  2. Navigate to the mUSD conversion education view (EarnMusdConversionEducationView) — verify it renders correctly after the significant refactor (108 lines added, 87 removed)
  3. Verify the new MusdConversionAssetRow component (175 lines) renders correctly with token logo, balance, and conversion CTA
  4. Verify the MusdConversionAssetListCta and MusdConversionAssetOverviewCta components render correctly after their simplification (9 lines removed from each)
  5. Verify the useMusdConversion hook (2 lines added, 39 removed — significant simplification) still correctly initiates conversion flows
  6. Verify the useMusdConversionNavbar hook (33 lines added, 23 removed) correctly sets up the navigation bar for the conversion flow
  7. Navigate through the EarnLendingWithdrawalConfirmationView — verify it renders correctly after the minor refactor
  8. Verify the EarnInputView renders correctly and input validation works

Expected Outcomes:

  • Earn section renders without crash after mUSD conversion refactor
  • MusdConversionAssetRow displays correct token information
  • useMusdConversion correctly initiates conversion after significant simplification
  • Navigation bar is correctly configured for conversion flows
  • Withdrawal confirmation view renders correctly

5. Multichain Transaction Details

Risk Level: MEDIUM

Why This Matters: MultichainTransactionDetailsSheet.tsx was refactored (21 lines added, 16 removed) and a new 258-line test file was added indicating significant behavioral changes. MultichainTransactionListItem and MultichainBridgeTransactionListItem both received 4-line additions. These changes affect how users view their cross-chain transaction history.

Preconditions:

  • User has completed at least one multichain transaction (bridge or cross-chain swap)
  • User has both EVM and non-EVM transactions in their activity feed

Test Steps:

  1. Navigate to the Activity feed — verify MultichainTransactionListItem renders correctly (4 lines added)
  2. Tap on a multichain bridge transaction — verify MultichainBridgeTransactionListItem renders correctly (4 lines added)
  3. Open the MultichainTransactionDetailsSheet — verify it renders correctly after the refactor (21 lines added, 16 removed)
  4. Verify all transaction details are displayed correctly (amount, fee, status, chain information)
  5. Verify the transaction status updates correctly if the transaction is pending
  6. Close the details sheet and verify navigation returns to the activity feed correctly
  7. Test with a failed transaction — verify the error state is displayed correctly in the details sheet
  8. Verify the sheet renders correctly in both light and dark mode

Expected Outcomes:

  • MultichainTransactionDetailsSheet renders correctly after refactor
  • All transaction details are displayed accurately
  • Transaction status updates work correctly
  • Sheet opens and closes without navigation issues
  • Error states are displayed correctly

6. Braze Banner Integration

Risk Level: MEDIUM

Why This Matters: BrazeBanner is an entirely new integration (90-line component, 243-line hook, 63-line deep link filter, 66-line properties utility, 105-line README) adding a third-party marketing SDK. Even with the flag disabled, the SDK initialization code runs and the isAllowedBrazeDeeplink function is in the deep link handling path. Any SDK initialization error or deep link filter regression could affect all users.

Preconditions:

  • brazeBannerHome feature flag is DISABLED — the banner should NOT appear on the home screen
  • brazeSegmentForwarding is DISABLED
  • Test that the Braze SDK integration does not cause crashes even when banners are disabled

Test Steps:

  1. Launch the app and navigate to the wallet home screen — verify no Braze banner appears (flag is disabled) and the home screen renders correctly
  2. Verify the app does not crash on startup due to Braze SDK initialization (BrazeBanner.tsx is 90 lines of new code)
  3. Navigate through all main screens — verify no unexpected Braze-related UI elements appear
  4. Verify the isAllowedBrazeDeeplink function (63 lines) does not interfere with existing deep link handling
  5. Test a metamask:// deep link — verify it is correctly identified as an allowed deep link and not blocked by the Braze deep link allowlist
  6. Verify the useBrazeBanner hook (243 lines) does not cause any performance issues or unnecessary re-renders when the flag is disabled
  7. Check that the brazeBannerProperties utility (66 lines) does not throw errors when called with edge case inputs
  8. Verify memory usage is not impacted by the Braze SDK being initialized but inactive

Expected Outcomes:

  • No Braze banner appears when the flag is disabled
  • App does not crash due to Braze SDK initialization
  • Deep link handling is not affected by Braze deep link filtering
  • No performance regressions from inactive Braze integration
  • No unexpected UI elements from Braze

Teams Sign-off Status (0/23)

Awaiting sign-off (23): Accounts, Assets, BE Trade, Bots Team, Card, Confirmations, Core Platform, Delegation, Design System, Earn, LavaMoat, Mobile Platform, Mobile UX, Money Movement, Networks, Onboarding, Perps, Predict, Rewards, Social & AI, Swaps and Bridge, team-mobile-delivery, Transactions

Excluded Features - Feature Flags Disabled (59)

The following features are disabled via feature flags and should NOT be tested:

  • aiSocialLeaderboardEnabled
  • aiSocialWhatsHappeningEnabled
  • bitcoinTestnetsEnabled
  • brazeBannerHome
  • brazeBannerHomeMinVersion
  • brazeSegmentForwarding
  • configRegistryApiEnabled
  • confirmations_pay_hardware
  • coreMCU589AbtestHubPageDiscoveryTabs
  • earnFeatureFlagTemplate
  • earnMusdConversionRewardsUiEnabled
  • earnPooledStakingServiceInterruptionBannerEnabled
  • earnStablecoinLendingServiceInterruptionBannerEnabled
  • exploreSearchV2Enabled
  • forceRampsStagingEnvironment
  • fullPageAccountList
  • googleLoginIosUnsupportedBlockingEnabled
  • hapticsKillSwitch
  • homeTMCU610AbtestWalletHomePostOnboardingSteps
  • homeTMCU725AbtestHomepagePerpsPillsEmptyState
  • legacyIosGoogleConfigEnabled
  • moneyActivityMockDataEnabled
  • moneyEnableMoneyAccount
  • moneyHomeScreenEnabled
  • moneyShowMoneyAccountAddress
  • pepsSamplePhasedRolloutFlag
  • perpsDefaultPayTokenWhenNoBalanceEnabled
  • perpsMyxProviderEnabled
  • perpsPerpGtmOnboardingModalEnabled
  • perpsPerpTradingServiceInterruptionBannerEnabled
  • platformNewLinkHandlerSystem
  • predictBottomSheet
  • predictClobV2UseLegacyClobHost
  • predictExtendedSportsMarkets
  • predictHotTab
  • predictMarketHighlights
  • predictTabFeaturedCarousel
  • predictUpDown
  • predictWithAnyToken
  • predictWorldCup
  • rewardsAnnouncementModalEnabled
  • rewardsBitcoinEnabled
  • rewardsDropsEnabled
  • rewardsEnableMusdDeposit
  • rewardsEnableMusdHolding
  • rewardsMissingEnrolledAccounts
  • rewardsReferralCodeEnabled
  • rewardsReferralEnabled
  • rewardsTronEnabled
  • socialAiTSA495AbtestCardRotationInterval
  • solanaOnboardingModal
  • solanaTestnetsEnabled
  • tempoConfig
  • tokenDetailsOhlcvWsIntegration
  • tokenDetailsV2ButtonLayout
  • tokenDiscoveryBrowserEnabled
  • tronStaking
  • walletHomeOnboardingSteps
  • socialAiTSA531AbtestWhatsHappeningExplore

Generated by AI Test Plan Analyzer (claude-sonnet-4-6) at 2026-05-16T09:37:24.754Z

AI generated test plan (JSON): Available as artifact test-plan-7.78.0 in the build workflow

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

Labels

size-XL skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-bots Bot team (for MetaMask Bot, Runway Bot, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.