Skip to content

[pull] main from MetaMask:main#636

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

[pull] main from MetaMask:main#636
pull[bot] merged 16 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 27, 2026

See Commits and Changes for more details.


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

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

jpuri and others added 16 commits March 27, 2026 11:33
…27862)

<!--
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 time calculation for metrics `mm_pay_time_to_complete_s`. Replace
the use of submittedTime in current transaction to latest submitted time
of child 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: https://consensyssoftware.atlassian.net/browse/CONF-1086

## **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]
> **Medium Risk**
> Changes MetaMask Pay analytics attribution logic (parent/child
relationships and completion time calculation), which can affect
reporting correctness across multi-transaction flows. Risk is moderate
due to reliance on `requiredTransactionIds` (removing `batchId`/nonce
ordering) and updated tests covering new behavior.
> 
> **Overview**
> Fixes `mm_pay_time_to_complete_s` to avoid under-reporting by
computing completion time from the **latest `submittedTime` among a
parent MM Pay transaction’s `requiredTransactionIds`**, instead of using
the current transaction’s `submittedTime`.
> 
> Simplifies transaction linkage and step calculation by **dropping
`batchId`/nonce-based grouping** and relying solely on
`requiredTransactionIds` to find parents and order steps; updates unit
tests accordingly (including asserting the metric is *not* emitted for
finalized child transactions).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
22bbd5c. 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**

https://consensyssoftware.atlassian.net/browse/RWDS-1109

## **Changelog**

CHANGELOG entry: prevent ondo campaign opt in based on cut off date

## **Screenshots/Recordings**

<img width="929" height="1957" alt="image"
src="https://github.com/user-attachments/assets/6310d2fe-12d4-43f5-92a9-257ed1d4c2c2"
/>


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes opt-in eligibility and leaderboard rendering based on a new
`depositCutoffDate`, which can affect user ability to join campaigns and
what data is fetched/rendered. Risk is moderate due to time-based logic
and UI state/loading interactions, but scoped to Rewards campaign
details.
> 
> **Overview**
> Adds `depositCutoffDate` support for `ONDO_HOLDING` campaigns and
introduces `isOptinAllowed` to centralize the time-based opt-in gating.
> 
> Updates `OndoCampaignDetailsView` and `CampaignJoinCTA` to **hide the
join CTA once entries close**, show a new dismissible
`CampaignEntriesClosedBanner`, and treat *active-but-closed* campaigns
similar to completed campaigns for leaderboard fetching/rendering (with
a skeleton while participant status loads).
> 
> Extends types and i18n strings for the new cutoff field and banner
text, and adds/updates unit tests to cover cutoff, banner visibility,
and loading behaviors.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
94596b3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Rik Van Gulck <vangulckrik@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
nock already has great types built in, we should not be overriding the
limiting the type inference from nock with our own definitions file.

<!--
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: refactor: remove nock definition file

## **Related issues**

Fixes: from a DX perspective, the definitions override is incredibly
limiting which prevents us from fully utilising the nock API

## **Manual testing steps**

```gherkin
Feature: my feature name

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

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

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because this only removes a test-only TypeScript declaration
override and relies on `nock`’s published types; primary risk is minor
compile-time type changes in component-view test mocks.
> 
> **Overview**
> Removes the local `tests/component-view/api-mocking/nock.d.ts` module
declaration that was overriding `nock` typings, so component-view API
mock helpers now use `nock`’s upstream TypeScript definitions and
benefit from full type inference.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9bd94b4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…rt (#28026)

## **Description**

Adds `TransactionType.perpsWithdraw` support across the activity list,
transaction details, analytics, metrics, and notifications — mirroring
the existing patterns for `predictWithdraw` and `perpsDeposit`.

This is the first of two PRs for Perps Withdraw. It makes the app
correctly display, label, and handle `perpsWithdraw` transactions
without any changes to the confirmation flow. All additions are to
existing arrays/switch statements and are dormant until the transaction
type is actually used.

## **Changelog**

CHANGELOG entry: Add Perps Withdraw transaction display and activity
support

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1112

## **Manual testing steps**

```gherkin
Feature: Perps Withdraw transaction display

  Scenario: user views a completed perpsWithdraw transaction in Activity
    Given the user has a completed perpsWithdraw transaction

    When user opens the Activity tab
    Then the transaction displays as "Perps withdraw" with the correct fiat value

  Scenario: user views perpsWithdraw transaction details
    Given the user has a completed perpsWithdraw transaction

    When user taps the transaction in the Activity list
    Then the transaction details page shows "Withdrawal" as the title
    And the fee row shows "Provider fee" instead of "Bridge fee"
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Mostly additive wiring for a new `TransactionType.perpsWithdraw`, but
it touches shared transaction decoding, metrics/analytics
classification, and notification-suppression lists which could affect
reporting or user-visible notifications if misclassified.
> 
> **Overview**
> Adds end-to-end display support for `TransactionType.perpsWithdraw` in
Activity and the new Transaction Details screen, including correct
titles, network badge chain selection, totals/fee labeling (using
*Provider fee* for withdrawals), and post-quote `metamaskPay.targetFiat`
amount display.
> 
> Extends transaction action-key mapping/decoding, analytics
monetization classification, MetaMetrics transaction-type values,
MetaMask Pay metrics handling, and the notification skip list to
recognize `perpsWithdraw`, with corresponding unit tests and new i18n
strings (e.g., `tx_review_perps_withdraw`,
`transaction_details.title.perps_withdraw`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7750ce7. 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**
User change biometric ( add / remove fingerprint) Metamask wallet not
able to detect and handle it properly
[TO-454]



<!--
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: Alert User on biometric changed

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Detect Biometric Changed

  Scenario: user create MM wallet with biometric enabled
    Given User create MM wallet with biometric enabled

    When user remove 1 of N fingerprint / change faceId from system ( fingerprint/face)
    Then MM should Alert user that biometric changed and previous biometric become invalid
```

## **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/94987fd0-2aa6-4572-8e0b-b4ffe4b5ae9b



### **After**

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




https://github.com/user-attachments/assets/aabb6c25-ff42-41ba-aaba-f8f26960c464



## **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 unlock and credential-reset flows: mis-detection could
incorrectly reset local auth settings or interrupt login, though changes
are scoped and covered by new unit tests.
> 
> **Overview**
> Adds handling for the Android "biometrics changed" failure case during
`Authentication.unlockWallet`: when the thrown `Error.message` contains
`USER_NOT_AUTHENTICATED`, the app shows a non-cancelable alert and then
locks the app with `reset: true` to clear stored credentials.
> 
> Refactors auth cleanup by centralizing removal of legacy auth storage
flags and remember-me state into `clearAuthStorageFlags`, reusing it
from both `storePassword` and `resetPassword`, and ensuring
`resetPassword` also disables OS auth in Redux.
> 
> Updates constants and strings to include
`UNLOCK_WALLET_ERROR_MESSAGES.USER_NOT_AUTHENTICATED` plus new
`login.biometric_changed*` i18n keys, and extends tests to cover the new
reset behavior and alert/lock paths.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
288036e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->







[TO-454]:
https://consensyssoftware.atlassian.net/browse/TO-454?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!--
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 analytics and marketing-consent for seedless / social
(OAuth) onboarding
<!--
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: Improved analytics consistency during social login
onboarding.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

Scenario: Social new user completes password and reaches success
    Given seedless / social onboarding is enabled
    And the user signs in with Google or Apple as a new user
    When the user sets a password on Choose Password and submits
    Then the app navigates to onboarding success
    And marketing preference is sent to the auth API according to the checkbox
    And analytics receives preference for marketing consent.

```

## **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**
> Adds new analytics tracking and user-trait updates in the OAuth
onboarding success path, including an awaited call that could impact
timing or failure behavior before navigation.
> 
> **Overview**
> Adds explicit MetaMetrics instrumentation for *seedless/social (OAuth)
onboarding* on the `ChoosePassword` success path: emits
`ANALYTICS_PREFERENCE_SELECTED` with marketing-consent + `account_type`
(derived from the OAuth `provider`) and updates the user profile via
`addTraitsToUser` with device/user settings metadata and configured
chain IDs.
> 
> Updates `ChoosePassword` tests to mock the expanded analytics API
(`identify`, `addTraitsToUser`, event builder output), pass `provider`
in OAuth route params, and assert the new tracking/trait calls occur
when completing OAuth wallet creation.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
24d270a. 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**

Update transaction controller to fix possible sentry issue
https://consensyssoftware.atlassian.net/browse/CONF-1086.

## **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: https://consensyssoftware.atlassian.net/browse/CONF-1086

## **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]
> **Medium Risk**
> Dependency-only change, but it updates the core transaction controller
package, which can affect transaction lifecycle/telemetry behavior and
should be validated via regression testing.
> 
> **Overview**
> Updates the `@metamask/transaction-controller` dependency from
`^63.1.0` to `^63.3.0`.
> 
> Refreshes `yarn.lock` to resolve the new controller version and its
updated transitive dependency set/checksums.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
34d36f6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…le loading (#28033)

## **Description**

Shows a success toast ("You're in!") after a user successfully opts into
a campaign via `CampaignOptInSheet`. Also hides the Join Campaign CTA
entirely while participant status is loading (previously it rendered a
disabled/loading button), and removes the skeleton loader from
`OndoCampaignDetailsView` during that loading phase.

Jira:
[RWDS-1101](https://consensyssoftware.atlassian.net/browse/RWDS-1101)

## **Changelog**

CHANGELOG entry: Added a success confirmation toast when users opt in to
a rewards campaign.

## **Related issues**

Fixes:
[RWDS-1101](https://consensyssoftware.atlassian.net/browse/RWDS-1101)

## **Screenshots/Recordings**

<img width="750" height="408" alt="image"
src="https://github.com/user-attachments/assets/0fddb8ea-3ec2-4a39-a278-c6b371e9fb95"
/>



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI/UX behavior changes around opt-in feedback and CTA
visibility, with minor logging/empty-state tweaks; main risk is
unintended hiding of the join CTA during slow participant-status
fetches.
> 
> **Overview**
> Adds a success confirmation toast ("You're in!") after a campaign
opt-in completes successfully in `CampaignOptInSheet`, only closing the
sheet when the API reports `optedIn: true`.
> 
> Updates the campaign details/join flow to **hide** the "Join Campaign"
CTA while participant status is loading (and removes the
loading/skeleton CTA handling), with tests updated to reflect the new
visibility rules.
> 
> Treats an Ondo portfolio with **zero positions** as an empty state
(showing the empty banner instead of the container) and adds error
logging when portfolio fetch fails; includes the new
`rewards.campaign.opt_in_success_toast` i18n string.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ee88724. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: sophieqgu <sophieqgu@gmail.com>
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?
-->

This PR makes the custom slippage modal cursor-aware. It adds a
dedicated slippage cursor hook that reuses the shared raw cursor editing
utilities, wires controlled `selection` / `onSelectionChange` through
`InputStepper`, preserves the existing slippage-specific max and decimal
validation rules, resets cursor state when the stepper buttons change
the value, and sanitizes trailing decimals such as `2.` before saving
the selected slippage.

## **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 custom slippage input so keypad edits respect
cursor placement and trailing decimals are sanitized before saving.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: custom slippage cursor-aware editing

  Scenario: user inserts a digit at a chosen cursor position
    Given the user opens Bridge and opens the custom slippage modal
    And the custom slippage value is "12.5"

    When the user places the caret between "1" and "2"
    And the user taps "5" on the keypad
    Then the displayed custom slippage value updates to "152.5"

  Scenario: user resets the cursor by using the stepper buttons
    Given the user opens Bridge and opens the custom slippage modal
    And the user places the caret in the middle of the custom slippage value

    When the user taps the "+" stepper button
    And the user taps "5" on the keypad
    Then the next keypad edit follows the new stepper-updated value instead of the old caret position

  Scenario: user confirms a value with a trailing decimal
    Given the user opens Bridge and opens the custom slippage modal
    And the custom slippage value is "2."

    When the user taps "Confirm"
    Then the saved slippage value is "2"
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches user input/editing logic in the Bridge slippage flow (cursor
mapping + keypad handling), which can introduce subtle edge-case
regressions, but scope is localized and covered by new tests.
> 
> **Overview**
> Makes the Bridge `CustomSlippageModal` cursor-aware by introducing
`useCustomSlippageCursor`, which tracks and maps selection between
formatted and raw values and applies keypad edits at the current caret
position (while preserving max/decimal validation and over-max
flagging).
> 
> Extends `InputStepper` to accept controlled
`selection`/`onSelectionChange`, wires these through the slippage modal,
resets cursor state when +/- stepper buttons adjust the value, and
sanitizes trailing decimals (e.g., `2.` -> `2`) before dispatching
`setSlippage`. Tests are updated/added to cover cursor
insertion/backspace behavior, trailing-decimal sanitization, and the new
selection plumbing.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b963576. 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?
-->

This adds a verified trust signal to the swap/bridge asset picker when
the backend returns `isVerified` on popular and search token results.
The change threads the new field through the bridge token models,
preserves it during token-to-balance merging, renders the verified badge
inline in picker rows, and adds focused coverage for popular tokens,
search results, and row rendering.

## **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 verified badges to swap asset picker tokens

## **Related issues**

Fixes:
Refs: SWAPS-4219

## **Manual testing steps**

```gherkin
Feature: Swap asset picker verified trust signals

  Background:
    Given I am logged into MetaMask Mobile
    And I can open the swap or bridge asset picker

  Scenario: user sees a verified badge for a popular token
    Given the popular token response includes a token with isVerified set to true

    When user opens the source or destination asset picker
    Then the verified token should display a verified badge in its list row
    And tokens without isVerified should not display the badge

  Scenario: user sees a verified badge for a searched token
    Given the search token response includes a token with isVerified set to true

    When user searches for that token in the asset picker
    Then the search result should display a verified badge in its list row
    And the token should remain selectable as usual
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI/model threading of a new optional `isVerified` flag; main
risk is minor layout/test regressions in the token picker row rendering.
> 
> **Overview**
> Adds support for an optional `isVerified` trust signal on Bridge API
token results and threads it into the in-app `BridgeToken` model.
> 
> Updates the token picker row (`TokenSelectorItem`) to render a small
verified icon next to the token symbol when `token.isVerified` is true,
and extends unit tests/fixtures to assert the flag is preserved through
popular/search fetching and balance-merging, and is passed through
`BridgeTokenSelector` into row rendering.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
02a4efd. 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?
-->

This fixes
[#27843](#27843),
where opening Swap from a trending token details page could land the
user back on Bridge with the view still scrolled down and the prefilled
form off-screen. The fix adds a minimal `scrollToTopOnNav` route param
for that navigation path and has `BridgeView` consume it once on focus
so token-details Swap entry points return with the swap form visible at
the top.

## **Changelog**

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

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

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

CHANGELOG entry: Fixed a bug that kept the swap screen scrolled down
after opening Swap from a trending token details page.

## **Related issues**

Fixes: #27843

## **Manual testing steps**

```gherkin
Feature: Swap navigation from trending token details

  Scenario: user opens swap from the token details action row
    Given the user is on the Home tab
    And the user opens Swap
    And the user scrolls to the Trending tokens list
    And the user opens a trending token details page
    When the user taps "Swap"
    Then the Bridge view opens with the prefilled swap form visible at the top of the screen

  Scenario: user opens swap from the token details sticky footer
    Given the user is on a trending token details page with the sticky footer visible
    When the user taps the sticky footer swap action
    Then the Bridge view opens with the prefilled swap form visible at the top of the screen
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: adds a one-time navigation flag that triggers a
`ScrollView.scrollTo` on focus and clears itself; scope is limited to
swaps/bridge navigation and related tests.
> 
> **Overview**
> Fixes a navigation UX bug where returning to `BridgeView` from Token
Details (notably trending tokens) could leave the unified swap form
scrolled off-screen.
> 
> This introduces a `scrollToTopOnNav` route param in
`useSwapBridgeNavigation`, has `BridgeView` consume it via
`useFocusEffect` to scroll the main `ScrollView` to `y=0` and then
`setParams` to clear the flag, and updates Token Details swap entry
points (including sticky footer and buy/sell handlers) to request this
behavior. Tests were updated/added to cover the new param propagation
and one-time clearing.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
86c6e2d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Removes the `@metamask/error-reporting-service` package. This service
registered a `ErrorReportingService:captureException` messenger action,
but no controller ever called it. Error reporting is now handled
directly via the built-in `messenger.captureException` method in
`@metamask/messenger`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

```gherkin
Feature: App startup

  Scenario: user opens the app after removing error-reporting-service
    Given the app is built from this branch

    When user launches the app
    Then the app starts without errors
```

## **Screenshots/Recordings**

N/A

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: removes an unused controller/messenger layer and its
dependency, with no functional logic changes beyond no longer
instantiating `ErrorReportingService`. Main risk is any hidden reliance
on the removed messenger namespace/action at runtime.
> 
> **Overview**
> Removes the unused `@metamask/error-reporting-service` integration by
deleting its controller init and messenger wiring, and by dropping
`ErrorReportingService` from Engine controller initialization and
associated type unions.
> 
> Updates dependencies by removing `@metamask/error-reporting-service`
from `package.json` and `yarn.lock`, and deletes the related unit tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f95f656. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…#26537)

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

**Summary**

Replaces the fragile amount-based withdrawal/deposit completion matching
with a deterministic FIFO (First In, First Out) queue approach to
resolve stuck pending withdrawal indicators.

**Problem:** Pending withdrawals could get permanently stuck in the UI
because the old matching logic compared amounts and assets between
pending requests and completed ledger entries. This was unreliable when
multiple withdrawals of the same amount/asset existed, leading to
mismatches or missed completions.

**Solution:** The new approach treats pending transactions as a FIFO
queue. The oldest pending transaction is matched with the first
completed transaction in the user's history that occurred after its
submission time. This eliminates ambiguity and ensures each pending
request is resolved exactly once.

**Changes**

Refactored useWithdrawalRequests hook (useWithdrawalRequests.ts):
Rewrote from scratch to use FIFO matching instead of amount-based
matching.

Replaced `getUserNonFundingLedgerUpdates` with `getUserHistory` API. Now
delegates completion to the controller via
`completeWithdrawalFromHistory `instead of calling
`updateWithdrawalStatus` directly.

Removed `startTime` option (no longer needed -- search window is derived
from oldest pending timestamp).

How FIFO Matching Works
1. Pending deposits/withdrawals are maintained as sorted queues (oldest
first) in PerpsController state.
2. The hook polls getUserHistory to fetch completed transactions from
the API.
3. The oldest pending withdrawal is matched with the first completed
withdrawal in history where:
```
completed.timestamp > pending.timestamp AND completed.timestamp > lastCompletedTimestamp.
```

On match, the controller removes the request from the queue and bumps
lastCompletedTimestamp to prevent the same history entry from being
matched again.

Deposits and withdrawals are tracked independently -- a completed
deposit never clears a pending withdrawal and vice versa.

## **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 stuck pending withdraw

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: FIFO Pending Transaction Queue Matching

  Scenario: user initializes a pending perps withdraw
    Given a user has multiple pending withdrawals of the same amount and asset in the queue
    When the oldest pending withdrawal is completed, the previous gets cleared
    Then this continues until all pending withdraws are complete, and no pending withdraw gets stuck in the queue

```

## **Screenshots/Recordings**

Start Withdraw


https://github.com/user-attachments/assets/f09dafa5-fdc1-4d5e-91a2-d7160a2bbcfd

Mid to End Withdraw


https://github.com/user-attachments/assets/944b45dc-a4e1-4957-8027-ab44b495e4e2


## **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 withdrawal completion flow, controller state, and
persistence/migrations; mistakes could leave pending indicators stuck or
prematurely cleared, especially around polling/history timestamp guards.
> 
> **Overview**
> Refactors perps pending-withdrawal handling to a **FIFO queue model**:
the UI now displays only pending/bridging requests and polls
`getUserHistory` to complete the *oldest* pending item, instead of
amount/asset-based matching.
> 
> Adds FIFO completion guards to `PerpsController`
(`lastCompletedWithdrawalTimestamp` persisted + per-session
`lastCompletedWithdrawalTxHashes`) and a new controller method
`completeWithdrawalFromHistory` that removes the matched request,
updates guards, clears progress when appropriate, and emits completion
analytics.
> 
> Updates withdrawal execution/error handling to **remove** requests
from the queue on direct txHash completion or failure (and record txHash
for de-dupe), introduces migration `128` to clear existing persisted
deposit/withdrawal queues/progress flags, and refreshes/rewrites tests
and mocks accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
aaa4e4f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Nick Gambino <gambinish@users.noreply.github.com>
Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
…t by token support (#27958)

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

Fixed a bug where selecting a provider for some token (e.g. MUSD on
Linea) would instantly show "No payment methods are available" because
the provider's cached `supportedCryptoCurrencies` map was stale and
didn't include the token.

**Root cause:** The providers data (`supportedCryptoCurrencies`) was
persisted across sessions and only refreshed on region change or fresh
install. For tokens added to the backend after the user's last provider
cache update, the map wouldn't include the token, causing the payment
methods query to be disabled and the "Token Not Available" modal to show
— even though the API supports it.

**Evidence from reporter's state logs (v7.71.0 build 4173):**
- MUSD Linea
(`eip155:59144/erc20:0xaca92e438df0b2401ff60da7e4337b687a2435da`) was
`NOT IN MAP` for all 11 providers
- Fresh `/providers` endpoint already includes MUSD Linea for Transak
and Mercuryo
- Providers data was served from stale Redux persist cache

**Fix:**
1. `queries/providers.ts` + `useRampsProviders`: added a react-query
wrapper for `getProviders` with `staleTime: 15min` and `refetchOnMount:
true`. Providers (including `supportedCryptoCurrencies`) are refreshed
when data is stale (>15min) and a component using `useRampsProviders`
mounts (e.g. after password unlock or entering the buy flow). On app
restart, react-query cache is empty so the first mount always fetches
fresh data. The query calls `getProviders(regionCode, { forceRefresh:
true })` to bypass the controller's internal cache.
2. `ProviderSelectionModal`: skip quotes fetch when
`selectedPaymentMethod` is null (prevents API error "Payment methods are
required"), and set `showQuotes=false` so no "No providers available"
error is shown
3. `ProviderSelection`: when quotes are not available, fall back to
separating providers by `supportedCryptoCurrencies` — supported tokens
on top, others under "Other options"

**Companion fix in core:** George's `feat: removes provider and token
persistence in ramps controller`
([#8307](MetaMask/core#8307)) sets `persist:
false` for providers and tokens so stale data won't survive across app
restarts. The react-query refresh complements this by also catching
stale data within long-running sessions.

## **Changelog**

CHANGELOG entry: Fixed payment methods and provider availability for
newly added tokens by refreshing providers via react-query (15min TTL)
on mount and separating the provider list by token support

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Payment methods load for tokens missing from supportedCryptoCurrencies

  Scenario: providers are refreshed when stale on mount
    Given the app has provider data older than 15 minutes
    When the user enters the buy flow or unlocks the app (component mounts)
    Then providers data should be refetched from the API via react-query
    And supportedCryptoCurrencies should be up to date

  Scenario: providers are always fresh after app restart
    Given the user restarts the app (react-query cache is empty)
    When the user enters the password and the app loads
    Then providers data should be fetched fresh from the API
    And supportedCryptoCurrencies should include newly added tokens

  Scenario: user opens change provider when no payment method is selected
    Given user is on the Buy screen with a provider that does not support the selected token
    And no payment method is selected (selectedPaymentMethod is null)

    When user taps "Change provider"
    Then the provider list should show supported providers at the top
    And unsupported providers should appear under "Other options" separator
    And no "No providers available" error should be shown
```

## **Screenshots/Recordings**

### **Before**



https://github.com/user-attachments/assets/0b4ea4fc-9a59-4fe6-a706-da95ec60c3af


### **After**

Payment methods query fires and returns results from the API.



https://github.com/user-attachments/assets/c3081ec5-63d8-460a-996e-3e8dabc90b7c



https://github.com/user-attachments/assets/0ebb7fdc-1d5f-40ce-82c8-4fa7f47ef90f



## **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**
> Medium risk due to new react-query-driven provider refetching and
conditional quote fetching logic that can change network request
patterns and provider ordering in the buy flow.
> 
> **Overview**
> Prevents stale `supportedCryptoCurrencies` from breaking buy flows by
adding a react-query `providers` query (15min `staleTime`,
`refetchOnMount`, `forceRefresh`) and wiring it into `useRampsProviders`
(triggered when `regionCode` is available).
> 
> Tightens “token unavailable” and provider selection behavior:
`BuildQuote` now treats missing entries in `supportedCryptoCurrencies`
as unsupported, `ProviderSelectionModal` skips quote fetching and
disables quote UI when `selectedPaymentMethod` is `null`, and
`ProviderSelection` groups providers into supported vs unsupported (with
an “Other options” separator) when quotes aren’t shown/available.
> 
> Adds/updates unit tests for the new query options, provider grouping,
quote-fetch gating, and the token-unavailable edge case.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
707342f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Pedro Pablo Aste Kompen <wachunei@gmail.com>
## **Description**

Removes static hex color values from tests and replaces them with
theme-aware color lookups.

Why: hardcoded hex values are brittle.
- In production UI, hex literals can drift from the active theme, become
incorrect as the color system evolves, and regress when token/theme
mappings change.
- In tests, hex literals in mocks/assertions can fail just because a
token’s underlying value changed (noise during token upgrades; see PR
#27825).

Goal: no static hex colors anywhere inside app/components/ or
app/component-library/ (including their tests and Storybook stories).

Enforcement:
- ESLint: @metamask/design-tokens/color-no-hex is turned on as error
only for app/components/** and app/component-library/**.
- Cursor rule: .cursor/rules/unit-testing-guidelines.mdc explicitly
calls out “Never hardcode design token hex values” (backed by the eslint
rule).

Notable changes in this PR:
- Tests: update theme mocks to reference mockTheme/design tokens instead
of literals.
- UI: replace a couple of production hex literals with token-backed
values (e.g. SecurityTrustScreen, MarketInsights gradient).

Related: #26639
Related: #27825

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: static hex prevention in tests

  Scenario: tests pass after design token upgrade
    Given the design tokens package is upgraded
    When the test suite runs
    Then tests that check colors should not fail due to hex value changes
```

## **Screenshots/Recordings**

### **Before**

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

### **After**

<img width="813" height="226" alt="Screenshot 2026-03-25 at 10 05 41 PM"
src="https://github.com/user-attachments/assets/e3bdd558-b3f0-4b37-93a7-ae946382d75d"
/>

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: mostly lint configuration and test mock updates, with minor
UI color token substitutions that could slightly change appearance if
token mappings differ.
> 
> **Overview**
> Removes hardcoded hex colors in multiple tests by switching
mocks/props to mockTheme/design-token values, reducing flakiness when
design tokens change; adds a targeted eslint disable for a #12345
token-id false positive.
> 
> Updates UI constants/components to use design tokens instead of hex
literals (e.g., Market Insights gradient border colors and Security
Trust distribution bar/dot). Also tightens linting by enabling
@metamask/design-tokens/color-no-hex as an error across all
app/components and app/component-library while turning the rule off
globally (removing the prior test-only override).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1d8241e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
## Version Bump After Release

This PR bumps the main branch version from 7.72.0 to 7.73.0 after
cutting the release branch.

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

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

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

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

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

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