Skip to content

release: 7.78.21 (OTA)#28755

Closed
metamaskbot wants to merge 396 commits into
stablefrom
release/7.78.21
Closed

release: 7.78.21 (OTA)#28755
metamaskbot wants to merge 396 commits into
stablefrom
release/7.78.21

Conversation

@metamaskbot
Copy link
Copy Markdown
Collaborator

OTA hotfix: branch release/7.78.21.

  • Native semver and build version are not bumped.
  • OTA_VERSION in app/constants/ota.ts is v7.78.21.
  • CHANGELOG.md uses the SemVer prerelease format 7.78.2-ota.1 (maps to Runway 7.78.21) because auto-changelog validates all headers as strict SemVer.

abretonc7s and others added 30 commits April 2, 2026 12:57
…28072)

## **Description**

Replaces `Arrow2Left`/`Arrow2Right` (bidirectional arrow icons) with
`ArrowLeft`/`ArrowRight` (standard directional arrows) on three perps
screens. The `Arrow2*` variants imply a two-way swap which is incorrect
for a back button and before→after value transition indicators.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Correct arrow icons on perps order screens

  Scenario: Back button uses standard back arrow
    Given I am on the Perps tab with an open BTC position
    When I tap the close position button
    Then the header back button shows a single left-pointing arrow

  Scenario: Flip position direction indicator uses standard right arrow
    Given I have an open position
    When the flip position confirmation sheet is displayed
    Then the arrow between the current and target direction shows a single right-pointing arrow

  Scenario: Adjust margin transition arrows use standard right arrow
    Given I am on the adjust margin screen
    When I change the margin amount
    Then both the liquidation price and distance rows show single right-pointing transition arrows
```

## **Screenshots/Recordings**

_Evidence available in task artifacts — will be added by reviewer if
needed._

### **Before**

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


https://github.com/user-attachments/assets/ed23ac56-b5d3-413c-aaa0-baafdc1eefb8


### **After**

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


https://github.com/user-attachments/assets/0a7905df-94ed-4096-ab92-f267c3810ac0


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

## **Validation Recipe**

<details>
<summary>recipe.json</summary>

```json
{
  "pr": "28072",
  "title": "Arrow symbols on perps order pages use correct icon variants",
  "jira": "TAT-2368",
  "acceptance_criteria": [
    "Back button on perps order pages uses ArrowLeft (not Arrow2Left)",
    "No new TypeScript errors"
  ],
  "validate": {
    "static": ["yarn lint:tsc"],
    "runtime": {
      "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"],
      "steps": [
        {
          "id": "assert-position-exists",
          "description": "BTC position must exist to access close position view",
          "action": "eval_async",
          "expression": "Engine.context.PerpsController.getPositions().then(function(ps){var p=ps.find(function(x){return x.symbol==='BTC'});return JSON.stringify({found:!!p})})",
          "assert": { "operator": "eq", "field": "found", "value": true }
        },
        {
          "id": "nav-market-detail",
          "description": "Navigate to BTC market details",
          "action": "navigate",
          "target": "PerpsMarketDetails",
          "params": {
            "market": {
              "symbol": "BTC",
              "name": "BTC",
              "price": "0",
              "change24h": "0",
              "change24hPercent": "0",
              "volume": "0",
              "maxLeverage": "100"
            }
          }
        },
        {
          "id": "wait-close-button",
          "action": "wait_for",
          "test_id": "perps-market-details-close-button"
        },
        {
          "id": "press-close",
          "action": "press",
          "test_id": "perps-market-details-close-button"
        },
        {
          "id": "wait-order-header",
          "action": "wait_for",
          "test_id": "perps-order-header-back-button"
        },
        {
          "id": "assert-back-arrow-icon",
          "description": "Assert back button uses ArrowLeft, not Arrow2Left",
          "action": "eval_sync",
          "expression": "JSON.stringify((function(){var hook=globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!hook)return{iconName:null,error:'no hook'};var found=null;function walk(f){if(!f)return;if(f.memoizedProps&&f.memoizedProps.testID==='perps-order-header-back-button'){found=f;return;}walk(f.child);if(!found)walk(f.sibling);}for(var [id] of hook.renderers){var roots=hook.getFiberRoots?hook.getFiberRoots(id):null;if(roots)roots.forEach(function(r){if(!found)walk(r.current);});}if(!found)return{iconName:null,error:'back btn not found'};return{iconName:found.memoizedProps.iconName||null};})())",
          "assert": { "operator": "eq", "field": "iconName", "value": "ArrowLeft" }
        },
        {
          "id": "evidence-order-header",
          "action": "screenshot",
          "filename": "evidence-order-header-arrow.png"
        },
        {
          "id": "go-back",
          "action": "press",
          "test_id": "perps-order-header-back-button"
        },
        {
          "id": "wait-market-details",
          "action": "wait_for",
          "route": "PerpsMarketDetails"
        },
        {
          "id": "verify-no-errors",
          "action": "log_watch",
          "window_seconds": 5,
          "must_not_appear": ["TypeError", "ReferenceError"]
        }
      ]
    }
  }
}
```

</details>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk visual/test change: swaps icon variants and adds a testID for
the perps order header back button, with updated unit tests to assert
correct icon usage.
> 
> **Overview**
> **Corrects perps order-page arrow iconography** by replacing
`Arrow2Left`/`Arrow2Right` with standard `ArrowLeft`/`ArrowRight` on the
order header back button, the flip-position direction transition
indicator, and the adjust-margin liquidation price/distance transition
arrows.
> 
> Adds `PerpsOrderHeaderSelectorsIDs.BACK_BUTTON` and wires it into
`PerpsOrderHeader`’s `ButtonIcon` for stable targeting, and
updates/extends unit tests (including mocks) to assert the new icon
names and transition behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e0306cd. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Navigation screens were using the default (unthemed) card background
color, which could cause a visible flash of incorrect color during
screen transitions — particularly noticeable when switching between dark
and light themes.

This PR applies `cardStyle: { backgroundColor: colors.background.default
}` to multiple navigators and individual screens across the app,
ensuring that the background color used during transitions always
matches the current theme.

Several arrow-function navigator components were converted from implicit
returns to explicit function bodies so they can call the `useTheme()`
hook and access `colors`.

## **Changelog**

CHANGELOG entry: Fixed navigation screens flashing incorrect background
color during transitions

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Navigation background color matches theme

  Scenario: user navigates between screens in dark mode
    Given the app is in dark mode

    When user navigates to Settings or Onboarding Default Settings
    Then the screen transition background matches the dark theme background
    And no white flash is visible during the transition

  Scenario: user navigates between screens in light mode
    Given the app is in light mode

    When user navigates to Settings or Onboarding Default Settings
    Then the screen transition background matches the light theme background
    And no dark flash is visible during the transition

  Scenario: user opens multichain address list
    Given the user is on the accounts screen

    When user taps to open the multichain address list
    Then the screen slides in from the right with the correct themed background
```

## **Screenshots/Recordings**

### **Before**



https://github.com/user-attachments/assets/7bf229d2-9b9c-4320-88b4-f2672193b804



### **After**



https://github.com/user-attachments/assets/b29c42e3-8f74-4741-8d85-5226f630fa38



https://github.com/user-attachments/assets/20a48c50-6f21-4c5d-ac63-547a793db9d1





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

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches multiple React Navigation stacks and screen options, which can
subtly affect transition behavior and modal presentation across the app,
though changes are mostly cosmetic (themed background only).
Added/updated tests reduce risk but they are extensive and may be
brittle.
> 
> **Overview**
> Fixes navigation transition flashes by applying themed
`cardStyle`/`headerStyle` background colors (via `useTheme()`) across
several navigators and key screens (onboarding success/default settings,
hardware wallet flows, settings/main stacks, and multichain address list
slide-in).
> 
> Refactors several navigator components from implicit returns to
function bodies to access theme colors, and updates/expands navigation
tests and snapshots to cover version-handling branches, tracing calls,
conditional routing, and rendering of many nested navigators/modals.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
56fc9f9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

This PR isolates the websocket follow-up from `#28176`.

The root issue is that Perps always-on moved HyperLiquid websocket
initialization into wallet lifecycle paths, and foreground return was
still forcing full reconnects even when the socket was already healthy.
That inflated non-interactive websocket handshakes and turned some
startup/foreground failures into hard Perps errors.

This change keeps always-on enabled, but makes wallet-root and tutorial
preloads best-effort. Foreground resume now validates the existing
socket before reconnecting, full-screen Perps entry still forces an
interactive reconnect when needed, and suppressed startup attempts stop
logging hard initialization errors to Sentry.

## **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 a bug that caused Perps to reconnect too
aggressively and surface intermittent websocket connection errors.

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: perps always-on websocket lifecycle

  Scenario: wallet lifecycle keeps a healthy websocket alive
    Given Perps is enabled for the current wallet
    When the user backgrounds the app briefly and returns to the wallet
    Then the always-on connection should reuse a healthy websocket instead of forcing a full reconnect

  Scenario: entering Perps recovers after a silent startup failure
    Given a non-interactive always-on websocket initialization fails during wallet startup
    When the user opens the full-screen Perps experience
    Then the app should attempt an interactive reconnect and load Perps without showing a stale startup error
```

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

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

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches Perps WebSocket lifecycle and error-suppression behavior;
mistakes could cause missed reconnects or hidden connection failures,
but changes are localized and covered by expanded unit tests.
> 
> **Overview**
> Reduces aggressive Perps WebSocket reconnections by introducing
`PERPS_CONNECTION_SOURCE` + `suppressError` options and a new
`PerpsConnectionManager.resumeFromForeground()` that pings a healthy
socket before forcing a full reconnect.
> 
> Wallet-root always-on and tutorial preload connections are now
*best-effort* (silent on failure with delayed retry), while full-screen
Perps entry proactively calls `ensureConnected()` when disconnected and
not showing an error view.
> 
> Adds a per-attempt context (`perpsConnectionAttemptContext`) to thread
`source`/`suppressError` into provider initialization and downgrades
suppressed startup failures (e.g., HyperLiquid init) from Sentry errors
to debug logs; also dedupes Sentry breadcrumbs for repeated error codes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c647313. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…lLoginIosUser (#28333)

## **Description**

Fixes the `SocialLoginIosUser` screen to properly use the theme
background color and center-align the title text. Current dark mode it
appears white and hardly legible

### Key changes

- Added `backgroundColor: colors.background.default` to `SafeAreaView`
wrapper and root `View` so the screen respects the current theme
- Added `textAlign: 'center'` to the title `Text` via a stylesheet
constant (avoids inline style lint violation)

## **Changelog**

CHANGELOG entry: null

## **Related issues**

N/A

## **Manual testing steps**

```gherkin
Feature: SocialLoginIosUser screen theming

  Scenario: New social login user sees themed background
    Given user completes social login on iOS as a new user

    When the success screen is shown
    Then the background matches the current theme color
    And the title text is centered

  Scenario: Existing social login user sees themed background
    Given user completes social login on iOS as an existing user

    When the success screen is shown
    Then the background matches the current theme color
    And the title text is centered
```

## **Screenshots/Recordings**

### **Before**

<img width="300" height="2622" alt="image"
src="https://github.com/user-attachments/assets/4d359463-be0c-45d7-aae7-c925c386d44e"
/>


### **After**

<img width="300" height="2622" alt="Simulator Screenshot - iPhone 17 -
2026-04-02 at 18 09 45"
src="https://github.com/user-attachments/assets/b8428bbc-985e-494f-a1b7-1c960eeabb5c"
/>


## **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 UI-only changes limited to styling and theming on a single
onboarding screen, plus snapshot updates.
> 
> **Overview**
> Ensures the `SocialLoginIosUser` success screen respects the active
theme by applying `colors.background.default` to the `SafeAreaView`
wrapper and root container.
> 
> Centers the title text via a new `styles.title` rule, and updates Jest
snapshots to reflect the new background style arrays and `textAlign:
'center'`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
479288b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…28267)

## **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 Ramp BUY and SELL screens in `MainNavigator.js` were missing
`cardStyle` with `backgroundColor`, causing the navigation card to use
React Navigation's default white background. This made the header (top
safe area) and footer (bottom safe area) appear white in dark mode.

Other screens in the same navigator (Send, Bridge, Browser, etc.)
already set `cardStyle: { backgroundColor: colors.background.default }`.
This PR applies the same pattern to the Ramp screens for consistency.

## **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 white header and footer on Ramp buy/sell screens
in dark mode

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Ramp buy screen dark mode theming

  Scenario: user opens Buy crypto from Perps with dark mode enabled
    Given the app is set to dark mode
    And the user is on the Perps home screen with zero balance

    When user taps "Add funds"
    And user taps "Buy crypto"
    Then the Ramp buy screen header and footer use the dark theme background color
    And there are no white areas at the top or bottom of the screen
```

## **Screenshots/Recordings**

### **Before**

<img width="1179" height="2556" alt="Simulator Screenshot - iPhone 15
Pro - 2026-04-01 at 09 26 16"
src="https://github.com/user-attachments/assets/83c59cdb-c2b7-48e7-b982-15ac10db8cdf"
/>


### **After**

<img width="1179" height="2556" alt="Simulator Screenshot - iPhone 15
Pro - 2026-04-01 at 09 23 38"
src="https://github.com/user-attachments/assets/6467aa48-8c1e-4157-aabd-9950ec3a015e"
/>


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

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only navigation styling change that should not affect Ramp
flow logic; primary risk is unintended background color differences on
the Ramp screens across themes.
> 
> **Overview**
> Fixes Ramp `BUY`/`SELL` screens in `MainNavigator` to use the app
theme background by adding `options.cardStyle.backgroundColor =
colors.background.default` on those stack screens, preventing white
safe-area/header/footer regions in dark mode.
> 
> Updates the `MainNavigator` Jest snapshots to reflect the new
per-screen `options` for `RampBuy` and `RampSell`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
11ad411. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…/misc (#28185)

## **Description**

Migrate 5 RootModalFlow security/misc components from prop-based route
access to `useRoute()` hook (PR 9 of 13).

**Components:** SRPQuiz, OriginSpamModal, ChangeInSimulationModal,
LearnMoreBottomSheet, ReturnToAppNotification

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

N/A — pure refactoring. All existing 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.

## **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 refactor limited to navigation param plumbing and test
updates; behavior should be unchanged aside from stricter typing and
slightly different test rendering expectations.
> 
> **Overview**
> Refactors several RootModalFlow security/misc screens (`SRPQuiz`,
`OriginSpamModal`, `ChangeInSimulationModal`, `ReturnToAppNotification`)
to read navigation params via `useRoute()` instead of prop-injected
`route`, and removes the `as ScreenComponent` casts for these routes in
`App.tsx`.
> 
> Makes `LearnMoreBottomSheet`’s `onClose` prop optional and updates
affected unit tests to mock `useRoute()` rather than passing `route`
props; `ReturnToAppNotification` tests were expanded from a snapshot to
detailed assertions around toast display, delays (`wait`), and one-time
execution.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fc3d334. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…28335)

<!--
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 sets the Carousel mocks to false on the network manager spec in
order to improve token visibility.
Some urls were also removed from the allow list since they have been
mocked previously

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

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

Fixes:
https://consensys.slack.com/archives/C02U025CVU4/p1775117808791299

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

## **Screenshots/Recordings**

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

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

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are limited to E2E/smoke test setup and allowlist
cleanup, with no production runtime logic touched.
> 
> **Overview**
> Stabilizes smoke tests by forcing remote feature flags to disable
`carouselBanners` in `network-manager2.spec.ts`, ensuring banner UI
doesn’t obscure token visibility during network filtering checks.
> 
> Cleans up E2E request allowlisting by removing now-mocked endpoints
from `mock-e2e-allowlist.ts`, and adds a small workaround in the gasless
swap 7702 smoke test to dismiss a sticky keyboard via a tap on
`QuoteView.networkFeeLabel`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f1d0068. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

> **Migrates performance testing from `appwright` to `playwright` and
modernizes the Playwright/Appium test harness.** The GitHub workflow and
`package.json` scripts are switched to `run-playwright:*`, and several
performance specs are rewritten from legacy WDIO screen-objects to new
page-objects/flows.
> 
> **Adds new Playwright fixtures and utilities for performance runs.** A
`currentDeviceDetails` fixture is introduced, plus a
`performanceTracker` fixture that auto-attaches metrics post-test,
validates quality gates (skipping retries after threshold-only
failures), publishes scenarios to Sentry, and stores session metadata.
> 
> **Improves Appium interaction reliability and provider integration.**
Playwright matchers/gestures gain stability-aware `waitAndTap`, better
text/XPath handling, app lifecycle helpers
(terminate/activate/background/hide keyboard), standardized default
timeouts, and BrowserStack/emulator capability updates including
per-platform app identifiers and a provider `getRecordingUrl` for video
links.
> 
> **Updates test IDs and selectors used by E2E.** Predict market details
testIDs are normalized (tab vs tab-content), and confirmations add a
`KEYBOARD_CONTAINER` id with corresponding page-object updates.
> 

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

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

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

## **Screenshots/Recordings**

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

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

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Broad changes across the E2E/performance harness (fixtures,
matchers/gestures, BrowserStack capabilities, and multiple rewritten
specs) could introduce new test flakiness or CI/run-time regressions
despite being non-production code.
> 
> **Overview**
> Migrates BrowserStack performance test execution from `appwright` to
`playwright` by switching the GitHub workflow and `package.json` scripts
to `run-playwright:*` commands.
> 
> Refactors the Playwright/Appium test harness with **new fixtures**
(including `currentDeviceDetails` and an auto-managed
`performanceTracker` that attaches metrics, enforces quality gates, and
publishes to Sentry), plus reliability improvements to matchers/gestures
(stability-aware `waitAndTap`, richer XPath/text handling, app lifecycle
helpers, and standardized default timeouts).
> 
> Rewrites several performance specs and page objects to the unified
page-object/flow style (wallet/login, swaps, perps), adds a new
`perps.flow` helper, and updates/normalizes test IDs used by E2E
(Predict market details tab/content IDs and a new confirmations
`KEYBOARD_CONTAINER` selector).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7a072f2. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Christopher Ferreira <christopher.ferreira@consensys.net>
Co-authored-by: Christopher Ferreira <104831203+christopherferreira9@users.noreply.github.com>
Co-authored-by: Javier Garcia Vera <javier.vera@consensys.net>
## **Description**

Mirrors [MetaMask/core#8352](MetaMask/core#8352)
for the mobile PerpsController.

- Expand `MESSENGER_EXPOSED_METHODS` from 35 to 84 methods
(alphabetized)
- Auto-generate `PerpsController-method-action-types.ts` using
`messenger-generate-action-types` CLI
- Export `PerpsControllerGetStateAction` and all individual action types
- Add `generate-method-action-types` check/fix scripts to
`lint`/`lint:fix`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

N/A — type-only changes, no user-facing behavior

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Expands the messenger-exposed surface area of `PerpsController`, which
could affect callers and permissions if any method was not intended to
be remotely invokable. Also adds a new lint-time codegen check that may
introduce CI failures if generation drifts across environments.
> 
> **Overview**
> **Exposes the full `PerpsController` API through the messenger** by
expanding and alphabetizing `MESSENGER_EXPOSED_METHODS`, and introduces
a named `PerpsControllerGetStateAction` type.
> 
> **Switches Perps messenger action typing to generated output**:
`PerpsController-method-action-types.ts` is regenerated to include
JSDoc’d action types for all controller methods and `index.ts` now
re-exports these individual action types.
> 
> **Build/CI enforcement changes**: bumps `@metamask/messenger` to
`^1.1.0` (for the codegen CLI) and wires
`messenger-generate-action-types` into `lint`/`lint:fix` via new
`generate-method-action-types` scripts to keep generated types in sync.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0fe513d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…[GE-168] (#28345)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
Adds Braze Android resource in braze.xml to specify the small and large
push notification icons

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: resource-only configuration change that just points Braze to
existing mipmap icons; main risk is misconfigured/missing icon resources
affecting push rendering.
> 
> **Overview**
> Adds Braze Android resource overrides in `braze.xml` to specify the
small and large push notification icons
(`com_braze_push_small_notification_icon` and
`com_braze_push_large_notification_icon`), pointing to
`@mipmap/ic_notification_small` and `@mipmap/ic_notification`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
64eef30. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ated APIs (#28115)

## **Description**

Upgraded `@metamask/design-system-react-native` from `^0.11.0` to
`^0.12.0` and migrated affected mobile screens to the latest API.

This removes deprecated `TextFieldSize` and `TextButtonSize` usage,
removes deprecated `TextButton isInverse`, and replaces one
icon/disabled `TextButton` usage with a tertiary `Button` per migration
guidance.

https://github.com/MetaMask/metamask-design-system/releases/tag/v26.0.0

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

```gherkin
Feature: Design system 0.12.0 migration compatibility

  Scenario: user can authenticate and reset password using migrated text fields
    Given the app is running on a branch with this PR
    When user opens Login, Onboarding, Choose Password, and Reset Password flows
    Then password input fields render correctly and accept input without runtime errors

  Scenario: user can copy seed phrase only when reveal state allows it
    Given the user is on the Reveal Secret Recovery Phrase screen
    When the seed phrase is hidden
    Then the copy action is disabled
    When the seed phrase is revealed and user taps copy
    Then the copy action triggers successfully
```

## **Screenshots/Recordings**

### **Before**

Main fix was alignment of TextField for password type


https://github.com/user-attachments/assets/31218d04-876b-4b53-87b3-7349e59416ec

### **After**


https://github.com/user-attachments/assets/1623c271-cee3-4d66-aa8c-2c5430ac4990

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it upgrades the shared design-system dependency
and changes `TextField`/button props in login, password creation/reset,
and seed phrase screens, which could cause subtle styling/accessibility
regressions in critical authentication flows.
> 
> **Overview**
> Upgrades `@metamask/design-system-react-native` to `^0.12.0` (and
`design-system-shared` to `^0.5.0`) and updates affected screens to
match the new component APIs.
> 
> Removes deprecated `TextFieldSize` usage across `Login`,
`ChoosePassword`, `ResetPassword`, `ManualBackupStep1`, and
`RevealPrivateCredential` components, and adjusts button APIs by
dropping `TextButton` sizing/`isInverse` props and switching the
seed-phrase copy action to a tertiary `Button`.
> 
> Updates Jest snapshots to reflect the new `TextField`
rendering/styling and accessory layout from the design-system upgrade.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1780297. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

Migrated `Skeleton` to DSRN usage (confirmations scope).

## **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/DSYS-274

## Manual testing steps

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**


https://github.com/user-attachments/assets/33b4a13d-8b50-45e1-95db-5be88e3d50b6

### **After**


https://github.com/user-attachments/assets/26fe026f-9a9b-4cd6-8690-c604bcfd869f

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only change that swaps the `Skeleton` placeholder
component import paths in confirmations-related screens and one test
mock. Main risk is visual/regression differences if the temp Skeleton
behaves differently, but no business logic is altered.
> 
> **Overview**
> Migrates confirmations-scope loading placeholders to use the new DSRN
`Skeleton` implementation by switching imports from
`component-library/components/Skeleton` to
`component-library/components-temp/Skeleton` across confirmation rows,
footers, keyboards, and related components.
> 
> Updates the send `Recipient` test to mock the new `Skeleton` module
path accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0922bf9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

The Swaps and Bridge screens were navigating without a slide animation,
creating an abrupt transition that felt inconsistent with the rest of
the app. This PR applies `slideFromRightAnimation` to both screens so
they slide in from the right, matching the smooth navigation pattern
already used by Settings, Asset, Stake, Earn, Perps, and other screens
in `MainNavigator`.

## **Changelog**

CHANGELOG entry: Fixed abrupt navigation transition to Swaps and Bridge
screens by adding smooth slide-from-right animation

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Smooth navigation transitions

  Scenario: user navigates to the Swaps screen
    Given the user is on the wallet home screen

    When user taps the Swap action button
    Then the Swaps screen slides in smoothly from the right

  Scenario: user navigates to the Bridge screen
    Given the user is on the wallet home screen

    When user initiates a Bridge action
    Then the Bridge screen slides in smoothly from the right
```

## **Screenshots/Recordings**

### **Before**


https://github.com/user-attachments/assets/4d023c14-1f59-4fec-8a81-01a527e85e42


### **After**



https://github.com/user-attachments/assets/f45809a4-e175-4741-80ef-d496803f31f2


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

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

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


https://github.com/user-attachments/assets/fcb30371-1684-4cc6-873d-c7c01ea380d5


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only navigation change that adjusts stack screen
transition options; main risk is unintended animation/gesture behavior
differences on these routes.
> 
> **Overview**
> Applies the shared `slideFromRightAnimation` stack transition to the
`Send` and `Bridge` routes in `MainNavigator`, so these screens slide in
consistently with other flows.
> 
> Updates the `MainNavigator` Jest snapshot to reflect the new
`animationEnabled` and `cardStyleInterpolator` options on those screens.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fc1507d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…n-production builds. (#28311)

<!--
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**
Currently the branch name is only displayed for QA builds (isQa check),
leaving RC, beta, and dev builds indistinguishable from production.
This PR:

- replaces isQa check with !isProduction() to show build info for all
non-production builds (RC, beta, dev, etc.)
- prepends uppercased METAMASK_ENVIRONMENT as build type label (e.g., RC
| Branch: release/7.69.0)
- production builds remain unchanged (no branch info displayed) 

Before: Branch: release/7.69.0 (QA only)
After:    RC | Branch: release/7.69.0 (all non-production builds)  

<!--
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/MMQA-1559

## **Manual testing steps**
- Verify non-production builds show {ENV} | Branch: {branch} on About
screen
- Verify production builds do not show branch info
- Run unit tests: yarn jest
app/components/Views/Settings/AppInformation/index.test.tsx
```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only change that tweaks when/what build metadata is
displayed and updates associated Jest tests/snapshots; no runtime
behavior changes for production builds beyond hiding this label.
> 
> **Overview**
> Updates the About MetaMask (`AppInformation`) screen to show a
**build-type label + git branch**
(`${METAMASK_ENVIRONMENT.toUpperCase()} | Branch: ...`) for *all
non-production builds* by replacing the old `isQa` gate with
`!isProduction()`.
> 
> Refreshes tests to mock `isProduction`, adds explicit coverage that
production builds do not render branch info, and updates the snapshot
accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6e63822. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

When `BridgeView` stayed in zero-state, tapping into the amount input
and then tapping outside without entering an amount could leave the
keypad open.

This change centralizes keypad dismissal into a shared helper and
restores keypad dismissal for zero-state taps and scroll starts so the
keypad closes correctly even when no amount has been entered.

## **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 the bridge keypad staying open when no amount was
entered

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Bridge zero-state keypad dismissal

  Scenario: user dismisses the keypad with no amount entered
    Given I am on the Bridge screen with swaps trending tokens enabled
    And I have tapped the source amount input so the keypad is visible
    And I have not entered an amount

    When user taps or starts scrolling in the content area above the keypad
    Then the source input should blur
    And the keypad should close
```

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

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI interaction change limited to blur/close behavior for the
amount input and `SwapsKeypad` in `BridgeView`; potential risk is only
unintended extra dismissals on touch/scroll in zero-state.
> 
> **Overview**
> Fixes a zero-state interaction bug in `BridgeView` where the
`SwapsKeypad` could remain open after tapping outside the amount input
when *trending tokens* are shown.
> 
> This centralizes input/keypad dismissal into `dismissInputAndKeypad`
and wires it to zero-state touch and scroll gestures
(`onResponderRelease`, `onScrollBeginDrag`, and `onTouchEnd`) using a
shared `shouldShowTrendingTokens` guard.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
32a9d3e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…oute files (#28093)

<!--
# PR Title

refactor(navigation): deduplicate clearStackNavigatorOptions across
route files

-->
## **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 `clearStackNavigatorOptions` object was duplicated across 7 route
files (Bridge, Card, Ramp, Ramp/Aggregator, Ramp/Deposit, Earn, Stake)
with identical definitions. Some used `colors.transparent` while others
used the string `'transparent'`, creating an inconsistency.

This PR removes all 7 local definitions and replaces them with a single
import from `constants/navigation/clearStackNavigatorOptions`, which was
introduced earlier in the migration branch. This reduces duplication and
ensures consistent navigator options across all feature route stacks.

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

N/A — internal refactor with no behavior change.

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches shared React Navigation `screenOptions` used by multiple
modal/stack flows; small changes to animation/overlay configuration
could subtly affect transition behavior across several screens.
> 
> **Overview**
> Deduplicates repeated `clearStackNavigatorOptions` definitions across
Bridge/Card/Ramp (incl. Aggregator + Deposit)/Earn/Stake route stacks by
importing the shared constant from
`constants/navigation/clearStackNavigatorOptions`.
> 
> Updates `MainNavigator` and several modal stacks to use a new exported
variant, `clearStackNavigatorOptionsWithTransitionAnimation`, and adds
that variant in `clearStackNavigatorOptions.ts` (restoring the overlay
`cardStyleInterpolator` while keeping transparent background and
animations disabled).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0a94894. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Nicholas Smith <nick.smith@consensys.net>
…ettings (#28184)

## **Description**

Migrate 4 RootModalFlow assets/settings components from prop-based route
access to `useRoute()` hook (PR 8 of 13).

**Components:** BasicFunctionalityModal, AssetHideConfirmation,
AssetOptions, NftOptions

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

N/A — pure refactoring. All 22 existing 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.

## **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 refactor that standardizes React Navigation param access and
removes `any`/`ScreenComponent` casts; primary risk is runtime crashes
if a modal is opened without expected `route.params`.
> 
> **Overview**
> Migrates `BasicFunctionalityModal`, `AssetHideConfirmation`,
`AssetOptions`, and `NftOptions` from prop-based `route` access to typed
`useRoute()` hooks, allowing `RootModalFlow` to stop casting these
screens to `ScreenComponent`.
> 
> Updates and adds tests to mock `useRoute()` params accordingly
(including new coverage for `AssetHideConfirmation` and `NftOptions`),
without changing the underlying user-facing behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
df5b2b8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net>
## **Description**

WalletConnect reported 7,818 anomalous relay sessions from MetaMask
Mobile. A relay complexity limit takes effect April 15, 2026. Chain
change amplification is a major contributor — a single chain switch with
20 sessions generates ~80 relay messages instead of the expected ~40.

The root cause is two independent notification paths for chain changes:
1. **Store subscription path**: each `WalletConnect2Session` subscribes
to Redux and calls `handleChainChange()` → sends `updateSession` +
`emitSessionEvent` (2 messages)
2. **WalletConnectPort path**: `BackgroundBridge` emits `chainChanged` →
`WalletConnectPort.postMessage` intercepts and calls `updateSession()` →
sends another `updateSession` + `emitSessionEvent` (2 more messages)

This PR:
- Removes the duplicate WalletConnectPort `chainChanged` forwarding
(path 2 above)
- Adds a `lastEmittedChainId` dedup guard in `handleChainChange` to
prevent sequential duplicates from the `approveRequest` + store
subscription race
- Captures the `store.subscribe()` unsubscribe function and calls it in
`removeListeners()` to prevent leaked subscriptions

**Result**: 1 chain switch × 20 sessions = ~40 relay messages (2 per
session), down from ~80.

## **Changelog**

CHANGELOG entry: Fixed duplicate WalletConnect relay messages when
switching chains

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: WalletConnect chain change notifications

  Scenario: dapp requests chain switch
    Given the user has a dapp connected via WalletConnect on Mainnet

    When user approves a wallet_switchEthereumChain request from the dapp
    Then the dapp shows the new chain once (no duplicate notification)

  Scenario: chain round-trip A to B to A
    Given the user has a dapp connected via WalletConnect on Mainnet

    When user switches to Polygon then back to Mainnet
    Then the dapp reflects Polygon, then Mainnet (both transitions work)

  Scenario: account change still works
    Given the user has a dapp connected via WalletConnect

    When user switches the active account in MetaMask
    Then the connected dapp receives the account change notification
```

## **Screenshots/Recordings**

### **Before**

<!-- N/A - relay-level change, not visual -->

### **After**

<!-- N/A - relay-level change, not visual -->

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the WalletConnect v2 chain-change notification flow by
removing Redux store subscription and manual `chainChanged` emissions in
`WalletConnect2Session`, which could affect dapp network sync if the
remaining BackgroundBridge/Port path misbehaves. Scope is limited to
WalletConnect session lifecycle and related tests.
> 
> **Overview**
> Reduces WalletConnect v2 chain-change relay noise by removing
`WalletConnect2Session`'s Redux `store.subscribe` chain tracking, the
internal `handleChainChange`/request caching logic, and the extra
`chainChanged` event emission after `switchToChain`.
> 
> Updates tests to drop expectations around store unsubscription and
manual chain-change handling, and adds coverage for `WalletConnectPort`
reacting to `metamask_chainChanged` notifications (via mocked
`AppConstants.NOTIFICATION_NAMES`) by calling `updateSession` with the
selected account + parsed chainId.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a028535. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: jiexi <jiexiluan@gmail.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Removes unused code

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk refactor that removes an unused navbar helper and its tests;
main risk is any remaining external call sites that expected this export
at runtime.
> 
> **Overview**
> Removes the legacy `getTransactionsNavbarOptions` helper (and its
`AccountRightButton` dependency) from `Navbar/index.js`.
> 
> Cleans up the unit/integration tests in `Navbar/index.test.js` and
`Navbar/index.test.jsx` by deleting the corresponding
`getTransactionsNavbarOptions` test coverage.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
155917c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ions store (#28290)

## Summary

- **Fixes a bug** where `useOriginSource` misclassified all SDKConnectV2
(MWP) connections as `in-app browser`, causing the `source` property on
`CONNECT_REQUEST_STARTED`, `CONNECT_REQUEST_COMPLETED`, and
`CONNECT_REQUEST_CANCELLED` analytics events to be incorrect for V2
connections.
- The hook's existing check for the `MMSDKCONNECTV2::` prefix was dead
code — the prefix is stripped by `RPCMethodMiddleware` before it reaches
the permission system. V2 connections arrive with a bare UUID as their
origin.
- Adds a lookup against the `v2Connections` Redux store (already
populated by `HostApplicationAdapter.syncConnectionList`) to correctly
identify V2/MWP connections and return `SourceType.SDK_CONNECT_V2`.

## Root cause

The `RPCBridgeAdapter` constructs `middlewareHostname =
MMSDKCONNECTV2::<connId>`, but:
1. `RPCMethodMiddleware.ts` immediately strips the prefix
(`hostname.replace(SDK_CONNECT_V2_ORIGIN, '')`)
2. For the CAIP path (`wallet_createSession`),
`BackgroundBridge.channelIdOrOrigin` returns the bare `channelId` (UUID)
when `isMMSDK=true`
3. The `PermissionController` approval request therefore carries a bare
UUID as `metadata.origin`
4. `useOriginSource` couldn't match this UUID to V2 — it only checked
the V1 `SDKConnect` store

CHANGELOG entry: `null`

## Test plan

- [x] Unit tests: 7 passing (2 new V2-specific tests added)
- [ ] Manual: Open an MWP deeplink, verify `CONNECT_REQUEST_STARTED`
event has `source: 'sdk_connect_v2'` instead of `source: 'in-app
browser'`
- [ ] Verify no regression for V1 SDK connections (`source: 'sdk'`)
- [ ] Verify no regression for WalletConnect connections (`source:
'walletconnect'`)
- [ ] Verify no regression for in-app browser connections (`source:
'in-app browser'`)

## Related

- Fixes:
[WAPI-1380](https://consensyssoftware.atlassian.net/browse/WAPI-1380)
- Related PR: #27864 (wallet-side analytics for SDKConnectV2/MWP — this
fix reduces the scope of new events needed there)


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the source-classification logic used for connection-request
analytics by introducing a new SDK v2 detection path and reordering
precedence, which could shift event attribution if the v2Connections
store is incomplete or stale.
> 
> **Overview**
> Fixes `useOriginSource` to correctly detect **SDK Connect v2 (MWP)**
permission origins by treating a *bare UUID* as v2 when it exists in the
Redux `sdk.v2Connections` map (instead of relying on a removed/stripped
v2 prefix).
> 
> Refactors the hook to use an explicit priority order (**v2 → v1 →
WalletConnect → in-app browser**) and adds unit coverage for v2
detection (including the case where the same UUID exists in both v1 and
v2, with v2 winning). Tests that build mock Redux `sdk` state were
updated to include an empty `v2Connections` field.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5a7473e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…con/BannerAlert/Button (#28298)

## **Description**

Updates deprecated component docblocks to consistently include links to
both the component README and the component-specific migration section
in the design-system-react-native migration guide.

This aligns `Icon`, `BannerAlert`, and `Button` with the same
deprecation guidance format used by `Text`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Deprecated component doc links are consistent

  Scenario: engineer checks deprecation notices
    Given the component wrapper files for Text, Icon, BannerAlert, and Button
    When viewing each component JSDoc deprecation block
    Then each includes a README link and a migration docs link with the component anchor
```

## **Screenshots/Recordings**

### **Before**

N/A (documentation-only JSDoc updates)

### **After**

N/A (documentation-only JSDoc updates)

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: documentation-only JSDoc link updates with no runtime or
behavior changes.
> 
> **Overview**
> Standardizes the `@deprecated` JSDoc blocks for `Text`, `Icon`,
`BannerAlert`, and `Button` to consistently include a component-specific
anchor link into the design-system React Native `MIGRATION.md`.
> 
> This replaces generic migration guide references with
`#text-component`, `#icon-component`, `#banneralert-component`, and
`#button-component` links alongside the existing README links.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d933095. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…unt sheets (#28182)

## **Description**

Migrate 3 RootModalFlow SDK/account sheet components from prop-based
route access to `useRoute()` hook, removing their `as ScreenComponent`
casts in App.tsx.

Part of the effort to remove `no-explicit-any` violations from route
files (PR 6 of 13).

**Components migrated:**
- `AddNewAccountBottomSheet` - reads optional scope/clientType params
for non-EVM account creation
- `SDKSessionModal` - reads channelId, icon, urlOrTitle, version,
platform, isV2 for SDK session management
- `SDKDisconnectModal` - reads channelId, account, accountName, dapp,
accountsLength, isV2 for SDK disconnect flows

**Changes:**
- Switch each component to `useRoute()` with typed `RouteProp` generic
- Remove dead Props interfaces (`SDKSEssionMoodalProps`,
`SDKDisconnectModalProps`)
- Simplify `AddNewAccountBottomSheet` types to export only `RouteParams`
- Remove 3 `as ScreenComponent` casts from `App.tsx`
- Update all 3 test files to mock `useRoute()`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

N/A — pure refactoring with no user-facing behavior change. All 26
existing 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.

## **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 refactor that only changes how route params are accessed for
three modal sheets and updates tests accordingly; behavior should be
unchanged but regressions could occur if route params are
missing/mistyped at runtime.
> 
> **Overview**
> Refactors three RootModalFlow sheet components
(`AddNewAccountBottomSheet`, `SDKSessionModal`, `SDKDisconnectModal`) to
stop receiving `route` as a prop and instead read typed params via React
Navigation’s `useRoute()`.
> 
> Removes the corresponding `as ScreenComponent` casts in `App.tsx`,
deletes the old prop interfaces in favor of route-param types, and
updates the associated tests to mock `useRoute()` rather than passing
`route` props.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bdc9a64. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
- Use push EAS update in the Runway workflow directly
- Fix PR number null issue

## **Changelog**

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

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

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

CHANGELOG entry:null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the release/OTA GitHub Actions orchestration by switching from
API dispatch to a reusable workflow and tweaking PR-number resolution;
mistakes here could block OTA publishing or target the wrong ref.
> 
> **Overview**
> Updates the OTA publishing pipeline to call `push-eas-update.yml` as a
*reusable workflow* (`workflow_call`) instead of dispatching it via
`actions/github-script`, simplifying `runway-ota-build-core.yml`.
> 
> Also fixes PR-number discovery to treat `gh pr list` returning `null`
as empty (avoiding false positives), and updates `CODEOWNERS` to include
the new `build-and-upload-to-testflight.yml` workflow under
`@MetaMask/mobile-admins`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
633c2ac. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cal-L <cal.leung@consensys.net>
## **Description**

Integrating the new `money-account-controller`.

If you wish to see the logs of this new controller, make sure to add
this to your `.env.js`:
```
export DEBUG=metamask:money-account-controller
```

To enable with a local feature flag (`.js.env`):
```
export OVERRIDE_REMOTE_FEATURE_FLAGS="true"
export MM_MONEY_ENABLE_MONEY_ACCOUNT="true"
```

You should see logs like this (the first time the Money account gets
created):
```
(NOBRIDGE) DEBUG  metamask:money-account-controller Money keyring (entropy:01KN6N42H46T44X2XMFNNGSJBR) not found, creating one... +0ms
(NOBRIDGE) DEBUG  metamask:money-account-controller Money keyring (entropy:01KN6N42H46T44X2XMFNNGSJBR) has no accounts, creating one... +4ms
(NOBRIDGE) DEBUG  metamask:money-account-controller Money keyring (entropy:01KN6N42H46T44X2XMFNNGSJBR) account created: 0x7fd31648732ad5d5e60d724652d3517184647b2b (d50016b8-6db3-422a-8d74-31514d276073) +34ms
(NOBRIDGE) DEBUG  metamask:money-account-controller Money keyring (entropy:01KN6N42H46T44X2XMFNNGSJBR - primary) account is: 0x7fd31648732ad5d5e60d724652d3517184647b2b (d50016b8-6db3-422a-8d74-31514d276073) +1ms
```

And logs like this afterward (e.g after an unlock):
```
(NOBRIDGE) DEBUG  metamask:money-account-controller Money keyring (entropy:01KN6N42H46T44X2XMFNNGSJBR - primary) account is: 0x7fd31648732ad5d5e60d724652d3517184647b2b (d50016b8-6db3-422a-8d74-31514d276073) +8m
```

You can also, visually see the Money account address by applying this
patch:
```diff
diff --git a/app/components/UI/Money/components/MoneyHeader/MoneyHeader.tsx b/app/components/UI/Money/components/MoneyHeader/MoneyHeader.tsx
index 0bd441d..d1348a4cd3 100644
--- a/app/components/UI/Money/components/MoneyHeader/MoneyHeader.tsx
+++ b/app/components/UI/Money/components/MoneyHeader/MoneyHeader.tsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import { useSelector } from 'react-redux';
 import {
   Box,
   BoxAlignItems,
@@ -7,8 +8,11 @@ import {
   ButtonIcon,
   ButtonIconSize,
   IconName,
+  Text,
+  TextVariant,
 } from '@metamask/design-system-react-native';
 import { MoneyHeaderTestIds } from './MoneyHeader.testIds';
+import { selectPrimaryMoneyAccount } from '../../../../../selectors/moneyAccountController';

 interface MoneyHeaderProps {
   /**
@@ -21,29 +25,40 @@ interface MoneyHeaderProps {
   onMenuPress: () => void;
 }

-const MoneyHeader = ({ onBackPress, onMenuPress }: MoneyHeaderProps) => (
-  <Box
-    flexDirection={BoxFlexDirection.Row}
-    alignItems={BoxAlignItems.Center}
-    justifyContent={BoxJustifyContent.Between}
-    twClassName="px-1 pt-2 pb-5"
-    testID={MoneyHeaderTestIds.CONTAINER}
-  >
-    <ButtonIcon
-      iconName={IconName.ArrowLeft}
-      size={ButtonIconSize.Md}
-      onPress={onBackPress}
-      accessibilityLabel="Back"
-      testID={MoneyHeaderTestIds.BACK_BUTTON}
-    />
-    <ButtonIcon
-      iconName={IconName.MoreVertical}
-      size={ButtonIconSize.Md}
-      onPress={onMenuPress}
-      accessibilityLabel="Menu"
-      testID={MoneyHeaderTestIds.MENU_BUTTON}
-    />
-  </Box>
-);
+const MoneyHeader = ({ onBackPress, onMenuPress }: MoneyHeaderProps) => {
+  const primaryMoneyAccount = useSelector(selectPrimaryMoneyAccount);
+
+  return (
+    <Box
+      flexDirection={BoxFlexDirection.Row}
+      alignItems={BoxAlignItems.Center}
+      justifyContent={BoxJustifyContent.Between}
+      twClassName="px-1 pt-2 pb-5"
+      testID={MoneyHeaderTestIds.CONTAINER}
+    >
+      <ButtonIcon
+        iconName={IconName.ArrowLeft}
+        size={ButtonIconSize.Md}
+        onPress={onBackPress}
+        accessibilityLabel="Back"
+        testID={MoneyHeaderTestIds.BACK_BUTTON}
+      />
+      {
+        primaryMoneyAccount ? (
+          <Text variant={TextVariant.BodySm}>
+            {primaryMoneyAccount.address}
+          </Text>
+        ) : null
+      }
+      <ButtonIcon
+        iconName={IconName.MoreVertical}
+        size={ButtonIconSize.Md}
+        onPress={onMenuPress}
+        accessibilityLabel="Menu"
+        testID={MoneyHeaderTestIds.MENU_BUTTON}
+      />
+    </Box>
+  );
+};

 export default MoneyHeader;
```

And you can navigate to the `MoneyHomeView` (by clicking on `Cash >`).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

### **Before**

### **After**

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> High risk because it adds a new background controller into `Engine`
initialization/state and conditionally introduces a `MoneyKeyring` that
pulls and encodes HD keyring mnemonics, impacting key management and
startup behavior.
> 
> **Overview**
> Integrates `@metamask/money-account-controller` into the background
`Engine` (init wiring, messenger delegation, stateChange subscriptions,
persisted initial state/log snapshots) so its state is available via
`Engine.context`/`Engine.state`.
> 
> Adds a new remote+env gated flag (`moneyEnableMoneyAccount` /
`MM_MONEY_ENABLE_MONEY_ACCOUNT`) and uses it to (a) conditionally
initialize/clear `MoneyAccountController` during account-tree startup
and (b) conditionally register a `MoneyKeyring` builder in
`keyringControllerInit`, including a `getMnemonic` callback that locates
the matching HD keyring and encodes its mnemonic for Money keyring
initialization.
> 
> Introduces selectors for Money accounts (`selectMoneyAccounts`,
`selectPrimaryMoneyAccount`) plus a `selectPrimaryHDKeyring` helper, and
updates/extends unit tests and feature-flag registry accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fda78f6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Gustavo Antunes <17601467+gantunesr@users.noreply.github.com>
…nified swaps context cp-7.73.0 (#28361)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

When a destination token has a security warning (e.g. a Blockaid
malicious/suspicious flag), the unified swaps bridge view was entering
an infinite quote request loop.

**Root cause:** `tokenWarning` was included as a dependency of the
`useMemo` that builds the analytics `context` object in
`useUnifiedSwapBridgeContext`. `tokenWarning` is itself derived from
quote results (blockaid data returned by the bridge controller). This
created a feedback cycle:

```
Quote fetched → tokenWarning updates → context object recreates
→ updateQuoteParams identity changes → useEffect fires
→ new quote request → repeat ∞
```

**Fix:** Remove `tokenWarning` from the `useMemo` dependency array and
clear `security_warnings` to `[]` for now. The `security_warnings` field
will be populated properly in the bridge controller instead, removing
the React dependency cycle entirely.

## **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 a bug that caused repeated quote requests when
swapping to a token with a security warning.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Unified Swaps/Bridge quote fetching with token warnings

  Scenario: user swaps to a token with a Blockaid security warning
    Given the user has opened the Swap/Bridge screen
    And the user has selected a source token with sufficient balance

    When the user selects a destination token that has a Blockaid security warning
    And the user enters a valid source amount
    Then the app fetches a quote once
    And does not repeatedly fire additional quote requests
    And the security warning banner is displayed on screen

  Scenario: user swaps to a normal token (no warning)
    Given the user has opened the Swap/Bridge screen
    And the user has selected a source token with sufficient balance

    When the user selects a destination token with no security warning
    And the user enters a valid source amount
    Then the app fetches a quote once
    And quote results are displayed normally
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**


Uploading Screen Recording 2026-04-02 at 4.24.51 PM.mov…



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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: small change limited to analytics context memoization, but
it temporarily drops `security_warnings` data which could affect
warning-related telemetry until re-populated elsewhere.
> 
> **Overview**
> Prevents an infinite bridge quote re-fetch loop by removing
destination token warning state from `useUnifiedSwapBridgeContext`’s
memoized context object.
> 
> `security_warnings` is now always an empty array (*TODO*) and the
`useMemo` dependency list no longer includes the warning selector,
stabilizing the `context` identity passed into
`BridgeController.updateBridgeQuoteRequestParams`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
21dec81. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…28285)

## **Description**

Fixes a bug where the network selector icon in the In-App Browser was
stuck displaying the global selected network due to incorrect dapp
origin information being used

## **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 a bug where the network selector icon in the
In-App Browser would not correctly reflect the currently selected
network for the dapp

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/WAPI-1031

## **Manual testing steps**

1. Open Explore
2. Click the top right In-App Browser tab icon
3. Tap the top right network selector icon
4. Select a network that differs from the current icon
5. The icon should change to match

## **Screenshots/Recordings**

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

### **Before**



https://github.com/user-attachments/assets/d68fc3a2-4145-4189-ae97-bc2ece8a018a



### **After**



https://github.com/user-attachments/assets/2cd0a33a-7885-402c-b537-ebbd1448aae1



## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: scoped UI/navigation parameter plumbing to ensure per-dapp
network context is used; main risk is callers missing the new required
`dappOrigin` prop or origin parsing yielding empty origin in edge URLs.
> 
> **Overview**
> Fixes the In-App Browser network picker/avatar to reflect the
*dapp-selected* network by threading an explicit `dappOrigin` through
`BrowserUrlBar` into `AccountRightButton`.
> 
> `AccountRightButton` no longer derives origin from navigation route
params; it now uses `dappOrigin` for `useNetworkInfo` and includes it as
`hostInfo.metadata.origin` when opening the `NetworkSelector` sheet, so
the selector can resolve the per-origin network. Tests were updated
accordingly to supply a non-empty `dappOrigin` and remove the `useRoute`
mock.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9c4cbaa. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Alex Donesky <adonesky@gmail.com>
…28111)

## **Description**

Uses the self reported dapp url when available for the
`CONNECT_REQUEST_COMPLETED` event when the connection is a SDKv1, SDKv2,
or WC connection. It uses the trusted origin otherwise.

## **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/WAPI-1338

## **Manual testing steps**

1. Establish a WC or SDKv1 or SDKv2 connection
2. Check analytics events for a property value `referrer` that should be
the dapp's url, not a UUID

It may be easier to use an expo build and the js debugger to view
analytic network events.

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk analytics-only change that alters the `referrer` value
emitted for `CONNECT_REQUEST_COMPLETED`, potentially affecting
downstream dashboards but not user-facing behavior.
> 
> **Overview**
> Updates analytics for connection approvals so
`MetaMetricsEvents.CONNECT_REQUEST_COMPLETED` now reports a computed
`referrer` (SDK/WC self-reported dapp URL when available, otherwise the
trusted hostname/origin) instead of always using
`request.metadata.origin`.
> 
> Applies the same `referrer` logic in both `AccountConnect` and
`MultichainAccountConnect`, and wires it into the `handleConnect`
tracking dependencies.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ad3bb42. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Alex Donesky <adonesky@gmail.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

The `trigger-ota` job mixed shell steps with a reusable workflow (`uses:
./.github/workflows/push-eas-update.yml`). In GitHub Actions, a job must
either define `steps:` or call another workflow with job-level `uses:`,
not both.
This splits that into:
1. **`validate-ota-pr`** — Validates a PR number exists before OTA (same
guard as before).
2. **`trigger-ota`** — Only calls `push-eas-update.yml`, with `secrets:
inherit` for caller secrets.
**`create-ota-production-tag`** now sets `tag_name` from
`needs.decide.outputs.ota_version` (same value the old `release_tag`
step echoed). It still `needs: trigger-ota` so tagging runs only after
the OTA workflow finishes.

successful workflow run:
https://github.com/MetaMask/metamask-mobile/actions/runs/23923283109

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes the job graph for Runway OTA
publishing/tagging; misconfigured `needs`/`uses`/secrets inheritance
could block OTA releases or trigger the wrong follow-up jobs.
> 
> **Overview**
> Fixes `runway-ota-build-core.yml` to correctly invoke the reusable
`push-eas-update.yml` workflow as a **job-level** `uses:` instead of
mixing it with `steps:`.
> 
> Adds a separate `validate-ota-pr` job to guard OTA runs when no PR
number is resolvable, updates `trigger-ota` to inherit secrets, and
adjusts production tagging to use `needs.decide.outputs.ota_version`
directly (removing the intermediate `release_tag` output).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
92b5c4c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…p-7.73.0 (#28302)

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

Addresses several UAT issues in the Predict buy-with-any-token flow:

- **Auto-select best payment token**: New
`usePredictDefaultPaymentToken` hook auto-selects the token with the
highest fiat balance when Predict balance is below MINIMUM_BET ($1),
instead of requiring manual selection. Resets to Predict balance when
sufficient.
- **Optimistic positions on deposit**: Creates optimistic positions from
the order preview at deposit time so the position appears immediately in
the portfolio while the deposit confirms. Clears optimistic positions on
failure (both direct order failures and failed deposit-and-order
transactions).
- **Navigate back on deposit**: Navigate back when the deposit-and-order
flow begins, so the user isn't stuck on the buy form.
- **Keep token selection always enabled**: Removes the `canSelectToken`
gate — the pay-with-token row is now always interactive (disabled only
while placing an order).
- **"Predict balance first" hint**: Shows "Your Predict balance will be
used first" below the pay-with row when an external token is selected,
so users understand the payment order.
- **Deposit amount guards**: `depositAmount` now returns 0 when the
preview is unavailable or the bet is below minimum, preventing premature
deposit calculations and stale values from triggering the deposit flow.
- **Updated insufficient funds messaging**: Error messages now suggest
trying a different token when funds are insufficient.
- **Fix text overflow on Polymarket terms**: Nests the "learn more" link
inside the disclaimer text and adds horizontal padding to prevent
overflow.
- **Fix premature payment token reset**: Adds a
`totalPayForPredictBalance > 0` guard so the auto-reset effect only
fires when there is an actual bet amount, preventing the selected token
from being cleared immediately after selection.
- **Depositing toast notification**: Shows a "Prediction in progress"
toast with spinner when the deposit phase begins and invalidates
position queries to reflect the optimistic position.


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

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

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

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Updates buy-with-any-token order state transitions, optimistic
position caching, and navigation/toast behavior; mistakes could cause
incorrect UI state or stale/phantom positions during deposit/order
failures.
> 
> **Overview**
> Improves the *buy-with-any-token* flow by introducing a new `order`
event status `depositing` and publishing it when the flow transitions
into the deposit phase, with a matching “Prediction in progress” toast
and positions query invalidation.
> 
> Adds preview-based **optimistic positions** during deposit via
`PolymarketProvider.createOptimisticPositionFromPreview`, and ensures
cleanup via `clearOptimisticPosition` when `placeOrder` fails or when a
`depositAndOrder` transaction fails.
> 
> Refines buy screen UX: auto-selects a default payment token when
Predict balance is below `MINIMUM_BET` (new
`usePredictDefaultPaymentToken`), removes the `canSelectToken` gate (row
only disabled while placing), navigates back when entering `DEPOSITING`,
adds a “Predict balance will be used first” hint, guards deposit amount
calculation until fees/minimum bet are available, and updates
insufficient-funds copy to suggest trying another token; also adjusts
the Polymarket TOS disclaimer layout to prevent overflow.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7f97218. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

Migrated `Button` to DSRN package usage.

## **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/DSYS-445

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**


https://github.com/user-attachments/assets/26db059b-4937-4e94-827c-7ca7b9624596

### **After**


https://github.com/user-attachments/assets/56fbddab-9c75-40fc-bbb5-6ee3560f3ecc

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it swaps button implementations across multiple
settings/network/account screens, which can subtly change
press/disabled/accessibility behavior and snapshot structure.
> 
> **Overview**
> Migrates multiple screens (e.g., `EditAccountName`, network
connect/selector flows, and several Settings sections) from the internal
`component-library` `Button` to `@metamask/design-system-react-native`
`Button`, updating props (`label` -> children, `disabled` ->
`isDisabled`, `width` -> `isFullWidth`, and new `ButtonVariant` enums).
> 
> Updates tests and snapshots to match the new rendered
structure/accessibility output, including tightening the
`NetworkConnectMultiSelector` loading test to assert the update CTA is
disabled and that “select all” is a no-op while loading, and removing
the now-unneeded `disabledOpacity` styling.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
136d88e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
abretonc7s and others added 20 commits April 13, 2026 00:31
…et test (#28708)

## **Description**

Fix Prettier formatting violations and eslint errors in
`SafeAreaViewWithHookTopInset.test.tsx` introduced by #28622. These
break lint checks on any unrelated PR that touches this file.

**Changes:**
- Reformat JSX to match Prettier config
- Extract inline styles to `StyleSheet.create` to fix
`react-native/no-inline-styles`
- Replace `require()` with `jest.requireActual()` in `jest.mock` factory
to fix `@typescript-eslint/no-require-imports`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes lint/formatting regressions from #28622

## **Manual testing steps**

```gherkin
Feature: SafeAreaViewWithHookTopInset test lint compliance

  Scenario: lint and tests pass on the test file
    Given the file app/shims/SafeAreaViewWithHookTopInset.test.tsx

    When running eslint on the file
    Then zero errors are reported

    When running jest on the file
    Then all 20 tests pass
```

## **Screenshots/Recordings**

N/A — no visual changes, formatting and lint fixes only.

### **Before**

6 eslint errors on `main`:
- 2x `@typescript-eslint/no-require-imports` — `require()` inside
`jest.mock` factory
- 4x `react-native/no-inline-styles` — inline style objects in test
assertions

### **After**

0 eslint errors, 0 eslint-disable comments, all 20 tests passing.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are confined to a Jest test file and only adjust
mocks/style declarations to satisfy linting/formatting, without touching
runtime code paths.
> 
> **Overview**
> Cleans up `SafeAreaViewWithHookTopInset.test.tsx` to pass lint/format
checks by switching `jest.mock` factories from `require()` to typed
`jest.requireActual()` and tightening ref typings in the mock
`SafeAreaView`.
> 
> Replaces inline style objects used in tests with a shared
`StyleSheet.create` (`testStyles`) and applies minor Prettier-driven
JSX/line-wrap formatting changes, leaving test coverage/behavior
unchanged.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
00a20c7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Add app lifecycle actions (`app_background`, `app_foreground`,
`app_restart`) to the agentic tooling with platform-aware
implementations (iOS `simctl` + Android `adb`). Enable multi-device CDP
target discovery so `status` probes all targets across both platforms.
Fix preflight to reuse a healthy Metro instance (curl /status check) and
warn on platform mismatch instead of failing. Add `--input key=value`
flag to `validate-recipe.js`.

Also fixes switch/end nodes bypassing `when` guards (caused TypeError on
default config), and adds automatic `run.log` capture for every recipe
execution.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Agentic lifecycle actions and multi-device support

  Scenario: run app-lifecycle recipe in dry-run mode
    Given the agentic tooling is available

    When user runs validate-recipe with app-lifecycle.json --dry-run
    Then recipe parses and validates without errors

  Scenario: CDP bridge status shows multiple targets
    Given both iOS simulator and Android emulator are running

    When user runs cdp-bridge.js status
    Then both platform targets are listed

  Scenario: lifecycle actions execute per platform
    Given the app is running on iOS simulator

    When user triggers app_background action
    Then the app moves to background via simctl
```

## **Screenshots/Recordings**

### **Before**

N/A — new tooling feature

### **After**

- `node validate-recipe.js recipes/app-lifecycle.json --dry-run` —
parses OK
- Lifecycle actions validated on both iOS simulator and Android emulator
- Multi-device target discovery working across platforms

## **Validation Recipe**

<details><summary>app-lifecycle.json (20 nodes — short background, long
background, restart)</summary>

```json
{
  "title": "App Lifecycle — validate data survives background, long background, and restart",
  "description": "Reference recipe demonstrating three lifecycle stress levels: short background (within WS grace period), long background (exceeds grace period, forces full WS reconnection), and full app restart. Use as a template for PR recipes that need lifecycle validation.",
  "inputs": {
    "symbol": { "type": "string", "default": "BTC" },
    "short_background_ms": { "type": "number", "default": 5000 },
    "long_background_ms": { "type": "number", "default": 30000 },
    "test_short_background": { "type": "boolean", "default": true },
    "test_long_background": { "type": "boolean", "default": true },
    "test_restart": { "type": "boolean", "default": false }
  },
  "validate": {
    "workflow": {
      "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"],
      "entry": "nav-market-list",
      "nodes": {
        "nav-market-list": { "action": "navigate", "target": "PerpsTrendingView", "next": "wait-markets" },
        "wait-markets": { "action": "wait_for", "assert": { "operator": "gt", "field": "count", "value": 0 }, "next": "baseline-price" },
        "baseline-price": { "action": "eval_async", "description": "Baseline — confirm markets and price data loaded", "next": "short-background" },
        "short-background": { "action": "app_background", "when": "test_short_background", "duration_ms": "{{short_background_ms}}", "next": "short-foreground" },
        "short-foreground": { "action": "app_foreground", "next": "wait-post-short" },
        "wait-post-short": { "action": "wait_for", "next": "verify-post-short" },
        "verify-post-short": { "action": "eval_async", "description": "Confirm markets + price survive short background", "next": "long-background" },
        "long-background": { "action": "app_background", "description": "Exceeds WS grace period", "duration_ms": 30000, "next": "long-foreground" },
        "long-foreground": { "action": "app_foreground", "next": "wait-post-long" },
        "wait-post-long": { "action": "wait_for", "next": "verify-post-long" },
        "verify-post-long": { "action": "eval_async", "description": "Confirm markets + DEXs recover after WS reconnection", "next": "restart-app" },
        "restart-app": { "action": "app_restart", "when": "test_restart", "next": "detect-post-restart" },
        "...": "remaining restart/unlock/verify nodes",
        "done": { "action": "end", "status": "pass" }
      }
    }
  }
}
```

</details>

## **Validation Logs**

Command:
```bash
node scripts/perps/agentic/validate-recipe.js \
  scripts/perps/agentic/teams/perps/recipes/app-lifecycle.json
```

<details><summary>Full output (11/17 passed, 6 skipped — iOS)</summary>

```
Running recipe: App Lifecycle — validate data survives background, long background, and restart
Team: perps
Pre-conditions: wallet.unlocked, perps.feature_enabled
Workflow nodes: 20

Pre-conditions: PASS

[nav-market-list] navigate to PerpsTrendingView
  result: {"navigated":"PerpsTrendingView",...}
  PASS

[wait-markets] wait for condition
  result: {"count":291}
  PASS

[baseline-price] Baseline — confirm markets and price data loaded
  result: {"found":true,"price":"$71,046"}
  PASS

[short-background] Short background — within WS grace period, cache should be preserved
  backgrounded for 5000ms
  PASS

[short-foreground] foreground app
  foregrounded (io.metamask.MetaMask)
  PASS

[wait-post-short] wait for condition
  result: {"count":291}
  PASS

[verify-post-short] Confirm markets + price survive short background
  result: {"found":true,"price":"$71,058"}
  PASS

[long-background] Long background — exceeds WS grace period, forces full reconnection
  backgrounded for 30000ms
  PASS

[long-foreground] foreground app
  foregrounded (io.metamask.MetaMask)
  PASS

[wait-post-long] wait for condition
  result: {"count":291}
  PASS

[verify-post-long] Confirm markets + DEXs recover after full WS reconnection
  result: {"markets":291,"dexs":9,"price":"$71,039"}
  PASS

[restart-app] restart app
  [SKIPPED - when condition did not match]

[detect-post-restart] Detect login vs wallet after restart
  [SKIPPED - when condition did not match]

[check-needs-unlock] evaluate branch
  [SKIPPED - when condition did not match]

[nav-after-restart] navigate to PerpsTrendingView
  [SKIPPED - when condition did not match]

[wait-post-restart] wait for condition
  [SKIPPED - when condition did not match]

[verify-post-restart] Confirm markets reload cleanly after full restart
  [SKIPPED - when condition did not match]

----------------------------------------
Results: 11/17 passed, 6 skipped
Recipe: PASS
```

</details>

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new workflow actions that spawn `xcrun`/`adb` processes and
changes CDP target selection/reporting, which can affect automation
reliability across devices. Also introduces automatic log
capture/redaction and new CLI flags that alter runner behavior.
> 
> **Overview**
> **Agentic workflows can now exercise app lifecycle events.** The
recipe runner adds new actions (`app_background`, `app_foreground`,
`app_restart`) implemented via a new `lib/app-lifecycle.js` that uses
`simctl`/AppleScript on iOS and `adb` on Android, and documents these
actions plus a new `teams/perps/recipes/app-lifecycle.json` reference
recipe.
> 
> **CDP and preflight scripts now better support multi-device setups.**
`cdp-bridge.js status` probes *all* discovered Hermes targets (via new
`discoverAllTargets`) and returns either a single object or an array;
`preflight.sh` reuses an already-healthy Metro instance by probing
`/status` and loosens the platform check to a warning when the expected
platform target isn’t found.
> 
> **Recipe execution UX improved.** `validate-recipe.js` adds `--input
key=value` for overriding recipe inputs, `--no-log` to disable logging,
captures console output to `run.log` with basic redaction, and fixes
`when` guards to apply to `switch`/`end` nodes (skipping them safely
instead of executing).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b3948ed. 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**

Removed the scheduled cron trigger from
`.github/workflows/run-e2e-regression-tests-android.yml` so this
workflow no longer runs every 3 hours.

The workflow can still be run manually via `workflow_dispatch`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

```gherkin
Feature: Android regression workflow trigger behavior

  Scenario: workflow can be manually triggered only
    Given the GitHub Actions workflow file `run-e2e-regression-tests-android.yml`
    When I inspect the `on` section
    Then it contains `workflow_dispatch` inputs
    And it does not contain a `schedule` cron trigger
```

## **Screenshots/Recordings**

Not applicable (CI workflow configuration change only).

### **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
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-6074cff0-b322-43a4-898b-b8b12af5bb28"><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-6074cff0-b322-43a4-898b-b8b12af5bb28"><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>
Co-authored-by: cmd-ob <cmd-ob@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Fix design of mush deposit page.

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

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

## **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**
<img width="395" height="853" alt="Screenshot 2026-04-10 at 4 22 11 PM"
src="https://github.com/user-attachments/assets/584fab12-a80f-4092-a57e-6ec0e662dabd"
/>

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI/prop change limited to the confirmations custom amount
view and mUSD conversion flow; main risk is unintended layout/row
visibility regressions when `hidePayTokenAmount` is enabled.
> 
> **Overview**
> Updates `CustomAmountInfo` to **remove `overrideContent`** and
introduce `hidePayTokenAmount`, which hides the default `PayTokenAmount`
(and the associated extra content block) while keeping `PayWithRow`
rendering logic consistent.
> 
> Simplifies `MusdConversionInfo` by deleting the bespoke override UI
(output tag + embedded `PayWithRow`) and instead passing
`hidePayTokenAmount` to `CustomAmountInfo`; tests are updated
accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3c829f9. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Speed up and cancel failures no longer open a blocking **Retry** modal.
Users see a **toast** with a clear title and, when available, a short
error description—including a friendlier message when the failure is due
to **“nonce too low”** (already confirmed).

**Changes**  
- Removed `RetryModal` and related state (`retryIsOpen`, `errorMsg`,
`toggleRetry`, `retry`) from the legacy **Transactions** screen and
**UnifiedTransactionsView**.
- On failure, **legacy** `Transactions` uses `ToastService.showToast`
with shared options from `getTransactionUpdateErrorToastOptions`.
- **Unified** flow uses `ToastContext` in `useUnifiedTxActions` to show
the same toast shape.
- Centralized toast config in `app/util/confirmation/transactions.ts`
(variant, icon, colors, transparent background, copy) so both entry
points stay in sync.
- Added `resolveTransactionUpdateErrorMessage` to map raw errors to
user-facing strings where we special-case known cases.


<!--
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: Redesigned speed-up/cancel retry modal with error
toasts

## **Related issues**

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

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

[toast
failed.webm](https://github.com/user-attachments/assets/3baec8fe-8513-4e99-ad14-f36c16a72043)


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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UX refactor that changes how speed-up/cancel failures are
surfaced (toast instead of a blocking modal) without altering
transaction update logic; main risk is missing toast context/service
wiring in some views.
> 
> **Overview**
> Speed-up/cancel failures no longer open a blocking **Retry** modal;
they now show an **error toast** in both the legacy `Transactions` list
(via `ToastService`) and the unified flow (via `ToastContext`).
> 
> Adds shared helpers `resolveTransactionUpdateErrorMessage` and
`getTransactionUpdateErrorToastOptions` in
`util/confirmation/transactions.ts`, including a friendlier message for
*“nonce too low”* (already confirmed), and updates tests/mocks
accordingly. Locale strings are migrated from
`transaction_update_retry_modal` to `transaction_update_toast` across
supported languages.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d49b050. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

This updates the A/B testing documentation to make the implementation
path much easier for a new engineer to follow.

The guide now starts with a quickstart and definition of done,
consolidates the implementation guidance into one end-to-end example,
and moves agent-specific workflow details to an appendix so they do not
interrupt the main onboarding flow.

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

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

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

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

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

Using alert system for money account related errors.

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

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

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes how `moneyAccountDeposit` “no funds” is surfaced by
introducing a new blocking alert and wiring it into the shared
pending-amount alert pipeline, which can affect confirm-button
enablement and user flow. Risk is limited to confirmations/UX and is
covered by added unit tests.
> 
> **Overview**
> Moves the `moneyAccountDeposit` “no funds” state into the
confirmations *alert system* by introducing a new blocking
`AccountNoFunds` alert (with metrics mapping) and feeding it through
`usePendingAmountAlerts`.
> 
> Removes the old inline “no funds” red text from `CustomAmountInfo`,
updates tests to assert alert-driven rendering, and adds new i18n under
`alert_system.account_no_funds` while deleting the legacy
`confirm.no_funds_use_different_account` string.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c92ce45. 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.74.0.

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

Wires up the Social Leaderboard to live data from the Social API.
Integrate the social-controllers (SocialService + SocialController) into
the Engine, adds useTopTraders hook using useQuery from
@metamask/react-data-query to fetch leaderboard data through the Data
Services pattern.
Also adds the homepage TopTradersSection (horizontal card carousel) and
the full TopTradersView (ranked list) with skeleton loading states.

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new Social data service/controller to the Engine and wires UI
screens to fetch live leaderboard data from a new `SOCIAL_API_URL`,
which could impact app startup/state persistence and introduce new
network failure modes.
> 
> **Overview**
> Adds live Social Leaderboard integration by introducing Engine-managed
`SocialService` and `SocialController` (new messengers, init wiring,
persisted state, and data-service registration) and configuring a new
`SOCIAL_API_URL` build/env constant.
> 
> Updates the homepage `TopTradersSection` to fetch and render the top 3
traders (cards + skeleton loading, refresh via ref, hide when empty/flag
off) and upgrades `TopTradersView` to display the full ranked list with
a network filter entry point and follow toggles.
> 
> Includes new UI components (`TopTraderCard`, `TraderRow`, skeletons,
`NetworkFilterButton`), a `formatPnl` formatter, the `useTopTraders`
hook built on `@metamask/react-data-query`, plus expanded unit tests and
updated mocks/strings.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5881e59. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
https://consensyssoftware.atlassian.net/browse/RWDS-1163

### Leaderboard tier selector
- Replaced TabsBar with a Pressable trigger that opens a
RewardsSelectSheet bottom sheet for tier selection
- Created RewardsSelectSheet -- a generic, reusable select bottom sheet
registered as a transparentModal in MainNavigator.js at
Routes.MODAL.REWARDS_SELECT_SHEET. Accepts title, options,
selectedValue, and onSelect callback
- Default tier is the user's projected tier (from leaderboard position)
when available, otherwise the top tier (last in list)

### Stats summary
- Added CampaignStatsSummary component displaying Return, Market Value,
Rank, and Tier in a 2x2 grid with loading skeletons and error banners

### Leaderboard neighbor display (preview mode)
- When maxEntries is set and the user's tier matches the selected tier:
- If user rank is within visible range: highlights their row with
bg-background-muted
- If user rank is outside visible range: shows top 3 entries + dot
separator + neighbor entries (rank-1, user, rank+1)
- Handles edge cases: first/last in tier (1-2 neighbors), tier mismatch,
no position data

### Pending tag / Qualified tag
- Add `qualified` and `qualifiedDays` to CampaignLeaderboardEntry and
CampaignLeaderboardPositionDto
- Display `Pending` Tag if qualified: false, `Qualified` tag if true

### Activity view
- Group activity rows by date

### Prize pool
- Add prize pool progress bar according to hardcoded breakpoints given
by PRD
- Fetch total deposit volume from new endpoint
Get(':campaignId/stats/deposits')

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

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

### Pending
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-09 at 17 59 47"
src="https://github.com/user-attachments/assets/bfdcec83-6f2b-4c29-b416-35b1c3275be9"
/>

<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 15 05"
src="https://github.com/user-attachments/assets/500d7428-f0bc-40f1-ace7-c7048b38e23f"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 15 41"
src="https://github.com/user-attachments/assets/a0af5d73-a265-4c0b-b8c7-d9f928cc10e3"
/>

<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 18 33"
src="https://github.com/user-attachments/assets/c695d664-4465-4f07-9027-668ae1d2fd7d"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 18 40"
src="https://github.com/user-attachments/assets/a1a0da1a-31ed-4207-bf4f-379485655cb5"
/>

### Qualified
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 20 27"
src="https://github.com/user-attachments/assets/29b8def5-4d08-4cf0-9e2f-3272ecdf93c2"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 20 31"
src="https://github.com/user-attachments/assets/9e0c3c85-7a10-4f50-8418-8d40b5f29afb"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 23 10"
src="https://github.com/user-attachments/assets/19f2ab07-f255-4767-b90a-e07dc8265c08"
/>

### Activity view
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 15 28 48"
src="https://github.com/user-attachments/assets/e8b42158-b6ff-47e9-b44d-ab23ba87ecc1"
/>

### Prize pool
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 17 24 02"
src="https://github.com/user-attachments/assets/ac0b1219-2252-41ed-bd26-656f188076eb"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 17 29 36"
src="https://github.com/user-attachments/assets/6f47ff55-db28-4318-919d-ce50319d0010"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-10 at 17 29 58"
src="https://github.com/user-attachments/assets/c4d64e3a-aa0d-44bf-bd50-8f9703986acf"
/>


*

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate UI/behavior changes in Rewards campaign flows plus a new data
fetch (`getOndoCampaignDeposits`) and updated leaderboard rendering,
which could affect navigation and correctness of displayed stats/tier
selection.
> 
> **Overview**
> Updates Ondo campaign rewards UI to support **tier-based
leaderboards** via a new reusable `RewardsSelectSheet` modal (registered
in `MainNavigator`) and localized tier display names.
> 
> Reworks campaign details/leaderboard presentation by replacing
`OndoLeaderboardPosition` with a new `CampaignStatsSummary`
(return/market value/rank/tier, pending/qualified tags, SWR-style
loading/error handling), adding a `OndoPrizePool` progress section
backed by a new `useGetOndoCampaignDeposits` hook, and enhancing
`OndoLeaderboard` with preview mode (`maxEntries`), current-user
highlighting, and neighbor/split-view rendering.
> 
> Refactors the portfolio activity view to be **activity-only**, grouped
by date headers, and updates activity rows to support `timeOnly`, signed
USD formatting, and external outflow address shortening; tests are
updated/added accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ecd1e4b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…-3331] (#28337)

## **Description**

When selecting a token in the UB2 Buy flow, a quick error ("We've
encountered an error") flashes on the amount input screen before the
correct "Powered by [provider]" text appears.

The root cause is a provider ID mismatch: the quotes API can return
provider IDs in a prefixed format (`/providers/transak`) while the
controller state stores them without the prefix (`transak`). This caused
`selectedQuote` to resolve to `null`, briefly rendering the error
banner.

The fix normalizes provider IDs on both sides of the comparison using
`normalizeProviderCode()` and switches from array destructuring to
`.find()` so all returned quotes are searched.

## **Changelog**

CHANGELOG entry: Fixed Buy amount screen sometimes showing a generic
error when quotes returned for the selected provider but provider id
strings differed in format.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3331
Based on draft PR #27779

## **Manual testing steps**

```gherkin
Feature: Token selection in Buy flow

  Scenario: user selects a token and navigates to amount input
    Given user is on the token selection screen in the Buy flow

    When user selects a token (e.g. ETH)
    Then the amount input screen shows "Powered by [provider]" without any error flash
```

## **Screenshots/Recordings**

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

### **Before**

<!-- [screenshots/recordings] -->
N/A. Reason: This is an extremely rare race condition. It doesn't happen
often, and after several changes on main, it's even less common.
Nevertheless, we still want to solve this logical condition via this PR.

### **After**

<!-- [screenshots/recordings] -->
N/A. Reason: This is an extremely rare race condition. It doesn't happen
often, and after several changes on main, it's even less common.
Nevertheless, we still want to solve this logical condition via this PR.


## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches Buy flow quote-selection and payment-method loading state;
small logic changes but in a user-critical conversion path and could
affect when errors/continue button appear.
> 
> **Overview**
> Prevents the Buy amount input screen from briefly showing the generic
*no quotes* error by updating `BuildQuote` to **normalize provider IDs**
(handling `/providers/...` vs short codes) and to **search all returned
quotes** via `.find()` when deriving `selectedQuote`.
> 
> Tightens `useRampsPaymentMethods` loading behavior so `isLoading`
stays true while auto-selecting a payment method when the previously
selected method is no longer present, avoiding UI flashes of stale
selection. Adds targeted tests covering provider-ID matching scenarios,
empty/mismatched quote responses, continue-button disabled state, and
the stale-selection loading fallback.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2d4d9d7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…saction confirmation (#28040)

## Summary
- Fixes a race condition in `Toast.showToast` where rapid successive
calls (e.g., transaction approved + confirmed in the same tick on Linea)
cause the success toast to persist indefinitely
- Tracks pending `setTimeout` with a ref so only the latest `showToast`
call wins, ensuring the success toast renders with its proper
auto-dismiss animation
- Adds test coverage for the rapid successive `showToast` scenario


https://github.com/user-attachments/assets/12064e1e-3beb-4d36-82e3-3237b2045eb6

## Test plan
- [x] Toast unit tests pass (`yarn jest
app/component-library/components/Toast/Toast.test.tsx`)
- [x] Manual: trigger a Max DAI→mUSD conversion on Linea and verify the
success toast auto-dismisses after ~3s
- [x] Verify normal (non-rapid) toast transitions still work correctly

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches toast display timing/animation logic; small but could regress
toast sequencing or dismissal behavior if timer clearing interacts with
existing transitions.
> 
> **Overview**
> Fixes a race in `Toast.showToast` where back-to-back calls could leave
multiple queued `setTimeout` updates, causing the wrong toast
state/timeout behavior (e.g., a success toast persisting).
> 
> `Toast` now tracks and clears any pending `setTimeout` via a ref so
only the latest `showToast` call applies. Adds a unit test asserting
rapid successive calls leave a single pending timer and only the latest
toast renders.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
111df6d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

```markdown
## [1.25.2]

### Fixed

- Relax Trongrid `internal_transactions` validation to avoid sync failures on sparse legacy payloads ([#289](MetaMask/snap-tron-wallet#289))
- Handle TRC10 token identifiers correctly in the current Trongrid account-history transaction flow, without mis-parsing endpoint-specific `asset_name` formats ([#289](MetaMask/snap-tron-wallet#289))
- Decouple assets and transactions synchronization so one failure does not prevent the other from completing ([#289](MetaMask/snap-tron-wallet#289))
```

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

n/a

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk dependency bump confined to the Tron snap package; behavior
changes are limited to Tron sync handling and should not affect
unrelated wallet flows.
> 
> **Overview**
> Bumps `@metamask/tron-wallet-snap` from `^1.25.1` to `^1.25.2`,
updating both `package.json` and `yarn.lock` resolution/checksum.
> 
> This pulls in upstream fixes around Tron sync robustness (more
permissive Trongrid `internal_transactions` validation, correct TRC10
token identifier handling, and separating asset vs transaction sync so
one failure doesn’t block the other).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
235931c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…nd update result properties (#28645)

## **Description**

Rename `initModularizedControllers` to `initMessengerClients`, drop
`existingControllersByName`, rename `controllerInitFunctions` to
`initFunctions`, and update return type to `messengerClientsByName`.
Update all consumers in `Engine.ts`, `utils.test.ts`, and test utility
functions.

80 files changed. **PR 3 of 4** — depends on PR 2 (#28641).
- ~~PR 1: Core type renames (`Controller` → `MessengerClient`, etc.)
(#28610)~~
- ~~PR 2: `CONTROLLER_MESSENGERS` → `MESSENGER_FACTORIES` (#28641)~~
- **PR 3 (this):** `initModularizedControllers` → `initMessengerClients`
+ utils/Engine.ts renames
- PR 4: Property renames (`controller` → `messengerClient`,
`getController` → `getMessengerClient`) in all init files + tests

Relates to
[WPC-916](https://consensyssoftware.atlassian.net/browse/WPC-916).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/WPC-916

## **Manual testing steps**

```gherkin
Feature: Messenger client init system

  Scenario: App builds and runs normally
    Given the app is built from this branch

    When user opens the app
    Then the app behaves identically to main (no runtime behavior change)
```

## **Screenshots/Recordings**

N/A — no UI changes.

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] 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.

[WPC-916]:
https://consensyssoftware.atlassian.net/browse/WPC-916?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Refactors the Engine’s initialization wiring for all
controller/messenger clients, so mistakes could break startup order or
dependency resolution despite being a rename-focused change.
> 
> **Overview**
> **Renames and reshapes the Engine init helper** by replacing
`initModularizedControllers` with `initMessengerClients`, renaming
`controllerInitFunctions` to `initFunctions`, and returning
`messengerClientsByName`.
> 
> **Simplifies initialization state** by dropping support for
`existingControllersByName` and updating the dependency lookup
helper/error messaging to `getMessengerClientOrThrow`.
> 
> Updates `Engine.ts` wiring and a large set of controller init tests to
use the new request mock helper (`buildMessengerClientInitRequestMock`)
and the new result property names.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
80bf6e1. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This PR polishes the Money feature so the patterns for Headers, List,
Sections, Filtering and Spacing are visually cohesive.

## **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: Money account activity and hub layout polish

  Scenario: User opens Money activity from the Money hub
    Given the user is logged in with a Money account that can show activity
    And the user is on the Money hub (home) screen

    When the user navigates to Money activity (Activity)
    Then the activity screen loads with the expected header and back affordance
    And activity is grouped and readable (date sections and list items render without layout overlap)

  Scenario: User filters Money activity by type
    Given the user is on the Money activity screen
    And there is activity data available for more than one filter category

    When the user changes the activity filter (e.g. All / Deposits / Transfers as applicable)
    Then the list updates to match the selected filter
    And section headers and row content remain correctly aligned and legible

  Scenario: User reviews Money hub summary and quick actions after layout updates
    Given the user is on the Money hub (home) screen

    When the user views the balance summary and the primary action buttons row
    Then balances and labels use the updated typography and spacing (no clipped text or misaligned controls)
    And primary actions remain tappable with expected labels and icons
```

## **Screenshots/Recordings**

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

### **Before**

<img width="1462" height="680" alt="Screenshot 2026-04-13 at 4 30 22 PM"
src="https://github.com/user-attachments/assets/38255e3a-a6c7-4ada-9a5b-7a0b5406eba0"
/>



### **After**

<img width="1442" height="643" alt="Screenshot 2026-04-13 at 4 30 37 PM"
src="https://github.com/user-attachments/assets/5bf37578-baf5-4b7f-8391-2a9611bb11c1"
/>




## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk visual-only tweaks to layout, spacing, and typography within
Money screens; main risk is minor UI regressions like
truncation/clipping on edge device sizes.
> 
> **Overview**
> Improves visual cohesion across Money hub and activity screens by
adjusting padding/spacing, alignment, and typography in headers, section
headers, lists, and filter buttons.
> 
> Updates action buttons and activity rows to better handle sizing and
truncation (larger icons/avatars, centered/stretch layouts,
`min-w-0`/`shrink` Tailwind classes), and lightly refines secondary text
weights and button container padding for consistency.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5ae2126. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Feature Flag Registry Drift Report

Feature flag drift was detected between E2E tests and production.

Download the [`drift-report`
artifact](https://github.com/MetaMask/metamask-mobile/actions/runs/24060043070)
for the full report.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Priya <priya.narayanaswamy@consensys.net>
## **Description**

New: Campaign Stats Screen

A dedicated screen showing the user's personal performance in the
campaign — their current return (positive in green, negative in red),
total portfolio value, rank, tier (Bronze, Silver, Platinum), net
deposit amount, days held, and whether they're Qualified or Pending.

New: Tier-based Leaderboard

The leaderboard now lets users filter by tier (Bronze, Silver,
Platinum). Each entry shows rank, referral code, and return percentage.
Users see their own position highlighted, plus a count of total
participants in that tier.

New: "Qualify for this rank" & "You're qualified" cards

- If a user is pending, they see a card telling them exactly how much
more they need to deposit and how many more days to hold to qualify.
- Once they meet the requirements, the card flips to "You're qualified."

New: After-Hours Trading popup

When a user tries to swap an asset outside market hours, a popup appears
explaining that trading is closed, shows a countdown to when markets
reopen, and warns about wider price spreads.

New: Eligibility warning popup

If there aren't enough days left in the campaign to meet the holding
requirement, a warning popup tells the user their new position won't
count toward the campaign, with options to cancel or proceed anyway.

New: "Entries closed" state

If the campaign has ended and the user never opted in, the join button
is locked and shows "Entries closed." Tapping it shows a message
explaining they missed the opt-in window.

Updated: Portfolio section

Now shows each deposited asset with its current value, shares owned, and
profit/loss percentage. Users can tap a position to swap it for a
different asset, or tap a link to view their full activity history.

Updated: Prize pool display

Shows the current prize pool size and how much additional volume is
needed to unlock the next reward tier.

## **Changelog**


CHANGELOG entry: ondo campaign rewards - stats page

## **Screenshots/Recordings**

- Active Campaign

- Opted in

Negative return but qualified

<img width="952" height="1763" alt="negative-qualified"
src="https://github.com/user-attachments/assets/0e27784a-f5ce-4033-b338-e2916a259427"
/>

<img width="952" height="1763" alt="negative-qualified-2"
src="https://github.com/user-attachments/assets/d07d0535-b2a1-4603-b4b4-4be694dc33c7"
/>

Positive return but pending

<img width="1025" height="1799" alt="positive-pending-1"
src="https://github.com/user-attachments/assets/b4e231a0-a0af-45db-90a8-572551c8322d"
/>

<img width="1025" height="1799"
alt="positive-pendin-2-leaderboard-bottom-20"
src="https://github.com/user-attachments/assets/14e37219-9605-466b-b788-507527fce233"
/>

Leaderboard top 5 (in others its 18th position)

<img width="943" height="539" alt="leaderboard-top-5"
src="https://github.com/user-attachments/assets/55c98e89-0c94-494d-882b-b02516ef6731"
/>

Prize pool variants

<img width="962" height="324" alt="prize-pool-fully-reached"
src="https://github.com/user-attachments/assets/c154f79a-723b-4fa8-ba9b-5885b3fd541b"
/>

<img width="962" height="324" alt="prize-pool-unlock"
src="https://github.com/user-attachments/assets/da6f91f0-d12c-4654-a87d-680412769d4d"
/>

Leaderboard page (positive return pending)

<img width="1025" height="1799" alt="positive-pending"
src="https://github.com/user-attachments/assets/636d6806-c6ee-4635-bd07-6e2761919db0"
/>

Stats page positive but pending

<img width="952" height="1763" alt="positive-pending"
src="https://github.com/user-attachments/assets/6d5c8d1f-e519-47b6-9b43-e26a4df7c8dc"
/>

Stats page positive & qualified 

<img width="951" height="1830" alt="positive-qualified-complete"
src="https://github.com/user-attachments/assets/570f8f11-1d4e-415f-ab48-a0e70a747b47"
/>

Stats page but negative return and cashed out

<img width="952" height="1763" alt="negative-qualified-cashed-out"
src="https://github.com/user-attachments/assets/9298e079-30ff-4625-8ac1-eec3890df4fb"
/>

Open position or swap position but outside of market hours

<img width="957" height="845" alt="open-position-market-hours"
src="https://github.com/user-attachments/assets/52accff5-3d36-4e0b-af50-a2062fb58b78"
/>

Open position but can't qualify for tier treshold  anymore

<img width="1156" height="701" alt="not eligible"
src="https://github.com/user-attachments/assets/b67d484a-0977-4d63-bec5-f4f414273ca4"
/>

- Not Opted in

<img width="916" height="1813" alt="Screenshot from 2026-04-13 15-32-09"
src="https://github.com/user-attachments/assets/afc04260-729d-4867-bdd8-7caad4db9527"
/>

<img width="916" height="1813" alt="Screenshot from 2026-04-13 15-32-12"
src="https://github.com/user-attachments/assets/12cb1a91-c999-4f38-b535-e8aa8a6b6c4a"
/>




<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new rewards navigation routes, screens, and bottom sheets with
updated Ondo campaign eligibility/pending logic and new `minDeposit`
data plumbing; mistakes could impact campaign UX and leaderboard/stats
rendering but do not touch security-critical flows.
> 
> **Overview**
> Introduces a dedicated **Ondo campaign Stats** screen
(`RewardsOndoCampaignStats`) and wires it into the rewards navigator,
including navigation from the campaign details stats header.
> 
> Adds new bottom sheets for **Pending** (`RewardsOndoPendingSheet`),
**After-hours trading** (`OndoAfterHoursSheet`), and **Not eligible**
(`OndoNotEligibleSheet`), and updates campaign details/portfolio/CTA
flows to gate swaps/position actions when the user can no longer meet
the `ONDO_GM_REQUIRED_QUALIFIED_DAYS` requirement.
> 
> Extends Ondo leaderboard tier data with `minDeposit` and updates
`OndoLeaderboard`/`CampaignStatsSummary` to show qualify messaging, open
the pending sheet from pending tags/cards, unify stats error handling,
and tweak prize pool/max-tier copy and various UI text/icon styles
(including ET→EST strings).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a7be45e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: sophieqgu <sophieqgu@gmail.com>
@metamaskbot metamaskbot added the team-bots Bot team (for MetaMask Bot, Runway Bot, etc.) label Apr 13, 2026
@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.

@socket-security
Copy link
Copy Markdown

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

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​metamask/​assets-controller@​2.4.0 ⏵ 3.3.07010080 +197 +2100
Updatednpm/​@​metamask/​snaps-controllers@​18.0.4 ⏵ 19.0.071 +110076 +198 +150
Updatednpm/​@​metamask/​assets-controllers@​101.0.1 ⏵ 103.1.172 +110091 +199100
Addednpm/​@​metamask/​react-data-query@​0.2.0721007392100
Updatednpm/​@​metamask/​keyring-internal-api@​10.0.0 ⏵ 10.0.11001007394 +2100
Addednpm/​@​metamask/​eth-money-keyring@​2.0.0731008191100
Updatednpm/​@​metamask/​logging-controller@​8.0.0 ⏵ 8.0.11001007394 +2100
Addednpm/​@​metamask/​money-account-controller@​0.1.0741007389100
Updatednpm/​@​metamask/​base-controller@​9.0.0 ⏵ 9.0.1100 +11007393 +6100
Updatednpm/​@​metamask/​address-book-controller@​7.1.0 ⏵ 7.1.11001007394 +2100
Updatednpm/​@​metamask/​compliance-controller@​1.0.1 ⏵ 2.0.0741009593 +2100
Addednpm/​@​metamask/​social-controllers@​0.1.0741007589100
Updatednpm/​@​metamask/​multichain-transactions-controller@​7.0.2 ⏵ 7.0.4981007497 +1100
Addednpm/​@​metamask/​keyring-sdk@​1.1.0751008592100
Updatednpm/​@​react-navigation/​bottom-tabs@​5.11.11 ⏵ 6.6.1991007599100
Updatednpm/​@​metamask/​keyring-snap-client@​8.2.0 ⏵ 8.2.1991007594 +3100
Updatednpm/​@​react-navigation/​native@​5.9.4 ⏵ 6.1.189910075 +199 -1100
Updatednpm/​@​metamask/​preferences-controller@​23.0.0 ⏵ 23.1.010010075 +196 +2100
Addednpm/​@​metamask/​hw-wallet-sdk@​0.7.0831007695100
Updatednpm/​@​metamask/​approval-controller@​9.0.0 ⏵ 9.0.11001007693 +2100
Updatednpm/​@​metamask/​snaps-utils@​11.7.1 ⏵ 12.1.29810076 +197 +2100
Updatednpm/​@​metamask/​gas-fee-controller@​26.1.0 ⏵ 26.1.1991007693 +1100
Updatednpm/​@​metamask/​remote-feature-flag-controller@​4.1.0 ⏵ 4.2.09910076 +194 +1100
Updatednpm/​@​metamask/​multichain-network-controller@​3.0.5 ⏵ 3.0.6981007697100
Updatednpm/​@​metamask/​snaps-rpc-methods@​15.0.0 ⏵ 15.0.1981007694 -150
Updatednpm/​@​react-navigation/​stack@​5.14.9 ⏵ 6.4.198 +110077100100
Updatednpm/​@​metamask/​accounts-controller@​37.0.0 ⏵ 37.2.09810077 +198 +1100
Updatednpm/​@​metamask/​controller-utils@​11.19.0 ⏵ 11.20.09710077 +194 +3100
Updatednpm/​@​metamask/​snaps-execution-environments@​11.0.1 ⏵ 11.0.299 +110077 +197 +180
Updatednpm/​@​metamask/​messenger@​0.3.0 ⏵ 1.1.19910078 +294100
Updatednpm/​@​metamask/​keyring-controller@​25.1.0 ⏵ 25.2.098 +110078 +196 +2100
Updatednpm/​@​metamask/​signature-controller@​39.1.0 ⏵ 39.1.2981007898 +1100
See 27 more rows in the dashboard

View full report

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

⏭️ Smart E2E selection skipped - draft PR

All E2E tests pre-selected.

View GitHub Actions results

@socket-security
Copy link
Copy Markdown

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 High
Obfuscated code: npm @metamask/snaps-controllers is 98.0% likely obfuscated

Confidence: 0.98

Location: Package overview

From: package.jsonnpm/@metamask/snaps-controllers@19.0.0

ℹ Read more on: This package | This alert | What is obfuscated code?

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 not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@metamask/snaps-controllers@19.0.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 High
Obfuscated code: npm @metamask/solana-wallet-snap is 91.0% likely obfuscated

Confidence: 0.91

Location: Package overview

From: package.jsonnpm/@metamask/solana-wallet-snap@2.8.0

ℹ Read more on: This package | This alert | What is obfuscated code?

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 not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@metamask/solana-wallet-snap@2.8.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/base-data-service in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: ?npm/@metamask/react-data-query@0.2.0npm/@metamask/social-controllers@0.1.0npm/@metamask/base-data-service@0.1.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/@metamask/base-data-service@0.1.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 @metamask/social-controllers in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: package.jsonnpm/@metamask/social-controllers@0.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/social-controllers@0.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.

Warn Low
Potential code anomaly (AI signal): npm @metamask/transaction-controller is 100.0% likely to have a medium risk anomaly

Notes: The code performs straightforward signature verification using ethers.js, returning true when the recovered signer matches the provided publicKey. While generally safe, the silent catch and potential mismatch between data formatting and signing process should be addressed to avoid silent failures. Overall, a benign utility with moderate input-format sensitivity.

Confidence: 1.00

Severity: 0.60

From: ?npm/@metamask/eip-5792-middleware@2.0.0npm/@metamask/transaction-controller@61.3.0

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

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

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

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@metamask/transaction-controller@61.3.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 jiti is 100.0% likely to have a medium risk anomaly

Notes: The fragment implements a sophisticated on-the-fly loader using JITI for transpilation and execution, with careful handling of JSON interop based on nearby package.json type. There is no explicit malicious behavior identified (no external network activity, no hardcoded secrets). However, the dynamic code execution path introduced by _wrapSource and the synthetic module environment represents a potential risk vector if untrusted inputs are loaded, or if jiti/mjs execution context could be manipulated. This warrants strict review of the loader environment, the version and security of JITI, and checks on the sources being loaded to mitigate potential code execution or supply chain concerns.

Confidence: 1.00

Severity: 0.60

From: ?npm/webdriverio@9.27.0npm/jiti@2.6.1

ℹ 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/jiti@2.6.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.

View full report

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
74.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@weitingsun weitingsun closed this Apr 13, 2026
@weitingsun weitingsun deleted the release/7.78.21 branch April 13, 2026 21:02
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

size-XL team-bots Bot team (for MetaMask Bot, Runway Bot, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.