Skip to content

[pull] main from MetaMask:main#574

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

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

Conversation

@pull
Copy link
Copy Markdown

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

ffmcgee725 and others added 15 commits March 4, 2026 12:00
<!--
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 wallet-side error handling in SDKConnectV2 previously had a binary
classification for RPC response errors: either EVM user rejection (code
`4001`) showing "Approval rejected", or anything else showing "Failed to
establish connection." This was misleading when the connection itself
was fine but an RPC method returned an error (e.g. a Solana
`signMessage` rejection showing as a connection failure).

This PR introduces three distinct error categories for post-connection
RPC responses:

- **User rejection** (`REJECTION_CODES` or rejection message pattern) →
"Approval rejected"
- **Internal/unexpected error** (JSON-RPC internal range `-32603`,
`-32000` to `-32099`) → "Something went wrong"
- **RPC method failure** (all other codes) → "Request failed"

The `showConnectionError` toast is now reserved exclusively for
transport/handshake failures in `connection-registry.ts`, which is its
intended meaning.

A message-based fallback (`isRejectionMessage`) is also included to
handle a known bug in `@metamask/eth-snap-keyring` where
`_SnapKeyring_handleRequestRejected` discards the original `4001` code
and re-throws a plain `Error`, which `serializeError` then wraps as
`-32603`. Without this fallback, Solana `signMessage` rejections would
show "Something went wrong" instead of "Approval rejected". An upstream
fix request has been filed with the Snaps team
(`app/core/SDKConnectV2/docs/snap-keyring-rejection-code-loss.md`).

Full error payload (`code` + `message`) is now logged at `warn` level
whenever any error toast is shown, improving debuggability.

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

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: SDKConnectV2 error toast categorisation

  Scenario: user rejects a Solana signMessage request
    Given a dApp is connected via MetaMask Connect (MWP)
    And the dApp sends a Solana signMessage request
    When user taps "Reject" in the confirmation UI
    Then the "Approval rejected" toast is shown
    And the "Failed to establish connection" toast is NOT shown

  Scenario: user rejects an EVM eth_sendTransaction request
    Given a dApp is connected via MetaMask Connect (MWP)
    And the dApp sends an eth_sendTransaction request
    When user taps "Reject" in the confirmation UI
    Then the "Approval rejected" toast is shown

  Scenario: an RPC method returns an unexpected error
    Given a dApp is connected via MetaMask Connect (MWP)
    And the dApp sends a request that results in an internal wallet error
    When the wallet returns an error response
    Then the "Something went wrong" toast is shown
    And the "Failed to establish connection" toast is NOT shown

  Scenario: connection handshake fails
    Given a dApp attempts to connect via MetaMask Connect (MWP)
    When the WebSocket transport fails to establish
    Then the "Failed to establish connection" toast is shown
```

## **Screenshots/Recordings**

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

### **Before**

Solana `signMessage` rejection → "Failed to establish connection" toast

### **After**

Solana `signMessage` rejection → "Approval rejected" toast

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes runtime error-handling branches for
all SDKConnectV2 RPC responses and adds new host-app adapter API
surface; misclassification could show the wrong toast but does not alter
transaction/auth flows.
> 
> **Overview**
> Improves SDKConnectV2 post-connection RPC error handling by
**splitting the previous generic error toast into three categories**:
user rejection (code-based + message-pattern fallback), JSON-RPC
internal/server errors, and all other method failures.
> 
> Adds new host adapter APIs `showInternalError` and `showMethodError`
(with new i18n strings) and updates the `Connection` response handler to
log error details at `warn` level while dispatching the appropriate
toast; tests are expanded to cover the new classification (including
Solana code `5000` and rejection-message fallback).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
dad4714. 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**

This PR moves the perps “Add funds” (deposit) flow into the pay-with
token filter so the Pay With modal can show the perps balance row and
“Add funds” without receiving a deposit callback from the parent.

## **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: Inlined perps “Add funds” flow in the pay-with token
filter so the Pay With modal no longer depends on a deposit callback
from the parent.

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Perps pay-with and inline deposit

  Scenario: user opens Pay With for a perps deposit-and-order transaction
    Given a perps deposit-and-order transaction is in the approval flow and the user opens the Pay With modal

    When the modal is shown
    Then a “Perps balance” row appears at the top with the perps balance and an “Add funds” button
    And tapping the row selects perps balance as the payment token
    And tapping “Add funds” navigates to the perps flow and starts the deposit-with-confirmation flow

```

## **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="1206" height="2622"
alt="simulator_screenshot_77596920-937B-44BE-AFB1-816160B96C76"
src="https://github.com/user-attachments/assets/07cecad2-1489-46cc-8007-f7b35ab3b652"
/>


## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes Pay With list item shape/typing and
wires navigation + `depositWithConfirmation()` from within the filter,
which could impact payment token selection and deposit initiation for
`perpsDepositAndOrder` confirmations.
> 
> **Overview**
> For `perpsDepositAndOrder` transactions, replaces the synthetic
perps-balance `AssetType` entry with a `HighlightedItem` (outside the
asset list) that displays the perps balance and includes an inline
**“Add funds”** button.
> 
> The highlighted row now **self-initiates the deposit flow** by calling
`navigateToConfirmation({ stack: Routes.PERPS.ROOT })` and
`depositWithConfirmation()`, and selecting the row triggers
`onPerpsPaymentTokenChange(null)`.
> 
> Tests are updated accordingly, including loosening `util/networks`
mocks to spread `jest.requireActual` to satisfy transitive dependencies.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c01f0ad. 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>
…ace cp-7.67.2 (#26982)

## **Description**

After long backgrounds (5+ min), Perps failed to reload positions, 24h
price change was missing, and closing positions threw "BTC is not
tradeable asset". After closing a position and backgrounding for >20s,
the closed position would reappear on foreground.

**Root causes:**

1. **Duplicate AppState listener race** — `usePerpsConnectionLifecycle`
hook and `PerpsConnectionManager.setupStateMonitoring()` both fired on
foreground. The `force` reconnect path cancelled the hook's in-flight
`connect()` and ran a competing `performReconnection()`, cleaning up
prewarm subscriptions mid-flight and leaving positions/prices without
data.

2. **Stale cache after grace-period disconnect** —
`performActualDisconnection()` (fires after 20s grace period) did not
clear stream channel caches or reset subscriber state
(`hasReceivedFirstUpdate`). On next foreground, the old closed position
was served from cache until the throttle window passed.

3. **`isPreloading` not reset on disconnect** — If a preload was
in-flight when the grace period fired, `isPreloading` stayed `true`. The
next `connect()` would silently skip all subscription prewarm, leaving
positions and prices with no data.

**Fixes:**
- Remove the manager-level AppState listener (hook already handles
foreground recovery)
- Fix `isInternetReachable` null handling in NetInfo listener (`null`
treated as offline was blocking network-restore reconnects)
- Add `isPreloading` concurrency guard to `preloadSubscriptions()` to
prevent concurrent calls racing on reconnect
- Call `clearCache()` on all stream channels in
`performActualDisconnection()` — wipes stale positions, resets
`hasReceivedFirstUpdate`, puts UI into loading state on next foreground
- Reset `isPreloading = false` in `performActualDisconnection()`
alongside `hasPreloaded`

The NetInfo listener from #26780 is kept — it handles the distinct
offline→online restore scenario.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: TAT-2598

## **Manual testing steps**

```gherkin
Feature: Perps reconnection after long background

  Scenario: user returns to Perps after long background
    Given the user has open Perps positions
    And the app has been backgrounded for 5+ minutes

    When user foregrounds the app
    Then positions load correctly
    And 24h price change is displayed
    And closing a position succeeds without "not tradeable asset" error

  Scenario: closed position does not reappear after background
    Given the user closes a Perps position and sees the success toast
    And the app has been backgrounded for more than 20 seconds

    When user foregrounds the app
    Then the closed position is NOT shown in the positions list
    And no stale "already closed" error appears on interaction

  Scenario: user returns after network loss
    Given the user has open Perps positions
    And airplane mode was enabled then disabled while app was backgrounded

    When user foregrounds the app
    Then the connection is restored
    And positions load correctly
```

## **Screenshots/Recordings**

### **Before**

Positions blank, 24h change missing, close position fails with "BTC is
not tradeable asset". Closed positions reappear after >20s background.

### **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 Perps connection lifecycle (reconnect/disconnect, NetInfo
handling, preload guards) and could impact data freshness and
reconnection reliability if regressions occur, though changes are
localized and well-covered by tests.
> 
> **Overview**
> Prevents a foreground reconnection race by **removing the
manager-level `AppState` listener** so only the lifecycle hook initiates
foreground recovery.
> 
> Hardens reconnect/disconnect behavior by **clearing all Perps stream
channel caches on grace-period expiry**, resetting subscriber
`hasReceivedFirstUpdate`, and resetting the in-flight preload state
(`isPreloading`) so subsequent `connect()` calls reliably prewarm
subscriptions.
> 
> Improves offline→online recovery by treating
`NetInfo.isInternetReachable: null` as “unknown” and falling back to
`isConnected`, and expands `PerpsConnectionManager` tests to cover these
concurrency, cache-clearing, and network edge cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
72739b2. 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**

**Reason:** The network details header always showed a trash/delete icon
when editing a network, including for networks that cannot be removed
(e.g. Ethereum mainnet, Linea, Goerli, testnets). That suggested
deletion was possible when it wasn’t.
**Solution:** Introduced canDeleteNetwork(chainId) in app/util/networks
(aligned with NetworkSelector: mainnet, Linea, Goerli, and testnets are
non-deletable). The header delete control is only rendered when
!formHook.form.addMode && canDeleteNetwork(formHook.form.chainId ?? ''),
so the trash icon is hidden for non-deletable networks.

## **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 network details screen showing a delete (trash)
icon for networks that cannot be removed (e.g. Ethereum mainnet, Linea,
Goerli, testnets).

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Network details – delete icon visibility

  Scenario: user opens network details for a non-deletable network
    Given the user has network management enabled and is on the networks list
    When the user taps "Ethereum Mainnet" (or Linea / Goerli / a testnet)
    Then the header does not show a trash/delete icon

  Scenario: user opens network details for a deletable custom network
    Given the user has added a custom network (e.g. Polygon or a custom RPC)
    When the user taps that network to edit it
    Then the header shows the trash/delete icon and delete remains available
```

## **Screenshots/Recordings**

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

### **Before**
<img width="396" height="844" alt="Screenshot 2026-03-04 at 12 53 36"
src="https://github.com/user-attachments/assets/6c3efda6-d8c4-430a-98e4-e6730027383b"
/>
<img width="391" height="842" alt="Screenshot 2026-03-04 at 12 53 53"
src="https://github.com/user-attachments/assets/c9876c13-a0b1-4d14-87b1-94b9d172a459"
/>
<img width="397" height="834" alt="Screenshot 2026-03-04 at 12 54 09"
src="https://github.com/user-attachments/assets/12466e41-4991-40ad-9b50-9022e158914e"
/>

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

### **After**
<img width="391" height="841" alt="Screenshot 2026-03-04 at 12 49 51"
src="https://github.com/user-attachments/assets/852a4cd4-ba36-4b9c-b47b-ccea5e5185c9"
/>
<img width="395" height="839" alt="Screenshot 2026-03-04 at 12 50 26"
src="https://github.com/user-attachments/assets/5534268b-8f90-4327-90a2-64147e53ae46"
/>
<img width="390" height="841" alt="Screenshot 2026-03-04 at 12 50 34"
src="https://github.com/user-attachments/assets/fa93f229-3064-4630-9d1d-32ec8c540b73"
/>

<!-- [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 gating change: it only conditionally hides the delete icon
based on chain ID and adds unit coverage; core deletion flow is
unchanged.
> 
> **Overview**
> Fixes the Network Details header to **only show the trash/delete icon
for deletable networks** by introducing `canDeleteNetwork(chainId)` and
using it to gate the header end accessory (e.g., hides delete for
Ethereum mainnet, Linea mainnet, and testnets).
> 
> Adds unit tests for `canDeleteNetwork` and a UI test ensuring the
trash icon is not rendered when editing a non-deletable network.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9852c50. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

- bumps `@metamask-assets-controllers` to `^100.1.0`
- removes patch (fixed in 100.1.0)

<!--
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: feat: bump `@metamask-assets-controllers` to `^100.1.0`

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2857

## **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**
> Upgrades a core controller package and pulls in newer transitive
controller versions (notably `@metamask/transaction-controller` and
`@metamask/network-enablement-controller`), which can affect
balance/asset and network behavior at runtime.
> 
> **Overview**
> Updates `@metamask/assets-controllers` from a locally patched
`100.0.3` to the upstream `^100.1.0` package, and deletes the
corresponding `.yarn/patches/...assets-controllers...patch` file.
> 
> Refreshes `yarn.lock` to resolve the new release and its transitive
dependency bumps (including `@metamask/network-enablement-controller`
`4.2.0` and `@metamask/transaction-controller` `62.20.0`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0cc5d53. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…lures (#26977)

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

  `SmokeTrade: Swap from Actions` was failing in CI with:

Error: Aborted at IncomingMessage.failWithAbortError
(node_modules/mockttp/src/u...)

  Two compounding issues:

1. **Wrong endpoint mocked.** The bridge controller uses
`getQuoteStream` (SSE) for all quote requests, not `getQuote`.
The existing mock patterns (`/getQuote.*slippage=.*/`) happened to
substring-match `getQuoteStream` for requests *with* a
slippage param, but the **initial render request** (fired before
`useInitialSlippage` dispatches the first slippage
value) has no `slippage=` param and matched no rule. It fell through to
`handleDirectFetch` → real network call to
  `bridge.api.cx.metamask.io` in CI.

2. **Wrong response format.** Even when a mock matched, it returned raw
JSON (`[{...}]`). The bridge controller's
`fetchServerEvents` SSE parser only calls `onMessage` for lines prefixed
with `data:` — raw JSON yields zero quotes, so
  `activeQuote` was never set and the confirm button never appeared.

The combination caused: real API call in flight → bridge controller
fires `AbortController.abort()` on the next param
change → TCP connection dropped → mockttp throws `Error: Aborted` from
its callback chain — bypassing the existing
`_installAbortFilter` (which only catches `unhandledRejection`, not
errors propagating through the callback chain).

  ## Changes

  **`tests/helpers/swap/constants.ts`**
- Added `toSSEResponse()` helper that wraps quote fixture arrays into
SSE format (`data: {...}\n\n` per quote)

  **`tests/helpers/swap/swap-mocks.ts`**
  - Changed all mock URL patterns from `getQuote` → `getQuoteStream`
- Wrapped all quote fixture responses in `toSSEResponse()` so the SSE
parser receives and dispatches quotes correctly
- Added a priority-1 blanket catch-all for any `getQuoteStream` URL as a
safety net for no-slippage initial requests

  **`tests/api-mocking/MockServerE2E.ts`**
- Wrapped both `handleDirectFetch` call sites (the `/proxy` catch-all
and `forUnmatchedRequest`) with a try-catch that
converts `Error: Aborted` to a 499 response, preventing it from
propagating out of the mockttp callback chain
## **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]
> **Low Risk**
> Low risk: changes are isolated to E2E test mocking and mock server
error handling, with no production logic impacted. Main risk is
overly-broad catch-all mocks or `499` masking unexpected abort-related
failures in tests.
> 
> **Overview**
> Fixes flaky swap E2E runs by updating swap quote mocks to match the
bridge-controller’s SSE `getQuoteStream` endpoint and returning
SSE-formatted quote data via a new `toSSEResponse` helper.
> 
> Adds low-priority catch-all mocks for both `getQuoteStream` (SSE) and
`/getQuote?` (JSON fallback) to prevent accidental live-network
fallthrough, and hardens `MockServerE2E` forwarding so `Error: Aborted`
from dropped client connections is converted into a benign `499`
response instead of failing the test harness.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ed9c27d. 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**

Fixes several cashback-related issues in the Card feature: hides the
cashback option for US users, shows a differentiated cashback rate for
Metal Card holders, navigates back after a successful withdrawal, and
applies minor UI polish.

**Why**: US users should not see the cashback option. Metal Card holders
earn a higher cashback rate (3%) that was not reflected in the UI. After
a successful cashback withdrawal, users remained on the Cashback screen
with no clear dismissal path.

**What changed**:
- **`CardHome.tsx`**: Added `userLocation !== 'us'` guard so the
cashback list item is hidden for US users. Updated the cashback
description to show "Earn 3% back on all spending" when
`cardDetails.type` is `METAL`, falling back to the existing 1%
description otherwise.
- **`Cashback.tsx`**: Added `useNavigation().goBack()` call after a
successful withdrawal (when `monitoringStatus === 'success'`), so the
user is automatically returned to the Card home screen. Migrated
`Skeleton` import to `@metamask/design-system-react-native`. Changed
background color tokens from `bg-background-alternative` to
`bg-background-muted` for the error and details cards.
- **`en.json`**: Added `cashback_description_metal` translation key
("Earn 3% back on all spending").
- **`CardHome.test.tsx`**: Added 7 tests covering cashback item
visibility (international vs US, authenticated vs not, verified KYC vs
pending), description text for virtual vs metal card, and
navigation/analytics on press.
- **`Cashback.test.tsx`**: Added `useNavigation` mock and 3 tests
verifying `goBack` is called on success and not called on failure or
idle status.

## **Changelog**

CHANGELOG entry: Hide cashback option for US users on Card home screen.
CHANGELOG entry: Show "Earn 3% back" cashback description for Metal Card
holders.
CHANGELOG entry: Automatically navigate back after successful cashback
withdrawal.
CHANGELOG entry: Update Cashback screen background tokens to
`bg-background-muted`.
CHANGELOG entry: Add comprehensive test coverage for cashback
visibility, description, and navigation behavior.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Cashback visibility by region

  Scenario: Cashback item hidden for US users
    Given the user is authenticated with verified KYC
    And the user location is "us"
    When the Card home screen renders
    Then the Cashback list item is not visible

  Scenario: Cashback item visible for non-US users
    Given the user is authenticated with verified KYC
    And the user location is not "us"
    When the Card home screen renders
    Then the Cashback list item is visible

Feature: Cashback description by card type

  Scenario: Standard cashback description for virtual card
    Given the user has a virtual card
    And the user is a non-US authenticated user with verified KYC
    When the Card home screen renders
    Then the cashback description reads "Earn 1% back on all spending"

  Scenario: Metal cashback description for metal card
    Given the user has a metal card
    And the user is a non-US authenticated user with verified KYC
    When the Card home screen renders
    Then the cashback description reads "Earn 3% back on all spending"

Feature: Navigate back after successful withdrawal

  Scenario: User is returned to Card home after successful withdrawal
    Given the user is on the Cashback screen with a withdrawable balance
    When the user taps Withdraw and the withdrawal succeeds
    Then a success toast is shown
    And the user is navigated back to the Card home screen
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots or recordings -->

### **Before**

<!-- Cashback item was visible for US users; description always showed
1%; user stayed on Cashback screen after successful withdrawal -->

### **After**

<!-- Cashback item hidden for US users; Metal Card users see "Earn 3%
back"; user auto-navigates back after successful withdrawal -->

## **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**
> Updates Card home eligibility/visibility rules and adds an automatic
navigation side effect after cashback withdrawal success, which could
change what actions users can access and when they’re redirected. Scope
is limited to card UI/UX and copy, with added test coverage to reduce
regression risk.
> 
> **Overview**
> **Cashback visibility and copy is updated on Card home.** The cashback
list item is now hidden for `userLocation === 'us'`, and its description
switches to a new Metal-specific string when `cardDetails.type ===
CardType.METAL`.
> 
> **Cashback withdrawal UX is tightened.** On `monitoringStatus ===
'success'`, the Cashback screen now shows the success toast *and*
navigates back via `goBack()`, plus minor UI polish (design-system
`Skeleton` import and background token change to `bg-background-muted`).
Tests are expanded in `CardHome.test.tsx` and `Cashback.test.tsx`, and
`en.json` adds `cashback_description_metal`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ddd5192. 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**

Fix metrics parameter `gas_paid_with` for MMPay transactions.

## **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: MetaMask/MetaMask-planning#6994

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**
NA

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk metrics-only change: updates how
`gas_paid_with`/native-balance checks are derived for MM Pay
transactions and adds a focused unit test to prevent regressions.
> 
> **Overview**
> Fixes gas metrics derivation for **MM Pay** transactions by preferring
`transactionMeta.metamaskPay.tokenAddress`/`chainId` over
`selectedGasFeeToken`/`chainId` when computing `gas_paid_with` and
`gas_insufficient_native_asset`.
> 
> Adds a unit test ensuring `gas_paid_with` resolves to the symbol for
the MM Pay token even when `selectedGasFeeToken` differs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b4fe282. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

When the homepage was redesigned from tabs to sections, the `detectNfts`
call that ran when the NFTs tab was visited was lost. This PR ports over
the missing behavior by using `useFocusEffect` in `NFTsSection` to
trigger `detectNfts` (via the existing `useNftDetection` hook) whenever
the Homepage screen gains focus. Detection is aborted on blur/unmount
via the effect's cleanup function.

## **Changelog**

CHANGELOG entry: Fixed missing NFT detection on homepage focus,
restoring auto-detection when the user navigates to the homepage

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: NFT detection on homepage focus

  Scenario: user navigates to homepage and NFTs are detected
    Given user has NFT-owning accounts configured
    And the homepage is not currently focused

    When user navigates to the homepage
    Then NFT detection is triggered automatically for configured chains

  Scenario: user navigates away from homepage and detection is aborted
    Given user is on the homepage and NFT detection is in progress

    When user navigates away from the homepage
    Then the in-flight NFT detection is aborted
```

## **Screenshots/Recordings**

N/A — no UI changes, behavioral fix only.

### **Before**

NFT detection was not triggered when navigating to the homepage.

### **After**

NFT detection runs on homepage focus and is aborted on blur.

## **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 focus-driven side effects that start/cancel NFT detection, which
can impact network activity and loading UI timing when navigating
between screens.
> 
> **Overview**
> Restores missing NFT auto-detection on the redesigned Homepage by
running `useNftDetection().detectNfts()` from `NFTsSection` via
`useFocusEffect`, and cancelling via `abortDetection()` on blur/unmount.
> 
> Adjusts loading UI to avoid showing the skeleton during *silent*
re-detection after the first successful load, and adds/updates tests to
mock `useFocusEffect` and assert detection/abort behavior (including
rejected detection).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
500bdab. 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**

Bump `snaps-controllers` to the latest version which includes a
mitigation for production issues where the source code of Snaps is
unavailable.

## **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 an issue with running Snaps

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Updates a core Snaps dependency used at runtime; even a patch bump can
affect Snap execution/permissions and should be regression-tested with
common Snaps flows.
> 
> **Overview**
> Bumps `@metamask/snaps-controllers` from `^18.0.1` to `^18.0.2` (with
corresponding `yarn.lock` updates) to pick up the latest fixes.
> 
> Includes a small transitive dependency update within that package
(notably `@metamask/json-rpc-engine` to `^10.2.3`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
67b823f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…throws correctly cp-7.67.2 (#26979)

<!--
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 adjusts our existing patch for
`redux-persist-filesystem-storage` to always return a promise for
`setItem` so it can be awaited correctly, fixing potential race
conditions. This was broken when the patch originally was created by
adding brackets to an arrow function and not returning. The PR also
fixes a bug where not passing in a callback would cause errors to be
swallowed. Additionally, this PR moves our existing patch to use the
built-in Yarn patch feature (because creating new patches with
`patch-package` seems broken).

## **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: Improve reliability of persistence

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches persistence write behavior by changing the patched
`redux-persist-filesystem-storage` `setItem` control flow and error
propagation, which could affect app startup/migrations if any callers
depend on the old callback-only semantics. Also introduces an iOS-only
side effect (exclude-from-backup) after writes.
> 
> **Overview**
> This PR updates the Yarn patch for `redux-persist-filesystem-storage`
so `setItem` **always returns a Promise** that can be awaited, rather
than potentially relying on callback chaining.
> 
> It also fixes error handling so write failures are **thrown when no
callback is provided** (instead of being swallowed), and adds an
optional `isIOS` flag to run
`ReactNativeBlobUtil.ios.excludeFromBackupKey(...)` after successful
writes on iOS.
> 
> Dependency wiring is switched from a normal semver dependency to
Yarn’s built-in `patch:` reference for
`redux-persist-filesystem-storage@4.2.0`, with corresponding `yarn.lock`
updates.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
192a5c8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

The error message shown when a user has insufficient native token (e.g.
POL) to cover gas fees during a **Predict Withdraw** was misleading. It
suggested switching to a token on another network as a recovery option —
which is valid for deposits but not for withdrawals, where the source
funds come from the withdrawal transaction itself.

This PR introduces a dedicated copy key for post-quote (withdrawal)
flows that omits the network-switch hint, and wires it up in the alert
hook.

## **Changelog**

CHANGELOG entry: Fixed incorrect error message shown when there is not
enough native token to cover gas fees during a withdrawal.

## **Related issues**

Fixes: #26926

## **Manual testing steps**

```gherkin
Feature: Insufficient native token error message on Predict Withdraw

  Scenario: user sees correct error message when POL balance is too low to cover gas on withdrawal
    Given the user has a Predict account with a balance
    And the user has no POL (or insufficient POL) on their EOA
    When the user navigates to Withdraw and enters an amount
    Then the error message reads "Not enough POL to cover fees. Add POL to continue."
    And the message does NOT mention "Use a token on another network"

  Scenario: deposit flow still shows the full error message
    Given the user has insufficient native token to cover gas on a deposit
    When the user reviews the deposit confirmation
    Then the error message reads "Not enough <ticker> to cover fees. Use a token on another network or add more <ticker> to continue."
```

## **Screenshots/Recordings**

### **Before**

> Not enough POL to cover fees. Use a token on another network or add
POL to continue.

### **After**

> Not enough POL to cover fees. Add POL to continue.
<img width="444" height="907" alt="image"
src="https://github.com/user-attachments/assets/b7f60f4e-6115-45ee-9629-eb1045a1a679"
/>


## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: this only changes which i18n string is used for an existing
blocking alert, plus adds test coverage; no transaction logic or state
mutations are altered.
> 
> **Overview**
> Updates the insufficient native-token gas-fee alert copy for
*post-quote (withdrawal)* flows to remove the misleading “switch
network” hint.
> 
> Adds a new i18n key
`alert_system.insufficient_pay_token_native_post_quote.message` and
switches `useInsufficientPayTokenBalanceAlert` to choose between the
standard vs. post-quote message based on `isPostQuote`, with tests
updated to assert both behaviors.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
df4ee3a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com>
## **Description**

Bumps `@metamask/ramps-controller` from the preview version
(`10.0.0-preview-225638478`) to the stable release `^10.2.0`. This also
removes the preview registry override that was previously set in the
`resolutions` field of `package.json`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Ramps controller upgrade

  Scenario: user accesses buy/sell ramps flow
    Given the app is installed and the user is logged in

    When user navigates to the buy or sell flow
    Then the ramps flow loads correctly with no regression
```

## **Screenshots/Recordings**

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

1. **Reason**: When using Cursor's worktree feature to run agents in
separate checkouts, each worktree needs the same env files and plan
files as the main repo so that install/build and agent context work
correctly.
2. **Solution**:
  - Add `.cursor/worktrees.json` so that when Cursor creates a worktree
- Add setup commands that copy `.js.env`, `.ios.env`, `.android.env`,
`.e2e.env`, and `.cursor/plans` (recursively as it's a folder) from the
root repos into the new worktree.

## **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: N/A

## **Manual testing steps**

```gherkin
Feature: Cursor worktree setup

  Scenario: worktree is created with env and plans copied
    Given the repo has .cursor/worktrees.json configured

    When dev creates a new agent tab using "worktree" agent location
    And Cursor creates a new worktree
    Then .js.env, .ios.env, .android.env, .e2e.env and .cursor/plans (and content) exist in the worktree
```

## **Screenshots/Recordings**

The worktree menu available when creating a new local chat agent:
<img width="266" height="274" alt="image"
src="https://github.com/user-attachments/assets/67e7c406-b6f4-4220-aaf3-4f00ec1ba98b"
/>

## **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 developer-experience change that only adds a Cursor
configuration file and does not affect runtime app behavior. Main risk
is overwriting local env/plan files in worktrees if users have
customized them.
> 
> **Overview**
> Adds `.cursor/worktrees.json` to configure Cursor’s *worktree* setup
so new worktrees automatically copy `.js.env`, `.ios.env`,
`.android.env`, `.e2e.env`, and `.cursor/plans` from the root worktree
into the new checkout.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
85347a6. 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**
revert of #25793 (only
the part where sourcemaps are not uploaded to bitrise)
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

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

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

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

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes CI build artifacts and iOS bundling script paths; risk is
mainly build/pipeline breakage or missing sourcemaps if paths/envs
differ across workflows.
> 
> **Overview**
> Restores/introduces Bitrise deployment of React Native sourcemaps for
**Android** and **iOS** builds so they’re available as CI artifacts (and
can be used for profiling/debugging).
> 
> On iOS, updates `scripts/ios/bundle-js-and-sentry-upload.sh` to write
the JS sourcemap to a stable absolute path under
`sourcemaps/ios/index.js.map` (anchored at repo root) to avoid
CWD-related path mismatches during Sentry upload, and adds a Bitrise
step to deploy that file via `BITRISE_APP_STORE_SOURCEMAP_PATH`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f39ba21. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Mar 4, 2026
@pull pull Bot added the ⤵️ pull label Mar 4, 2026
@pull pull Bot merged commit 2f8713e into Reality2byte:main Mar 4, 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.