Skip to content

[pull] main from MetaMask:main#635

Merged
pull[bot] merged 61 commits intoReality2byte:mainfrom
MetaMask:main
Mar 27, 2026
Merged

[pull] main from MetaMask:main#635
pull[bot] merged 61 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 27, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

metamaskbot and others added 30 commits March 19, 2026 21:22
…alance layout (#27714)

## **Description**

Cherry pick swaps a/b test that barely missed RC cutoff.

<!--
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 adds an A/B test for the bridge token selector balance layout.

Control keeps the current presentation by showing fiat balance on the
top row and keeping the ticker in the token balance text. Treatment
moves the token balance to the top row, removes the duplicate ticker
from the token balance text, and keeps the top and bottom rows aligned
with the intended size and color hierarchy.

The PR also passes the active experiment through the bridge page-view
and submit analytics paths using `active_ab_tests` so the treatment can
be evaluated against downstream conversion metrics.

## **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: Added an experiment for the bridge token selector
balance layout.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Bridge token selector balance layout experiment

  Scenario: User sees the control layout in the bridge token selector
    Given the token selector balance layout experiment is in the control variant
    And the user opens the Bridge flow
    When the token selector list is shown
    Then the fiat balance is shown on the top row
    And the token balance is shown on the bottom row with the ticker included

  Scenario: User sees the treatment layout in the bridge token selector
    Given the token selector balance layout experiment is in the treatment variant
    And the user opens the Bridge flow
    When the token selector list is shown
    Then the token balance is shown on the top row without the duplicate ticker
    And the fiat balance is shown on the bottom row

  Scenario: Analytics include the active experiment
    Given the token selector balance layout experiment is active
    When the user opens the Bridge flow
    And submits a bridge quote
    Then the relevant page-view and submit analytics payloads include active_ab_tests for the active experiment
```

## **Screenshots/Recordings**

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

### **Before**

Control variant:
<img width="322" height="683" alt="Screenshot 2026-03-18 at 19 11 16"
src="https://github.com/user-attachments/assets/572bffbe-8ab3-446c-8da8-564cd0ded31d"
/>


### **After**

Treatment variant:
<img width="317" height="690" alt="Screenshot 2026-03-19 at 18 24 35"
src="https://github.com/user-attachments/assets/46b6241d-dd00-4ee1-8de6-7097a7533d14"
/>


## **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 changes bridge token list balance rendering and
threads new `activeAbTests` metadata through bridge submission/page-view
analytics, which could affect UI correctness and controller call
signatures if mismatched.
> 
> **Overview**
> Adds a new A/B experiment
(`swapsSWAPS4242AbtestTokenSelectorBalanceLayout`) that toggles the
bridge token selector’s balance layout: *control* keeps fiat-on-top with
token balance including ticker, while *treatment* shows token balance
first and can omit the ticker.
> 
> Updates bridge analytics and submission paths to include an
`active_ab_tests`/`activeAbTests` array when experiments are active (now
aggregating both the existing numpad quick actions test and the new
token selector test), with new/updated unit tests covering the
variant-driven UI ordering and the forwarded experiment metadata.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fb21046. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->



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

## **Description**

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

## **Changelog**

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

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

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

CHANGELOG entry:

## **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.
…ck cp-7.71.0 (#27763)

- chore: Exempt `metamaskbotv2` from CLA check cp-7.71.0 (#27758)

## **Description**

The CLABot workflow has been updated to exempt `metamaskv2` (i.e.
commits created by Patroll tokens) from the CLA check.

We saw the CLA check fail recently on a release branch due to some
commits appearing for the first time from Patroll (see

#27708 (comment)).
This change will fix that CI failure.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

N/A

## **Manual testing steps**

N/A

## **Screenshots/Recordings**

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 workflow change limited to expanding the CLA bot allowlist;
main impact is potentially skipping CLA enforcement for this additional
bot account.
> 
> **Overview**
> Updates the `CLA Signature Bot` GitHub Actions workflow to add
`metamaskbotv2[bot]` to the CLA exemption allowlist, preventing CLA
check failures on PRs/merge groups created by that bot.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f1f4342. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[0f0a400](0f0a400)

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
…re flag to single selector cp-7.71.0 (#27762)

- refactor: simplify rampsUnifiedBuyV2 feature flag to single selector
cp-7.71.0 (#27760)

## **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 `rampsUnifiedBuyV2` feature flag previously used three chained
selectors (`selectRampsUnifiedBuyV2Config` →
`selectRampsUnifiedBuyV2ActiveFlag` /
`selectRampsUnifiedBuyV2MinimumVersionFlag`) and a custom 2-arg
`hasMinimumRequiredVersion` utility. This was inconsistent with how
other feature flags (e.g. homepage redesign) are handled in the
codebase.

This PR consolidates the three selectors into a single
`selectRampsUnifiedBuyV2Enabled` selector that uses the shared
`validatedVersionGatedFeatureFlag` utility from
`app/util/remoteFeatureFlag`. The remote flag shape is updated from `{
active, minimumVersion }` to `{ enabled, minimumVersion }` to match the
standard `VersionGatedFeatureFlag` type.

**Key changes:**
- **Selector file** (`rampsUnifiedBuyV2.ts`): Replaced 3 selectors +
`RampsUnifiedBuyV2Config` interface with a single
`selectRampsUnifiedBuyV2Enabled` selector
- **Hook** (`useRampsUnifiedV2Enabled.ts`): Simplified from two
`useSelector` calls + `hasMinimumRequiredVersion` to a single
`useSelector`
- **Utility** (`isRampsUnifiedV2Enabled.ts`): Simplified to delegate
directly to the selector
- **Controller init** (`ramps-controller-init.ts`): Replaced local
interface + `hasMinimumRequiredVersion` with
`validatedVersionGatedFeatureFlag`; imports shared flag key constant
- **Flag key constant**: Exported `RAMPS_UNIFIED_BUY_V2_FLAG_KEY` from
the selector file as single source of truth
- **E2E mocks/fixtures**: Updated flag shape from `active` to `enabled`
in `FixtureBuilder`, `feature-flags-mocks`, and `feature-flag-registry`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

N/A — this is a pure refactor of internal selector structure. Behavior
is unchanged. All unit tests have been updated and pass.

## **Screenshots/Recordings**

### **Before**

N/A

### **After**




https://github.com/user-attachments/assets/13ab83a0-f3b1-4862-95cc-ec02fc5b89b5



## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches feature-flag gating that controls whether the ramps V2 flow
and controller initialization run, and changes the expected remote flag
shape from `active` to `enabled`. Main risk is misconfigured/older flag
payloads causing the feature to be incorrectly disabled.
> 
> **Overview**
> Simplifies `rampsUnifiedBuyV2` enablement checks by replacing the
chained config/active/min-version selectors and custom gating logic with
a single `selectRampsUnifiedBuyV2Enabled` that delegates to
`validatedVersionGatedFeatureFlag`.
> 
> Updates the Ramp hook/utility and `ramps-controller-init` to consume
this unified version-gated flag (keeping the build-flag override), and
standardizes the remote flag payload from `{ active, minimumVersion }`
to `{ enabled, minimumVersion }` across unit tests, E2E mocks/fixtures,
and the feature-flag registry defaults.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3edd562. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[73198ff](73198ff)

Co-authored-by: Pedro Pablo Aste Kompen <wachunei@gmail.com>
Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com>
…uring Transak navigation reset -> cp-7.71.0 (#27772)

- fix(ramps): Preserve user-entered amount during Transak navigation
reset -> cp-7.71.0 (#27742)

## **Description**

Fixes the Buy flow amount reverting from the user-entered value back to
the default $100 during the Transak native provider loading transition.

When a user enters a custom amount (e.g. $30) and taps Continue, the
Transak routing callbacks use `navigation.reset()` to rebuild the
navigation stack with a fresh `BuildQuote` screen as the base route.
This fresh instance initialized with `DEFAULT_AMOUNT = 100`, causing a
visible flash of $100 during the transition to the checkout/KYC screen.

The fix passes the current `quote.fiatAmount` as a route param
(`amount`) to the `AMOUNT_INPUT` base route in every
`navigation.reset()` call. `BuildQuote` now reads `params?.amount` as
the initial state, preserving the user-entered amount through stack
resets.

## **Changelog**

CHANGELOG entry: Fixed Buy flow amount input reverting to $100 during
Transak native provider checkout transition.

## **Related issues**

Fixes:
[TRAM-3348](https://consensyssoftware.atlassian.net/browse/TRAM-3348)

## **Manual testing steps**

```gherkin
Feature: Amount persists through Transak native provider checkout transition

  Scenario: Custom amount does not revert to default during Continue loading
    Given the user is on the Buy screen with Transak Native provider
    And the default amount is $100
    When the user changes the amount to $30
    And the user taps Continue
    Then the displayed amount remains $30 during the loading transition
    And the amount does not flash back to $100

  Scenario: Default amount is preserved when no custom amount is entered
    Given the user is on the Buy screen with Transak Native provider
    And the default amount is $100
    When the user taps Continue without changing the amount
    Then the displayed amount remains $100 throughout the flow

  Scenario: Amount persists when navigating back from KYC/checkout screens
    Given the user entered $50 and proceeded through Continue
    When the user navigates back to the Buy screen
    Then the amount input shows $50 (not $100)
```

## **Screenshots/Recordings**

### **Before**

<!-- Screenshot/video showing amount reverting from $30 to $100 during
loading -->




https://github.com/user-attachments/assets/ba7fb42b-c43a-43f8-b438-0484090d7895



### **After**

<!-- Screenshot/video showing amount staying at $30 during loading
transition -->




https://github.com/user-attachments/assets/6d60c1ae-f0eb-448b-b7f3-297efbce85df




https://github.com/user-attachments/assets/099ebf69-face-4bb0-8568-80357f59b35e

<img width="523" height="877" alt="Screenshot 2026-03-20 175035"

src="https://github.com/user-attachments/assets/6bebcd4a-c04d-40c6-90d4-7e50ed683824"
/>


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

- [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**
> Updates Transak native-provider navigation/reset logic and initial
screen state; mistakes could regress Buy/KYC routing or amount display
during transitions, but changes are localized and covered by tests.
> 
> **Overview**
> Fixes the Transak native Buy flow so the user-entered fiat amount is
preserved when the app uses `navigation.reset()` during KYC/checkout
transitions.
> 
> `BuildQuote` now supports an `amount` route param to initialize the
amount state (and to prevent region defaults from overriding it), and
`useTransakRouting` propagates this amount through all reset-based
navigation paths (KYC approved → checkout, KYC forms, additional
verification, verify identity, and KYC webview). Tests are updated/added
to assert the amount is passed through routing callbacks and used as the
initial displayed value.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a8bdee0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[8a03f66](8a03f66)

Co-authored-by: Yu-Gi-Oh! <54774811+imyugioh@users.noreply.github.com>
Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com>
….0 (#27801)

- fix(ramp): fixes order details bug cp-7.71.0 (#27755)

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

Fixes an order details UI bug where the title for bank transfer details
was displaying for non bank-transfer orders.

[TRAM 3359](https://consensyssoftware.atlassian.net/browse/TRAM-3359)

<!--
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: fixes an order details UI bug

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

### *
<img width="458" height="974" alt="Screenshot 2026-03-20 at 10 03 02 AM"

src="https://github.com/user-attachments/assets/4d94ca14-1e17-401d-945b-5f38acf28e4a"
/>
*Before**

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

### **After**

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

<img width="451" height="976" alt="Screenshot 2026-03-20 at 11 39 11 AM"

src="https://github.com/user-attachments/assets/19595c85-e138-4fdc-bb52-a57271593ff8"
/>


## **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 gates rendering of the bank details
section; main risk is unintentionally hiding bank details if upstream
field names/structure change.
> 
> **Overview**
> Fixes an order details UI bug where the bank-transfer section header
could render for non-bank-transfer orders.
> 
> `OrderContent` now returns `null` for `bankDetailFields` unless at
least one expected bank detail field (e.g., amount, routing/account,
IBAN/BIC) is present, and tests add coverage for
absent/empty/non-matching `paymentDetails` vs. bank-transfer/SEPA
scenarios.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
65f6cfc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[7e9748e](7e9748e)

Co-authored-by: George Weiler <georgejweiler@gmail.com>
Resolved conflicts between stable (7.70.0) and release/7.71.0:

Build/version: take release/7.71.0 (7.71.0, build 4148)
- android/app/build.gradle, ios project, bitrise.yml

Dependencies: take release/7.71.0 versions
- package.json, yarn.lock

Source: take release/7.71.0 (newer release work)
- MarketInsightsView, testIds, mUSD events, MusdAggregatedRow tests, mp4Mock

CHANGELOG, AndroidManifest, remote flag defaults, and selector updates from stable.

Merge with "Create a merge commit" — do NOT squash.

Made-with: Cursor
…re flags hydrate cp-7.71.0 (#27807)

- fix: start Ramps V2 init when remote feature flags hydrate cp-7.71.0
(#27778)

## **Description**

On a fresh install, `RemoteFeatureFlagController` loads flags
asynchronously while Engine builds controllers. `rampsControllerInit`
previously read the unified buy V2 flag only once; if flags were not in
state yet, `RampsController.init()` never ran, so buy token lists stayed
empty until a full app restart.

This change subscribes to `RemoteFeatureFlagController:stateChange`
(already delegated on `RampsControllerInitMessenger`) and re-runs the
same V2 startup path when remote flag state updates. Order-status
subscriptions are registered at most once. `RampsController.init()`
remains idempotent for repeated calls.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3350

## **Manual testing steps**

```gherkin
Feature: Unified buy V2 after fresh install

  Scenario: Buy token list loads without restarting the app
    Given a dev build with unified buy V2 enabled via remote flags
    And the app is installed fresh (or remote flag cache cleared)

    When the user completes onboarding and opens Buy / token selection
    Then tokens and providers load without requiring an app restart
```

## **Screenshots/Recordings**

<div>
<a href="https://www.loom.com/share/e80a3794612d4030aa963834e5a8d7bf">
<p>Fix Ramps controller not initializing on fresh install - Watch
Video</p>
    </a>
<a href="https://www.loom.com/share/e80a3794612d4030aa963834e5a8d7bf">
<img style="max-width:300px;"

src="https://cdn.loom.com/sessions/thumbnails/e80a3794612d4030aa963834e5a8d7bf-13202ae1a2494608-full-play.gif#t=0.1">
    </a>
  </div>

### **Before**

### **After**

## **Pre-merge author checklist**

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

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

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

## **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 subscription-driven initialization path triggered by
`RemoteFeatureFlagController:stateChange`, which can change startup
behavior and potentially cause repeated init/polling if underlying
idempotency assumptions are wrong.
> 
> **Overview**
> Ensures Unified Buy V2 startup runs even when remote feature flags
hydrate *after* Engine/controller initialization by subscribing to
`RemoteFeatureFlagController:stateChange` and re-checking the V2 flag.
> 
> Refactors V2 startup into a helper that conditionally calls
`RampsController.init()`/`startOrderPolling()` and registers
order-status subscriptions only once. Updates tests to cover the “flag
off at startup then enabled on stateChange” scenario and to include
`subscribe` in the thrown-state mock.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
78ff800. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[c6d96b6](c6d96b6)

Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com>
…rder data is not yet available cp-7.71.0 (#27812)

- fix(ramps): fixes 0 ETH ramps issue when order data is not yet
available cp-7.71.0 (#27756)

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

"0 ETH" was displayed on some order pages when the order info was not
yet available. This bug fixes by adding "..." placeholder until the info
arrives.

[TRAM-3360](https://consensyssoftware.atlassian.net/browse/TRAM-3360)

<!--
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: Fixes small UI issue with ramps orders

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

<img width="544" height="319" alt="Screenshot 2026-03-20 at 11 51 50 AM"

src="https://github.com/user-attachments/assets/cc2fd384-2c79-49c0-93fa-66b07192ffa6"
/>

<img width="436" height="933" alt="Screenshot 2026-03-20 at 11 53 40 AM"

src="https://github.com/user-attachments/assets/1d350708-6bfe-4fae-af10-80868d26914c"
/>


## **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**
> Adjusts order-details loading/terminal-state logic and amount
formatting, which could change what users see for certain pending/failed
orders; impact is limited to UI display and snapshots.
> 
> **Overview**
> Prevents ramps order UIs from showing `0 ETH`/`0` amounts when data
hasn’t arrived by treating `0`/missing `cryptoAmount` (and related fiat
fields) as **unknown** and rendering an `...` placeholder in both the
orders list (`displayOrder`) and order details (`OrderContent`).
> 
> Order details now distinguishes *loading* vs *terminal* statuses
(e.g., `Failed`, `Cancelled`) so terminal orders without amounts render
placeholders instead of skeleton loaders, and fiat `fees`/`total`
formatting is switched to `formatWithThreshold` currency formatting
(snapshot updates included).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a9bc072. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
[174afa0](174afa0)

Co-authored-by: George Weiler <georgejweiler@gmail.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
## Description

Sync `stable` into `release/7.71.0` so the release branch includes
everything merged to stable through **7.70.0** (e.g. hotfixes and
changelog), matching the pattern from
[#27468](#27468).

## Changelog

CHANGELOG entry: null

---


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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it alters Android permission declarations
(Bluetooth/location) and changes feature-flag override precedence in
certain build environments, which could affect runtime behavior or Play
Store compliance if misconfigured.
> 
> **Overview**
> Updates `CHANGELOG.md` with release notes for `7.70.0`, adds
`7.69.1`/`7.68.3`, and updates the compare links for the new tags.
> 
> Adjusts Android Bluetooth-related permissions in `AndroidManifest.xml`
by removing the API 30 maxSdk constraint on `ACCESS_FINE_LOCATION` and
dropping the `neverForLocation` flag from `BLUETOOTH_SCAN`.
> 
> Changes feature-flag selectors so that when
`BUILDS_ENABLED_WITH_GH_ACTIONS_TEMPORARY=true` (and not `E2E`),
**remote flags take precedence** and local env overrides are ignored for
`extensionUxPna25` and `additionalNetworksBlacklist`, plus adds a small
`buildTimeDefaultsConfig` helper for this gating.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
63cee1a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…etaMask/core#8251 -> cp-7.71.0 (#27823)

- chore(deps): ramps-controller preview for MetaMask/core#8251 ->
cp-7.71.0 (#27709)

## **Description**

Integration PR to validate **MetaMask/core** changes in mobile CI/E2E by
resolving `@metamask/ramps-controller` from a **preview** npm package
(`previewBuilds` in `package.json` + updated `yarn.lock`). No
application code changes.

**Core PR:** MetaMask/core#8251

After core merges and a **released** version is published, this PR
should be updated to remove `previewBuilds` and bump `dependencies` to
the real version before merge.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A (validation / dependency preview only)

## **Manual testing steps**

```gherkin
Feature: ramps-controller preview validation

  Scenario: app resolves preview package
    Given a clean install from this branch
    When the app bundles and runs
    Then @metamask/ramps-controller resolves to the preview version from previewBuilds

  Scenario: ramps flows still work
    Given the app is built from this branch
    When user exercises on-ramp flows that use ramps-controller
    Then no regressions vs main (same UX; underlying package is preview)
```

## **Screenshots/Recordings**

N/A — dependency-only change.

## **Pre-merge author checklist**

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

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] 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**

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

---

<!-- Optional: paste below into GitHub if you use Cursor Bugbot summary
-->

> [!NOTE]
> **Low Risk**
> Low risk because this is a dependency source/version switch for
`@metamask/ramps-controller` with no application code changes; main risk
is behavior changes introduced by the preview package at runtime.
>
> **Overview**
> Switches `@metamask/ramps-controller` to a **preview build** via
`previewBuilds` in `package.json` and `yarn.lock` (e.g.
`@metamask-previews/ramps-controller@12.0.0-preview-434bd0c`). Update
the preview version string if the bot publishes a newer build for
core#8251.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk patch-level dependency update; main risk is any runtime
behavior changes in `@metamask/ramps-controller` affecting ramp flows,
plus potential test fixture mismatches if state shape changes again.
> 
> **Overview**
> Updates `@metamask/ramps-controller` from `12.0.0` to `12.0.1`
(including lockfile resolution changes).
> 
> Aligns the default E2E/unit fixture (`default-fixture.json`) with the
newer `RampsController` state shape by adding persisted sub-state for
countries, providers/payment methods/tokens, native provider (Transak)
auth/kyc/user details, requests, and orders.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0b2fc2f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[4a4f0ae](4a4f0ae)

Co-authored-by: Yu-Gi-Oh! <54774811+imyugioh@users.noreply.github.com>
…s view entry point cp-7.71.0 (#27821)

- chore: adds market insights metric to Perps view entry point cp-7.71.0
(#27814)

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

## **Description**

Adds two missing metric events to the Perps Market Details view to bring
it to parity with the token details flow. `MARKET_INSIGHTS_OPENED` now
fires whenever a user taps the Market Insights entry card, and
`PERPS_SCREEN_VIEWED` now includes a `market_insights_displayed` boolean
property that reflects whether a report was actually shown, with the
event held until the insights fetch resolves so the value is fully
accurate.

## **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: changes are limited to analytics instrumentation and event
timing gated on Market Insights loading, with added unit tests to
validate tracking and navigation behavior.
> 
> **Overview**
> Adds missing Market Insights instrumentation to the Perps market
details screen.
> 
> `PerpsMarketDetailsView` now fires
`MetaMetricsEvents.MARKET_INSIGHTS_OPENED` (with `perps_market`) when
the Market Insights entry card is tapped, and delays
`MetaMetricsEvents.PERPS_SCREEN_VIEWED` until insights loading completes
so it can include an accurate `market_insights_displayed` boolean.
> 
> Updates/extends `PerpsMarketDetailsView.test.tsx` with mocks for
`useMarketInsights`/feature flags and new tests covering the new
tracking payloads and navigation to `Routes.MARKET_INSIGHTS.VIEW` with
`isPerps: true`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
dc97116. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[6e0f698](6e0f698)

Co-authored-by: António Regadas <antonio.regadas@consensys.net>
…ack redirection cp-7.71.0 (#27829)

- fix(ramps): improve external-browser callback redirection cp-7.71.0
(#27804)

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

Fixes the external-browser return flow for unified ramps by moving
callback resolution out of Build Quote and into Order Details.

The bug was that external-browser returns were resolved too early in
BuildQuote. If callback parsing or order lookup failed there, users
could get bounced around or end up on a broken Order Details screen.

This change fixes that by moving callback resolution into Order Details
itself. BuildQuote now only hands off the callback context, and Order
Details fetches the real order itself. That makes the flow more
reliable: bailed callbacks return to Build Quote, and real fetch
failures show a retryable error instead of a broken redirect.

**What changed**

- **Build Quote -> Order Details callback handoff**  
After a successful external-browser return, Build Quote now navigates to
Order Details with the full `callbackUrl`, `providerCode`, and
`walletAddress` instead of trying to resolve the order immediately.

- **Order Details callback bootstrap**  
Order Details now supports loading from callback params, fetching the
real order on first render, and updating route params once the order has
been resolved.

- **Bailed / invalid callback handling**  
If the callback resolves to a bailed order state or no usable order, the
user is sent back to Build Quote instead of landing on a blank or broken
Order Details screen.

- **Retryable callback error state**  
If fetching the order from the callback URL fails, Order Details now
shows a retryable error screen rather than silently resetting away. This
makes transient backend/network failures recoverable.

- **Navigation tests updated**  
Tests were updated to reflect the callback-based route shape and the new
Order Details retry behavior.

**What stays untouched**  
This PR does not change Order Content amount rendering, list display
formatting, or duplicate placeholder cleanup. It is scoped only to
fixing the external-browser redirection and callback-resolution path.




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



Paypal Order going to build quote page first:
Uploading Screen Recording 2026-03-23 at 1.00.39 PM.mov…



### **After**

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



Native Transak Redirection


https://github.com/user-attachments/assets/32d1a7f9-23c7-4df1-aba8-f639338d7a6f



Bailed Paypal order (return to build quote page):


https://github.com/user-attachments/assets/8ed07fa3-e7df-4b69-b2f0-9318799c8249

Paypal order going to order details page:


https://github.com/user-attachments/assets/5a2e8489-a4b0-488d-8aca-7982df63c45c





## **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**
> Changes the unified ramps external-browser return flow and navigation
params, which can impact users reaching the correct order state after
checkout; failures may surface as new retry/error behaviors.
> 
> **Overview**
> Fixes unified ramps external-browser return handling by **moving
callback URL resolution out of `BuildQuote` and into `OrderDetails`**.
> 
> `BuildQuote` no longer calls `getOrderFromCallback`/`addOrder` on
InAppBrowser success; it now resets navigation to `OrderDetails` with
`callbackUrl`, `providerCode`, and `walletAddress`. `OrderDetails`
bootstraps from these callback params, fetches the real order (bailing
back to `BuildQuote` for invalid/bailed statuses), updates route params
to the resolved `orderId`, and shows a retryable error state if the
callback fetch fails.
> 
> Updates `rampsNavigation` to support an `OrderDetails` route shaped
around callback params (and makes `orderId` optional), and adjusts/adds
tests to cover the new handoff and retry behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0eabfd6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[4efb704](4efb704)

Co-authored-by: George Weiler <georgejweiler@gmail.com>
)

- fix: support webcredentials cp-7.71.0 (#27741)

<!--
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 patch the expo-web-browser to support https redirect schema
Taking reference from expo-web-browser sdk 55


https://github.com/expo/expo/blob/308031a6665f885811760aff7aebb68aea4a846a/packages/expo-web-browser/ios/WebAuthSession.swift#L36

<!--
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: expo-web-browser support https redirect scheme 
CHANGELOG entry: use webcredential for ios google login 

## **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**
> Moderate risk because it changes iOS `ASWebAuthenticationSession`
callback configuration and entitlements, which can affect login/redirect
flows and associated-domain behavior.
> 
> **Overview**
> Enables **HTTPS redirect-based auth callbacks** on iOS by patching
`expo-web-browser`’s `WebAuthSession` to use iOS 17.4+/macOS 14.4+
`.https(host:path)` callbacks when the `redirectUrl` is `https`, falling
back to the legacy `callbackURLScheme` behavior otherwise.
> 
> Updates iOS entitlements (`MetaMask.entitlements` and
`MetaMaskDebug.entitlements`) to include
`webcredentials:link.metamask.io`, and wires the patch into the build
via a Yarn `resolutions` entry plus corresponding `yarn.lock` changes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7730be3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[a2f8164](a2f8164)

Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
…27868)

- feat: add metrics opt In event  (#27846)

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

## **Description**
* Add Metrics Opt In event in Onboarding, Optinmetrics and
MetaMetricsAndDataCollectionSection screen

<!--
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: METRICS_OPT_IN analytics on user opt-in

  Scenario: User opts in from onboarding MetaMetrics screen
    Given the user is on the onboarding MetaMetrics / data collection screen with basic usage enabled by default

    When the user continues without turning off basic usage
    Then the app completes onboarding as before and analytics pipelines receive a "Metrics Opt In" event with onboarding location and expected properties in addition to "Analytics Preference Selected"

  Scenario: User enables MetaMetrics from Settings
    Given the user is logged in and MetaMetrics is currently off

    When the user opens Settings > Security & privacy and turns the MetaMetrics switch on
    Then the app opts in successfully and emits "Metrics Opt In" with settings location and updated_after_onboarding before the preference-selected event

  Scenario: User enables marketing which requires MetaMetrics
    Given MetaMetrics is off and marketing data collection is off

    When the user turns marketing data collection on (which enables MetaMetrics)
    Then MetaMetrics turns on and "Metrics Opt In" is recorded before the subsequent preference events

```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**
<img width="702" height="94" alt="Screenshot 2026-03-24 at 3 35 19 PM"

src="https://github.com/user-attachments/assets/e5177be9-8c93-413b-ae76-8e10c3e50352"
/>
<img width="703" height="50" alt="Screenshot 2026-03-24 at 3 36 30 PM"

src="https://github.com/user-attachments/assets/6da0d4cb-f660-49b9-818e-bb45fe1e413e"
/>
<img width="695" height="91" alt="Screenshot 2026-03-24 at 3 40 10 PM"

src="https://github.com/user-attachments/assets/229e4a2d-80c3-469e-b1a9-639df7068c17"
/>

<!-- [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 analytics-only change that adds an additional tracking call
when users enable metrics (onboarding, social login, and settings). Main
risk is event ordering/duplication affecting downstream dashboards
rather than app behavior.
> 
> **Overview**
> Adds a new `MetaMetricsEvents.METRICS_OPT_IN` event and emits it
whenever users enable metrics, including the onboarding opt-in screen
(`location: onboarding_metametrics`), social login onboarding flow
(`location: onboarding_social_login`), and the settings MetaMetrics
toggle (`location: settings` / `onboarding_default_settings`).
> 
> Updates tests to assert the new opt-in event is sent (and in
settings/onboarding cases is sent *before*
`ANALYTICS_PREFERENCE_SELECTED`), including verifying
`updated_after_onboarding` and optional `account_type` properties.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9968f73. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[79b1aa8](79b1aa8)

Co-authored-by: Gaurav Goel <grvgoel19@gmail.com>
… details for selected account -> cp-7.71.0 (#27865)

- fix(ramps): filter activity tab's transfer details for selected
account -> cp-7.71.0 (#27830)

## **Description**

### Activity — on-ramp orders scoped to the selected account

The Activity **Orders** tab merges legacy fiat orders with V2
`RampsController` orders. Legacy rows were already limited to the
**selected account group** via `getOrders`. V2 orders were not filtered,
so purchase history from other wallets could appear.

This change adds `selectRampsOrdersForSelectedAccountGroup`, which keeps
only orders whose `walletAddress` matches any formatted address in the
selected account group (same semantics as legacy, using
`areAddressesEqual` for EVM vs non-EVM). Hook and modal consumers that
should reflect “current wallet context” now use this selector instead of
the raw controller list.

### Transak — preserve user-entered fiat amount on Build Quote (in-app)

After **additional verification**, opening the KYC/payment webview
called `navigateToKycWebview` with **`quote.fiatAmount`**, and the stack
reset rewrote **RampAmountInput** params with that value. The quote
total can differ from what the user typed (e.g. fees), so Build Quote
could show **27.37** after the user entered **25**, and that value
persisted after closing the sheet or going back.

**Change:** `routeAfterAuthentication(..., amount)` already carried the
typed fiat; `navigateToAdditionalVerificationCallback` now puts the same
`amount` on **both** `RampAmountInput` and `RampAdditionalVerification`
route params. **V2 Additional Verification** reads that param and passes
**only** it into `navigateToKycWebview` (no `quote.fiatAmount` for this
purpose).

**Out of scope:** Order detail screens and stored order payloads are
unchanged. The **Transak payment webview** URL is unchanged (no
`fiatAmount` override in widget params); only in-app Build Quote / stack
state matches the user’s input.

## **Changelog**

CHANGELOG entry: Fixed Activity on-ramp (Orders) list showing V2
purchases from wallets other than the selected account group; fixed
Transak unified buy flow so the fiat amount on Build Quote after
additional verification matches the user-entered amount on the amount
screen (in-app stack), without changing Transak’s payment widget totals.

### Tests

- `selectRampsOrdersForSelectedAccountGroup` and ramp hook consumers
(selector + hook unit tests).
- `useTransakRouting`: IDPROOF / additional verification navigation with
user `amount` set and omitted.
- V2 `AdditionalVerification`: continue passes route `amount` into
`navigateToKycWebview`.

## **Related issues**

Refs:
[TRAM-3361](https://consensyssoftware.atlassian.net/browse/TRAM-3361)

## **Manual testing steps**

```gherkin
Feature: Activity on-ramp orders and Transak amount (TRAM-3361)

  Scenario: Orders tab shows only selected account group’s V2 on-ramp orders
    Given the user has two wallets (or account groups) with separate on-ramp purchase history
    And unified ramps V2 orders exist for more than one wallet address

    When the user selects account group A and opens Activity → Orders
    Then only on-ramp orders whose destination wallet belongs to account group A are listed

    When the user switches to account group B
    Then the Orders tab lists only orders for account group B

  Scenario: Custom fiat amount survives Transak additional verification on Build Quote
    Given the user is in unified Buy with Transak (native) as provider
    And the user enters a custom fiat amount (e.g. 25) on the amount screen

    When the user continues through flows that require additional verification
    And the user taps Continue on the additional verification screen
    Then Build Quote under the KYC/payment sheet still shows the entered amount (e.g. 25), not only the quote total

    When the user closes the webview or goes back from the flow
    Then the amount screen still shows the same entered amount (e.g. 25)
```

## **Screenshots/Recordings**

### **Before**

<!-- Add video: Activity Orders showing other wallet’s purchases / wrong
fiat amount after verification or in widget -->




https://github.com/user-attachments/assets/b26bb3cb-8219-48a3-8128-7c79026fdd18



### **After**

<!-- Add video: Activity Orders scoped to selected account / correct
custom amount through verification and widget -->




https://github.com/user-attachments/assets/3e1929e3-7e1a-42c9-98bd-ea8f7bc9b1eb




https://github.com/user-attachments/assets/ef6d14ed-6533-4e04-a5a4-8cbd44477170


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

- [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 UX/data-scoping change: filters which on-ramp orders appear
based on multichain account selection and adjusts Transak navigation
params, which could hide expected history or affect flow state if
account/address resolution is off.
> 
> **Overview**
> Fixes unified ramp UI to **scope V2 `RampsController` orders to the
selected account group**, preventing purchases from other wallets from
showing up in Activity-derived surfaces. This introduces
`selectRampsOrdersForSelectedAccountGroup` (address-matched via
`areAddressesEqual`) and switches key consumers (`useRampsOrders`,
`useRampsProviders`, `useRampsButtonClickData`,
`ProviderSelectionModal`) from the unfiltered selector.
> 
> Updates the Transak additional-verification flow to **preserve the
user-entered fiat amount** through stack resets: `useTransakRouting` now
carries `amount` into `RampAdditionalVerification` params, and
`AdditionalVerification` uses that param (not `quote.fiatAmount`) when
opening the KYC webview. Selector and routing behavior are covered with
expanded unit tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
39d5861. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[4661cdb](4661cdb)

---------

Co-authored-by: Yu-Gi-Oh! <54774811+imyugioh@users.noreply.github.com>
…27876)

- feat: legacy-ios-feature-flag cp-7.71.0 (#27848)

<!--
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**
Support webcredential for ios google login
Part 2/4 - Add feature flag 

This pr add feature flag for the ios google login


PR list
Part 1/ 4 - #27741
Part 2/ 4 - #27848
Part 3/ 4 - #27850
Part 4/ 4 - TBA

<!--
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: added legacyIosGoogleConfigEnabled feature flag

## **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: adds a new remote feature flag and selector with env
override, without changing authentication flow yet; main risk is
misconfiguration since the selector defaults to enabled.
> 
> **Overview**
> Adds a new remote feature flag, `legacyIosGoogleConfigEnabled`,
including registry metadata and a dedicated selector
`selectLegacyIosGoogleConfigEnabled` (defaulting to `true`) that can be
force-overridden via `MM_LEGACY_IOS_GOOGLE_CONFIG_ENABLED`.
> 
> Includes unit tests covering default/remote/env override behavior, and
updates `babel.config.tests.js` to avoid inlining env vars for the new
selector and its tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ca7e813. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[6ae4c95](6ae4c95)

Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
metamaskbot and others added 27 commits March 25, 2026 09:08
…7892)

- fix: hardware wallet eip 7702 issue (cp-7.71.0) (#27615)

<!--
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 will provide a fix for hardware wallet to gas free network like
Monad and Sei.
Due to currently Hardware wallet is not supported for EIP 7702 gas
sponsorship, and Swap feature is not working for hardware wallet user.

This fix will fall back the Gasless transaction to User pay gas previous
model so that user can still do the swap and sign transaction like
bfore.

This is temporately fix for current version of extensions, and we will
do a proper support in the future.

Similar to extension PR:
MetaMask/metamask-extension#40915
Ticket:

https://consensyssoftware.atlassian.net/jira/software/c/projects/NEB/boards/3738/backlog?selectedIssue=NEB-767


## **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: Hardware wallet user will fall back to use `User pay
gas` for those Gasless network due to hardware wallet not supported in
Gasless network like Sei and Monad.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Gas sponsorship disabled for hardware wallet accounts

  Scenario: Hardware wallet user does not use gas sponsorship on sponsored network
    Given the user has added a hardware wallet account (Ledger or QR-based)
    And the hardware wallet account is selected as the active account
    And the user has added a gas-sponsored network (e.g. Monad)

    When the user attempts to perform a swap a dapp interaction or send a transaction on the sponsored network
    Then the transaction should not use gas sponsorship
    And the UI should not display any gas sponsorship labels (e.g. "No network fee", "Paid by MetaMask")
    And the user should see the normal network gas fee
    And the transaction should follow the standard user-pays-gas flow
```

## **Screenshots/Recordings**

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

### **Before**

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

> With HW account: 

Network list: 
<img width="392" height="800" alt="Screenshot 2026-03-18 at 16 05 48"

src="https://github.com/user-attachments/assets/601c30cc-fd78-456e-87b5-cc70e7ce3433"
/>

Tx flow: 
<img width="392" height="800" alt="Screenshot 2026-03-18 at 15 53 04"

src="https://github.com/user-attachments/assets/7c7b60cf-3f79-4701-a1e5-1fbba2bfe84e"
/>
<img width="392" height="800" alt="Screenshot 2026-03-18 at 15 55 20"

src="https://github.com/user-attachments/assets/a3258815-f1d2-4abf-8b22-209b73a0fbba"
/>
<img width="392" height="800" alt="Screenshot 2026-03-18 at 15 55 47"

src="https://github.com/user-attachments/assets/9275c82c-e56a-47ad-a203-a34f67ed6ed9"
/>


### **After**

> With HW account: 

Network list: 
<img width="392" height="800" alt="Screenshot 2026-03-18 at 16 06 19"

src="https://github.com/user-attachments/assets/03a296be-17fe-4387-baa0-23bae3ba00eb"
/>

Tx flow:
<img width="392" height="800" alt="Screenshot 2026-03-18 at 15 49 55"

src="https://github.com/user-attachments/assets/b39bc1b0-4b28-4e06-ae06-a381458ba7f6"
/>
<img width="392" height="800" alt="Screenshot 2026-03-18 at 15 50 29"

src="https://github.com/user-attachments/assets/76a31213-9ecd-4290-b407-58ffb8d82f48"
/>


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

## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches gasless sponsorship and transaction publishing paths
(including 7702 delegation), which can affect whether transactions are
sponsored vs user-paid and could change behavior on supported chains.
Changes are scoped to hardware-wallet detection gates with added tests,
reducing regression risk.
> 
> **Overview**
> Hardware wallet accounts now **opt out of gasless / EIP-7702
sponsorship**, forcing swaps/bridge and confirmations to use the normal
*user-pays-gas* path.
> 
> This adds an `accountSupports7702` gate to `TransactionControllerInit`
so `Delegation7702PublishHook` and `isEIP7702GasFeeTokensEnabled` only
activate for keyrings that support 7702, and updates
`useIsGaslessSupported`/`useIsGasIncluded7702Supported` (via new
`useIsHardwareWalletForBridge`) to report unsupported for hardware
signers.
> 
> Network selection UI (`NetworkSelector`, `NetworkMultiSelectorList`,
`CustomNetwork`) now hides the “No network fee” sponsored label for
hardware wallets, and a patched `@metamask/bridge-status-controller`
waits for approval tx confirmation when required. Tests were
added/updated to cover the new hardware-wallet gating behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
83f66fc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: Julien Fontanel <julien.fontanel@consensys.net>
Co-authored-by: Frederic HENG <frederic.heng@consensys.net>
Co-authored-by: Arafet (CN - Hong Kong)
<52028926+arafetbenmakhlouf@users.noreply.github.com>
Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
[c4b93de](c4b93de)

---------

Co-authored-by: khanti42 <florin.dzeladini@consensys.net>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: Julien Fontanel <julien.fontanel@consensys.net>
Co-authored-by: Frederic HENG <frederic.heng@consensys.net>
Co-authored-by: Arafet (CN - Hong Kong) <52028926+arafetbenmakhlouf@users.noreply.github.com>
Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
…ure from dual-cache desync cp-7.70.1 (#27912)

- fix(perps): fix HIP-3 asset ID lookup failure from dual-cache desync
cp-7.70.1 (#27854)

## **Description**

Fix HIP-3 asset ID lookup failure (`"Asset ID not found for
xyz:BRENTOIL"`) that blocked trading on HIP-3 markets when navigating
via the old Perps tab layout.

**Root cause**: Dual-cache desync between `#cachedValidatedDexs` (string
DEX names) and `#cachedAllPerpDexs` (raw API objects for `perpDexIndex`
computation). The standalone preload path
(`#getStandaloneValidatedDexs`) populated one cache but not the other.
When `#buildAssetMapping` later ran, it found "xyz" in `dexsToMap` but
couldn't compute its `perpDexIndex` because `#cachedAllPerpDexs` was
null.

**Why old Perps tab vs new Homepage Sections**: Both layouts sit inside
`Wallet/index.tsx`, which calls `startMarketDataPreload()` on mount.
This fires standalone HTTP calls that populate `#cachedValidatedDexs`
but not `#cachedAllPerpDexs`.

- **New homepage sections**: `PerpsSectionWithProvider` mounts
immediately. Stream hooks fire `ensureReady()` before or concurrently
with the standalone preload. Since `#cachedValidatedDexs` is often still
null, `fetchValidatedDexsInternal` runs fresh and sets **both** caches
correctly.
- **Old tab layout**: The Perps tab doesn't mount until the user taps
it. By that time, `startMarketDataPreload()` has already completed →
`#cachedValidatedDexs` is populated by standalone. When the tab mounts →
`getValidatedDexs()` → **cache hit** → `fetchValidatedDexsInternal` is
never called → `#cachedAllPerpDexs` stays null → `buildAssetMapping`
can't find "xyz".

**Changes (1 file, 3 sites)**:

1. **Root cause fix**: `#getStandaloneValidatedDexs` now sets
`this.#cachedAllPerpDexs = allDexs` after a successful `perpDexs()`
call, keeping both caches in sync.
2. **Cache poisoning fix**: Removed `this.#cachedAllPerpDexs =
this.#cachedAllPerpDexs ?? [null]` from the catch block in
`#buildAssetMapping`.
3. **Cache poisoning fix**: Replaced persistent `if (!cache) { cache =
[null] }` with local `const allPerpDexs = cache ?? [null]` — consumers
read the cache, only the owner writes it.

## **Changelog**

CHANGELOG entry: Fixed a bug where closing positions on HIP-3 markets
(e.g., xyz:BRENTOIL) failed with "Asset ID not found" when navigating
via the Perps tab

## **Related issues**

Fixes: HIP-3 asset ID lookup failure on old Perps tab layout

## **Manual testing steps**

```gherkin
Feature: HIP-3 position management via Perps tab

  Scenario: user closes a HIP-3 position from the old Perps tab
    Given user has an open position on a HIP-3 market (e.g., xyz:BRENTOIL)
    And user is using the old tab layout (homepage redesign v1 disabled)

    When user navigates to the Perps tab
    And user taps close on the xyz:BRENTOIL position
    Then the position closes successfully without "Asset ID not found" error

  Scenario: user opens a HIP-3 position from the old Perps tab
    Given user is on the Perps tab (old layout)

    When user navigates to xyz:BRENTOIL market and places a market order
    Then the order executes successfully with correct asset ID routing
```

## **Screenshots/Recordings**

### **Before**

Metro logs show the desync:
```
getValidatedDexs CACHE HIT {"cachedAllNull": true, "dexs": [null, "xyz"]}
buildAssetMapping state  {"allPerpDexsLen": 1, "cachedAllNull": true}
Could not find perpDexIndex for DEX xyz
Asset ID not found for xyz:BRENTOIL
```

### **After**

Metro logs show both caches in sync:
```
buildAssetMapping state {"allPerpDexsLen": 8, "cachedAllNull": false, "dexsToMap": [null, "xyz"]}
Asset map state at order time {"assetExistsInMap": true, "hip3AssetsCount": 54, "totalAssetsInMap": 283}
Resolved DEX-specific asset ID {"assetId": 110049, "coin": "xyz:BRENTOIL"}
usePerpsClosePosition: Close result {"success": true, "orderId": "359617825254"}
```

## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches HIP-3 market routing/asset-ID mapping in
`HyperLiquidProvider`, so a mistake could break trading on some perps
markets; scope is small and localized to cache population/fallback
behavior.
> 
> **Overview**
> Fixes a HIP-3 asset mapping failure where `#cachedValidatedDexs` could
be populated via the standalone preload path while `#cachedAllPerpDexs`
stayed `null`, leading to missing `perpDexIndex` during
`#buildAssetMapping`.
> 
> `#getStandaloneValidatedDexs()` now also populates
`#cachedAllPerpDexs` after a successful `perpDexs()` call, and
`#buildAssetMapping()` no longer “poisons” the shared cache with a
persistent `[null]` fallback (it uses a local fallback instead).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c925609. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[2898ec8](2898ec8)

Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
## Description

Sync `stable` into `release/7.71.0` so the release branch includes
everything merged to stable through **7.70.1** (hotfixes and changelog
from [#27824](#27824))

## Changelog

CHANGELOG entry: null

---

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: only updates release metadata (CHANGELOG links/entries and
`OTA_VERSION`) with no functional code changes beyond versioning.
> 
> **Overview**
> Adds a `7.70.1` section to `CHANGELOG.md` (including two perps-related
fixes) and updates the compare links so *Unreleased* starts from
`v7.70.1`.
> 
> Bumps `OTA_VERSION` in `app/constants/ota.ts` from `v7.65.1` to
`v7.70.1` to match the hotfix release.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b8fba18. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com>
Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
…Action cp-7.71.0 (#27934)

- chore: New Crowdin translations by Github Action cp-7.71.0 (#27496)

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
[0b1f7be](0b1f7be)

Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
…n behind remote flag cp-7.71.0 (#27959)

- feat(earn): gate Tron unstaked claim button behind remote flag
(#27908)

## **Description**

Adds the remote boolean flag **`tronClaimUnstakedTrxButtonEnabled`** so
we can hide the **claim** action on the Tron unstaked banner if
something goes wrong in production, without removing the banner copy.

**Why:** We need a safe kill switch for the claim CTA only.

**How:**

- Register the flag in `FeatureFlagNames` with default `false`
(missing/undefined → button hidden; opt-in).
- **`selectTronClaimUnstakedTrxButtonEnabled`** in
`app/selectors/featureFlagController/tronClaimUnstakedTrxButtonEnabled/`
reads merged remote flags (same pattern as other boolean flags).
- `TronUnstakedBanner` uses
`useSelector(selectTronClaimUnstakedTrxButtonEnabled)` and renders the
primary claim button only when the flag is `true`; title and description
stay visible when the button is hidden.
- Register the flag in
**`tests/feature-flags/feature-flag-registry.ts`** (`inProd: true`,
`productionDefault: false`) so CI/E2E mocks match production
client-config.

**Ops:** Ensure **`tronClaimUnstakedTrxButtonEnabled`** exists in
LaunchDarkly / client-config; set to **`true`** where the claim button
should appear.

## **Changelog**

CHANGELOG entry: Added a remote feature flag to control visibility of
the Tron unstaked TRX claim button on the token details banner.

## **Related issues**

Fixes: NEB-838

## **Manual testing steps**

```gherkin
Feature: Tron unstaked banner claim button behind remote flag

  Scenario: user views TRX token details with claimable unstaked balance and flag enabled
    Given a Tron account with TRX ready for withdrawal and remote flag `tronClaimUnstakedTrxButtonEnabled` is true (or overridden in dev tools)

    When user opens native TRX token details and the unstaked banner is shown
    Then the banner shows title, description, and the claim button, and tapping claim still triggers the existing flow

  Scenario: user views TRX token details when flag is off or unset
    Given the same balance state but `tronClaimUnstakedTrxButtonEnabled` is false, missing, or undefined in remote flags

    When user opens native TRX token details and the unstaked banner is shown
    Then the banner shows title and description but does not show the claim button
```

## **Screenshots/Recordings**

### **Before**

See prior screenshots on this PR (token details with banner).

### **After**

Feature flag disabled / enabled — screenshots attached in thread (banner
with and without claim CTA).

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

Co-authored-by: Ulisses Ferreira <ulisses@hey.com>
… cp-7.71.0 (#27941)

- feat: show legacy ios login warning prompt cp-7.71.0 (#27875)

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

## **Description**
Add warning prompt for ios <17.4 for google login 

Supports the fix for:
https://github.com/MetaMask/MetaMask-planning/issues/7148
Part 1/ 4 - #27741
Part 2/ 4 - #27848
Part 3/ 4 - #27850 (deferred to 7.72.0)
Part 4/ 4 - #27875


<!--
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: Add warning prompt for ios <17.4 for google login

## **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] -->
For  < iOS 17.4




https://github.com/user-attachments/assets/f6f3a031-82cc-486d-af5f-e6e1bbc7ed10


For >= iOS 17.4



https://github.com/user-attachments/assets/2cdc0bf3-d59b-4858-be81-baae5e0a4dd2



## **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**
> Modifies the onboarding social login path by inserting a conditional
pre-login warning and new navigation helper, which could affect Google
login flow timing/navigation on iOS devices. Changes are localized but
touch user authentication entrypoints and analytics tracking.
> 
> **Overview**
> Adds an **iOS < 17.4 warning gate** before starting Google OAuth
during onboarding (both create and import flows), showing a
non-interactable `SuccessErrorSheet` that must be acknowledged before
proceeding.
> 
> Introduces `Device.comparePlatformVersionTo()` (using
`compare-versions`) and a reusable
`navigateToSuccessErrorSheetPromise()` helper to await sheet dismissal,
plus a new MetaMetrics event (`WALLET_GOOGLE_IOS_WARNING_VIEWED`) and
localized warning copy.
> 
> Updates onboarding tests to mock the new device helper/navigation and
to assert the warning sheet + tracking fire before continuing with
Google login.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3b43b83. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[002d91a](002d91a)

Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
…en user has a position cp-7.71.0 (#27924)

- fix: hides perps buttons in ai insights when user has a position
cp-7.71.0 (#27919)

<!--
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 is a bug fix for
#27916 where:
- In the AI Market Insights in Perps, the action buttons are wrong when
user has an open position: the action buttons should be the same in AI
market insight page and market page, ie. “modify” and “Close” when user
has an open position

Fix:
- When the user has an existing perps position, the MarketInsights
footer action buttons (Long/Short) are hidden since the relevant actions
(modify/close) live on the Perps market details page
- The "AI summary for information only" disclaimer is moved inline below
the feedback section when the footer is hidden, so it remains visible
- Position state is passed via route params (hasPerpsPosition) from the
caller rather than fetched async inside MarketInsightsView, preventing a
flash where buttons briefly appear then disappear while the position
loads

<!--
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: Fixed a bug that was causing incorrect Perps action
buttons to be displayed

## **Related issues**

Fixes: #27916

## **Manual testing steps**

```gherkin
- Open MarketInsights from token details → Swap/Buy buttons visible with disclaimer in footer
- Open MarketInsights from perps with no position → Long/Short buttons visible with disclaimer in footer
- Open MarketInsights from perps with an existing position → no footer buttons, disclaimer shown below "Was this helpful?"
- Verify no flash/layout shift on the perps + position flow
```

## **Screenshots/Recordings**

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

### **Before**

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



https://github.com/user-attachments/assets/0373c1bb-d433-4c9a-8768-117a40d98f9e



### **After**

<!-- [screenshots/recordings] -->
<img width="3699" height="3090" alt="SCR-20260325-nzfa"

src="https://github.com/user-attachments/assets/4b058c59-6df0-4d16-acf7-8d6bb839183f"
/>


## **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/navigation tweak that changes which CTAs are shown based
on a new route param; main risk is incorrect param wiring causing
missing actions or disclaimer placement in the Perps insights flow.
> 
> **Overview**
> Fixes Perps AI Market Insights showing inappropriate `Long`/`Short`
CTAs when the user already has an open position.
> 
> Adds a `hasPerpsPosition` route param (set by
`PerpsMarketDetailsView`) and uses it in `MarketInsightsView` to **hide
the footer action buttons** for Perps-with-position while **keeping the
informational disclaimer visible** by moving it inline under the
feedback section for that case.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
833593b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[8a7bced](8a7bced)

Co-authored-by: João Santos <joaosantos15@users.noreply.github.com>
This PR updates the change log for 7.71.0. (Hotfix - no test plan
generated.)

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: chloeYue <chloe.gao@consensys.net>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
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/MUL-1546

## **Manual testing steps**

no manual testing steps

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches the hardware wallet connection flow and bottom-sheet callbacks
to emit new analytics, so incorrect state resets or callback wiring
could affect connection UX/cleanup. No auth or funds-handling logic
changes, and coverage is added with extensive unit tests.
> 
> **Overview**
> Adds a new hardware-wallet analytics module that classifies **flow
context** (Connection/Send/Swaps/Transaction/Message) and normalizes
**error types/details**, then emits three new MetaMetrics events for
recovery: `HARDWARE_WALLET_RECOVERY_MODAL_VIEWED`, `..._CTA_CLICKED`,
and `..._SUCCESS_MODAL_VIEWED`.
> 
> Wires this into the hardware wallet UI/flow by deriving the analytics
flow from the first pending approval at the start of each
`ensureDeviceReady` run, tracking CTA taps from error screens via a new
`onCTAClicked` prop on `HardwareWalletBottomSheet`, and resetting
analytics state when the sheet is closed. Includes comprehensive unit
tests for helper mappings, Redux-derived flow detection, and event
firing/counting behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9bec1b0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…27708) (#28016)

## Description

Merges `stable` into `release/7.71.0` and resolves `CHANGELOG.md`
conflicts so [PR
#27708](#27708)
(`release/7.71.0` → `stable`) can merge cleanly.

### CHANGELOG resolution (per local release changelog guidelines)

- Kept **`## [7.71.0]`** (cleaned release notes) **above** **`##
[7.70.1]`** / **`## [7.70.0]`** from stable.
- **Compare links:** `[Unreleased]` → `v7.71.0...HEAD`; `[7.71.0]` →
`v7.70.1...v7.71.0`; left `[7.70.1]` / `[7.70.0]` lines unchanged below.

### After this PR

1. Merge this PR into `release/7.71.0` using **Create a merge commit**
(not squash), per release process.
2. Re-try / update [PR
#27708](#27708).

## Changelog

CHANGELOG entry: null

---

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: merge-conflict resolution focused on `CHANGELOG.md`
ordering/compare links with no runtime code changes.
> 
> **Overview**
> Merges `stable` into `release/7.71.0` and resolves the `CHANGELOG.md`
conflict by keeping the cleaned `7.71.0` notes above `7.70.1`/`7.70.0`
and updating the compare links (`[Unreleased]` → `v7.71.0...HEAD`,
`[7.71.0]` → `v7.70.1...v7.71.0`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
424324a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
# 🚀 v7.71.0 Testing & Release Quality Process

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

---

## 📋 Key Processes

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

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

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

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

---

## 🗓️ Timeline and Milestones

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

---

## ✅ Signoff Checklist

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

# Team sign-off checklist
- [x] Accounts Framework
- [x] Assets
- [x] Bots Team
- [x] Card
- [x] Confirmations
- [x] Core Platform
- [x] Design System
- [x] Earn
- [x] Mobile Platform
- [x] Mobile UX
- [ ] Money Movement
- [x] Networks
- [x] Onboarding
- [x] Perps
- [x] Predict
- [x] Rewards
- [x] Social & AI
- [x] Swaps and Bridge
- [x] team-hardware-wallets
- [ ] team-ramp
- [x] Transactions
- [x] Wallet Integrations

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

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

Many thanks in advance

# Reference
- Testing plan sheet -
https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372
This PR syncs the stable branch to main for version 7.73.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.73.0
…#27844)

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

Users with open Perpetuals or Predict positions could not see aggregate
unrealized P&L on the wallet homepage next to those sections, and the
Perps tab “Your positions” subtitle duplicated similar layout logic.

This PR:

- **Wallet homepage — Perps:** Shows a sub-row under “Perpetuals” with
aggregate unrealized P&L (and ROE %) when the user has **filled** open
positions; hides it for privacy mode, while loading account data, or
when there are no positions (including **orders-only** — no row). Colors
follow profit (green) / loss (red) / flat (default text).
- **Wallet homepage — Predict:** Shows the same style of row under
“Predictions” using the existing unrealized P&L API
(`useUnrealizedPnL`); pull-to-refresh also invalidates that query.
Respects privacy mode.
- **Perps home (tab):** Keeps the positions subtitle visible whenever
there are open positions (including flat P&L), uses design-system text
colors, and reuses the shared **`HomepageSectionUnrealizedPnlRow`** for
the value + “Unrealized P&L” line so layout matches the homepage spec
(4px under title, 8px between value and label).
- **Shared UI:** New `HomepageSectionUnrealizedPnlRow` under homepage
components (used by homepage sections + `PerpsHomeSection`).
- **Predict:** `formatPredictUnrealizedPnLStringParts` in `format.ts`
centralizes i18n interpolation for unrealized P&L strings;
`PredictPositionsHeader` and `PredictionsSection` both use it.

## **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: Added unrealized P&L summary on the wallet homepage for
Perpetuals and Predictions, and aligned the Perps home “Your positions”
subtitle with the same layout.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-584

## **Manual testing steps**

```gherkin
Feature: Unrealized P&L on homepage Perps and Predict

  Scenario: Perps section shows aggregate unrealized P&L with open positions
    Given the user has at least one open Perpetuals position and privacy mode is off
    When the user views the wallet homepage
    Then the Perpetuals section shows a line with signed dollar P&L, percentage, and an unrealized P&L label below the section title
    And positive P&L is green and negative P&L is red

  Scenario: Perps section hides P&L without open positions
    Given the user has no open Perpetuals positions (only limit orders or none)
    When the user views the wallet homepage
    Then no unrealized P&L sub-row appears under Perpetuals and spacing below the title is unchanged

  Scenario: Predict section shows unrealized P&L with open positions
    Given the user has open Predict positions and privacy mode is off
    When the user views the wallet homepage
    Then the Predictions section shows the unrealized P&L sub-row consistent with design

  Scenario: Privacy mode hides homepage P&L values
    Given privacy mode is enabled
    When the user views the wallet homepage with Perps and/or Predict positions
    Then unrealized P&L sub-rows for those sections are not shown

  Scenario: Perps tab positions subtitle matches homepage styling
    Given the user has open Perps positions
    When the user opens the Perps home screen
    Then “Your positions” shows the unrealized P&L value and label with the same visual treatment as the homepage row
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk: adds new homepage UI rows driven by live Perps account
state and Predict react-query data (including query invalidation on
refresh), which could affect loading/visibility states and performance
but does not touch auth or funds movement.
> 
> **Overview**
> Adds a shared `HomepageSectionUnrealizedPnlRow` component and uses it
to display **aggregate unrealized P&L** under the Wallet homepage
**Perpetuals** and **Predictions** section titles when the user has open
positions (and not in privacy mode), including loading placeholders and
tone-based coloring.
> 
> Refactors Perps tab `PerpsHomeSection`/`PerpsHomeView` to reuse the
same value+label row, switch to design-system `TextColor` tokens, and
keep the positions subtitle visible whenever positions exist (including
flat P&L). Predict’s positions header and homepage section now share a
centralized `formatPredictUnrealizedPnLStringParts` formatter, and
Predictions pull-to-refresh also invalidates the unrealized P&L query;
tests were updated/added accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
50ae867. 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**

Replace the default `QueryClient` with a custom `QueryClient` from
`createUIQueryClient`. This establishes the query client required for
using the `BaseDataService` pattern from the core repo, which handles
cache syncing. Existing UI-only queries should work as they did
previously.

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

https://consensyssoftware.atlassian.net/browse/WPC-445

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes how the global React Query
`QueryClient` is constructed and introduces messenger-backed
call/subscribe plumbing that could affect caching and network behavior
across the app.
> 
> **Overview**
> Switches `ReactQueryService` to build its `queryClient` via
`@metamask/react-data-query`’s `createUIQueryClient`, passing an Engine
messenger adapter to support data services and cache syncing while
keeping the existing default query options.
> 
> Adds a `DATA_SERVICES` registry (currently empty) for wiring in
available data services, updates unit tests to validate the new client
defaults and cache clearing behavior, and adds the new
`@metamask/react-data-query` dependency (plus lockfile updates).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
088a264. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…#28011)

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

> Updates Predict Market Details tab testIDs to be **stable and
semantic** by switching from index-based IDs to typed tab-key IDs
(`'positions' | 'outcomes' | 'about'`), and updates
`PredictMarketDetailsTabBar` plus its unit tests to use the new
`getPredictMarketDetailsSelector.tabBarTab(tabKey)` API.
> 
> Adds explicit testIDs to the confirmations `NetworkFilter` tabs by
introducing `network-filter.testIds.ts` and passing a required `testID`
prop into `NetworkFilterTab` for the “All networks” option and each
per-chain tab.
> 

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [ ] 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: changes are limited to test ID generation and wiring for UI
elements, with no business logic or data flow modifications.
> 
> **Overview**
> Updates Predict Market Details tab testIDs to be **stable and
semantic** by switching from index-based IDs to typed tab-key IDs
(`'positions' | 'outcomes' | 'about'`), and updates
`PredictMarketDetailsTabBar` plus its unit tests to use the new
`getPredictMarketDetailsSelector.tabBarTab(tabKey)` API.
> 
> Adds explicit testIDs to the confirmations `NetworkFilter` tabs by
introducing `network-filter.testIds.ts` and passing a required `testID`
prop into `NetworkFilterTab` for the “All networks” option and each
per-chain tab.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bea4356. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Mar 27, 2026
@pull pull Bot added the ⤵️ pull label Mar 27, 2026
@pull pull Bot merged commit 3e308f8 into Reality2byte:main Mar 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants