Skip to content

[pull] main from MetaMask:main#560

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

[pull] main from MetaMask:main#560
pull[bot] merged 15 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Feb 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 : )

oilnam and others added 15 commits February 27, 2026 18:27
<!--
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 removes the "Reset notifications" button which is not needed
anymore, and it's currently broken anyway.
Translation strings are also removed.

<img width="394" height="742" alt="image"
src="https://github.com/user-attachments/assets/4b29f6e0-8b84-4896-9757-4393d96d0b0b"
/>


## **Changelog**

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

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

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

CHANGELOG entry: Removed "Reset notifications" button from notifications
list

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Primarily removes dead/broken UI and navigation wiring; main risk is
missing a remaining reference to the removed route/string, but changes
are otherwise non-functional.
> 
> **Overview**
> Removes the broken **“Reset notifications”** entry from notification
settings by deleting the `ResetNotificationsButton`, the
`ResetNotificationsModal` bottom sheet, and their associated
tests/snapshots.
> 
> Cleans up navigation by removing `Routes.SHEET.RESET_NOTIFICATIONS`
and its route typing, and deletes related i18n strings across supported
languages; also stabilizes `useNotifications` hook tests by properly
mocking `usePushNotificationsToggle` and clearing mocks between tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3be27b9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Phase 3 analytics migration (Batch 3-10): migrate Onboarding/Account
Import's ImportNewSecretRecoveryPhrase, ExperienceEnhancerModal, and
Pna25BottomSheet from useMetrics/MetaMetrics to the new analytics
system.

**Reason**: Deprecate MetaMetrics in favour of the shared analytics
utility and AnalyticsController.

**Changes**: ImportNewSecretRecoveryPhrase, ExperienceEnhancerModal, and
Pna25BottomSheet now use `useAnalytics` and `AnalyticsEventBuilder` from
`app/components/hooks/useAnalytics` and `app/util/analytics`; test mocks
updated to mock useAnalytics instead of useMetrics.
ImportFromSecretRecoveryPhrase already used useAnalytics — no migration
needed.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-302 (Batch
3-10)

## **Manual testing steps**

```gherkin
Feature: Onboarding/Account Import analytics

  Scenario: user triggers an onboarding/account import flow event
    Given app is open and user is in an onboarding/account import flow

    When user performs an action that triggers analytics (e.g. import SRP completed, marketing consent modal accept/cancel, PNA25 notice viewed/closed)
    Then the event is tracked on Mixpanel
```

## **Screenshots/Recordings**

N/A – analytics migration, no UI change.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Replaces the legacy `useMetrics` analytics hook with `useAnalytics` in
onboarding/consent flows, which could change or break event
emission/consent traits if the new builder/hook behavior differs. No
functional UI changes, but tracking correctness is compliance- and
telemetry-sensitive.
> 
> **Overview**
> Migrates analytics instrumentation in **ExperienceEnhancerModal**,
**ImportNewSecretRecoveryPhrase**, and **Pna25BottomSheet** from legacy
`useMetrics` to `useAnalytics`, updating event/builder usage (e.g., SRP
import completion and PNA25 notice events) while keeping existing
`MetaMetricsEvents` names.
> 
> Updates Jest tests to mock `useAnalytics` and (for SRP import) swap
`MetricsEventBuilder` references to `AnalyticsEventBuilder`, ensuring
tracking assertions still validate emitted events/properties.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
09f4586. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Phase 3 analytics migration (Batch 3-11): migrate Hardware Wallet's
`LedgerSelectAccount` component from `useMetrics` to the new analytics
system.

**Reason**: Deprecate MetaMetrics in favour of the shared analytics
utility and AnalyticsController.

**Changes**: `LedgerSelectAccount/index.tsx` now uses `useAnalytics`
from `app/components/hooks/useAnalytics/useAnalytics` instead of
`useMetrics`; test mocks updated to mock `useAnalytics` instead of
`useMetrics`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-302 (Batch
3-11)

## **Manual testing steps**

```gherkin
Feature: Hardware Wallet analytics

  Scenario: user triggers a hardware wallet flow event
    Given app is open and user is in a hardware wallet flow

    When user performs an action that triggers analytics (e.g. open account selector, unlock account, forget device)
    Then the event is tracked on Mixpanel
```

## **Screenshots/Recordings**

N/A – analytics migration, no UI change.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Swaps the analytics hook used by `LedgerSelectAccount` and updates its
unit test mock; behavior should be equivalent but could affect event
emission if the new hook differs in runtime wiring.
> 
> **Overview**
> Migrates hardware wallet `LedgerSelectAccount` analytics from the
deprecated `useMetrics` hook to the new `useAnalytics` hook while
keeping the same `trackEvent`/`createEventBuilder` call sites.
> 
> Updates `LedgerSelectAccount` tests to mock `useAnalytics` instead of
`useMetrics` so existing analytics-related assertions continue to run
against the new hook.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d71565b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Phase 3 analytics migration (Batch 3-14): migrate Legal/Onboarding's
terms-of-use utilities from `MetaMetrics.getInstance()` to the new
analytics system.

**Reason**: Deprecate MetaMetrics in favour of the shared analytics
utility and AnalyticsController.

**Changes**: `termsOfUse.ts` now uses `analytics.trackEvent()` and
`AnalyticsEventBuilder` from `app/util/analytics`; test mocks updated to
mock the analytics utility instead of `MetaMetrics.getInstance()`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-302 (Batch
3-14)

## **Manual testing steps**

```gherkin
Feature: Legal/Onboarding analytics

  Scenario: user triggers a terms of use flow event
    Given app is open and user has not yet accepted terms of use

    When user performs an action that triggers analytics (e.g. terms of use shown, terms accepted)
    Then the event is tracked on Mixpanel
```

## **Screenshots/Recordings**

N/A – analytics migration, no UI change.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk refactor that swaps the event tracking implementation for
terms-of-use shown/accepted; behavior should be equivalent but could
impact whether/when these two events are emitted if the new analytics
queueing differs from `MetaMetrics.getInstance()`.
> 
> **Overview**
> Migrates terms-of-use analytics emission from
`MetaMetrics.getInstance().trackEvent`/`MetricsEventBuilder` to the
shared `analytics.trackEvent` helper with `AnalyticsEventBuilder` for
the `USER_TERMS_SHOWN` and `USER_TERMS_ACCEPTED` events.
> 
> Updates `termsOfUse` unit tests to mock `app/util/analytics/analytics`
and assert calls to `analytics.trackEvent` instead of mocking
`MetaMetrics`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f7c5c93. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Phase 3 analytics migration (Batch 3-15): migrate the ResetPassword view
from `MetaMetrics.getInstance()` / `MetricsEventBuilder` to the new
`analytics` utility and `AnalyticsEventBuilder`.

**Reason**: Deprecate MetaMetrics in favour of the shared analytics
utility and AnalyticsController.

**Changes**: `ResetPassword/index.js` now uses `analytics.trackEvent()`
and `AnalyticsEventBuilder` from `app/util/analytics`; test mocks
updated to mock the analytics utility instead of MetaMetrics.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-302 (Batch
3-15)

## **Manual testing steps**

```gherkin
Feature: Settings analytics

  Scenario: user triggers a password change event
    Given app is open and user is in Settings > Change Password flow

    When user performs an action that triggers analytics (e.g. password change confirmation)
    Then the event is tracked on Mixpanel
```

## **Screenshots/Recordings**

N/A – analytics migration, no UI change.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk refactor limited to analytics plumbing in the password reset
flow; main risk is mis-tracking or missing the `PASSWORD_CHANGED` event
due to the API swap.
> 
> **Overview**
> Migrates `ResetPassword` analytics from legacy
`MetaMetrics.getInstance()`/`MetricsEventBuilder` to the shared
`analytics` utility with `AnalyticsEventBuilder`, keeping the
`PASSWORD_CHANGED` event and its biometry-related properties.
> 
> Updates the `ResetPassword` tests to mock `util/analytics/analytics`
instead of `MetaMetrics`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
22501d0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Phase 3 analytics migration (Batch 3-16): migrate selectors
(`legalNotices`, `bridgeController`) from `MetaMetrics.getInstance()` to
the new analytics system.

**Reason**: Deprecate MetaMetrics in favour of the shared analytics
utility and AnalyticsController.

**Changes**: `legalNotices/index.ts` and `bridgeController/index.ts` now
use `analytics.isEnabled()` from `app/util/analytics/analytics` instead
of `MetaMetrics.getInstance().isEnabled()`; test mocks updated to mock
the analytics utility instead of MetaMetrics.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-302 (Batch
3-16)

## **Manual testing steps**

```gherkin
Feature: Selectors analytics

  Scenario: user triggers a selector-dependent flow event
    Given app is open and user is in a flow that relies on legalNotices or bridgeController selectors

    When user performs an action that triggers analytics (e.g. PNA25 notice display, bridge quote request)
    Then the event is tracked on Mixpanel
```

## **Screenshots/Recordings**

N/A – analytics migration, no UI change.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk refactor that only swaps the opt-in check from
`MetaMetrics.getInstance().isEnabled()` to `analytics.isEnabled()` in a
couple of selectors and updates unit test mocks accordingly.
> 
> **Overview**
> Migrates selector logic in `bridgeController` and `legalNotices` off
deprecated `MetaMetrics.getInstance()` and onto the shared `analytics`
helper.
> 
> `participateInMetaMetrics` (bridge app state) and the PNA25 notice
gating check now call `analytics.isEnabled()`, and the `legalNotices`
selector tests were updated to mock the new analytics utility instead of
`MetaMetrics`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
97d418a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…nd bridge transactions (#26701)

## **Description**

The "View on block explorer" button on the Bridge/Swap Transaction
Details screen was broken for both swaps and bridge transactions —
pressing it did nothing.

Root causes:

- Swap transactions: `navigation.navigate(Routes.BROWSER.VIEW, ...)` was
called directly, but `BROWSER.VIEW` is a nested screen inside the
`BROWSER.HOME` tab navigator. React Navigation silently ignores
navigation calls to nested screens made from outside their parent.
Additionally, navigating to a tab navigator replaces the current stack,
so the back button would return to the home screen instead of
activities.

- Bridge transactions:
`navigation.navigate(Routes.BRIDGE.MODALS.TRANSACTION_DETAILS_BLOCK_EXPLORER,
...)` was called directly, but this screen is nested inside
`BridgeModalStack` (registered as `Routes.BRIDGE.MODALS.ROOT`). Same
silent failure.

Fix:

- Swap path now uses `Routes.WEBVIEW.MAIN` → `Routes.WEBVIEW.SIMPLE`,
which pushes a `WebView` on top of the current stack (back button
returns to Transaction Details correctly)
- Bridge path now navigates to `Routes.BRIDGE.MODALS.ROOT` with screen:
`TRANSACTION_DETAILS_BLOCK_EXPLORER` as a nested param
- Tightened the condition from a bare else to else if (isBridge) to
prevent a swap with an unresolved explorer URL from accidentally opening
the bridge modal

## **Changelog**

CHANGELOG entry: Fixed "View on block explorer" button not working on
Bridge/Swap Transaction Details screen

## **Related issues**

Fixes: #26628

## **Manual testing steps**

```gherkin
Feature: View on block explorer from Transaction Details

  Scenario: user views a completed swap on block explorer
    Given user has a completed swap transaction (same-chain)
    When user taps the transaction in Activity to open Transaction Details
    And user taps "View on block explorer"
    Then a WebView opens showing the block explorer for that transaction
    And tapping back returns the user to Transaction Details

  Scenario: user views a completed bridge on block explorer
    Given user has a completed bridge transaction (cross-chain)
    When user taps the transaction in Activity to open Transaction Details
    And user taps "View on block explorer"
    Then a bottom sheet appears with source and destination chain explorer options
    When user taps one of the explorer options
    Then a WebView opens showing that chain's block explorer for the transaction
```

## **Screenshots/Recordings**

`~`

### **Before**


https://github.com/user-attachments/assets/9030e42a-32a5-4661-bc00-d4953ae17850

### **After**


https://github.com/user-attachments/assets/26da74e6-353b-4df9-9be2-7f45f00105fe

## **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**
> Changes React Navigation targets for the “View on block explorer” flow
and bridge explorer modal buttons, which is user-facing and could
regress routing/back-stack behavior if route params or navigator
structure differ across entry points.
> 
> **Overview**
> Fixes the broken “View on block explorer” actions in Bridge/Swap
transaction details by updating navigation to valid parent/nested
routes.
> 
> Swaps now open the in-app `WEBVIEW` (`Routes.WEBVIEW.MAIN` →
`Routes.WEBVIEW.SIMPLE`) instead of `Routes.BROWSER.VIEW`, while bridges
now navigate via `Routes.BRIDGE.MODALS.ROOT` to show the
explorer-selection bottom sheet; the fallback logic is tightened to only
open the modal for actual bridge transactions.
> 
> Updates/expands unit tests to mock navigation and assert the new
webview/modal navigation behavior, including pressing source/destination
explorer buttons in `BlockExplorersModal`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
77221e0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…works in transaction details (#26659)

## **Description**

`getBlockExplorerForChain()` in `TransactionDetails` only resolved block
explorer URLs for hardcoded built-in networks (Mainnet, Linea, Sepolia)
and user-added custom RPC networks. Popular networks (Arbitrum, Polygon,
BNB Chain, etc.) are neither — they aren't stored in
`networkConfigurations` — so the method fell through to
`NO_RPC_BLOCK_EXPLORER`, hiding the "View on X" link entirely.

The fix adds a `PopularList` lookup as a fallback, matching the pattern
already used correctly in useBlockExplorer.ts.

## **Changelog**

CHANGELOG entry: Fixed a bug where transactions on popular networks
(Arbitrum, Polygon, BNB Chain, etc.) were missing the block explorer
link in transaction details

## **Related issues**

Fixes: #26419

## **Manual testing steps**

```gherkin
Feature: Block explorer link in transaction details

  Scenario: user views a transaction from a Popular network
    Given the user has transactions on Arbitrum, Polygon, or BNB Chain
    And the activity feed is filtered by "Popular networks"

    When user taps a confirmed transaction from one of those networks
    Then a "View on Arbiscan" / "View on Polygonscan" / "View on Bscscan" link appears
    And tapping it opens the correct block explorer tx URL in the webview

  Scenario: user views a transaction on Ethereum Mainnet
    Given the user has transactions on Ethereum Mainnet
    When user taps a confirmed transaction
    Then a "View on Etherscan" link still appears (regression check)
```

## **Screenshots/Recordings**

`~`

### **Before**


https://github.com/user-attachments/assets/0b15c664-e62e-4811-94f6-e12687454025

### **After**


https://github.com/user-attachments/assets/8c71420a-f95a-4ebe-ba4c-dedd7cfebc0e

## **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]
> **Low Risk**
> Low risk UI fix that only changes how the transaction details screen
resolves a block explorer URL, with added test coverage to prevent
regressions.
> 
> **Overview**
> Fixes missing **“View on …”** links in `TransactionDetails` for
*popular networks* that aren’t present in `networkConfigurations` by
falling back to `PopularList` to resolve `rpcPrefs.blockExplorerUrl`.
> 
> Adds unit tests ensuring the correct explorer link text/URL is
produced for Arbitrum, Polygon, and BNB Chain, alongside existing
mainnet/custom-network coverage.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0e7e142. 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**

Extract various logic into separate pure functions and hooks. 

<!--
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/SWAPS-4188

## **Manual testing steps**

```gherkin
This PR introduce no change to business logic. Ensure that no regressions got introduced. 
```

## **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**
> Mostly refactoring with broad surface-area touch in Bridge quoting/fee
display and validation filtering; moderate risk of UI regressions around
fee formatting and when quote sections render/clear on expiry.
> 
> **Overview**
> **Refactors Bridge quote presentation logic into reusable
utilities/hooks.** Network-fee formatting is extracted to
`formatNetworkFee` + `useFormattedNetworkFee`, and gas-sponsorship logic
is moved into `useIsNetworkGasSponsored` +
`useShouldRenderGasSponsoredBanner`, with gasless detection centralized
in `isGaslessQuote`.
> 
> **Hardens quote-driven UI and data selection.** `BridgeView` now
avoids rendering the bottom action section when there’s no `activeQuote`
(fixing an expiry/redirect edge case), and `useBridgeQuoteData` adds
`validQuotes` by filtering sorted quotes to those matching the selected
destination token and non-expired state.
> 
> **Consolidates fiat formatting.** The existing `useFiatFormatter` hook
is simplified to delegate to a new shared `util/formatFiat` helper, with
extensive new unit tests added across the new hooks/utilities.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9096d32. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ity (#26676)

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

Part "4.5" of the hardware wallet connection & error management
overhaul. This does not introduce user facing changes.

Will close:
- https://consensyssoftware.atlassian.net/browse/MUL-1495

Final implementation will look like this ([Figma
designs](https://www.figma.com/design/1F3yNWYLOVPFpTPeJugH20/SWAP?node-id=11110-19571&t=tPMZNNiwCgbDfegd-0)):
<img width="1404" height="631" alt="image"
src="https://github.com/user-attachments/assets/68850711-f53b-4060-8b47-6faceb67f82f"
/>

Reference feature branch:
#25519

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

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**
> Refactors core hardware-wallet connection flow and transport
monitoring into new hooks, which could subtly change state transitions
(scanning/connecting/error/ready) or cleanup behavior. No new security
surface, but regressions could impact device connectivity and error
handling.
> 
> **Overview**
> Refactors `HardwareWalletProvider` by extracting adapter lifecycle,
transport monitoring, device discovery, and connection/retry/close logic
into new hooks (`useAdapterLifecycle`, `useTransportMonitoring`,
`useDeviceDiscovery`, `useDeviceConnectionFlow`) and wiring the provider
to these hook APIs.
> 
> Simplifies the connecting UI contract by removing adapter-provided
`connectionTips`: `getConnectionTips()` is removed from
`HardwareWalletAdapter` (and Ledger/NonHardware adapters),
`HardwareWalletBottomSheet` no longer accepts `connectionTips`, and
`ConnectingContent` now derives tips via
`getConnectionTipsForWalletType()` in `helpers.ts`. Also makes
bottom-sheet `onClose` required and updates tests accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b84edf3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Add comprehensive analytics events to the Unified Buy v2 flow, covering
every user interaction across Token Selection and Amount Input screens.
Flow identity uses **`ramp_type` only** (e.g. `'UNIFIED BUY 2'`); for a
single dimension in Segment and Data Council.

**Reason for change:** Measure UB2 funnel conversion and drop-offs;
compare UB2 vs UB1.
**Improvement:** 18 new events + enhanced existing events; screen viewed
once per visit; Change provider only in Payment Selection modal.

### Changes
- **18 new events:** Ramps Screen Viewed, Back Button Clicked, Network
Filter Clicked, Token Searched, Settings Clicked, Setting Option
Clicked, Payment Method Selector Clicked, Quick Amount Clicked, Change
Provider Button Clicked, Provider Selected, Continue Button Clicked
(KPI), Terms Consent Clicked, External Link Clicked, Close Button
Clicked, Quote Error, Quote Error Tooltip Clicked, Unsupported Token
Tooltip Clicked, Toast Button Clicked.
- **Existing enhanced:** `RAMPS_TOKEN_SELECTED` and
`RAMPS_BUTTON_CLICKED` accept `ramp_type: 'UNIFIED BUY 2'`.
- **Screens:** TokenSelection, BuildQuote, PaymentSelectionModal (Change
provider only).

### Related PRs
- Segment schema: Consensys/segment-schema#471

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Unified Buy v2 analytics events

  Scenario: user completes token selection and amount input in UB2 flow
    Given Unified Buy v2 is enabled (MM_RAMPS_UNIFIED_BUY_V2_ENABLED=true) and user is on Buy from home

    When user opens Token Selection then searches token, filters by network, selects token, opens Amount Input, taps quick amount, opens payment selector, taps Change provider in Payment Selection modal, taps Settings, then taps Continue

    Then Segment debugger shows Ramps Screen Viewed (once per visit per screen), Ramps Token Searched, Ramps Network Filter Clicked, Ramps Token Selected with ramp_type UNIFIED BUY 2, Ramps Quick Amount Clicked, Ramps Payment Method Selector Clicked, Ramps Change Provider Button Clicked, Ramps Settings Clicked, Ramps Continue Button Clicked with no feature_flag_unified_buy_v2 in payloads
```

## **Screenshots/Recordings**

<div>
<a href="https://www.loom.com/share/ac98af2b79cc41c1a37336329fd06cb5">
      <p>Ramps Unified Buy V2 Analytics Walkthrough - Watch Video</p>
    </a>
<a href="https://www.loom.com/share/ac98af2b79cc41c1a37336329fd06cb5">
<img style="max-width:300px;"
src="https://cdn.loom.com/sessions/thumbnails/ac98af2b79cc41c1a37336329fd06cb5-564c55257a094c01-full-play.gif#t=0.1">
    </a>
  </div>


## **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/changes analytics instrumentation across multiple ramp screens
and entry points, which is moderately risky due to potential schema
regressions or event-volume changes (but no funds/auth logic is
altered).
> 
> **Overview**
> Adds **Unified Buy v2 (UB2)** analytics instrumentation across the
ramps flow, introducing a new `ramp_type` value (`UNIFIED_BUY_2`) and a
set of new MetaMetrics events (screen views, back/close, settings, quick
amounts, provider/payment selection, external links, quote errors,
tooltips, etc.).
> 
> Updates existing ramps events to match the new schema (notably
renaming the `RAMPS_BUTTON_CLICKED` property from `text` to
`button_text`) and wires UB2-aware `ramp_type` selection into multiple
entry points (e.g., `BalanceEmptyState`, `FundActionMenu`,
`AccountsMenu`, Card add-funds deposit).
> 
> Extends navigation header helpers to support an optional `onBackPress`
callback so screens can track back navigation, and adjusts unit/smoke
tests and snapshots accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2fb77db. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

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

## **Description**
- Fix geolocation mock to return plain text (us-ca) instead of a JSON
object, matching the real API's response format. The app reads this with
response.text(), so a JSON object gets stringified and can produce
malformed URLs when used in path segments.
- Support string responses in the mock server layer — both
MockServerE2E.ts and mockHelpers.ts now return string responses as raw
text instead of JSON-serializing them.
- Add catch-all mock for the legacy /regions/{region}/tokens endpoint to
DEFAULT_RAMPS_API_MOCKS, preventing unmocked live API calls.
- On mUSD convert disables the synchronization only after tapping the
CTA to make sure it is displayed before on a first time user.


This PR addresses a gigantic mocking error on default mocks,
specifically speaking the onramp geolocation. This issue was causing
random flakiness due to a bad formatted url coming from a mock.
Example:
`https://on-ramp-cache.uat-api.cx.metamask.io/regions/%7B%22id%22:%22/regions/us-ca%22,%22name%22:%22california%22,%22emoji%22:%22%F0%9F%87%BA%F0%9F%87%B8%22,%22detected%22:true%7D/tokens?action=deposit&sdk=2.1.5`
(see [run
reference](https://github.com/MetaMask/metamask-mobile/actions/runs/22429213914/job/64944977184))

The reason for this is that the request for
`https://on-ramp.<ENV>-api.cx.metamask.io/geolocation` was returning
```typescript
{
    id: region.id,
    name: region.name,
    emoji: region.emoji,
    detected: true,
}
```
when in reality the geolocation endpoint returns plaintext containing
the country code for the user's location. This PR adds the ability to
the mock server to accept plain text instead of json as a response and
fixes the mocking.

It then caused perps tests to fail due to region not available since the
[fallback country (US) is currently being
blacklisted](https://github.com/MetaMask/metamask-mobile/blob/main/builds.yml#L40)
and this was the country used in the onramps default geolocation mock.


## CI changes
`ref` was removed from the shard runner checkout as this was causing
inconsistencies with the way every single workflow uses checkout. Builds
do **not** contain a ref which results in building apps with a merge
commit instead of the branch commit while tests would run with a
different ref resulting in failed tests for changes that were already
fixed on main.

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



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk: changes test infrastructure by installing a
lifecycle-wide `unhandledRejection` filter and altering mock server
shutdown behavior, which could mask unexpected promise rejections if the
filter is too broad. Functional app code is untouched; impact is limited
to E2E reliability and mocking fidelity.
> 
> **Overview**
> Fixes onramp geolocation mocking to return *plain text* region codes
(matching the real API) and updates the mocking layer (`MockServerE2E`,
`setupMockRequest`) to return raw string bodies without
JSON-serializing; adds a catch-all mock for legacy
`/regions/{region}/tokens` to prevent live calls.
> 
> Hardens E2E infra by adding `MockServerE2E.startDraining()` (return
503 during cleanup) and installing a lifecycle-wide filter that
suppresses mockttp `Error('Aborted')` unhandled rejections, with cleanup
integrated into `withFixtures`.
> 
> Stabilizes flaky Detox flows: waits for elements to stop moving before
taps (wallet token rows, confirm button), relaxes a swap analytics
assertion to *min length*, adjusts unified-buy analytics region
assertions to expect a string, adds perps geolocation mocking
(non-blocked region), and tweaks/simplifies a few smoke tests (mUSD sync
timing, SOL send assertions).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
27fc622. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…nterface (#26703)

## **Description**

Consolidates scattered feature flag resolution in PredictController into
a single `resolveFeatureFlags()` method and injects flags into
PolymarketProvider via a constructor callback.

**Problem**: Feature flags (liveSportsLeagues, feeCollection,
marketHighlights) were resolved independently in 3 separate
PredictController methods (`getMarkets`, `getMarket`, `previewOrder`),
each calling `RemoteFeatureFlagController:getState` and unwrapping flags
ad-hoc. These flags were then passed as method parameters to
PolymarketProvider.

**Solution**:
- New `PredictFeatureFlags` type consolidating all predict feature flags
- New `resolveFeatureFlags()` private method on PredictController —
single resolution point
- PolymarketProvider now takes a `getFeatureFlags` callback in
constructor and reads flags internally
- Cleaned `PredictProvider` interface — removed per-method flag
parameters (`liveSportsLeagues`, `feeCollection`)
- Removed `liveSportsLeagues` from `GetMarketsParams` (internal concern,
not caller-facing)

This is a **pure refactor** — zero behavior changes. Foundation for
upcoming Permit2 fee authorization support.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/PRED-715

## **Manual testing steps**

```gherkin
Feature: Predict feature flag resolution refactor

  Scenario: user places prediction market orders as before
    Given user has Predict feature enabled and is in a supported region

    When user browses markets, views market details, and previews/places orders
    Then all functionality works identically to before (no behavior changes)
```

## **Screenshots/Recordings**

N/A — pure refactor, no UI changes.

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches Predict market fetching and order preview paths by changing
how feature flags are resolved and threaded into the Polymarket
provider. Risk is mainly around mismatched defaults or missing flag
injection impacting live sports overlays, highlights ordering, or fee
collection in previews.
> 
> **Overview**
> **Refactors Predict feature-flag plumbing** by introducing
`PredictFeatureFlags` and a single
`PredictController.resolveFeatureFlags()` that reads remote flags (live
sports leagues, market highlights, fee collection) and supplies them to
`PolymarketProvider` via a `getFeatureFlags` constructor callback.
> 
> `PolymarketProvider` now consumes flags internally (no longer accepts
`liveSportsLeagues`/`feeCollection` as method params), and the
`PredictProvider`/`GetMarketsParams` types are simplified accordingly.
Tests are updated to match the new provider constructor + method
signatures and to assert fee collection defaults are applied during
`previewOrder` and highlight fetching.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fdb4a95. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#26696)

## **Description**

This PR adds `@deprecated` JSDoc comments with README links to 20
component library files that have replacements in the MetaMask Design
System (MMDS).

The deprecation messages provide clear migration paths for developers
by:
1. Indicating which MMDS component to use as a replacement
2. Warning that the API may have changed
3. Linking directly to the component's README in the MMDS repository

This work improves developer experience by making it easier to migrate
from legacy component library components to the standardized MMDS
components.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: JSDoc deprecation comments

  Scenario: developer views deprecated component
    Given a developer opens a component library file
    
    When developer hovers over a deprecated component import
    Then the IDE should display the @deprecated JSDoc comment with migration guidance
    And the comment should include a link to the MMDS component README
```

## **Screenshots/Recordings**

N/A - Documentation-only changes

### **Before**

Components had either no deprecation messages or minimal ones without
full context.

### **After**

All 20 components now have consistent deprecation messages following
this pattern:

```javascript
/**
 * @deprecated Please update your code to use `ComponentName` from `@metamask/design-system-react-native`.
 * The API may have changed — compare props before migrating.
 * @see {@link https://github.com/MetaMask/metamask-design-system/blob/main/packages/design-system-react-native/src/components/ComponentName/README.md}
 */
```

**Components updated:**
- Avatar components: AvatarAccount, AvatarBase, AvatarFavicon,
AvatarGroup, AvatarIcon, AvatarNetwork, AvatarToken
- Badge components: BadgeBase, BadgeNetwork, BadgeNotifications,
BadgeWrapper
- Button components: Button, ButtonIcon, ButtonLink, ButtonPrimary,
ButtonSecondary
- Form components: Checkbox, TextField
- Other components: Card, Icon, Text

## **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 (N/A - documentation only)
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk documentation-only change: adds/standardizes `@deprecated`
JSDoc blocks and external README links without altering component
runtime behavior. Main risk is minor lint/formatting or tooling
differences in how IDEs surface these comments.
> 
> **Overview**
> Adds consistent `@deprecated` JSDoc annotations across legacy
component-library UI components (avatars, badges, buttons, checkbox,
text field, icon, text), pointing developers to the equivalent
`@metamask/design-system-react-native` replacements.
> 
> Each deprecation notice now includes a migration caution about
potential API differences and a direct link to the relevant MMDS README
for the replacement component.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
167e357. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Update the Xcode stack from osx-xcode-16.3.x to osx-xcode-26.2.x to
enable building with iOS SDK 26. This prepares for the April 2026 App
Store requirement that apps must be built with Xcode 26 or later.

This PR updates the ruby version to 3.2.9 according to the [Bitrise
stack
availability](https://bitrise.io/stacks/stack_reports/osx-xcode-26.2.x/).
It also updates the Ruby Version source for the `ci/docker` step.

It also requires an update to the .github-tools repo here:
https://github.com/MetaMask/github-tools/pull/220/commits

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

AI agent: Be specific about what you changed and why. Include context
about the fix/feature, not generic descriptions.
-->

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

AI agent: Use format `CHANGELOG entry: [fix/feat/chore]: [User-facing
description in past tense]`.
Examples: `fix: resolved token name display issue`, `feat: added dark
mode toggle`, `chore: updated dependencies`.
For non-user-facing changes, use `CHANGELOG entry: null`.
-->

CHANGELOG entry: null

## **Related issues**

<!--
AI agent: Replace with `Fixes: #[ISSUE_NUMBER]` using the actual issue
number you're implementing.
-->

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-329

## **Manual testing steps**

<!--
AI agent: Write specific, contextual Gherkin steps based on what you
actually implemented.
Do NOT use generic placeholders like "my feature name". Be concrete
about the feature, scenario, and 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**
Successful Bitrise:
https://app.bitrise.io/build/d8ffdf86-23f8-4476-afef-1b4dda76a554
Successful CI (note there a some flaky flask tests):
https://github.com/MetaMask/metamask-mobile/actions/runs/22237789978?pr=25136
Successful build.yml:
https://github.com/MetaMask/metamask-mobile/actions/runs/22241562536

## **Pre-merge author checklist**

<!--
AI agent: Check ALL boxes in this section (mark all as [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).
- [ ] 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**

<!--
AI agent: Leave ALL boxes unchecked ([ ]) - these are for reviewers to
check, not the author.
-->

- [ ] 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 core CI/build infrastructure (Bitrise
Xcode stack, Ruby toolchain, and shared `setup-e2e-env` action), which
can break iOS/Android build and E2E workflows if the new environment has
compatibility issues.
> 
> **Overview**
> Updates CI and Bitrise build environments to support iOS SDK 26 by
moving Bitrise stacks to `osx-xcode-26.2.x` and aligning the Ruby
toolchain to `3.2.9` (including `.ruby-version`, `ios/Gemfile`,
`Gemfile.lock`, and GitHub Actions `ruby/setup-ruby`).
> 
> Refreshes GitHub Actions workflows to use `MetaMask/github-tools`
`setup-e2e-env@v1.7` across build and E2E pipelines, and updates the
Docker CI image’s ruby-build pin used to install the newer Ruby.
> 
> Bumps iOS/Bitrise build numbers from `3607` to `3821` (including
`bitrise.yml` envs and `CURRENT_PROJECT_VERSION` in the Xcode project).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
01116b4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
Co-authored-by: tommasini <tommasini15@gmail.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators Feb 27, 2026
@pull pull Bot added the ⤵️ pull label Feb 27, 2026
@pull pull Bot merged commit d2eb1e1 into Reality2byte:main Feb 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.

10 participants