Skip to content

[pull] main from MetaMask:main#579

Merged
pull[bot] merged 17 commits into
Reality2byte:mainfrom
MetaMask:main
Mar 5, 2026
Merged

[pull] main from MetaMask:main#579
pull[bot] merged 17 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 5, 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 : )

gantunesr and others added 17 commits March 5, 2026 17:01
…26994)

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

Delete the `EvmAccountSelectorList` and `EvmAccountSelectorList`
components.

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

## **Manual testing steps**

Not applicable

## **Screenshots/Recordings**

Not applicable

## **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**
> Mostly deletes unused/deprecated UI components and their tests, with
minimal functional change. Main risk is an overlooked navigation or
import reference to the removed screens/components causing runtime or
test failures.
> 
> **Overview**
> **Removes deprecated UI surfaces.** Deletes `EvmAccountSelectorList`
(and associated styles, types, tests, and snapshots) and removes its
CODEOWNERS entry.
> 
> **Cleans up navigation and tests.** Drops the `TurnOnBackupAndSync`
screen from `MainNavigator` and deletes its
implementation/tests/snapshots, updating `MainNavigator` snapshots and
simplifying `MultichainAccountConnect` test mocks accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3d793d9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Migrates the BuildQuote screen header from the centralized
`Navbar/index.js` factory pattern (`getRampsBuildQuoteNavbarOptions` +
`navigation.setOptions()`) to an inline `<HeaderCompactStandard>`
rendered directly in the component.

**Why**: The codebase has established a clear pattern (40+ screens
including Ramp Settings, Rewards, Perps, Predict, and all Settings
screens) where `HeaderCompactStandard` is rendered inline in the
component with `headerShown: false` in the navigator. The BuildQuote
screen was one of the last Ramps screens still using the old centralized
factory approach. This change aligns it with the modern pattern as part
of TRAM-3321.

**What changed**:
- Added `headerShown: false` for BuildQuote in `routes.tsx`
- Replaced `useEffect` /
`navigation.setOptions(getRampsBuildQuoteNavbarOptions(...))` with
inline `<HeaderCompactStandard>` in `BuildQuote.tsx`
- Extracted `handleSettingsPress` and `handleBackPress` into
`useCallback` hooks
- Deleted `getRampsBuildQuoteNavbarOptions` from `Navbar/index.js` (no
other consumers)
- Updated tests to assert on rendered header content instead of mock
function calls
- Updated snapshots (header now in component tree)

**Net effect**: −41 lines across 6 files. The header renders a title
("Buy {ticker}"), subtitle ("on {networkName}"), back arrow, and
settings gear — matching the Figma design for TRAM-3321.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: BuildQuote header displays correctly with inline HeaderCompactStandard

  Scenario: user navigates to Buy crypto flow
    Given user is on the wallet home screen

    When user taps "Buy" and reaches the BuildQuote screen
    Then the header displays "Buy ETH" as title
    And the header displays "on Ethereum Mainnet" as subtitle
    And a back arrow button is visible on the left
    And a settings gear button is visible on the right

  Scenario: user taps back button on BuildQuote
    Given user is on the BuildQuote screen

    When user taps the back arrow button
    Then user is navigated back to the previous screen

  Scenario: user taps settings button on BuildQuote
    Given user is on the BuildQuote screen

    When user taps the settings gear button
    Then the Ramps settings sheet opens

  Scenario: header shows loading state when token not yet resolved
    Given user navigates to BuildQuote before token data loads

    When the screen renders
    Then the header does not display a title or subtitle
    And back and settings buttons are still functional
```

## **Screenshots/Recordings**

### **Before**

<img width="400" height="1000" alt="image"
src="https://github.com/user-attachments/assets/9267fd5a-a54f-42b2-9257-27f6cef8b11b"
/>


### **After**

<img width="400" height="1000" alt="image"
src="https://github.com/user-attachments/assets/076f0ae0-8359-4f23-bd77-993fae94efdb"
/>


## **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 BuildQuote header rendering and
navigation configuration; main risk is UI/regression in back/settings
interactions due to moving logic out of `navigation.setOptions`.
> 
> **Overview**
> BuildQuote’s header is migrated from the centralized
`getRampsBuildQuoteNavbarOptions` + `navigation.setOptions()` approach
to an inline `HeaderCompactStandard` rendered directly in
`BuildQuote.tsx`, with back/settings handlers extracted into
`useCallback` and title/subtitle gated on token/network availability.
> 
> The Ramp navigator now sets `options={{ headerShown: false }}` for the
BuildQuote route, the unused `getRampsBuildQuoteNavbarOptions` is
removed from `Navbar/index.js`, and BuildQuote tests/snapshots are
updated to assert rendered header elements (including
`build-quote-back-button` / `build-quote-settings-button`) rather than
mocked navbar option calls.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
dd51d28. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**
Adds the "refundTo" param for postQuote transactions, so refunds from
Relay will be refunded back to Predict balance. Updates the
transaction-pay-controller version, which supports this param.


## **Changelog**

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

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

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

CHANGELOG entry: Adds the "refundTo" param for postQuote transactions,
so refunds from Relay will be refunded back to Predict balance.

## **Related issues**

Fixes: #26990

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

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new `refundTo` address into post-quote transaction config and
bumps `@metamask/transaction-pay-controller`, which can affect where
bridge/relay refunds are sent. Scope is small and covered by unit tests,
but it touches payment/bridging transaction configuration.
> 
> **Overview**
> **Post-quote pay transactions now include a refund destination.**
`useTransactionPayPostQuote` computes a Predict proxy address from
`txParams.from` and sets `config.refundTo` alongside
`config.isPostQuote=true` when initializing the transaction.
> 
> Unit tests were expanded to mock `computeProxyAddress` and assert
`refundTo` behavior (including the missing-`from` case). Dependencies
were updated by bumping `@metamask/transaction-pay-controller` to
`16.3.0` (with corresponding lockfile changes).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8bab985. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
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 network logo for Tempo mainnet

## **Related issues**

Fixes:
https://consensyssoftware.atlassian.net/browse/NEB-143?atlOrigin=eyJpIjoiZWU5NTZkOTkxNmZmNDg5YTgzNWVjZDVmYzkyMTNjNmUiLCJwIjoiaiJ9

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

- Add Tempo network manually with:
Name: `Tempo`
RPC: `https://tempo-mainnet.drpc.org`
Currency: `USD`
ChainId: `4217`

- Observe network logo is displayed correctly.
- Tempo has no native token, which the plan is to hide it in an upcoming
support.

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

<img width="200" alt="image"
src="https://github.com/user-attachments/assets/2d76413c-ce68-4488-8997-1e3783c3bbd1"
/>
<img width="200" alt="image"
src="https://github.com/user-attachments/assets/b694212e-4d7f-41f7-ba42-0666a674af37"
/>

(worth noting that the native token will disappear as part as upcoming
Tempo support)

## **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 constant and image mapping entry for Tempo
Mainnet without changing any network logic or existing mappings.
> 
> **Overview**
> Adds support for displaying a logo for **Tempo Mainnet** by
introducing a new `NETWORK_CHAIN_ID.TEMPO_MAINNET` (`0x1079`) and wiring
it into `CustomNetworkImgMapping` to use the existing `tempo.png` asset.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
674e343. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…#26453)

<!--
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 updates copy for the mUSD conversion flow. All occurrences of
`"boost"` have been replaced with `"bonus"`.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

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

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

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

CHANGELOG entry: updated mUSD conversion flow copy to replace boost with
bonus

## **Related issues**

Fixes: [MUSD-352: Replace "Boost" with "Bonus"
Globally](https://consensyssoftware.atlassian.net/browse/MUSD-352)

## **Manual testing steps**

```gherkin
Feature: mUSD conversion bonus terminology

  Scenario: user sees mUSD conversion incentive wording
    Given user is viewing mUSD conversion entry points in the Earn flow

    When user views the conversion CTA and quick convert balance card
    Then the incentive is labeled as a "bonus" (not "boost")
```

## **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**
> Low risk copy-only change, but it renames i18n keys; any missed
references would surface as missing localized strings at runtime.
> 
> **Overview**
> Replaces **“boost”** wording with **“bonus”** across the mUSD
conversion entry points (asset overview CTA and quick convert balance
card), including MetaMetrics `cta_text` generation.
> 
> Renames the associated localization keys (e.g.,
`boost_title/description`, `percentage_boost` →
`bonus_title/description`, `percentage_bonus`) across supported
languages and updates affected unit/view tests accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ff9faa7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…a feature flag (#27028)

## **Description**

When the Permit2 feature flag is enabled, the provider now:

1. **Always uses Permit2 fee authorization** — removes the on-chain
allowance readiness gate that previously caused a fallback to Safe fee
authorization when the Permit2 allowance wasn't set on-chain yet.
2. **Attaches `allowancesTx`** to the relay order when the proxy wallet
lacks the required Permit2 allowances, so the relay can submit the
allowance transaction on-chain before processing the order.
3. **Simplifies `previewOrder` FAK logic** — FAK order type is now
determined purely from feature flags and Permit2 config, since
`placeOrder` guarantees allowances are available.
4. **Gates FAK on actual allowance readiness** — for fee-bearing Buy
orders, FAK requires both Permit2 fee auth AND confirmed allowance
availability (on-chain or via `allowancesTx`).
5. **Replaces on-chain Permit2 nonce bitmap** with random nonce
generation to avoid collisions on back-to-back orders and eliminate an
RPC round-trip.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Permit2 fee authorization and allowancesTx relay

  Scenario: user places a BUY order with Permit2 enabled and proxy wallet lacking allowances
    Given Permit2 feature flag is enabled
    And the proxy wallet does not have Permit2 allowances set on-chain

    When user places a BUY order with fees
    Then the order uses Permit2 fee authorization (not Safe fallback)
    And an allowancesTx is attached to the relay request
    And the order type is FAK (if fakOrdersEnabled)

  Scenario: user places a BUY order with Permit2 enabled and proxy wallet already has allowances
    Given Permit2 feature flag is enabled
    And the proxy wallet already has Permit2 allowances on-chain

    When user places a BUY order with fees
    Then the order uses Permit2 fee authorization
    And no allowancesTx is attached
    And the order type is FAK (if fakOrdersEnabled)

  Scenario: user places a SELL order with Permit2 enabled
    Given Permit2 feature flag is enabled

    When user places a SELL order (no fees)
    Then no fee authorization is generated
    And an allowancesTx is attached if proxy wallet lacks allowances
    And the order type is FAK (if fakOrdersEnabled)

  Scenario: allowancesTx generation fails gracefully
    Given Permit2 feature flag is enabled
    And getProxyWalletAllowancesTransaction throws an error

    When user places a BUY order with fees
    Then the order still submits (without allowancesTx)
    And the order type falls back to FOK (not FAK)
    And the error is logged but does not block order placement
```

## **Screenshots/Recordings**

### Before 

https://www.loom.com/share/5bd9ee06414042e7a4ba944c666b1b9a

### After

FOK + Permit2:
https://www.loom.com/share/1241e70594684c43bf86880ad29b9fdf

FAK + Permit2: 
https://www.loom.com/share/94c01e493c6149ef806f09b32afe5430

## **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 order submission/fee-collection logic and relayer request
payloads; incorrect gating or allowance handling could cause orders to
fail or use the wrong order type (FAK vs FOK). Changes are localized but
impact a critical trading path.
> 
> **Overview**
> **Permit2 fee collection is now treated as always-available when
enabled.** `placeOrder` no longer falls back to Safe fee authorization
based on an on-chain Permit2 allowance check, and `previewOrder` now
selects `FAK` purely from feature flags/config.
> 
> **Order submission can now include a prerequisite allowances
transaction.** When the Permit2 feature flag is on and the proxy wallet
lacks allowances, `placeOrder` generates and sends an `allowancesTx` to
the relayer (and logs/continues if generation fails); `submitClobOrder`
includes this optional field in the request body. Permit2 nonce
generation was also switched from on-chain bitmap reads to a random
nonce to avoid extra RPC calls/collisions, with tests updated
accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
373d73b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR is the Predict-only split of the `color-no-hex` batch work,
extracted from the original umbrella PR #26651 and the previously
combined batch branch.

Scope:
- Predict files only (`app/components/UI/Predict/**`)
- temporary eslint rollout override for
`app/components/UI/Predict/**/*.{js,jsx,ts,tsx}`

Reference PR: #26651

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: color-no-hex predict batch

  Scenario: validate predict lint and tests
    Given this branch is checked out
    When running eslint for Predict scope
    Then there are no lint errors

    When running jest for Predict scope with snapshot updates
    Then tests pass
```

## **Screenshots/Recordings**

### **Before**
N/A (test/lint/config updates only)

### **After**
N/A (test/lint/config updates only)

## **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]
> **Low Risk**
> Primarily test-only refactors plus an ESLint override for
`app/components/UI/Predict`; low runtime risk, but it may surface new
lint failures if any remaining hex colors exist in that folder.
> 
> **Overview**
> Enables `@metamask/design-tokens/color-no-hex` enforcement for
`app/components/UI/Predict/**/*` via an ESLint override.
> 
> Refactors Predict unit tests to comply by replacing inline hex strings
with a new shared `TEST_HEX_COLORS` fixture and by standardizing theme
mocks to reuse `mockTheme` from `app/util/theme` (including updating a
few toast/theme color mocks).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
99e9156. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…inea DAI and USDT (#27022)

<!--
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 missing block explorer link for mUSD conversions on aggregator
routes

#### Problem

The "Receive mUSD" row in transaction details was missing the block
explorer link for Linea USDT and DAI conversions.

These tokens use Relay's aggregator routes (approve + deposit batch)
instead of optimized single-deposit routes. For same-chain multi-step
routes, the Relay strategy skips status polling and sets the
musdConversion transaction hash to `'0x0'`, which the UI treated as "no
hash available."

### Fix

When the musdConversion hash is `'0x0'`, fall back to the relay deposit
transaction's on-chain hash (already available in
`relatedTransactions`). This is semantically correct since the relay
deposit IS the on-chain transaction where mUSD was received for
aggregator routes.
<!--
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 missing block explorer link on "Receive mUSD" row
for Linea USDT and DAI conversions using aggregator routes.

## **Related issues**

Fixes: [MUSD-404: Missing "Received mUSD" link in transaction details
for Linea DAI and
USDT](https://consensyssoftware.atlassian.net/browse/MUSD-404)

## **Manual testing steps**

```gherkin
Feature: mUSD conversion transaction details block explorer link

  Scenario: user views block explorer link for optimized route mUSD conversion (fixed-spread)
    Given user completed an mUSD conversion via an optimized relay route (e.g. Mainnet USDC)

    When user opens the transaction details
    Then the "Receive mUSD" row displays a block explorer link

  Scenario: user views block explorer link for aggregator route mUSD conversion
    Given user completed an mUSD conversion via an aggregator relay route (e.g. Linea DAI)

    When user opens the transaction details
    Then the "Receive mUSD" row displays a block explorer link using the relay deposit hash

  Scenario: user views mUSD conversion with no available hash
    Given user completed an mUSD conversion where no relay deposit hash is available

    When user opens the transaction details
    Then the "Receive mUSD" row renders without a block explorer link
```

## **Screenshots/Recordings**

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

### **Before**

<!-- [screenshots/recordings] -->
<img width="420" height="922" alt="image"
src="https://github.com/user-attachments/assets/78f33013-984f-46ef-b648-45287c06adb8"
/>

### **After**

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


https://github.com/user-attachments/assets/7eaf139a-8207-4c0a-83a8-fec8ba24690c

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only change that only affects which transaction hash is
used to build a block-explorer URL for `musdConversion` summaries. Main
risk is choosing an incorrect fallback hash if related transactions are
unexpected.
> 
> **Overview**
> Fixes the `musdConversion` receive summary line to **use the
`relayDeposit` tx hash** when the conversion tx hash is `0x0`, restoring
the block-explorer link for same-chain/aggregator routes.
> 
> Updates `TransactionDetailsSummary` to pass `relatedTransactions` into
`useBridgeReceiveData`, and extends unit tests to cover the new fallback
behavior and the no-relay-deposit case.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0c4493d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…tions (#27091)

<!--
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 mUSD-specific `NetworkFeeRow` with the generic
`TransactionFeeRow` on conversion confirmations, and update the
transaction fee tooltip copy to clarify that no MetaMask fee applies.

<!--
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: replaced mUSD conversion-specific network fee row with
the generic transaction fee row and updated fee tooltip copy

## **Related issues**

Fixes: [MUSD-394: Add generic "Transaction Fee" row to conversion
confirmations](https://consensyssoftware.atlassian.net/browse/MUSD-394)

## **Manual testing steps**

```gherkin
Feature: Generic transaction fee row for mUSD conversions

  Scenario: user views fee breakdown on mUSD conversion confirmation
    Given user is on the mUSD conversion confirmation screen

    When user views the fee details
    Then the generic transaction fee row is displayed instead of a network-fee-only row
```

## **Screenshots/Recordings**

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

### **Before**
mUSD conversions only displayed the "Network Fee"
<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->
### Custom conversion input
<img width="493" height="1014" alt="image"
src="https://github.com/user-attachments/assets/10ab06f2-ff3c-4039-85c9-da636fef70fc"
/>
<img width="493" height="1014" alt="image"
src="https://github.com/user-attachments/assets/015e4775-64e6-42c7-b303-4142d12a7132"
/>

### "Max" convert bottom sheet 
<img width="493" height="1014" alt="image"
src="https://github.com/user-attachments/assets/e60de70d-94ec-4da8-9cf1-070e18b05f26"
/>


## **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**
> UI-only confirmation changes to fee row rendering and tooltip copy;
main risk is mismatched testIDs or fee display expectations in mUSD
conversion flows.
> 
> **Overview**
> **mUSD conversion confirmations now use the generic
`TransactionFeeRow`** instead of the mUSD-specific `NetworkFeeRow`, so
conversions show the same combined transaction fee total (network +
provider + MetaMask) and tooltip breakdown as other pay flows.
> 
> Removes the `ConfirmationRowComponentIDs.NETWORK_FEE` selector and
deletes the associated `musdConversion` network-fee row/skeleton tests;
updates English tooltip copy to clarify *no MetaMask fee applies* for
mUSD conversions (and fixes `mUSD` casing in the predict-withdraw
tooltip).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
dd076d6. 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**
- Add global mUSD foreground cleanup to reject stale pending conversion
approvals when the app resumes.
- Wire cleanup into EarnTransactionMonitor so it covers all mUSD entry
points (Quick Convert + CTAs).
- Removed Quick Convert list loading spinner when transaction is pending
approval

<!--
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: hardened mUSD conversion quick convert status tracking.
Auto reject pending mUSD approvals when app is foregrounded.

## **Related issues**

Fixes:
- [MUSD-359: Loading circle going from MM Pay -> Convert
page](https://consensyssoftware.atlassian.net/browse/MUSD-359)
- [MUSD-345: Improve loading
states](https://consensyssoftware.atlassian.net/browse/MUSD-345)
- [MUSD-316: Screen stuck because of
navigation](https://consensyssoftware.atlassian.net/browse/MUSD-316)
- [MUSD-366: Disable Conversion CTAs when there's an in-flight
conversion.](https://consensyssoftware.atlassian.net/browse/MUSD-366)

## **Manual testing steps**

```gherkin
Feature: mUSD pending approval recovery on app resume

  Scenario: user resumes app after leaving mUSD conversion pending
    Given user started an mUSD conversion and left it in pending approval state
    When user backgrounds the app and returns via deeplink/notification
    Then stale pending mUSD approvals are automatically rejected
    And Quick Convert actions (Max/Edit) are not stuck disabled

  Scenario: user has no stale pending mUSD approval
    Given user has no pending unapproved mUSD approval
    When user returns the app to foreground
    Then no approval is rejected and normal behavior continues
```

## **Screenshots/Recordings**

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

### **Before**

<!-- [screenshots/recordings] -->
### Stale pending approvals are cleared when app is brought back to
foreground

https://github.com/user-attachments/assets/6b1eeb0f-040d-4d94-b62a-8104fe060b60

### **After**

<!-- [screenshots/recordings] -->
### Block user from entering mUSD conversion flow while existing
conversion is in flight

https://github.com/user-attachments/assets/d81a65d6-7e90-41cf-bc77-40991cc0f89b

## **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 confirmation navigation and auto-rejects pending approvals on
app foreground, which can affect transaction flows if the selectors or
app-state transitions behave unexpectedly. Scope is localized to mUSD
conversion/Earn paths with good test coverage, so risk is moderate.
> 
> **Overview**
> Hardens mUSD conversion flows by separating **unapproved** vs
**in-flight** conversion tracking and using that to gate Quick Convert
actions without treating unapproved approvals as “pending” conversions.
> 
> Adds `useMusdConversionStaleApprovalCleanup` (mounted via
`EarnTransactionMonitor`) to auto-reject stale unapproved mUSD
conversion approvals when the app returns from background, and to pop an
orphaned confirmations screen if it’s still focused.
> 
> Updates confirmation behavior for `TransactionType.musdConversion` to
use a new `useMusdConfirmNavigation` helper (go back when possible under
Quick Convert, otherwise navigate to `Routes.WALLET_VIEW`). Also
includes a small Earn toast icon size tweak.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7b091f0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ts vertically when text overflow is detected (#27010)

<!--
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**
Refactored token-conversion-asset-header to stack assets vertically when
text overflow is detected
<!--
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: refactored token-conversion-asset-header to stack
assets vertically when text overflow is detected

## **Related issues**

Fixes: [MUSD-363: Quick convert bottom sheet asset header should only
stack when text
overflows](https://consensyssoftware.atlassian.net/browse/MUSD-363)

## **Manual testing steps**

```gherkin
Feature: Adaptive token conversion asset header layout

  Scenario: user views conversion with short fiat amounts
    Given user sees the Max mUSD conversion bottom sheet confirmation

    When the input and output fiat amounts fit on one line
    Then the assets are displayed side-by-side horizontally

  Scenario: user views conversion with long fiat amounts
    Given user sees the Max mUSD conversion bottom sheet confirmation

    When either fiat amount overflows to a second line
    Then the assets stack vertically with a downward arrow
```

## **Screenshots/Recordings**

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

### **Before**
Asset header always had vertical layout
<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->
### Horizontal layout when text doesn't overflow (default behaviour)


https://github.com/user-attachments/assets/bd5f9771-ab83-4509-b61f-afbae8c8a612

### Vertical layout when text overflows (edge case)


https://github.com/user-attachments/assets/93810add-e4f7-4fea-ac46-ed990a89cecc

## **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**
> UI layout now depends on runtime text measurement and a new
hidden-render measurement pass, which could cause edge-case rendering or
skeleton timing regressions on different devices/font scales.
> 
> **Overview**
> Updates `TokenConversionAssetHeader` to **default to a horizontal,
side-by-side layout** and switch to a **stacked vertical layout** when
either fiat amount wraps to multiple lines (detected via
`onTextLayout`).
> 
> Introduces a measurement phase that **renders the real content hidden
under the skeleton** until both amounts are measured, updates the
skeleton to match the resolved layout (including arrow direction), and
expands styles/tests to cover horizontal vs stacked behavior and the new
`CONTENT_CONTAINER`/measurement flow.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
45ec77d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#26674)

Banner showing up in settings page if we detect enrolled accounts that
aren't on device:

<img width="989" height="359" alt="image"
src="https://github.com/user-attachments/assets/2f8c6fdf-05fd-48a3-bb6a-1a232e8d9617"
/>

Sheet when users click on cta: (scrollable list of addresses, sorted on
address value)

<img width="1414" height="1170" alt="image"
src="https://github.com/user-attachments/assets/332f5dc5-61c3-4dc8-9250-6260442a3afc"
/>

'Let us know' opens up external browser to `https://support.metamask.io`
(contact support)

<img width="817" height="1885" alt="image"
src="https://github.com/user-attachments/assets/36a968a0-1b21-4bbc-a887-530f66406544"
/>

The banner on settings page is behind a feature flag with key
`rewards-missing-enrolled-accounts`.

## Summary

- Adds `GET /subscriptions/accounts` to the rewards data service (new
backend endpoint from [va-mmcx-rewards PR
#464](consensys-vertical-apps/va-mmcx-rewards#464))
- `RewardsController:getOffDeviceSubscriptionAccounts` computes and
caches (5 min) the delta between backend CAIP-10 accounts and device
`InternalAccounts`; uses namespace-aware address matching (`eip155`
case-insensitive, all other namespaces such as `solana` and `bip122`
case-sensitive); cache is invalidated on `accountLinked`
- `useLinkedOffDeviceAccounts` hook calls the controller directly with
local state; re-fetches on screen focus and on `accountLinked` events
- `LinkedOffDeviceAccountsSheet` bottom sheet lists off-device accounts
(network icon, shortened address, copy CTA)
- Info banner shown at the top of `RewardsSettingsView` when off-device
accounts exist, with a CTA that opens the sheet

## Changelog

- **Added**: `RewardsController:getOffDeviceSubscriptionAccounts` action
— fetches accounts linked to the rewards subscription that are not
present on the current device, with a 5-minute cache
- **Added**: `useLinkedOffDeviceAccounts` hook — returns off-device
accounts, re-fetches on focus and account link events
- **Added**: `LinkedOffDeviceAccountsSheet` bottom sheet — FlatList of
off-device accounts with network icon, shortened address, and copy CTA
- **Added**: Info banner on `RewardsSettingsView` surfacing off-device
accounts with a CTA to open the detail sheet



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new rewards API call and cached controller state to compute
off-device subscription accounts, which could affect rewards data
fetching and persistence if the new endpoint or filtering logic
misbehaves (though gated by a feature flag). UI changes are contained to
the rewards settings screen and a new bottom sheet.
> 
> **Overview**
> **Adds “Missing Enrolled Accounts” surfacing in Rewards Settings.**
`RewardsSettingsView` now conditionally shows a banner (when off-device
accounts exist) that opens a new `LinkedOffDeviceAccountsSheet` listing
those accounts with network/short address display, copy-to-clipboard,
and a support link.
> 
> **Introduces the data pipeline to detect off-device accounts.** Adds
`useLinkedOffDeviceAccounts` (gated by the new
`rewards-missing-enrolled-accounts` feature flag) which fetches via
`RewardsController:getOffDeviceSubscriptionAccounts`; the controller
adds a persisted 5‑minute cache, filters backend CAIP-10 subscription
accounts against on-device multichain accounts (EVM case-insensitive,
non-EVM case-sensitive), and invalidates this cache on subscription
cache invalidation.
> 
> **Backend integration + flags/tests.** Adds
`RewardsDataService:getSubscriptionAccounts` (`GET
/subscriptions/accounts` with 401→`AuthorizationFailedError`), wires
messenger/types/state snapshots, adds new i18n strings, and adds/updates
unit tests covering UI, hook behavior, controller caching/filtering, and
the new API method.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0243306. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->





CHANGELOG entry: Added off-device linked accounts detection, caching,
and display in Rewards Settings

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…MarketDetails cp-7.69.0 (#27090)

## **Description**

The fee exemption logic in `PredictMarketDetails` was hardcoded to check
for a `'Middle East'` tag label, while `PredictController` and
`PolymarketProvider` already used a feature-flag-driven approach via
`feeCollection.waiveList`. This PR aligns the UI layer with the existing
pattern:

- **`parsePolymarketEvents`**: Switch tag mapping from `t.label` to
`t.slug` so parsed market tags match the slug-based `waiveList` entries
used by `waiveFees()`
- **`selectPredictFeeCollectionFlag`**: New selector that reads the
`predictFeeCollection` remote feature flag, falling back to
`DEFAULT_FEE_COLLECTION_FLAG`
- **`PredictMarketDetails`**: Replace hardcoded `tags?.includes('Middle
East')` with `tags?.some(slug => waiveList.includes(slug))` driven by
the selector
- Added defensive optional chaining on `tags` access for safety

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[PRED-736](https://consensyssoftware.atlassian.net/browse/PRED-736)

## **Manual testing steps**

```gherkin
Feature: Fee exemption display on market details

  Scenario: user views a market with a tag in the waiveList
    Given the remote feature flag predictFeeCollection has waiveList containing 'middle-east'
    And a market has the tag slug 'middle-east'

    When user navigates to the market details screen
    Then the fee exemption message is displayed

  Scenario: user views a market without waived tags
    Given the remote feature flag predictFeeCollection has waiveList containing 'middle-east'
    And a market only has tag slugs 'sports' and 'politics'

    When user navigates to the market details screen
    Then the fee exemption message is not displayed

  Scenario: user views a market when waiveList is empty
    Given the remote feature flag predictFeeCollection has an empty waiveList
    And a market has any tags

    When user navigates to the market details screen
    Then the fee exemption message is not displayed
```

## **Screenshots/Recordings**

### **Before**

N/A — logic change only, no visual diff

### **After**

N/A — logic change only, no visual diff

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes Predict market `tags` from human-readable labels to slugs and
uses remote `predictFeeCollection.waiveList` to control fee-exemption
UI, which could affect any UI/analytics expecting label-form tags. Logic
is straightforward and covered by updated/additional selector and view
tests.
> 
> **Overview**
> Aligns fee-exemption behavior in `PredictMarketDetails` with the
fee-collection feature flag by replacing the hardcoded `'Middle East'`
tag check with a `waiveList` (slug) match from the new
`selectPredictFeeCollectionFlag` selector (defaulting to
`DEFAULT_FEE_COLLECTION_FLAG`).
> 
> Updates Polymarket parsing to store market `tags` as tag **slugs**
(`t.slug`) instead of labels, and adjusts tests to validate the new
slug-based exemption behavior plus selector fallbacks when the remote
flag is missing/null/undefined.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
daf0e58. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…erage (#27093)

## **Description**

Evaluates the behaviors tested in `offramp.failing.ts` e2e test and
confirms they are already covered by existing component tests. Fills two
minor coverage gaps with new unit tests, then deletes the e2e test.

### Coverage Analysis

| E2E Behavior | Existing Coverage |
|---|---|
| Navigate to sell flow | N/A (navigation-level) |
| SellGetStartedView "Get Started" | Dead event —
`OFFRAMP_GET_STARTED_CLICKED` has zero call sites in source |
| BuildQuote: Amount to sell, Get Quotes | `BuildQuote.test.tsx` —
"Amount to sell input" section |
| BuildQuote: Cancel + analytics | `BuildQuote.test.tsx` — verifies
`OFFRAMP_CANCELED` |
| BuildQuote: Enter amount → Get Quotes | `BuildQuote.test.tsx` —
verifies navigation + `OFFRAMP_QUOTES_REQUESTED` |
| QuotesView: Quotes visible | `Quotes.test.tsx` — multiple render tests
|
| QuotesView: Expand quotes | **Gap filled** — added
`OFFRAMP_QUOTES_EXPANDED` sell-mode test |
| QuotesView: Continue with provider | `Quotes.test.tsx` —
`OFFRAMP_PROVIDER_SELECTED` (both browser types) |
| QuotesView: Quote errors | **Gap filled** — added
`OFFRAMP_QUOTE_ERROR` sell-mode test |

### New Tests Added
- `tracks OFFRAMP_QUOTES_EXPANDED when expanding quotes in sell mode` —
verifies the sell-mode variant of the quotes expand analytics event
- `tracks OFFRAMP_QUOTE_ERROR for sell quotes with errors` — verifies
the sell-mode quote error analytics event fires with correct properties

A separate component-view test is not needed because the existing
`Quotes.test.tsx` already uses `renderScreen()`, which renders the full
component within the navigation stack with Redux state — making it
functionally equivalent to a component-view test. Similarly,
`BuildQuote.test.tsx` uses the same `renderScreen()` pattern. Since both
test files already operate at the component-view level, adding a new
component-view test would duplicate existing coverage.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Offramp sell-mode unit test coverage

  Scenario: Existing component tests cover offramp e2e behaviors
    Given the offramp.failing.ts e2e test validates sell flow UI and analytics
    When existing component tests in Quotes.test.tsx and BuildQuote.test.tsx are reviewed
    Then all key behaviors are already covered by component-level tests

  Scenario: OFFRAMP_QUOTES_EXPANDED fires in sell mode
    Given the user is on the Quotes screen in sell mode
    When the user taps "Explore more options"
    Then the OFFRAMP_QUOTES_EXPANDED analytics event fires with correct sell-mode properties

  Scenario: OFFRAMP_QUOTE_ERROR fires for sell quote errors
    Given the user is on the Quotes screen in sell mode with errored quotes
    When quotes are received with errors
    Then the OFFRAMP_QUOTE_ERROR analytics event fires with correct sell-mode properties
```

## **Screenshots/Recordings**

### **Before**

- `offramp.failing.ts` e2e test existed but was not running (marked as
failing)
- `OFFRAMP_QUOTES_EXPANDED` only tested in buy mode
- `OFFRAMP_QUOTE_ERROR` test existed but mock data had empty errors
array, so sell error path was never exercised

### **After**

- `offramp.failing.ts` e2e test deleted — all behaviors confirmed
covered by component tests
- New unit test verifies `OFFRAMP_QUOTES_EXPANDED` fires with correct
properties in sell mode
- New unit test verifies `OFFRAMP_QUOTE_ERROR` fires with correct
properties for sell quote errors

## **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 because changes are test-only (adds unit assertions for
off-ramp analytics and removes an unstable smoke E2E), with no
production logic modifications.
> 
> **Overview**
> Adds sell-mode unit test coverage in `Quotes.test.tsx` to assert
`OFFRAMP_QUOTES_EXPANDED` is emitted when expanding quotes and
`OFFRAMP_QUOTE_ERROR` is emitted when sell quotes include provider
errors.
> 
> Removes the flaky `tests/smoke/ramps/offramp.failing.ts` E2E test and
updates the `Quotes` snapshot output accordingly (gesture handler tag
changes).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
eb7d1c0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…acy components (#27083)

## **Description**

Upgraded the MetaMask design system React Native package to the latest
compatible release and marked legacy components as deprecated.

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

Changes in this PR:
- Upgraded `@metamask/design-system-react-native` from `^0.8.0` to
`^0.10.0`
- Updated lockfile resolution to
`@metamask/design-system-react-native@0.10.0` and
`@metamask/design-system-shared@0.3.0`
- Added missing `@deprecated` JSDoc tags to local overlapping wrappers:
  - `BottomSheetHeader`
  - `ButtonBase`
  - `ActionListItem`
  - `ButtonHero`
  - `ButtonSemantic`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Design system dependency upgrade

  Scenario: install and lint after upgrade
    Given the branch with dependency and JSDoc updates is checked out
    When running yarn install
    Then dependencies resolve successfully with the updated lockfile

    When running eslint on modified component files
    Then lint passes with no errors
```

## **Screenshots/Recordings**

### **Before**

N/A (dependency and JSDoc changes only)

### **After**

N/A (dependency and JSDoc changes only)

General smoke test to ensure mobile still runs as expected


https://github.com/user-attachments/assets/b23b3c36-772c-4da5-8f72-a961271b1d7a

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk due to the design-system dependency bump (and
`design-system-shared` transitive update) potentially changing UI
behavior or typings at build/runtime. The code changes themselves are
limited to JSDoc deprecation annotations.
> 
> **Overview**
> **Upgrades the MetaMask React Native design system dependency** by
bumping `@metamask/design-system-react-native` from `^0.8.0` to
`^0.10.0` (with corresponding `yarn.lock` updates, including
`@metamask/design-system-shared` to `^0.3.0`).
> 
> **Deprecates local legacy/overlapping components** by adding
`@deprecated` JSDoc guidance (and upstream README links) to
`ActionListItem`, `ButtonHero`, `ButtonSemantic`, `BottomSheetHeader`,
and `ButtonBase`; `TextField`’s deprecation docs are also updated with a
`@since` tag.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ff051dd. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Fixes the Checkout WebView header so the provider title/name (for
example, `Moonpay (Staging)`) no longer renders on top of the WebView
content.

Per the design, the Checkout screen should only show the close (`X`)
button in the shared header. This change removes the rendered title from
the `BottomSheetHeader` used in
`app/components/UI/Ramp/Views/Checkout/Checkout.tsx`.

## **Changelog**

CHANGELOG entry: Fixed a bug where the Ramp checkout provider title
appeared above the WebView content.

## **Related issues**



## **Manual testing steps**

```gherkin
Feature: Ramp checkout header title removal

  Scenario: checkout webview does not show provider title
    Given the user starts the Buy flow and reaches the provider Checkout WebView screen

    When the Checkout screen is displayed
    Then the provider name/title is not shown above the WebView content
    And the close button is still visible in the header
    And the close button still works correctly
```

## **Screenshots/Recordings**

### **Before**

<img width="388" height="296" alt="Screenshot 2026-03-05 080429"
src="https://github.com/user-attachments/assets/ab97f344-0fcd-4445-9893-070629a5c7a4"
/>

### **After**

<img width="380" height="316" alt="Screenshot 2026-03-04 152121"
src="https://github.com/user-attachments/assets/b0f201f1-d075-451f-b189-2425791962b4"
/>

## **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
- [ ] 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**
> UI-only change that removes a duplicated header title; low risk aside
from potential minor navigation header title regressions.
> 
> **Overview**
> Removes the rendered provider title from the `Checkout` screen’s
`BottomSheetHeader`, leaving only the close (`X`) button so the WebView
content isn’t obscured.
> 
> Simplifies header option setup by dropping the cached `headerTitle`
fallback and updates the Jest snapshots to reflect the title-less shared
header.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
75e00bf. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Version Bump After Release

This PR bumps the main branch version from 7.69.0 to 7.70.0 after
cutting the release branch.

### Why this is needed:
- **Nightly builds**: Each nightly build needs to be one minor version
ahead of the current release candidate
- **Version conflicts**: Prevents conflicts between nightlies and
release candidates
- **Platform alignment**: Maintains version alignment between MetaMask
mobile and extension
- **Update systems**: Ensures nightlies are accepted by app stores and
browser update systems

### What changed:
- Version bumped from `7.69.0` to `7.70.0`
- Platform: `mobile`
- Files updated by `set-semvar-version.sh` script

### Next steps:
This PR should be **manually reviewed and merged by the release
manager** to maintain proper version flow.

### Related:
- Release version: 7.69.0
- Release branch: release/7.69.0
- Platform: mobile
- Test mode: false

---
*This PR was automatically created by the
`create-platform-release-pr.sh` script.*

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators Mar 5, 2026
@pull pull Bot added the ⤵️ pull label Mar 5, 2026
@pull pull Bot merged commit d8064c1 into Reality2byte:main Mar 5, 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.