Skip to content

[pull] main from MetaMask:main#595

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

[pull] main from MetaMask:main#595
pull[bot] merged 153 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

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

joaoloureirop and others added 30 commits February 20, 2026 00:23
)

- refactor(analytics): migrate Batch 2-11: metamask-earn (#26292)

## **Description**

Phase 2 analytics migration (Batch 2-11): migrate Stake/Earn's
`useMetrics` hook and `MetaMetrics.getInstance()` calls from the legacy
MetaMetrics system to the new analytics system.

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

**Changes**: Stake components and hooks now use `useAnalytics` from
`hooks/useAnalytics/useAnalytics` and import `MetaMetricsEvents`
directly from `core/Analytics`; `withMetaMetrics` utility now uses
`analytics.trackEvent()` and `AnalyticsEventBuilder` instead of
`MetaMetrics.getInstance().trackEvent()` and `MetricsEventBuilder`; test
mocks updated accordingly.

### Changes

**Source files (6)**:
- `LearnMoreModalFooter.tsx`, `StakingButtons.tsx`,
`StakingBalance.tsx`, `StakeButton/index.tsx`: replaced `useMetrics`
with `useAnalytics`; `MetaMetricsEvents` now imported from
`core/Analytics`
- `usePoolStakedDeposit/index.ts`: replaced `useMetrics` with
`useAnalytics` (also migrated as it's the source for a listed test file)
- `withMetaMetrics.ts`: replaced
`MetaMetrics.getInstance().trackEvent()` with `analytics.trackEvent()`
and `MetricsEventBuilder` with `AnalyticsEventBuilder`

**Test files (3)**:
- `StakeButton.test.tsx`: replaced `useMetrics` mock with `useAnalytics`
mock; added transitive `useMetrics` mock for unmigrated
`useStablecoinLendingRedirect` dependency; replaced
`MetricsEventBuilder` with `AnalyticsEventBuilder`
- `usePoolStakedDeposit.test.tsx`: replaced `useMetrics` mock/import
with `useAnalytics`; replaced `MetricsEventBuilder` with
`AnalyticsEventBuilder`
- `withMetaMetrics.test.ts`: replaced `MetaMetrics.getInstance()` spy
with `analytics` module mock; updated `MetaMetricsEvents` import from
`core/Analytics`

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-298 (Batch
2-11)

## **Manual testing steps**

```gherkin
Feature: Stake/Earn analytics

  Scenario: user triggers a stake/earn flow event
    Given app is open and user is in a stake/earn flow

    When user performs an action that triggers analytics (e.g. stake button, unstake button, learn more, view staked positions)
    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**
> This is a broad analytics plumbing migration across Stake/Earn UI and
transaction hooks; risk is mainly missed/changed event emission or
metadata due to swapped builders and tracking surfaces, not user-facing
flow changes.
> 
> **Overview**
> Migrates Stake/Earn (Earn CTA, staking balance/buttons, learn-more
modal, and pooled-stake deposit hook) from legacy
`useMetrics`/`MetaMetrics.getInstance()` tracking to the new analytics
stack via `useAnalytics`, `analytics.trackEvent`, and
`AnalyticsEventBuilder`.
> 
> Updates related unit tests to mock `useAnalytics`/`analytics` instead
of `useMetrics`/MetaMetrics, including a new mock for
`useStablecoinLendingRedirect` to avoid transitive legacy metrics
behavior and keep navigation assertions stable.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8971698. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[b5b8c71](b5b8c71)

Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
)

- refactor(analytics): migrate Batch 3-1: mobile-platform (#26312)

## **Description**

Phase 3 analytics migration (Batch 3-1): migrate Authentication core's
`Authentication.ts` from `MetaMetrics.getInstance()` to the new
analytics system.

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

**Changes**: `Authentication.ts` now uses `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-301 (Batch
3-1)

## **Manual testing steps**

```gherkin
Feature: Authentication analytics

  Scenario: user triggers an authentication flow event
    Given app is open and user is in an authentication flow

    When user performs an action that triggers analytics (e.g. unlock wallet, login)
    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**
> Small refactor limited to the metrics-consent check after unlocking
the wallet; main risk is a regression in opt-in navigation if
`analytics.isEnabled()` differs from the old `MetaMetrics` behavior.
> 
> **Overview**
> `Authentication.unlockWallet` now uses the shared
`analytics.isEnabled()` helper (from `util/analytics/analytics`) instead
of `MetaMetrics.getInstance().isEnabled()` when deciding whether to
route users to the metrics opt-in screen after login.
> 
> Unit tests were updated to mock and spy on the new `analytics` helper
rather than `MetaMetrics`, keeping the same enabled/disabled behavior
expectations.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a7de545. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[e4effa3](e4effa3)

Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
…Action cp-7.67.0 (#26457)

- chore: New Crowdin translations by Github Action cp-7.67.0 (#26152)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Localization-only JSON string changes; low functional risk aside from
potential missing/renamed keys affecting UI text rendering.
> 
> **Overview**
> Updates German locale strings (`locales/languages/de.json`) with a
large batch of Crowdin changes, including **new translation keys** for
features like Market Insights, homepage sections, device
authentication/biometrics messaging, network management, and MetaMask
Card freeze/unfreeze flows.
> 
> Also revises many existing strings (mostly English-to-German fixes and
copy updates) across swap/bridge, perps activity, QR scanning,
permissions/connect flows, and various error/toast messages, with some
removals/renames (e.g., `merkl_rewards`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e3e2bd4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

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

Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
… to fix stale cache on slow connections cp-7.67.0 (#26334)

- fix(perps): connection-aware ensureReady() to fix stale cache on slow
connections cp-7.67.0 (#26324)

## **Description**

Fixes [TAT-2597](https://consensys-mesh.atlassian.net/browse/TAT-2597)
and [TAT-2598](https://consensys-mesh.atlassian.net/browse/TAT-2598):
After the preload PR merged, slow connections caused StreamChannels to
exhaust 150 polling retries (30s) in `ensureReady()` and silently give
up, leaving users with stale REST cache and no live WebSocket data —
positions not appearing after trade, missing prices.

**Root Cause:** `StreamChannel.ensureReady()` used blind polling
(`isReady` every 200ms × 150 retries) with no awareness of WebSocket
connection state. On slow connections, the connection had not even
established yet, so polling burned through all retries before data could
arrive.

**Fix:**
- `PerpsConnectionManager.waitForConnection()` — exposes init/reconnect
promises so channels can `await` instead of blind-polling
- `StreamChannel.ensureReady()` — detects `isConnecting` state and
awaits the connection promise via `awaitConnectionThenConnect()`

**Result:** PriceStreamChannel retries dropped from **33 → 0** on device
after this fix.

## **Changelog**

CHANGELOG entry: Fixed stale cache on slow connections where positions
and prices were not updating after a trade

## **Related issues**

Fixes: [TAT-2597](https://consensys-mesh.atlassian.net/browse/TAT-2597),
[TAT-2598](https://consensys-mesh.atlassian.net/browse/TAT-2598)

## **Manual testing steps**

```gherkin
Feature: Perps live data on slow connections

  Scenario: user opens a trade on a slow connection
    Given the app is connected to a slow 3G network
    And the user has navigated to the Perps trading screen

    When user opens a new position
    Then the position appears immediately in the positions list
    And price stream connects without excessive retries

  Scenario: user recovers from network drop
    Given the user is viewing live perps positions
    And the network connection drops momentarily

    When the network connection is restored
    Then live WebSocket data resumes without stale cache
```

## **Screenshots/Recordings**

### **Before**

<!-- PriceStreamChannel: 33 retries before data appears, positions
missing on slow connections -->

### **After**

<!-- PriceStreamChannel: 0 retries, positions appear immediately -->

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

[TAT-2597]:

https://consensyssoftware.atlassian.net/browse/TAT-2597?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[TAT-2598]:

https://consensyssoftware.atlassian.net/browse/TAT-2598?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[TAT-2597]:

https://consensyssoftware.atlassian.net/browse/TAT-2597?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes connection/retry timing and sequencing for Perps WebSocket
subscriptions; regressions could delay or prevent live data if the new
await/sentinel logic misfires under edge cases (disconnects, rapid
resubscribe).
> 
> **Overview**
> Perps stream channels now become **connection-aware**:
`StreamChannel.ensureReady()` detects `PerpsConnectionManager`'s
`isConnecting` state and waits on a new `waitForConnection()` promise,
then retries `connect()` (with duplicate-wait suppression and polling
fallback on rejection).
> 
> Retry scheduling was tightened by clearing `deferConnect` timers on
fire and centralizing the retry delay via
`PERPS_CONSTANTS.ConnectRetryDelayMs`; `MarketDataChannel` now uses this
constant as well. Tests were expanded to cover the new await/deferral
behavior and the new `PerpsConnectionManager.waitForConnection()`
contract.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
39e206b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[43cf1d8](43cf1d8)

[TAT-2597]:
https://consensyssoftware.atlassian.net/browse/TAT-2597?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[TAT-2598]:
https://consensyssoftware.atlassian.net/browse/TAT-2598?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[TAT-2597]:
https://consensyssoftware.atlassian.net/browse/TAT-2597?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
…66.0 (#26337)

- fix: Fix StorageService Key Encoding cp-7.66.0 (#26268)

## **Description**

### Problem

The `redux-persist-filesystem-storage` library has two problematic
behaviors when handling arbitrary keys in `StorageService`:

1. **Slashes (`/`) create subdirectories**: Keys containing slashes are
stored in subdirectories, making them unreachable via `getAllKeys`. This
breaks the `clear` method for affected keys.

2. **Hyphens (`-`) get corrupted**: The library's internal
`fromFileName` function converts hyphens to colons (`:`), meaning keys
like `simple-key` are returned as `simple:key` by `getAllKeys`. This
causes a permanent mismatch between stored keys and returned keys.

### Solution

This PR introduces URI-style encoding for problematic characters in
**both namespace and key** portions of storage keys:

- `/` → `%2F` (prevents subdirectory creation)
- `-` → `%2D` (prevents hyphen-to-colon corruption)
- `%` → `%25` (prevents double-encoding issues)

The encoding is applied via shared utility functions
(`encodeStorageKey`/`decodeStorageKey`) used by both:
- `mobileStorageAdapter` in `storage-service-init.ts`
- Migration 118 which stores snap source code

### Backward Compatibility

**This change is backward compatible and will NOT break existing
production keys.**

- Existing keys like
`storageService:TokenListController:tokensChainsCache:0x1` are
**unaffected** because:
- The namespace (`TokenListController`) has no special characters →
encoding produces identical output
  - Colons (`:`) are **not encoded** - they pass through unchanged
- The key portion (`tokensChainsCache:0x1`) contains no hyphens or
slashes
- **Strings without `-`, `/`, or `%` characters produce identical output
when encoded**
- This means all current production keys work exactly as before, while
future keys with special characters will be handled correctly

### Examples

```
# No special characters → unchanged (backward compatible)
storageService:TokenListController:tokensChainsCache:0x1 → storageService:TokenListController:tokensChainsCache:0x1

# Snap ID with slashes and hyphens → encoded
storageService:SnapController:npm:@metamask/bip32-keyring-snap → storageService:SnapController:npm:@MetaMask%2Fbip32%2Dkeyring%2Dsnap

# Namespace with hyphen → encoded
storageService:Some-Controller:some-key → storageService:Some%2DController:some%2Dkey

# Key with slashes → encoded (prevents subdirectory creation)
storageService:TestController:nested/path/key → storageService:TestController:nested%2Fpath%2Fkey
```

### Files Changed

| File | Change |
|------|--------|
| `app/core/Engine/utils/storage-service-utils.ts` | New utility with
`encodeStorageKey`/`decodeStorageKey` functions |
| `app/core/Engine/utils/storage-service-utils.test.ts` | 35 unit tests
for the encoding utilities |
| `app/core/Engine/controllers/storage-service-init.ts` | Apply encoding
in `mobileStorageAdapter` methods |
| `app/core/Engine/controllers/storage-service-init.test.ts` | 22 new
tests for key and namespace encoding behavior |
| `app/store/migrations/119.ts` | Encode snap IDs when storing snap
source code |

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: StorageService key handling issues with
`redux-persist-filesystem-storage`

## **Manual testing steps**

```gherkin
Feature: StorageService key encoding

  Scenario: Keys with hyphens are stored and retrieved correctly
    Given the app is running

    When StorageService stores a key containing hyphens (e.g., "npm:@metamask/bip32-keyring-snap")
    Then the key is encoded as "npm:@MetaMask%2Fbip32%2Dkeyring%2Dsnap" on disk
    And getAllKeys returns the original key "npm:@metamask/bip32-keyring-snap"
    And getItem with the original key returns the stored data

  Scenario: Keys with slashes are stored and retrieved correctly
    Given the app is running

    When StorageService stores a key containing slashes (e.g., "nested/path/key")
    Then the key is stored as a single file (not in subdirectories)
    And getAllKeys returns the original key "nested/path/key"
    And clear removes the key correctly

  Scenario: Existing keys with colons remain unchanged
    Given existing production keys like "storageService:TokenListController:tokensChainsCache:0x1"

    When the app starts with this fix
    Then the existing keys are still accessible
    And no migration is required for existing data
```

## **Screenshots/Recordings**

N/A - No UI changes

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes how persistent storage keys are constructed and enumerated,
which could impact read/write/clear behavior for stored controller data
if encoding is applied inconsistently or assumptions about existing
on-disk keys differ.
> 
> **Overview**
> Fixes mobile `StorageService` persistence by **encoding both
`namespace` and `key` components** before writing to
`redux-persist-filesystem-storage` (and decoding on `getAllKeys`) to
avoid `/` creating subdirectories and `-` being corrupted.
> 
> Introduces shared `encodeStorageKey`/`decodeStorageKey` utilities and
updates migration `119` to encode snap IDs when persisting snap
`sourceCode`; expands/updates unit tests to cover encoding/decoding
behavior and the updated migration expectations.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bb0e8d6. 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>
[5d11a21](5d11a21)

Co-authored-by: Andre Pimenta <andrepimenta7@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…r account switch (#26349)

- fix: cp-7.66.0 refresh staked balance after account switch (#26332)

<!--
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 refresh staking balance after account switch

<!--
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: fix refresh staking balance after account switch

## **Related issues**

Fixes: #26323 

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



https://github.com/user-attachments/assets/1a720a48-83e6-45e0-84e7-29b2cb3479e7




### **After**

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




https://github.com/user-attachments/assets/826a347b-e003-4bd6-8816-8bec2b66c423



## **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**
> Small, localized change to a `useEffect` dependency plus a new test;
main risk is accidental extra refresh calls impacting performance or
causing redundant network requests.
> 
> **Overview**
> Refresh behavior on the `Wallet` screen is updated so
`AccountTrackerController.refresh` is re-triggered when
`selectedInternalAccount` changes (added to the relevant `useEffect`
dependency list), fixing stale balance/staking data after an account
switch.
> 
> Tests are updated to cover this regression by asserting `refresh` is
called again when `AccountsController.internalAccounts.selectedAccount`
changes, and snapshots are updated accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a15a4d1. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[c70f38d](c70f38d)

Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
…ount with getClaimPayoutFromReceipt cp-7.66.0 (#26361)

- refactor(musd): replace decodeMerklClaimAmount with
getClaimPayoutFromReceipt cp-7.66.0 (#26342)

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

## **Description**

The mUSD claim transaction amount was displaying the cumulative total
reward (from Merkl distributor calldata `amounts[0]`) instead of the
actual per-transaction payout. This caused incorrect amounts in the
Activity list and transaction detail views — e.g., if a user made
multiple claims, each one would show the running total rather than what
was actually claimed in that specific transaction.

The fix introduces `getClaimPayoutFromReceipt()` which extracts the real
payout from the ERC-20 `Transfer` event in the transaction receipt logs
(emitted when the Merkl distributor transfers mUSD to the user). This is
used as the primary source for confirmed transactions across:
- Activity list (`decodeMusdClaimTx`)
- Transaction detail hero (`useClaimAmount`)
- Confirmation flow (`useMerklClaimAmount`)

## **Changelog**

CHANGELOG entry: Fixed mUSD claim transactions showing incorrect
cumulative total instead of per-transaction payout amount


## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: mUSD claim transaction amount display

  Scenario: user views a confirmed mUSD claim transaction in Activity
    Given user has made one or more mUSD claim transactions from this device
    And at least one claim transaction is confirmed

    When user navigates to the Activity tab
    Then the claim transaction shows the correct per-transaction payout amount (not cumulative total)

  Scenario: user views claim transaction details
    Given user has a confirmed mUSD claim transaction visible in Activity

    When user taps on the claim transaction
    Then the detail view shows the correct claimed amount matching the actual payout

  Scenario: user views a pending mUSD claim in the Activity list
    Given user has a pending mUSD claim transaction

    When user views the transaction in Activity
    Then the amount shows "Not available" until the transaction confirms
    And once confirmed, the correct payout amount appears
```

## **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**
> Changes how `musdClaim` amounts are derived in
Activity/details/confirmation flows, relying on receipt log parsing and
BigInt decoding; incorrect log matching or missing receipts could cause
amounts to be blank or wrong.
> 
> **Overview**
> **Fixes incorrect mUSD claim amounts** by switching from decoding the
Merkl claim calldata (cumulative total) to extracting the
per-transaction payout from the ERC-20 `Transfer` event in the
transaction receipt via new `getClaimPayoutFromReceipt()`.
> 
> Updates `musdClaim` display/amount computation in the Activity list
(`decodeMusdClaimTx`), transaction details hero (`useClaimAmount`), and
confirmation flow hook (`useMerklClaimAmount`, which now prefers receipt
payout when confirmed and falls back to the async unclaimed-amount
calculation when pending). Tests are updated to validate receipt-log
extraction and the new UI behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c66b845. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[0ef570f](0ef570f)

Co-authored-by: Patryk Łucka <5708018+PatrykLucka@users.noreply.github.com>
…28hj-76wf cp-7.66.0 (#26427)

- chore: allow list audit finding GHSA-378v-28hj-76wf cp-7.66.0 (#26386)

add bn.js affected by an infinite loop. No fix available yet (latest is
5.2.1, affected <=5.2.3). Suppressing for now to unblock CI.
GHSA-378v-28hj-76wf

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

## **Description**

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

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Configuration-only change to suppress a specific audit warning; no
runtime logic changes, but it reduces audit signal for this known issue.
> 
> **Overview**
> Updates Yarn config to ignore the `bn.js` npm audit advisory
`GHSA-378v-28hj-76wf` (ID `1113402`) in `npmAuditIgnoreAdvisories`, to
unblock CI until a fix is available.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6560f97. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[ebce642](ebce642)

Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
…ted to super bowl banner on carousel (#26375)

- chore(predict): cp-7.66.0 remove code related to super bowl banner on
carousel (#26363)

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

## **Description**

The Carousel previously had special handling for the Predict Superbowl
banner: it could replace the entire carousel with a single
`PredictMarketSportCardWrapper` when a Superbowl slide with a `marketId`
was present, and hid that slide from the normal carousel. This change
removes that integration.

**What changed:**

- **Carousel (`index.tsx`):** Removed Predict/Superbowl imports, the
`predictSuperbowlSlide` and `predictSuperbowlMarketId` memos, the early
return that rendered `PredictMarketSportCardWrapper`, the filter that
excluded `PREDICT_SUPERBOWL_VARIABLE_NAME` from visible slides, and the
`handleSportCardDismiss` / `handlePredictSuperbowlLoad` callbacks
(including "Banner Display" tracking for the Superbowl card).
- **Tests (`index.test.tsx`):** Removed the
`PredictMarketSportCardWrapper` mock, the
`PREDICT_SUPERBOWL_VARIABLE_NAME` import, and the entire "Carousel
Predict Superbowl Integration" describe block and its five tests (render
with/without marketId, props, tracking).

The Carousel no longer has any Superbowl-specific behavior; any such
slides from Contentful would now be treated as normal carousel slides.


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

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Removes a time-bound/feature-specific code path and its tests without
touching core navigation or data handling; main risk is unintended
behavior if Contentful still serves Superbowl slides.
> 
> **Overview**
> Removes the Carousel’s special-case Predict Superbowl behavior so it
no longer replaces the carousel with a `PredictMarketSportCardWrapper`
when a Superbowl slide is present.
> 
> This deletes Superbowl-specific slide detection/metadata handling,
explicit filtering of the Superbowl slide from `visibleSlides`, and
related dismiss/load callbacks + “Banner Display” tracking. The test
suite is updated by dropping the Predict Superbowl mock and all
associated integration tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
4bde723. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[6eb88ac](6eb88ac)

Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
…sion and musd_claim transaction types to transaction-controller metrics_properties (#26433)

- feat: cp-7.66.0 MUSD-357 added musd_conversion and musd_claim
transaction types to transaction-controller metrics_properties (#26383)

<!--
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**
Added musd_conversion and musd_claim transaction types to
transaction-controller metrics_properties
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

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

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

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

CHANGELOG entry: added musd_conversion and musd_claim transaction types
to transaction-controller metrics_properties

## **Related issues**

Fixes: [MUSD-357: Add musdConversion and musdClaim Transaction Types to
"Transaction *"
Events](https://consensyssoftware.atlassian.net/browse/MUSD-357)

## **Manual testing steps**

```gherkin
Feature: mUSD transaction analytics classification

  Scenario: user submits mUSD conversion or claim transaction
    Given user has an mUSD conversion or mUSD claim transaction in the wallet flow

    When the wallet emits general transaction lifecycle events
    Then analytics include a specific transaction_type value
    And transaction_type is "musd_conversion" for conversion transactions
    And transaction_type is "musd_claim" for claim transactions
```

## **Screenshots/Recordings**

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

### **Before**

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

<!-- [screenshots/recordings] -->
N/A
## **Pre-merge author checklist**

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

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Small, additive change limited to analytics `transaction_type`
labeling plus test coverage; low risk aside from potential downstream
dashboard/event-name expectations.
> 
> **Overview**
> Adds analytics classification for nested mUSD transactions by mapping
`TransactionType.musdConversion` and `TransactionType.musdClaim` to
`transaction_type` values `musd_conversion` and `musd_claim` in
`getTransactionTypeValue`.
> 
> Extends the existing parameterized test to cover these new nested
transaction type mappings.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3aa4ee5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[435a464](435a464)

Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
This PR updates the change log for 7.66.0. (Hotfix - no test plan
generated.)

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: João Loureiro <175489935+joaoloureirop@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?
-->

sync release/7.67.0 with stable

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

---------

Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com>
Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net>
Co-authored-by: Michal Szorad <michal.szorad@consensys.net>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: Juanmi <95381763+juanmigdr@users.noreply.github.com>
Co-authored-by: Bruno Nascimento <brunonascimentodev@gmail.com>
Co-authored-by: Ale Machado <alejandro@macha.do>
Co-authored-by: Bryan Fullam <bryan.fullam@consensys.net>
Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com>
Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Co-authored-by: Cal-L <cal.leung@consensys.net>
Co-authored-by: Bruno Nascimento <bruno.nascimento@consensys.net>
Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com>
Co-authored-by: OGPoyraz <omergoktugpoyraz@gmail.com>
Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
Co-authored-by: Florin Dzeladini <florin.dzeladini@consensys.net>
Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com>
Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com>
Co-authored-by: Vince Howard <vincenguyenhoward@gmail.com>
Co-authored-by: sahar-fehri <sahar.fehri@consensys.net>
Co-authored-by: George Weiler <georgejweiler@gmail.com>
Co-authored-by: George Marshall <george.marshall@consensys.net>
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
Co-authored-by: sophieqgu <37032128+sophieqgu@users.noreply.github.com>
Co-authored-by: Wei Sun <wei.sun@consensys.net>
Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
Co-authored-by: himanshu <himanshuchawla2014@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Andre Pimenta <andrepimenta7@gmail.com>
Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
Co-authored-by: Patryk Łucka <5708018+PatrykLucka@users.noreply.github.com>
Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com>
- feat: Fix for Pull to Refresh IAB gesture bug (#26373)

## **Description**

Pull-to-refresh gesture was intercepting taps on buttons near the top of
the page (e.g., Polymarket "Sign Up" / "Log In" buttons). The gesture
handler called `stateManager.activate()` immediately in `onTouchesDown`
for the pull zone (`y < 50px`), stealing the touch from the WebView
before knowing whether the user intended to tap or pull.

### Changes

**Deferred activation for pull-to-refresh**: Instead of activating
immediately, the gesture enters a `pending_refresh` state in
`onTouchesDown`. New `onTouchesMove` and `onTouchesUp` handlers measure
the movement delta:
- Downward movement >10px → activate pull-to-refresh
- Horizontal/upward movement >10px → fail and let WebView handle
- Finger lifts with <10px movement (tap) → fail and let WebView handle

**`Gesture.Simultaneous` instead of `Gesture.Race`**: Deferred
activation requires that the Native gesture (WebView scroll) does not
cancel our Pan while it is deciding. `Gesture.Simultaneous` allows both
to run independently — taps pass through to the WebView while our Pan
stays in BEGAN state deciding, and when Pan activates for a real pull at
the top of the page, the WebView has nothing to scroll so both coexist
without visual conflict.

### Why not other approaches

- `Gesture.Race` + deferred activation: Native wins the race and cancels
Pan before `onTouchesMove` fires
- `Gesture.Race` + immediate activation + synthetic JS click replay:
Pull-to-refresh works but synthetic events have `isTrusted = false` —
React ignores them
- `Gesture.Exclusive` + deferred activation: Blocks Native while Pan is
in BEGAN — nothing works

## **Changelog**

CHANGELOG entry: Fixed pull-to-refresh gesture intercepting taps on
buttons near the top of the page in the in-app browser

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Browser gesture tap passthrough

  Scenario: User taps a button near the top of a webpage
    Given the user is on polymarket.com in the in-app browser
    And the page is scrolled to the top (not scrolled at all)

    When user taps the "Log In" or "Sign Up" button
    Then the login/signup modal should appear

  Scenario: User pulls to refresh from the top of the page
    Given the user is on any webpage in the in-app browser
    And the page is scrolled to the top

    When user places finger near the top of the page and drags downward
    Then the refresh indicator should appear
    And the page should reload when pulled past the threshold

  Scenario: User swipes back from the left edge
    Given the user has navigated to at least one page in the in-app browser

    When user swipes from the left edge of the screen toward the right
    Then the browser should navigate back to the previous page

  Scenario: User swipes forward from the right edge
    Given the user has navigated back at least once in the in-app browser

    When user swipes from the right edge of the screen toward the left
    Then the browser should navigate forward

  Scenario: User scrolls normally in the center of the page
    Given the user is on any webpage in the in-app browser

    When user scrolls up or down in the center of the page
    Then the page should scroll normally without triggering any gestures
```

## **Screenshots/Recordings**

### **Before**

<!-- Tapping buttons near the top of the page (e.g. Polymarket Sign
Up/Log In) shows button animation but does not trigger the action -->

### **After**

<!-- Tapping the same buttons now correctly opens the login/signup flow
-->



https://github.com/user-attachments/assets/75c70094-6f39-4086-aab4-368cc6b81177



## **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 low-level gesture coordination between the WebView native
handler and a manual-activation Pan gesture, which could affect
navigation/scroll/tap behavior across devices. Added tests reduce
regression risk but gesture interactions are inherently sensitive to
edge cases.
> 
> **Overview**
> Fixes an in-app browser bug where pull-to-refresh could steal taps
near the top of the page by introducing **deferred pull-to-refresh
activation**: touches in the pull zone now enter a `pending_refresh`
state and only activate refresh after moving downward more than
`PULL_MOVE_ACTIVATION` (10px), while horizontal/upward movement or
lifting the finger fails the gesture and lets the WebView handle the
tap.
> 
> Switches WebView gesture composition from `Gesture.Race` to
`Gesture.Simultaneous` so the WebView’s native gesture can continue
receiving taps while the Pan gesture decides whether to activate, and
extends unit tests/mocks to cover the new `onTouchesMove`/`onTouchesUp`
paths and the new constant.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
af9d1b7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->


[9b336fc](9b336fc)

Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com>
Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
joaoloureirop and others added 27 commits March 6, 2026 23:48
Resolved conflicts between stable (7.67.3) and release/7.68.0:

Build/version: take release/7.68.0 versions (7.68.0, build 3939)
- android/app/build.gradle, ios project, bitrise.yml

Dependencies: take release/7.68.0 versions
- package.json: assets-controllers v100.0.3, smart-transactions v22.6.0,
  transaction-controller v62.19.0, transaction-pay-controller v16.1.2
- yarn.lock: take release/7.68.0

Source code: take release/7.68.0 (newer analytics hooks, nav types, auth)
- DaimoPayModal, VerifyIdentity: useAnalytics over useMetrics
- PerpsOrderView: removed NavigationProp generic (nav v6 prep)
- Login: added useAuthCapabilities
- Authentication.test: type fix (undefined as never)
- babel.config.tests: added rewards/card env var exclusions

Config: OTA_VERSION kept at v7.67.2 (latest from stable)

Locales: take release/7.68.0 (14 language files with newer translations)
Made-with: Cursor
## Summary

This PR syncs the latest changes from `stable` into `release/7.68.0`.

## Why is this needed?

`release/7.68.0` is missing 74 commits from `stable`, including:
- release: 7.67.0 (#26310)
- release: 7.67.1 (#26799)
- release: 7.67.2 (#26985)
- release: 7.67.3 (#27040)
- Associated hotfixes and cherry-picks (Perps connection recovery, Snaps
controller bump, OTA updates, etc.)

## Action Required

**Please review and resolve any merge conflicts manually.**

If there are conflicts, they will appear in this PR. Resolve them to
ensure the release branch has all the latest fixes from stable.

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is
generating a summary for commit
3f6baad. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com>
Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com>
Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
Co-authored-by: Andre Pimenta <andrepimenta7@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
Co-authored-by: Patryk Łucka <5708018+PatrykLucka@users.noreply.github.com>
Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net>
Co-authored-by: Michal Szorad <michal.szorad@consensys.net>
Co-authored-by: Juanmi <95381763+juanmigdr@users.noreply.github.com>
Co-authored-by: Bruno Nascimento <brunonascimentodev@gmail.com>
Co-authored-by: Ale Machado <alejandro@macha.do>
Co-authored-by: Bryan Fullam <bryan.fullam@consensys.net>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Co-authored-by: Cal-L <cal.leung@consensys.net>
Co-authored-by: Bruno Nascimento <bruno.nascimento@consensys.net>
Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com>
Co-authored-by: OGPoyraz <omergoktugpoyraz@gmail.com>
Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
Co-authored-by: Florin Dzeladini <florin.dzeladini@consensys.net>
Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com>
Co-authored-by: Vince Howard <vincenguyenhoward@gmail.com>
Co-authored-by: sahar-fehri <sahar.fehri@consensys.net>
Co-authored-by: George Weiler <georgejweiler@gmail.com>
Co-authored-by: George Marshall <george.marshall@consensys.net>
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
Co-authored-by: sophieqgu <37032128+sophieqgu@users.noreply.github.com>
Co-authored-by: Wei Sun <wei.sun@consensys.net>
Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
Co-authored-by: himanshu <himanshuchawla2014@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Bernardo Garces Chapero <bernardo.chapero@consensys.net>
Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com>
Co-authored-by: Brian August Nguyen <brianacnguyen@gmail.com>
Co-authored-by: Alejandro Garcia <alejandro.garcia@consensys.net>
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
This PR updates the change log for 7.68.0. (Hotfix - no test plan
generated.)

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: chloeYue <chloe.gao@consensys.net>
# 🚀 v7.68.0 Testing & Release Quality Process

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

---

## 📋 Key Processes

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

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

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

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

---

## 🗓️ Timeline and Milestones

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

---

## ✅ Signoff Checklist

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

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

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

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

Many thanks in advance

# Reference
- Testing plan sheet -
https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372
<!--
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**

Migrated `Label` component (core UX scope).

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

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

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

<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/50065c3f-8fe8-4ad6-908a-08e4a0ae7d2d"
/>

### **After**

<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/4fbe9805-1ecf-418f-9ecd-555a266b042e"
/>

## **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]
> **Low Risk**
> Low risk UI-only change that swaps `Label` implementations and updates
props/snapshots; no business logic or data/auth flows are modified.
> 
> **Overview**
> Migrates `Label` usage in `ChoosePassword`, `ManualBackupStep1`,
`OAuthRehydration`, and `ResetPassword` from the local component-library
to `@metamask/design-system-react-native`.
> 
> Updates `Label` props to the design-system API (e.g., `fontWeight` and
`DSTextColor.TextDefault`) and refreshes Jest snapshots to reflect the
resulting style output changes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fa7ff7c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Replaces the sticky "Buy/Sell" footer buttons in the token details
treatment variant with "Swap/Buy":
* **Swap** uses the existing swap navigation (goToSwaps() with no
overrides — source = current token, dest = swap UI default)
* **Buy** redirects to on-ramp (fiat purchase), matching the existing
Cash Buy behavior

Button visibility is conditional on two signals:
* **Swap** shown when user has eligible tokens to swap from
(hasEligibleSwapTokens). Per Swaps lead guidance, the Swap button is no
longer gated on chain support — even if the current token's chain isn't
natively supported by Swaps, the user is routed into the Swap flow which
defaults to Ethereum pre-fills.
* **Buy** shown when ramp supports the token (isBuyable), or as a
fallback when user has no swap-eligible tokens — ensuring there is
always at least one CTA in the sticky footer.
 
No changes to the control variant (legacy inline action buttons).


## **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 token details sticky footer from Buy/Sell to
Swap/Buy buttons

## **Related issues**

Fixes: #27326

## **Manual testing steps**

```gherkin
Feature: Token details sticky Swap/Buy footer

  Scenario: user sees both Swap and Buy
    Given user has ETH and USDC in wallet
    When user opens a ramp-supported token (e.g. LINK)
    Then sticky footer shows "Swap" and "Buy"
    And tapping Swap opens bridge UI with source = LINK
    And tapping Buy opens the on-ramp flow

  Scenario: user sees Swap only when ramp unsupported
    Given user has ETH and USDC in wallet
    When user opens a token not supported by ramp providers
    Then sticky footer shows only "Swap"

  Scenario: user sees Swap on unsupported chain
    Given user has ETH on Ethereum mainnet
    When user opens a native token on Fantom (unsupported by Swaps)
    Then sticky footer still shows "Swap"
    And tapping Swap routes to Swap flow with Ethereum pre-fills

  Scenario: user sees Buy only when no swap-eligible tokens
    Given user has an empty wallet or only holds the viewed token
    When user opens a ramp-supported token
    Then sticky footer shows only "Buy"

  Scenario: user sees Buy as fallback
    Given user has an empty wallet
    When user opens a token not supported by ramp providers
    Then sticky footer shows only "Buy"
    And the ramp screen handles notifying the user it is unsupported

  Scenario: trending token swap direction
    Given user has ETH and taps a token from trending feed
    When user taps Swap in the sticky footer
    Then bridge UI opens with source = ETH, dest = trending token
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

<img width="381" height="775" alt="Screenshot 2026-03-11 at 09 24 41"
src="https://github.com/user-attachments/assets/dc45c238-5b39-40df-8ecb-4e379aaea7ef"
/>


## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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






<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Updates token details treatment CTA logic and navigation, which can
affect conversion flows (swaps/on-ramp) and button visibility across
tokens/chains. Risk is moderate due to UX/flow changes but limited to
the A/B treatment and covered by updated unit tests.
> 
> **Overview**
> Updates the Token Details *treatment* sticky footer to show
**`Swap`/`Buy`** CTAs instead of `Buy`/`Sell`. `Swap` now routes via
`goToSwaps()` and is shown when `useTokenActions` reports
`hasEligibleSwapTokens`; `Buy` routes to on-ramp via `onBuy` and is
shown when the token is ramp-buyable (`useTokenBuyability`) or as a
fallback when no swap-eligible tokens exist.
> 
> Extends `useTokenActions` to expose `hasEligibleSwapTokens` and
updates `TokenDetails.test.tsx` to reflect the new button set and
visibility matrix. Also adjusts the provider selection empty-state copy
to use `fiat_on_ramp_aggregator.no_providers_available` when quotes are
not shown.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
652129d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
…#26964)

<!--
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 improves the resilience of Android Google OAuth (ACM) error
handling and adds proper Sentry error segregation for OAuth login
failures.

**Problem:**
1. Android Credential Manager (ACM) errors with unrecognized message
formats fall through to `UnknownError`, bypassing the browser fallback —
leaving users stuck with a cryptic error instead of getting the
browser-based OAuth alternative.
2. All OAuth errors (iOS and Android, all providers) are grouped into a
single Sentry issue because `captureException` uses the same stack trace
fingerprint, making it impossible to distinguish platform-specific or
provider-specific failures.
3. `OAuthError` message construction produces ugly double-prefixed
strings like `"Unknown error - Error: e1 error..."` when wrapping Error
objects.

**Solution:**
- **Broadened ACM regex patterns** — `CANCEL` is now more specific
(avoids false positives), and `NO_PROVIDER_DEPENDENCIES` catches more
message variants across Android versions/vendors.
- **UnknownError browser fallback** — Any unrecognized ACM error on
Android Google now triggers the browser-based OAuth fallback instead of
surfacing a dead-end error to the user.
- **Sentry fingerprinting** — `handleOAuthLoginError` now includes
`oauth_platform`, `oauth_provider`, `oauth_error_code`, and
`oauth_is_fallback` tags, with a custom fingerprint that groups errors
by platform + provider + error code.

<!--
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 Android Google sign-in errors not falling back to
browser-based login for unrecognized credential manager failures

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TO-564

## **Manual testing steps**

```gherkin
Feature: Android Google ACM browser fallback

  Scenario: user signs in with Google on Android when ACM fails with unrecognized error
     Given user is on the Onboarding screen on an Android device
     And the Android Credential Manager is unavailable or returns an unrecognized error
     When user taps "Continue with Google"
     Then the app should automatically fall back to browser-based Google OAuth
     And the user should be able to complete sign-in via the browser

```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**



https://github.com/user-attachments/assets/700c76f7-322e-4cb0-b5b1-4806939fd5ca



https://github.com/user-attachments/assets/19276c56-635a-4c7f-82e6-8825f8b5b0f2





<!-- [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**
> Touching social login error handling and fallback paths can change
user sign-in behavior on Android and alters Sentry reporting; scope is
contained to onboarding OAuth flows and error classification.
> 
> **Overview**
> Ensures **Android Google sign-in** falls back to browser-based OAuth
not only for known ACM failures, but also for `UnknownError` cases that
previously surfaced as dead-end errors.
> 
> Improves observability by adding provider/platform/error-code tags and
a custom Sentry fingerprint in `handleOAuthLoginError`, and refines
Android ACM regex matching (cancel + provider dependency variants). Also
cleans up `OAuthError` message formatting to avoid double-prefixed error
strings, and adds tests covering the new Android-only `UnknownError`
fallback behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
62dcde6. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary

- Adds `.claude/commands/e2e-test.md` — new Claude skill (`/e2e-test`)
that guides through adding Detox E2E tests end-to-end
- Adds `.ai/skills/e2e-test/` — multi-AI skill definition (Cursor,
Copilot, Windsurf) with detailed reference docs

## What the skill does

The skill walks an AI agent through the full E2E test creation loop:

1. **Plan** — determine smoke vs regression, choose feature folder and
tag
2. **Infrastructure** — create/reuse Page Objects
(`tests/page-objects/`), selectors (`*.testIds.ts`), and API mocks
3. **Write spec** — `withFixtures` + `FixtureBuilder` + POM, mandatory
descriptions on all gestures/assertions
4. **Lint + TSC** — run before executing the test
5. **Run locally** — `detox test -c ios.sim.main --testPathPattern=...`
6. **Iterate** — analyze failure → fix → re-lint → re-run until green

## Reference docs structure

```
.ai/skills/e2e-test/
├── SKILL.md                    ← 10 golden rules + workflow overview + quick commands
└── references/
    ├── writing-tests.md        ← spec templates, FixtureBuilder patterns
    ├── page-objects.md         ← POM structure, Matchers/Gestures/Assertions API
    ├── mocking.md              ← testSpecificMock, feature flags, HTTP mocking
    └── running-tests.md        ← detox commands, common failures & fixes, retry pattern
```

## Related

Follows the same pattern as PR #27013 (component-view-test skill
reorganization).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only additions and pointer updates; no runtime code
paths or test framework behavior changes.
> 
> **Overview**
> Introduces a new canonical `e2e-test` agent skill under
`.agents/skills/e2e-test/`, including a decision tree, “golden rules”,
and focused reference guides for writing specs, page objects/selectors,
mocking, and running/debugging Detox.
> 
> Hooks the skill into agent tooling via
`.agents/skills/e2e-test/agents/openai.yaml`, adds a thin
redirect/enforcement stub at `.claude/skills/e2e-test/SKILL.md`, and
updates `tests/AGENTS.md` to point contributors/agents to the new
canonical skill.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3deb799. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…27377)

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

## **Description**

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

This PR adds a rule to ensure `react-native-gesture-handler`'s
`ScrollView` is used with `BottomSheet`.

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: documentation-only change with no runtime/code-path impact.
Only affects developer guidance and review checklist items.
> 
> **Overview**
> Adds a new *Platform-Specific Gotcha* to the UI development guidelines
specifying that `ScrollView` used inside a `BottomSheet` must be
imported from `react-native-gesture-handler` (to avoid Android scrolling
issues), including a correct/incorrect import example.
> 
> Updates the pre-commit checklist to include verifying this
`ScrollView` import rule.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6e32e1e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…27245)

## **Description**

Claims ownership of onboarding and SRP-related screens for the
`@MetaMask/web3auth` team in CODEOWNERS. These screens are part of the
onboarding flow that web3auth is responsible for, but were previously
unowned.

### Screens added:

| Screen | Path |
|--------|------|
| OnboardingSheet | `app/components/Views/OnboardingSheet` |
| ChoosePassword | `app/components/Views/ChoosePassword` |
| ManualBackupStep1 | `app/components/Views/ManualBackupStep1` |
| ManualBackupStep2 | `app/components/Views/ManualBackupStep2` |
| ManualBackupStep3 | `app/components/Views/ManualBackupStep3` |
| AccountBackupStep1 | `app/components/Views/AccountBackupStep1` |
| AccountBackupStep1B | `app/components/Views/AccountBackupStep1B` |
| ImportFromSecretRecoveryPhrase |
`app/components/Views/ImportFromSecretRecoveryPhrase` |
| ImportNewSecretRecoveryPhrase |
`app/components/Views/ImportNewSecretRecoveryPhrase` |
| SelectSRP | `app/components/Views/SelectSRP` |
| SrpInput | `app/components/Views/SrpInput` |
| RestoreWallet | `app/components/Views/RestoreWallet` |
| WalletCreationError | `app/components/Views/WalletCreationError` |
| OAuthRehydration | `app/components/Views/OAuthRehydration` |
| SocialLoginIosUser | `app/components/Views/SocialLoginIosUser` |
| RevealPrivateCredential |
`app/components/Views/RevealPrivateCredential` |

### Also cleaned up:

- Removed `OnboardingCarousel` entry (directory no longer exists)

## **Changelog**

CHANGELOG entry: null

## **Related issues**

N/A — Housekeeping to ensure proper code review routing.

## **Manual testing steps**

No testing required — CODEOWNERS-only change.

## **Screenshots/Recordings**

N/A

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md)
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on this PR
- [x] I've manually tested this PR
- [x] I've confirmed there are no breaking changes

## **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.
…27275)

<!--
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: remove thrown exceptions in migration 121 when
`NetworkEnablementController` is absent or
`NetworkEnablementController.nativeAssetIdentifiers` is missing.

## **Related issues**

Fixes: #27325

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

(if we want to test it since it is a log message thing)
- Reset data.
- Find a version of the app prior the creation of
`NetworkEnablementController` and install it.
- Update to latest.
- The error message will appear in the logs. 

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Limits Sentry reporting in migration `121` by no longer emitting
exceptions for expected/benign missing-state cases; migration
behavior/data transforms are otherwise unchanged.
> 
> **Overview**
> Migration `121` no longer calls `captureException` when
`NetworkEnablementController` is absent or when
`NetworkEnablementController.nativeAssetIdentifiers` is missing; these
cases now silently short-circuit.
> 
> Tests for migration `121` are updated to assert **no** Sentry
exception is captured for those missing-field scenarios, while retaining
exception expectations for type-mismatch cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5b65b69. 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**

Added new automated tests metrics to follow trends:
- qa metrics script extended
- artifact names changed

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

- revisit jobs and artefacts manually ✅
- check new metrics output  ✅

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches multiple GitHub Actions workflows and artifact
naming/patterns; misalignment could break test report downloads, rerun
merging, or metrics generation even though it doesn’t affect production
code.
> 
> **Overview**
> Updates QA stats collection to emit **namespaced** metrics
(`component_view`, `unit`, `e2e`, `performance`) and to derive counts
directly from CI artifacts: per-feature Jest counts from shard
`coverage-*` artifacts, executed E2E counts parsed from JUnit XML (with
main vs flask + platform health signals), and performance scenario
counts by scanning `tests/performance` specs. Metrics are now omitted
when artifacts/tests are missing rather than defaulting to zero.
> 
> Adjusts CI workflows to support this data: unit/CV shards now include
`jest-results.json` inside `coverage-*` artifacts, and E2E workflows
standardize artifact naming via a new `artifact_name_prefix` input
(default `main-`, blank for flask), update download patterns
accordingly, rename the fixture-validation artifact, and rebuild merged
JUnit XML after re-run result merging.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
beebe26. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR syncs the stable branch to main for version 7.70.0.

*Synchronization Process:*

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

*File Preservation:*

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

  Indicates the next version candidate of main to 7.70.0

---------

Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com>
Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com>
Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
Co-authored-by: Andre Pimenta <andrepimenta7@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Salim TOUBAL <salim.toubal@outlook.com>
Co-authored-by: Patryk Łucka <5708018+PatrykLucka@users.noreply.github.com>
Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com>
Co-authored-by: Caainã Jeronimo <caainaje@gmail.com>
Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com>
Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net>
Co-authored-by: Michal Szorad <michal.szorad@consensys.net>
Co-authored-by: Juanmi <95381763+juanmigdr@users.noreply.github.com>
Co-authored-by: Bruno Nascimento <brunonascimentodev@gmail.com>
Co-authored-by: Ale Machado <alejandro@macha.do>
Co-authored-by: Bryan Fullam <bryan.fullam@consensys.net>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Co-authored-by: Cal-L <cal.leung@consensys.net>
Co-authored-by: Bruno Nascimento <bruno.nascimento@consensys.net>
Co-authored-by: Alejandro Garcia Anglada <aganglada@gmail.com>
Co-authored-by: OGPoyraz <omergoktugpoyraz@gmail.com>
Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
Co-authored-by: Florin Dzeladini <florin.dzeladini@consensys.net>
Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com>
Co-authored-by: Vince Howard <vincenguyenhoward@gmail.com>
Co-authored-by: sahar-fehri <sahar.fehri@consensys.net>
Co-authored-by: George Weiler <georgejweiler@gmail.com>
Co-authored-by: George Marshall <george.marshall@consensys.net>
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
Co-authored-by: sophieqgu <37032128+sophieqgu@users.noreply.github.com>
Co-authored-by: Wei Sun <wei.sun@consensys.net>
Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
Co-authored-by: himanshu <himanshuchawla2014@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com>
Co-authored-by: Bernardo Garces Chapero <bernardo.chapero@consensys.net>
Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com>
Co-authored-by: Brian August Nguyen <brianacnguyen@gmail.com>
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
Co-authored-by: Jyoti Puri <jyotipuri@gmail.com>
Co-authored-by: dan437 <80175477+dan437@users.noreply.github.com>
Co-authored-by: Luis Taniça <matallui@gmail.com>
Co-authored-by: Alejandro Garcia <alejandro.garcia@consensys.net>
Co-authored-by: chloeYue <chloe.gao@consensys.net>
…ons in E2E CI (#27352)

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

**Problem**
  All iOS E2E tests were failing with:
main-qa-MetaMask.app is missing its bundle executable at
"main-qa-MetaMask.app/MetaMask"

  Two issues in the artifact upload/download pipeline:

1. Case mismatch — Xcode on the case-insensitive build runner stored the
binary as metamask (lowercase) while CFBundleExecutable
in Info.plist declared it as MetaMask. actions/upload-artifact packaged
the file under its actual on-disk name. xcrun simctl
install on the test runner validates the bundle with a case-sensitive
directory lookup, found no entry named MetaMask, and
  reported it as missing.
2. Permissions stripped — actions/upload-artifact does not preserve
execute bits when creating the ZIP, so the binary arrived on
  the test runner as -rw-r--r-- instead of -rwxr-xr-x.

  Fix

- Before upload (build-ios-e2e.yml): read CFBundleExecutable from
Info.plist, locate the binary case-insensitively, rename to the
correct case via a two-step move (required on case-insensitive APFS),
then chmod +x
- After download (run-e2e-workflow.yml): chmod +x as a safety net, with
the same case-fix logic
- Repack path (scripts/repack.js): chmod 755 on the repacked binary so
the cache-hit code path is also covered

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

- [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 iOS E2E build/test workflows and cached artifact handling;
missteps could break CI pipelines or increase rebuild frequency, but
changes are localized to automation scripts.
> 
> **Overview**
> Improves iOS E2E artifact reliability by **normalizing the app bundle
executable name and permissions** before upload and again after
download, preventing `simctl install` failures due to case-mismatched
binaries and stripped execute bits.
> 
> Updates iOS build caching by introducing `IOS_APP_CACHE_VERSION` in
cache keys (plus a centralized `XCODE_CACHE_VERSION` env), and hardens
`scripts/repack.js` to verify the repacked `.app` contains the expected
bundle executable and to restore its execute permissions, failing fast
if `@expo/repack-app` drops the binary.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
750b422. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.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?
-->

Filling PR descriptions thoroughly seems tedious and time-consuming,
which often results in incomplete templates, missing changelog entries,
or skipped manual testing steps.

By giving AI coding agents structured skills for each part of the PR
workflow, developers can generate complete, standards-compliant PR
descriptions with minimal effort — removing friction and making it easy
to do the right thing every time.

This PR adds a comprehensive suite of agent skills in
`.agents/skills/pr-*/SKILL.md` that provide step-by-step instructions
for:

- **`pr-title`** — generate conventional commit PR titles from diff
analysis
- **`pr-description`** — orchestrate full PR description generation
following the repo template
- **`pr-changelog`** — determine user-facing impact and write CHANGELOG
entries
- **`pr-issue-search`** — find related GitHub issues or Jira tickets
from branch name, commits, or keyword search
- **`pr-manual-testing`** — generate Gherkin-format manual testing
scenarios from code changes
- **`pr-readiness-check`** — scan branch diff for missing tests, JSDoc,
or guideline violations
- **`pr-codeowners`** — identify code owners and map them to Slack group
handles
- **`pr-create`** — validate preconditions, generate description, create
draft PR, and produce Slack review request message
- **`pr-review-queue`** — add PRs to the MetaMask project board with
priority and date fields

Each skill is self-contained and composable — `pr-create` and
`pr-description` orchestrate the others as sub-skills.

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

Refs: MCWP-392

## **Manual testing steps**

```gherkin
Feature: AI agent PR workflow skills

  Scenario: agent uses pr-create skill to open a draft PR
    Given I am on a feature branch with committed changes
    And the branch is pushed to origin

    When an AI agent invokes the pr-create skill
    Then a draft PR should be created on GitHub
    And the PR description should follow the repository template
    And the PR title should follow conventional commit format
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

This PR is generated using the new skills suite form the PR itself

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because this PR only adds new markdown-based agent
instructions and does not change application or CI/runtime behavior.
> 
> **Overview**
> Introduces a new `.agents/skills/pr-*` documentation suite that
defines repeatable agent workflows for PR tasks: generating
`pr-title`/`pr-description`, producing a `CHANGELOG entry`, finding
related issues, writing Gherkin manual testing steps, running a
non-blocking readiness scan, mapping changed files to CODEOWNERS/Slack
handles, creating draft PRs, and adding PRs to the MetaMask review queue
project.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f860fc8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…et (#27317)

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

## **Description**

Updates the Predict Unavailable bottom sheet to use the shared
`HeaderCompactStandard` component instead of `BottomSheetHeader`,
aligning with patterns used elsewhere.

## **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/issues?jql=issueKey%20in%20(DSYS-555%2CDSYS-556%2CDSYS-557%2CDSYS-558%2CDSYS-559)&selectedIssue=DSYS-559

## **Manual testing steps**

```gherkin
Feature: Predict headers

  Scenario: Predict Unavailable sheet shows HeaderCompactStandard
    Given the app is open and Predict is available

    When Predict Unavailable bottom sheet is shown (e.g. when Predict is unavailable in region)
    Then the sheet header shows HeaderCompactStandard with title and close button
    And content and footer padding look correct
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

<img width="1290" height="2796" alt="Simulator Screenshot - iPhone 15
Pro Max - 2026-03-10 at 16 20 57"
src="https://github.com/user-attachments/assets/7a47b69b-b54d-45b3-ada2-96c01c4f7aa3"
/>


<!-- [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 UI refactor that swaps the bottom-sheet header component and
tweaks spacing/text color, with no changes to data flow or business
logic.
> 
> **Overview**
> Updates the Predict Unavailable bottom sheet to use the shared
`HeaderCompactStandard` header (title + close) instead of
`BottomSheetHeader`, aligning the sheet with newer header patterns.
> 
> Also tweaks layout styling by adjusting horizontal padding on the
description and footer and changing the description text color to
`text-alternative`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e34e35b. 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**

Disable slide-to-dismiss behavior of swaps keypad to prevent potential
double triggers of keypad keys due to bottom sheet dismissal gesture
handler event.

<!--
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: disable slide-to-dismiss behavior of swaps keypad

## **Related issues**

Fixes: #26746

## **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]
> **Medium Risk**
> Changes bottom-sheet gesture behavior for the swap/bridge keypad,
which could affect how users dismiss the keypad and interact with
inputs. Test updates reduce flakiness but rely on mocked bridge status
responses and new timeouts that could mask regressions.
> 
> **Overview**
> Disables the `SwapsKeypad` slide/pan interaction by setting
`BottomSheetDialog` `isInteractable={false}` to prevent gesture-handler
double-firing of keypad button presses.
> 
> Updates `SwapsKeypad` unit tests to capture and assert the
`BottomSheetDialog` configuration, and adjusts bridge smoke-test
stability by replacing a fixed delay with visibility assertions, adding
confirmed-status verification, and mocking `getTxStatus` to return a
complete bridge status response.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0724794. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

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

## **Description**

Fixes a bug where the max button was no longer showing on select
networks.

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

## **Manual testing steps**

```gherkin
Feature: swap max button

  Scenario: user is using the swaps experience
    Given the chain they are on supports gasless 

    When user selects tokens
    Then the max button should be visible
```

## **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**
> Changes the gating logic for showing the Bridge/Swap “Max” option for
native assets, so regressions could hide/show the button on certain
networks depending on `gasIncluded`/`gasIncluded7702` selector outputs.
> 
> **Overview**
> Updates `useShouldRenderMaxOption` to **stop depending on Smart
Transactions/send-bundle support and quote sponsorship** and instead
show the Max option for native assets when
`selectGasIncludedQuoteParams` indicates `gasIncluded` or
`gasIncluded7702`.
> 
> Refactors the corresponding hook tests to mock the new selector shape
and to cover gas-included vs 7702-enabled vs disabled scenarios
(including non‑EVM native tokens), removing the old STX/send-bundle
assertions.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e2b4a06. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

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

Introduced changes:

- Permissions: New adapter method `ensurePermissions()` is called before
transport checks in `retryEnsureDeviceReady`. And adds Android
permission handling (Bluetooth on Android 12+, location on older
Android).
- Disconnect: Ledger BLE teardown uses
`TransportBLE.disconnectDevice(deviceId)` instead of `transport.close()`
for immediate disconnect. Cancelling “awaiting confirmation” also
triggers a best-effort adapter disconnect.

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

## **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**
> Changes affect BLE connection lifecycle and Android permission
prompting, which can alter user flow and connection stability; coverage
is included but behavior depends on platform permission APIs and
device/OS quirks.
> 
> **Overview**
> Improves the hardware-wallet connection retry path by introducing a
new `HardwareWalletAdapter.ensurePermissions()` contract and calling it
before transport checks in `retryEnsureDeviceReady`, aborting the retry
if the user must be redirected to OS Settings.
> 
> For Ledger BLE, adds Android permission prompting (Android 12+
Bluetooth permissions, older Android location permission) and updates
transport teardown to prefer `TransportBLE.disconnectDevice(deviceId)`
over `transport.close()` to force immediate disconnects; the
awaiting-confirmation cancel path now also triggers a best-effort
adapter disconnect. Tests/mocks are updated accordingly (Ledger adapter,
provider, non-hardware adapter).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2a94bd7. 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**

1. **What is the reason for the change?**  
The redesigned homepage needs a dedicated **Cash** section as the first
section, surfacing mUSD (MetaMask USD) and guiding users to convert
stablecoins and claim bonuses.

2. **What is the improvement/solution?**
- **Cash section (homepage):** When mUSD conversion is enabled and user
is geo-eligible, the first section is **"mUSD"**. It shows aggregated
mUSD balance (Linea + Ethereum), annualized bonus copy (e.g. "Get 3%
annualized bonus…" with the percentage in green), and a "Claim bonus"
CTA on the row when a bonus is claimable. Tapping the section header
navigates to the Cash token list. When the user has no mUSD, the section
shows a **Get mUSD** empty state: the same annualized copy, a tappable
mUSD token row that navigates to Token Details (Mainnet mUSD, same
destination as trending tokens), and a "Get mUSD" button that routes to
the Buy flow (when mUSD is buyable) or the Convert flow (when the user
has convertible stablecoins e.g. USDC).
- **Cash token list screen:** New full-view screen
(`CashTokensFullView`) that shows only mUSD positions across supported
networks (Ethereum Mainnet, Linea). When the user has no mUSD, the
screen renders the same Get mUSD empty state (handled by
`CashTokensFullView` via `useMusdBalance`); when the user has mUSD, it
renders `Tokens` with `showOnlyMusd`. Same network filter as the main
token list; no add-token or sort. No mUSD-specific empty-state logic
inside `Tokens`.
- **mUSD isolation:** mUSD is removed from the main Tokens section and
from the generic full token list; it appears only in the Cash section
and Cash full view.
- **Implementation details:** `Tokens` supports a `showOnlyMusd` prop
(filter list to mUSD, hide add/sort in control bar);
`TokenListControlBar` supports `showAddToken` and `hideSort`. Empty
state component `CashGetMusdEmptyState` is used on the homepage (in
`CashSection`) and in `CashTokensFullView`; token row uses
`NavigationService` to navigate to Token Details. New route
`CASH_TOKENS_FULL_VIEW` and screen registration. Uses design-system
components. Cash section does not expose a refresh ref (no-op removed).

## **Changelog**

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

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

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

CHANGELOG entry: Added a Cash section on the homepage that shows
aggregated mUSD balance, annualized bonus copy for stablecoin holders,
and a dedicated Cash token list view with network filter.

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Homepage Cash section and Cash token list

  Scenario: User with mUSD conversion enabled and geo-eligible sees Cash section first
    Given the user has mUSD conversion feature enabled and is in an eligible region
    When the user opens the redesigned homepage
    Then the Cash section appears as the first section with title "Cash"
    And if the user has convertible stablecoins, the annualized bonus copy is shown (e.g. "Get 3% annualized bonus...")
    And if the user has mUSD balance, the aggregated mUSD row is shown with balance and optional "Claim bonus"

  Scenario: User navigates to Cash token list from section header
    Given the user is on the homepage with Cash section visible
    When the user taps the Cash section header (or the ">" affordance)
    Then the app navigates to the Cash token list screen
    And the screen shows only mUSD positions (per network) or the cash empty state when none
    And the network filter is visible and works; add-token and sort buttons are not shown

  Scenario: User with network filter applied sees mUSD when opening Cash list
    Given the user has a network filter applied (e.g. single network) and has mUSD on that network
    When the user opens the Cash token list from the homepage
    Then mUSD positions for the enabled network(s) are shown
    And the user can change the network filter from the control bar
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**


https://github.com/user-attachments/assets/ed532349-cfcc-4495-9b38-6e97fbaec30f



<!-- [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**
> Adds new navigation routes and conditional token filtering (including
excluding mUSD from main lists) gated by feature flags/geo eligibility,
which could affect token visibility and analytics. Also changes fiat
formatting to use `currencyDisplay: 'narrowSymbol'`, which may alter
currency rendering across the app.
> 
> **Overview**
> Introduces a new **Cash (mUSD)** surface: a `CashSection` is added as
the first homepage section when mUSD conversion is enabled and
geo-eligible, showing either an aggregated mUSD row (with optional
*Claim bonus*) or a *Get mUSD* empty state that deep-links to mUSD
details and routes users into buy/convert flows with new
`home_cash_section` analytics location.
> 
> Adds a dedicated `CashTokensFullView` route/screen and extends
`Tokens`/`TokenListControlBar` to support an mUSD-only list
(`showOnlyMusd`) that hides add-token/sort and uses cash-specific empty
state messaging; when the Cash section is rendered, mUSD is filtered out
of the main tokens lists (including popular tokens) to avoid
duplication.
> 
> Updates mUSD-related token list items to show a non-clickable green
`"3% bonus"` label for mUSD when no claimable reward exists (only when
conversion + geo eligibility are true), expands/adjusts unit tests and
snapshots accordingly, and tweaks `formatFiat` to prefer `Intl` narrow
currency symbols.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
cc3ad61. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: Pedro Pablo Aste Kompen <wachunei@gmail.com>
@pull pull Bot locked and limited conversation to collaborators Mar 11, 2026
@pull pull Bot added the ⤵️ pull label Mar 11, 2026
@pull pull Bot merged commit 47741a3 into Reality2byte:main Mar 11, 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.