[pull] main from MetaMask:main#800
Merged
Merged
Conversation
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Pass the resolved ambient price color state (`isPricePositive` and `useAmbientColor`) from the Token Details page through to the Market Insights and Security Trust sub-screens so the Swap/Buy footer buttons consistently match the token details theme color (green when price is up, orange when price is down). Previously, navigating to Market Insights or the Security Trust page would always render the footer buttons in the default green, ignoring the ambient color A/B test treatment active on the parent screen. ## **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 Market Insights and Security Trust page footer buttons not reflecting the ambient price color from the Token Details page ## **Related issues** Fixes: [ASSETS-3307](https://consensyssoftware.atlassian.net/browse/ASSETS-3307) ## **Manual testing steps** ```gherkin Feature: Ambient color consistency across Token Details sub-screens Scenario: Footer buttons match token details color on Market Insights Given the user is on the Token Details page for a token with a negative price change And the ambient price color A/B test is active And the footer buttons are orange When user taps the Market Insights entry card Then the Swap/Buy buttons on the Market Insights page should also be orange Scenario: Footer buttons match token details color on Security Trust Given the user is on the Token Details page for a token with a negative price change And the ambient price color A/B test is active And the footer buttons are orange When user taps the Security Trust entry card Then the Swap/Buy buttons on the Security Trust page should also be orange Scenario: Positive price direction shows green on sub-screens Given the user is on the Token Details page for a token with a positive price change And the ambient price color A/B test is active And the footer buttons are green When user navigates to Market Insights or Security Trust Then the Swap/Buy buttons should remain green Scenario: Control group unaffected Given the user is in the control group for the ambient price color A/B test When user navigates to Market Insights or Security Trust Then the Swap/Buy buttons should display the default green color ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/3aff0900-edeb-4900-b2d0-4cc4f22f2610 ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] 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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only navigation prop plumbing for an existing A/B test; no auth, payments, or data-layer changes. > > **Overview** > **Token Details** now forwards chart price direction (`isPricePositive`) and the ambient price-color A/B flag (`useAmbientColor`) into **Market Insights** and **Security & Trust** navigation params and sticky footers. > > From `AssetOverviewContent`, opening Market Insights includes those fields on the route; the Security entry card passes them into `Routes.SECURITY_TRUST`. **MarketInsightsView** and **SecurityTrustScreen** read the params and pass them to `TokenDetailsStickyFooter`, so Swap/Buy styling stays aligned with Token Details (green vs orange) instead of defaulting to green on push. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 87ce159. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [ASSETS-3307]: https://consensyssoftware.atlassian.net/browse/ASSETS-3307?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-06-01 at 13 27 16"
src="https://github.com/user-attachments/assets/8c4aca53-104a-4c20-bd69-136130d90afd"
/>
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [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.
#### Performance checks (if applicable)
- [x] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Single Tailwind class on VIP splash title styling; cosmetic layout
only with no logic or data impact.
>
> **Overview**
> Adds **6px top padding** to the VIP splash screen gradient title
styles in `VipSplashScreen` so the masked `MMPoly-Regular` headline
aligns correctly with the layout (visual fix only; no behavior or copy
changes).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
208dcdc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ack (#30830) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** ## Summary - Migrate `NavigationUnitTest` from `@react-navigation/stack` to `@react-navigation/native-stack`. - This component is a navigation API regression harness (it verifies `useNavigationState` + `findRouteNameFromNavigatorState` still resolve the active route correctly). It is not imported anywhere in the app and has no active tests since the snapshot tests were removed in #29441. - No runtime behavior change today; this aligns the harness with the native stack navigator used elsewhere in the app. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry:null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Two-line import/API swap in an unused test-only view with no production or test runner impact. > > **Overview** > Updates the **NavigationUnitTest** regression harness to use `@react-navigation/native-stack` instead of `@react-navigation/stack` (`createNativeStackNavigator` / `createStackNavigator`). > > The harness still checks that `useNavigationState` and `findRouteNameFromNavigatorState` resolve the active route name; it is not wired into production navigation and has no active snapshot tests. The change aligns this isolated test view with the native stack pattern used in the rest of the app. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8c0c485. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…te-and-add-labels`" (#30881) Reverts #30875. The fallback is no longer necessary, as the original issue has been resolved and the Patroll token will eventually be removed. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > CI-only change that removes a secrets fallback; labeling jobs may fail if token exchange regresses, with no app or security surface impact. > > **Overview** > Reverts the temporary **Patroll** (`secrets.LABEL_TOKEN`) fallback in the **Check template and add labels** workflow. > > The **Get access token** step no longer uses `continue-on-error: true`, so a failed token exchange fails the job instead of continuing. **`LABEL_TOKEN`** is set only from `steps.get-token.outputs.token` (the `|| secrets.LABEL_TOKEN` fallback is removed). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a85d70c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
….80.0 (#30379) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## **Description** Adds `Token Details Action Clicked` analytics event instrumentation for the Token Details Page (TDP) secondary action buttons, enabling product to track how users interact with actions beyond the primary CTA. Segment Schema: Consensys/segment-schema#577 **What changed:** 1. **New event**: `Token Details Action Clicked` registered in `MetaMetrics.events.ts` 2. **New enum**: `TokenDetailsAction` with values: `send`, `receive`, `more_opened`, `remove_token`, `view_on_explorer`, `copy_token_address` 3. **New tracking hook**: `useTokenDetailsActionTracking` — accepts token params, balance, and severity; returns a stable callback that fires the event 4. **Instrumented components**: - `TokenDetailsActions` — fires on Send, Receive, and More (menu open) button presses - `MoreTokenActionsMenu` — fires on Remove Token and View on Block Explorer - `TokenDetailsList` → Copy Token Address button **Event properties:** | Property | Type | Description | |---|---|---| | `action` | enum | `send`, `receive`, `more_opened`, `remove_token`, `view_on_explorer`, `copy_token_address` | | `token_symbol` | string | e.g. ETH | | `token_address` | string | Token contract address | | `chain_id` | string | Chain ID | | `has_balance` | boolean | Whether user holds the token | | `severity` | string | Security classification: Verified, Benign, Warning, Spam, Malicious | | `source` | string | Mirrors `Token Details Opened` source enum | ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3212 ## **Manual testing steps** ```gherkin Feature: Token Details Action Clicked analytics Scenario: user taps Send on Token Details Page Given user is viewing a token with balance on Token Details Page When user taps the Send button Then "Token Details Action Clicked" event fires with action="send" Scenario: user taps Receive on Token Details Page Given user is viewing a token on Token Details Page When user taps the Receive button Then "Token Details Action Clicked" event fires with action="receive" Scenario: user taps More menu on Token Details Page Given user is viewing a token on Token Details Page When user taps the More (⋯) button Then "Token Details Action Clicked" event fires with action="more_opened" Scenario: user taps View on Block Explorer in More menu Given user has opened the More menu on Token Details Page When user taps View on Block Explorer Then "Token Details Action Clicked" event fires with action="view_on_explorer" Scenario: user taps Remove Token in More menu Given user has opened the More menu for a non-native token When user taps Remove Token Then "Token Details Action Clicked" event fires with action="remove_token" Scenario: user copies token contract address Given user is viewing token details section with contract address When user taps the copy address button Then "Token Details Action Clicked" event fires with action="copy_token_address" ``` ## **Screenshots/Recordings** https://www.loom.com/share/73dce87dc6bc47b48a0d40588213c4e1 ## **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. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-ba3c87c5-525c-4c40-9869-9f3a17eacea8"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-ba3c87c5-525c-4c40-9869-9f3a17eacea8"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** This PR migrates the Send flow's stack navigator (`app/components/Views/confirmations/components/send/send.tsx`) from the JS-based `createStackNavigator` to `@react-navigation/native-stack`. **Why** The JS stack adds overhead and produces less native-feeling transitions than the native stack used elsewhere in the migration effort. This migration has been done in other feature teams such as card, ramp, predict...etc **What changed:** 1. **Native stack migration** — `createStackNavigator` → `createNativeStackNavigator`, and `cardStyle` → `contentStyle` for the screen background. 2. **In-body headers** — With native-stack, a custom React header rendered by the navigator visibly lingers during the push/pop animation. To fix this, each Send screen (`Amount`, `Recipient`, `Asset`) now renders its own `HeaderCompactStandard` in-body (via `useSendNavbar`) with `headerShown: false`, so the header transitions natively with the screen content. 3. **Shared `Asset` component** — `Asset` is reused by `pay-with-modal` (which supplies its own header), so it gained a `hideHeader` prop. The `useSendNavbar` call is isolated in a child component (`AssetSendHeader`) that only mounts inside the Send flow, so `pay-with-modal` doesn't pull in `useSendNavbar`'s dependency chain. 4. **Back/Cancel fix** — Moving `useSendNavbar` from the parent `Send` route into the nested screens meant its navigation-state lookup no longer saw the main stack, which swapped the behavior (Back → home, Cancel → previous screen). `useSendNavbar` now reads the parent navigator's state, and `handleCancelPress` exits via the parent navigator, restoring correct Back (previous step) and Close (exit flow) behavior. Android build: https://github.com/MetaMask/metamask-mobile/actions/runs/26662374868 ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry:null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Send flow navigation (native stack) Scenario: Header transitions cleanly between Send screens Given the user is in the Send flow When the user navigates from Asset to Amount to Recipient Then the header transitions natively with the screen And no previous header lingers during the animation Scenario: Back button steps back within the Send flow Given the user is on a Send screen When the user taps the back button Then the user returns to the previous step (or exits Send correctly from the first screen) Scenario: Close button exits the Send flow Given the user is on a Send screen When the user taps the close button Then the entire Send flow is dismissed Scenario: Pay-with modal still works Given the user opens the "Other assets" picker from a Pay with confirmation Then the modal renders its own header (no duplicate Send header) And token selection works as before ``` ## **Screenshots/Recordings** happy path |before|after| |---|---| |<img width="370" height="808" alt="send happy path before" src="https://github.com/user-attachments/assets/41bbed29-e124-42b4-a2a6-ee2df9148726" />|<img width="370" height="808" alt="send happy path after" src="https://github.com/user-attachments/assets/4953ced0-1543-41ab-a20b-3300ee491a88" />| cancel path |before|after| |---|---| |<img width="370" height="808" alt="send cancel before" src="https://github.com/user-attachments/assets/3af10caf-f67f-45f1-9fb3-c006cf144c25" />|<img width="370" height="808" alt="send cancel after" src="https://github.com/user-attachments/assets/d9deddff-9c8d-489d-a244-6be62444394a" />| Token Selector |before|after| |---|---| |<img width="370" height="808" alt="pay with token before" src="https://github.com/user-attachments/assets/ec6bbf54-7c82-4b48-a39e-df7c679fd60c" />|<img width="370" height="808" alt="token selector after" src="https://github.com/user-attachments/assets/3a020e0f-eac5-470a-aa23-39b195c648d7" />| Android https://github.com/user-attachments/assets/ba847f25-c94e-4d39-8cda-796f07757c20 ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches core Send navigation and exit paths; incorrect parent-stack handling could mis-route users on back/close, though scope is limited to the Send stack and shared Asset picker. > > **Overview** > The Send flow’s nested navigator is switched from **JS stack** to **native stack**, with `headerShown: false` and **in-body** `HeaderCompactStandard` on Amount, Recipient, and Asset (via `useSendNavbar`) so headers animate with screen content instead of lingering during transitions. > > **Asset** gains `hideHeader` and an `AssetSendHeader` child so **pay-with-modal** can keep its own header without duplicating Send chrome or mounting the full navbar hook chain. **Back/close** behavior is corrected: `useSendNavbar` reads the **parent** stack for back navigation, and **close** calls `getParent().goBack()` to leave the whole Send flow. Tests are updated with navbar mocks and parent-navigation expectations. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4f3d780. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…rest questionnaire (#30876) ## **Description** This PR updates the onboarding interest questionnaire option cards to use `TouchableOpacity` instead of `Pressable`. Reason for change: - The option cards no longer need a pressed-state style callback for their interaction feedback. Improvement/solution: - Replaced the option card touch target with `TouchableOpacity` in `OnboardingInterestQuestionnaire.tsx`. - Simplified the `style` prop from a callback form to a static `tw.style(...)` expression. - Removed the `pressed` opacity condition while preserving selection-based border and background styling. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: N/A ## **Manual testing steps** ```gherkin Feature: onboarding interest selection card interaction Scenario: user selects and deselects an interest option Given the onboarding interest questionnaire is visible When user taps an unselected interest option card Then the card appears selected When user taps the same selected interest option card Then the card appears unselected ``` ## **Screenshots/Recordings** <!-- No visual change expected beyond removal of pressed-state opacity. --> ### **Before** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/7eac6d7a-4953-4505-99e4-6fb6bb9a7181 ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/3de229bf-4c5b-47cc-b15e-d0e4eb9c819a ## **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **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** > Single-screen UI touch component swap with no changes to selection logic, analytics, or navigation. > > **Overview** > Onboarding interest questionnaire **option cards** now use **`TouchableOpacity`** instead of **`Pressable`**, with a static `tw.style(...)` instead of a pressed-state style callback. > > **Removed** the custom **pressed opacity** (`opacity-70`); **selected vs unselected** border and background styling is unchanged. Toggle behavior, test IDs, and checkbox accessibility are the same. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 214fe40. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-06-01 at 14 30 25"
src="https://github.com/user-attachments/assets/5e91466e-2f70-471d-8b96-bd1c7d3b4df1"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-06-01 at 14 31 03"
src="https://github.com/user-attachments/assets/856c872a-30de-4ce4-8341-a93366de15f0"
/>
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [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.
#### Performance checks (if applicable)
- [x] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Small UI/theming change on the rewards leaderboard with a focused
test; no auth, data, or payment logic.
>
> **Overview**
> The **HyperTracker** wordmark on the perps trading campaign
leaderboard no longer stays hard-coded white. The SVG wordmark path now
uses **`currentColor`**, and **`PerpsTradingCampaignLeaderboard`**
passes **`colors.text.default`** from **`useTheme`** into
**`HyperTrackerLogo`** so the logo matches the active theme (e.g.
readable in light mode).
>
> A unit test wraps the leaderboard in **`ThemeContext`** and asserts
the logo receives the theme text color.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
909d29e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **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:
## **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**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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**
> CI-only flag change for nightly iOS TestFlight; no app runtime or auth
logic affected.
>
> **Overview**
> Nightly **iOS** `exp` and `rc` jobs now pass **`distribute_external:
true`** into `build-and-upload-to-testflight.yml`, so scheduled builds
are distributed to external TestFlight testers (still using the
**MetaMask BETA & Release Candidates** group) instead of relying on the
workflow default of internal-only upload.
>
> Android nightly jobs are unchanged.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c2648c5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…URE_BLACK_PREVIEW (#30661) ## **Description** Part of the pure-black dark mode migration (TMCU-798). When `MM_PURE_BLACK_PREVIEW=true`, `background.default` resolves to `#000000`, causing elevated surfaces bound to that token to collapse into the screen background (black-on-black). This PR addresses two design-system components plus their downstream consumers: - `ListItemSelect` selected-row background → uses `getElevatedSurfaceColor` shim (`background.alternative` under pure-black dark, unchanged otherwise). - Deprecated `Input` (and its SRP-input fork) → same shim. Bridge `TokenInputArea` and `InputStepper` previously relied on `Input`'s `background.default` to match the screen background and render "invisible"; both now explicitly opt out via `backgroundColor: importedColors.transparent` so the swap amount inputs stay flat. - `EditMultichainAccountName` was using a raw RN `TextInput` with no `backgroundColor`, so the field rendered as an outline-only border against pure black. Migrated to `TextField` from `@metamask/design-system-react-native`, which paints `background.muted` (translucent overlay → elevated under pure black). Net effect: elevated surfaces render correctly under pure-black, no regressions on the Bridge/Swap amount entry, and `EditMultichainAccountName` is now off a deprecated RN-native input. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-798 ## **Manual testing steps** ```gherkin Feature: Elevated surfaces remain visible under MM_PURE_BLACK_PREVIEW Scenario: ListItemSelect selected row is visibly elevated Given MM_PURE_BLACK_PREVIEW=true and the app is in dark mode When the user opens the Tokens sort bottom sheet Then the currently-selected sort option renders an elevated row (background.section) Scenario: Deprecated Input renders elevated where no parent provides elevation Given the same flag and theme When the user navigates to a screen using the deprecated Input directly (e.g. SRP input) Then the input fill is visibly elevated, not pure black Scenario: Bridge/Swap amount inputs stay flat Given the same flag and theme When the user opens the Swap screen Then the source and destination amount fields render flat against the screen background (no elevated rectangle around the "0") Scenario: EditMultichainAccountName field is visible Given the same flag and theme When the user opens Account details → Edit account name Then the "Account name" field renders with a visible elevated fill (DS TextField muted background) ``` ## **Screenshots/Recordings** ### ListItemSelect (Shows sort but the change is the same for all consumers | Before | After | |--------|-------| |  |  | ### Input (Nothing Changes) https://github.com/user-attachments/assets/6a2a4eb9-dddd-4476-bb84-a00009337e2a ### Migrate input from react native to design system component for edit wallet name | Before | After | |--------|-------| |  |  | ### **Before** `~` ### **After** `~` ## **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Theme and presentation-only changes behind a preview flag; no auth, persistence, or payment logic. > > **Overview** > Under **`MM_PURE_BLACK_PREVIEW`**, elevated UI no longer disappears on a pure-black screen: deprecated **`Input`** and **`ListItemSelect`** now use **`getElevatedSurfaceColor`** instead of **`background.default`**, so fills stay visible in dark mode while other themes stay the same. > > **Bridge/Swap** amount fields still look flat: **`TokenInputArea`** and **`InputStepper`** pass **`backgroundColor: transparent`** on the nested **`Input`** styles so the new elevated default does not draw a box around the amount. > > **Edit multichain account name** drops the raw RN **`TextInput`** (border-only on black) for design-system **`TextField`**, with error state and keyboard props moved into **`inputProps`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e4c092d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Wires Batch Sell final review submission using the preview Bridge Controller and Bridge Status Controller builds. This PR adds the required preview package configuration, allows `BridgeStatusController` to call `BridgeController:getState`, and introduces a Batch Sell-specific submit hook that calls `BridgeStatusController.submitBatchSell`. The submit path passes the list of executable recommended quote responses, matching the controller contract for Batch Sell. It also updates the final review modal to: - submit via the new `useSubmitBatchSellTx` hook - block `Sell all` until `isBatchSellTradeAvailable` is true - use `isBatchSellTradeAvailable` directly instead of returning a duplicate `networkFeeIsLoading` field - toggle the existing submitting state and navigate to the Transactions view after submit ## **Changelog** CHANGELOG entry: Added Batch Sell submit support ## **Related issues** Fixes: [SWAPS-4441](https://consensyssoftware.atlassian.net/browse/SWAPS-4441) ## **Manual testing steps** ```gherkin Feature: Batch Sell submit Scenario: user submits a Batch Sell transaction Given Batch Sell quotes have loaded on the final review screen And Batch Sell trades are available And the user has sufficient funds for gas When the user taps Sell all Then the app submits the list of recommended Batch Sell quote responses And the button enters the submitting state And the app navigates to the Transactions view after submission ``` ```gherkin Feature: Batch Sell unavailable trade state Scenario: Batch Sell trades are not ready Given the final review screen is open And isBatchSellTradeAvailable is false Then the network fee row shows its loading skeleton And the Sell all button is disabled ``` ```gherkin Feature: Batch Sell expired quote refresh Scenario: user refreshes an expired Batch Sell quote Given the final review screen is open And the quote has expired after max refresh When the user taps Get new quote Then BridgeController quote state is reset And fresh Batch Sell quote requests are made ``` ## **Screenshots/Recordings** ### **Before** n/a ### **After** https://github.com/user-attachments/assets/c6d9fddc-7c51-4abc-890f-6de3b98d6105 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **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. ## **Automated testing performed** - `yarn jest app/components/UI/Bridge/hooks/useSubmitBatchSellTx/useSubmitBatchSellTx.test.tsx app/components/UI/Bridge/components/BatchSellFinalReviewModal/BatchSellFinalReviewModal.test.tsx` - `yarn jest app/util/bridge/hooks/useSubmitBridgeTx.test.tsx app/components/UI/Bridge/hooks/useSubmitBatchSellTx/useSubmitBatchSellTx.test.tsx app/components/UI/Bridge/hooks/useBatchSellQuoteData/useBatchSellQuoteData.test.ts app/components/UI/Bridge/components/BatchSellFinalReviewModal/BatchSellFinalReviewModal.test.tsx app/components/UI/Bridge/Views/BatchSellReview/BatchSellReview.test.tsx` - `yarn eslint` on touched Batch Sell submit/final review files - `yarn lint:tsc` - `git diff --check` [SWAPS-4441]: https://consensyssoftware.atlassian.net/browse/SWAPS-4441?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Introduces real on-chain batch submission through Bridge Status Controller and changes when users can confirm trades; incorrect gating or submit payloads could block or mis-route user transactions. > > **Overview** > This PR **wires end-to-end Batch Sell submission** and tightens quote/trade readiness in the UI. > > **Final review:** **Sell all** now calls a new `useSubmitBatchSellTx` hook that forwards **recommended quote responses** to `BridgeStatusController.submitBatchSell` (wallet, STX, destination security). The modal toggles **submitting** state, blocks the CTA while trades are loading or unavailable, treats **gasless** fee coverage failures as insufficient funds, and **always navigates to Transactions** after submit (success or error). Quote data drops `networkFeeIsLoading` in favor of **`isBatchSellTradeAvailable` / `isBatchSellTradesLoading`** and exposes **`recommendedQuotes`** for submit. > > **Review screen:** The primary button stays **disabled while quotes are still fetching** (even with partial row data), shows **“Searching for best quotes”** during fetch, and keeps **Get new quote** when expired. > > **Platform:** Bumps **`@metamask/bridge-controller`** and **`@metamask/bridge-status-controller`**, delegates **`BridgeController:getState`** to `BridgeStatusController`, adds **BSC USDT** and **Linea MUSD** stablecoin metadata, plus tests and copy. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4e4859d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…rted tokens (#30824) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **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? --> Expands "Earn on your crypto" section of Money Home to include all supported MM Pay tokens. #### Changes - Added `useMoneyDepositTokens` as single source of truth for Money deposit payment tokens - Remotely configurable blocklist, minimum balance, "no fee" tokens, and sorting modes - Wired up "Add" buttons to the Money account deposit screen ## **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` 3. 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: Expanded "Earn on your crypto" in Money to show all MM Pay-supported deposit tokens and start deposit with the selected token. ## **Related issues** - Fixes: [MUSD-830](https://consensyssoftware.atlassian.net/browse/MUSD-830) ## **Manual testing steps** ```gherkin Feature: Money potential earnings uses MM Pay deposit tokens Scenario: user sees expanded eligible token list in potential earnings Given user opens Money Home with multiple MM Pay-supported tokens that pass filters When the potential earnings section renders Then the token rows are shown from the Money deposit token set Scenario: user starts deposit from token row Given user is on Money Home or Potential Earnings view When user taps a token row Then Money deposit flow opens with that token pre-selected Scenario: user starts deposit from primary CTA Given user is on Potential Earnings view with at least one eligible token When user taps "Convert" Then Money deposit flow opens with the first eligible token pre-selected ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> - Token list displayed mUSD conversion eligible tokens only - "Add" button redirected to the mUSD conversion screen ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/be14f704-7829-4367-8b76-cd4b396e6a4b ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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 --> [MUSD-830]: https://consensyssoftware.atlassian.net/browse/MUSD-830?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes which tokens users can fund Money from and switches the primary action from mUSD conversion to deposit initiation; mitigated by feature flags, blocklists, and extensive unit tests but still user-facing payment flow logic. > > **Overview** > **Earn on your crypto** on Money Home and Potential Earnings now uses **MM Pay–eligible deposit tokens** instead of the narrower mUSD conversion token list. > > A new **`useMoneyDepositTokens`** hook centralizes which wallet tokens appear: MM Pay blocklist, Money-specific blocklist, minimum fiat balance (remote/env), optional **no-fee** token lists, and sort modes (`fiatBalanceDesc` vs **no-fee first**). **Add/Convert** actions call **`initiateDeposit`** with a **preferred payment token** rather than **`initiateCustomConversion`**. > > **No fee** badges on token rows come from configurable **`isNoFeeToken`** (replacing hardcoded stablecoin symbols). New remote flags and `.js.env` fallbacks back the blocklist, no-fee map, min balance, and sort mode. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9b092ab. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Showcase of the transitions between views 👇 https://github.com/user-attachments/assets/67300465-117f-4168-9e66-67e9a996fe37 QuickBuy screens previously swapped instantly. This PR animates the screen change inside `QuickBuyRoot` with a direction-aware slide + fade: - **Forward** (going deeper, e.g. `amount -> payWith`, `quoteDetails -> selectQuote`): the new screen slides in from the right and fades in while the old screen slides out to the left and fades out. - **Back** (going shallower): the motion is mirrored. Direction is derived from a per-screen depth map (`SCREEN_DEPTH`) and stored in a reanimated shared value that the `entering`/`exiting` worklets read lazily, so both the entering (new) and exiting (old) views use the direction computed at navigation time rather than a stale value. The initial screen does not animate when the sheet first opens, and the content container keeps its locked height so the bottom sheet does not jump during transitions. Motion reuses the existing `AnimationDuration.Fast` (150ms) token from `@metamask/design-tokens`. The navigation `setActiveScreen` is now a thin `(screen) => void` wrapper that computes direction before updating state, so all existing call sites are unchanged. ## **Changelog** CHANGELOG entry: Animates transitions between views in the Quick Buy bottom sheet ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: QuickBuy screen transitions Scenario: user navigates forward through QuickBuy screens Given the QuickBuy bottom sheet is open on the amount screen When the user taps an action that opens a deeper screen (e.g. Pay with, or the rate to view quote details) Then the new screen slides in from the right and fades in while the previous screen slides out to the left Scenario: user navigates back Given the user is on a deeper QuickBuy screen When the user taps back Then the previous screen slides in from the left and fades in while the current screen slides out to the right Scenario: sheet opens without an awkward enter animation Given QuickBuy is triggered from the Buy button When the bottom sheet opens Then the amount screen appears without a slide/fade enter animation ``` ## **Screenshots/Recordings** ### **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 - [ ] 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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **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. Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only Quick Buy navigation and animation; trade/confirm logic is unchanged aside from routing through navigateToScreen. > > **Overview** > Quick Buy bottom sheet screens no longer swap instantly: **`QuickBuyRoot`** wraps the active screen in a keyed **`Animated.View`** with Reanimated **enter/exit** slide + fade, using a new **`transitions`** module (`SCREEN_DEPTH`, shared direction, `makeScreenTransitions`) and **`AnimationDuration.Fast`**. > > **Forward** vs **back** motion follows depth (deeper vs shallower); same-depth moves (e.g. `payWith` ↔ `quoteDetails`) use forward-style animation. Direction is set in **`navigateToScreen`** before state updates and read lazily in worklets so entering and exiting views stay in sync. The **first** screen when the sheet opens does **not** enter-animate; locked container height behavior is unchanged. > > Context **`setActiveScreen`** is typed as **`(screen) => void`** (still only screen-name calls from existing sites). Unit tests cover transition math and root navigation probes. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6ba1ab5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description**
Implements the `Token Details Closed` analytics event to track when and
how users leave the Token Details page. The event captures `exit_action`
(how they left) and `time_on_screen_ms` (how long they stayed).
### Event payload
```json
{
"chain_id": "0x1",
"token_symbol": "DAI",
"token_address": "0x6b17...",
"exit_action": "back_navigation | cta_clicked | app_backgrounded",
"time_on_screen_ms": 12345
}
```
## **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 token details closed event
## **Related issues**
Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3292
Related: Consensys/segment-schema#589
## **Manual testing steps**
```gherkin
Feature: Token Details Closed event tracking
**Scenario: user navigates back from token details**
Given the user is viewing the Token Details page
When user presses the back button
Then a "Token Details Closed" event is emitted with exit_action "back_navigation" and a valid time_on_screen_ms
**Scenario: user taps Swap CTA**
Given the user is viewing the Token Details page
When user taps the Swap button
Then a "Token Details Closed" event is emitted with exit_action "cta_clicked" and a valid time_on_screen_ms
**Scenario: user taps Buy CTA**
Given the user is viewing the Token Details page
When user taps the Buy button
Then a "Token Details Closed" event is emitted with exit_action "cta_clicked" and a valid time_on_screen_ms
**Scenario: user taps Send CTA**
Given the user is viewing the Token Details page
When user taps the Send button
Then a "Token Details Closed" event is emitted with exit_action "cta_clicked" and a valid time_on_screen_ms
**Scenario: user taps Long/Short CTA**
Given the user is viewing the Token Details page
When user taps the Long or Short button
Then a "Token Details Closed" event is emitted with exit_action "cta_clicked" and a valid time_on_screen_ms
**Scenario: user backgrounds the app**
Given the user is viewing the Token Details page
When user backgrounds the app
Then a "Token Details Closed" event is emitted with exit_action "app_backgrounded" and a valid time_on_screen_ms
**Scenario: user returns from a CTA and then navigates back**
Given the user is viewing the Token Details page
And the user previously tapped Swap and returned
When user presses the back button
Then a "Token Details Closed" event is emitted with exit_action "back_navigation" and a fresh time_on_screen_ms (timer resets on focus)
**Scenario: user opens Receive bottom sheet (no event)**
Given the user is viewing the Token Details page
When user taps the Receive button
Then NO "Token Details Closed" event is emitted (bottom sheet overlays, does not leave page)
```
## **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**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] 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.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] 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.
[ASSETS-3292]:
https://consensyssoftware.atlassian.net/browse/ASSETS-3292?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Analytics-only instrumentation in Token Details with tests; no auth,
payments, or transaction logic changes.
>
> **Overview**
> Adds **`Token Details Closed`** MetaMetrics tracking when users leave
the Token Details screen, with **`exit_action`** (`back_navigation`,
`cta_clicked`, `app_backgrounded`) and **`time_on_screen_ms`**.
>
> The route wrapper owns session state: **`beforeRemove`** for
back/stack pop, **`AppState`** only on **`background`** (not transient
**`inactive`**), and **`useFocusEffect`** cleanup when leaving via CTA
after **`cta_clicked`** is set. Returning from background resets the
timer and allows another close event. A **`firedRef`** guard prevents
duplicate emissions per session.
>
> CTAs wire through **`onCtaClicked`** / **`onExitAction`** on Buy,
Send, sticky Swap/Buy, and Perps Long/Short. Sticky footer
**`onSwapPress`/`onBuyPress`** now run only when navigation actually
proceeds (after geo checks and security **Proceed**, not on blocked or
modal-only paths).
>
> Tests cover AppState behavior and sticky footer callback timing.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ef680ff. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description** This change replaces `HeaderCompactStandard` (component-library) with **`HeaderStandard`** from `@metamask/design-system-react-native` across confirmation-related modals and sheets. --- ## **Changelog** CHANGELOG entry: null --- ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-698 --- ## **Manual testing steps** ```gherkin Feature: Confirmation modals use standard header Scenario: Account selector sheet shows standard header Given the user is on a transaction confirmation that supports switching accounts When the user opens the account selector from the confirmation UI Then the sheet shows a header with the expected title and a working close control Scenario: Pay with asset modal Given the user is on a confirmation that opens the pay-with token picker When the user opens the pay-with modal and closes it via the header Then the modal closes without errors and the confirmation flow remains usable Scenario: Gas-related modals Given the user can open network fee or gas fee token UI from the confirmation When the user opens the estimates modal or gas fee token modal and dismisses it Then the modal closes correctly and the underlying confirmation is unchanged Scenario: Tooltip and expandable detail modals Given a confirmation screen shows info that opens a tooltip or expandable modal When the user opens and closes those modals from the header Then content is readable and close behaves as before ``` --- ## **Screenshots/Recordings** ### **Before** ### **After** --- ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only header component migration with unchanged close handlers and transaction logic; main regression risk is visual/layout or accessibility on modal headers. > > **Overview** > Confirmation-related bottom sheets and modals now use **`HeaderStandard`** from `@metamask/design-system-react-native` instead of the temporary **`HeaderCompactStandard`** from the component library. > > The swap is applied across account selection, pay-with, gas (estimates and fee token), cancel/speedup, tooltip, and expandable flows. Existing props (`title`, `onClose`, `closeButtonProps`) are preserved so dismiss behavior and test IDs stay the same. > > **AccountSelector** tests drop the dedicated header mock and instead partially mock the design system (including `useTailwind`) while spreading the real package so **`HeaderStandard`** can render in tests. A style comment is updated to reference **`HeaderStandard`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e5bb661. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description** This PR replaces `HeaderCompactStandard` with `HeaderStandard` from `@metamask/design-system-react-native` across several flows that previously depended on `component-library/components-temp`. **Reason:** Use the canonical design-system header and reduce reliance on temporary header components. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-705 ## **Manual testing steps** ```gherkin Feature: Headers use design system HeaderStandard Scenario: Card region selector Given the user is in Card onboarding and opens the region selector sheet When they view the header and close the sheet Then the sheet dismisses as before Scenario: Network manager Given the user opens the networks manager bottom sheet from the wallet When they view the header title and tap close Then the sheet closes as before Scenario: OTA updates modal Given an OTA update prompt is shown When the user views the branded header and taps close Then the modal dismisses as before Scenario: Seed phrase info and select picker Given the user opens “What is a seed phrase?” from backup flow or a SelectComponent modal (e.g. settings flows using that picker) When they use the header close control Then behavior matches prior implementation Scenario: Pool staking learn-more and list header with search Given the user opens pool staking learn-more or a screen using ListHeaderWithSearch When they navigate back or use search as applicable Then navigation and layout match prior behavior ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **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** > Presentational header swap with preserved close/dismiss behavior; only notable detail is OTA close testID for tests. > > **Overview** > This PR swaps the temporary **`HeaderCompactStandard`** component for **`HeaderStandard`** from `@metamask/design-system-react-native` on several bottom sheets and modals: card region selector, network manager, OTA updates, seed phrase info, `SelectComponent` picker, and pool staking learn-more. > > Behavior stays the same (titles, close handlers, and dismiss flows). The OTA modal keeps a **custom branded header** via `HeaderStandard` children and wires **`closeButtonProps.testID`** so tests can still hit close without a dedicated mock. **`OTAUpdatesModal.test.tsx`** drops the old `HeaderCompactStandard` Jest mock in favor of the real design-system header. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e92392d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…30903) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Updates Token list mUSD filtering to include check for Money hub enablement. When Money hub is disabled mUSD is included in the Token list. <!-- 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: update token list mUSD filtering to include check for money hub enablement; when money hub is disabled mUSD is included in the Token list. ## **Related issues** Fixes: [MUSD-856: Can't see mUSD in the token list since Money Hub was released](https://consensyssoftware.atlassian.net/browse/MUSD-856) ## **Manual testing steps** ```gherkin Feature: mUSD cash section token filtering Scenario: user has Money Hub enabled with mUSD balance Given user has the Money Hub, mUSD conversion flow, and geo eligibility all enabled And user holds mUSD on a supported network When user views the homepage token list Then mUSD is hidden from the token list And mUSD is shown only in the Cash section Scenario: user has Money Hub disabled Given user has the Money Hub feature flag disabled When user views the homepage token list Then mUSD appears in the token list alongside other tokens And no Cash section filtering is applied ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** #### When Money Hub feature is disabled <img width="494" height="1020" alt="image" src="https://github.com/user-attachments/assets/204d2dd2-7bf7-4418-a6df-e825cd39ed29" /> <img width="494" height="1020" alt="image" src="https://github.com/user-attachments/assets/38f11eba-51ca-41f1-8f19-c76c614c3394" /> <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only feature-flag gating for token list filtering with matching test updates; no auth, payments, or persistence changes. > > **Overview** > **mUSD** is no longer removed from homepage and wallet token lists unless the **Money Hub** feature flag is on, in addition to the existing mUSD conversion flow, geo eligibility, and (for the main `Tokens` list) homepage sections checks. > > The shared **Cash section** gate (`isCashSectionEnabled`) now requires `selectMoneyHubEnabledFlag` in `Tokens`, `TokensSection`, and `usePopularTokens`, so filtering and popular-token exclusions only run when Cash/Money Hub is actually available. Tests and feature-flag setup were updated to cover the three-way flag combination. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e5c32e4. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adds a `variant` prop to the shared `Pressable` primitive so a single component covers the three touch-feedback models used in the app: - `PressableVariant.Default` — dims caller subtree opacity to `0.7` on press. Mirrors `TouchableOpacity` behaviour. Use for buttons, icon affordances, inline tappable elements. - `PressableVariant.Highlight` — composites `background.pressed` over the caller's resting surface. Use for list rows / settings rows / sheet rows. - `PressableVariant.None` — applies no visual feedback. Use only when the caller component already renders its own press-state styling internally (e.g. a button that toggles its own background via `useState(pressed)`). Without this, those callers get double feedback after migration. The default is `Default` (opacity) so the broader codebase migration from `TouchableOpacity` becomes a mechanical sweep — every existing call site keeps the visual model it already had. List-row primitives explicitly opt into `Highlight`. Components with internal press-state implementations opt into `None`. Follows the MMDS const-enum pattern (`PressableVariant.X`), matching `TextVariant`, `ButtonVariants`, etc. Updated in this PR: - `Pressable` and `PressableGH` primitives, including `forwardRef` preservation and tests for the pure `pressedStyleFor` helper. - `ListItemSelect`, `ListItemMultiSelect`, `ListItemMultiSelectButton`, `ListItemMultiSelectWithMenuButton` — opted into `PressableVariant.Highlight`. - README, Storybook story, and `index.ts` exports updated. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-790 ## **Manual testing steps** ```gherkin Feature: Pressable variant feedback Scenario: default variant dims subtree on press Given a Pressable rendered without a variant prop When the user presses it Then the caller subtree opacity briefly drops to 0.7 And no background overlay is applied Scenario: highlight variant composites background.pressed on press Given a Pressable rendered with variant={PressableVariant.Highlight} When the user presses it Then the background briefly shifts to colors.background.pressed And the subtree opacity is unchanged Scenario: DS list rows show backdrop highlight Given the app is open When the user taps a ListItemSelect / ListItemMultiSelect / multi-select row Then the row flashes background.pressed (no subtree dim) And feedback is visible in pure-black mode ``` ## **Screenshots/Recordings** ### Pressable - default is dimming on press while highlight variant behavior needs to be explicitly set https://github.com/user-attachments/assets/e51aaf22-f868-4ecc-88fe-0de9a6f13162 ### List Item - highlight variant behavior is explicitly set for `ListItems` behavior is the same as `main` https://github.com/user-attachments/assets/51e8621d-d0c4-404a-884c-a2aa188f6014 ### **Before** `~` ### **After** `~` ## **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only component-library press feedback; no auth, data, or payment paths. Default variant changes global Pressable press appearance unless callers opt into Highlight or None. > > **Overview** > Adds a **`variant`** prop to the shared **`Pressable`** / **`PressableGH`** primitives so press feedback is explicit instead of one global behavior. **`PressableVariant.Default`** (the default) dims the subtree to **0.7** opacity on press, matching **`TouchableOpacity`**-style feedback. **`PressableVariant.Highlight`** applies **`background.pressed`** over the caller’s surface (the previous always-on overlay model). **`PressableVariant.None`** skips built-in feedback for callers that style press state themselves. > > List-row components (**`ListItemSelect`**, **`ListItemMultiSelect`**, and the multi-select button variants) now pass **`PressableVariant.Highlight`** so row taps keep the backdrop highlight pattern. Docs, Storybook (**Default** vs **Highlight**), tests for **`pressedStyleFor`**, and **`PressableVariant`** exports are updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c8877b0. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** When Rive can't play the splash animation (corrupted file, stuck state machine, unsupported renderer — typically low-end Android), `FoxLoader` falls back to the static fox and forces app reveal via a timeout. Two problems with the current behavior: 1. The timeout was 5s, which is longer than necessary on devices where Rive will *never* play — users stare at the static fox for an avoidable ~2s. 2. The timeout fired `Logger.error`, which generates Sentry noise for what is expected, recoverable behavior on unsupported hardware. This PR reduces `ANIMATION_TIMEOUT_MS` from 5s → 3s and downgrades the timeout log from `Logger.error` to `Logger.log`. The other two `Logger.error` calls in the file (hideAsync rejection in the timeout path; onError bail-out) are unchanged — those remain genuine failures worth a Sentry signal. No functional change to the fallback itself; the static fox path was already working. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-717 ## **Manual testing steps** ```gherkin Feature: Splash fallback on Rive failure Scenario: Rive fails to play on launch Given a device where Rive cannot render (e.g. low-end Android, or a forced Rive onError in dev) When the user launches the app Then the static fox is shown And the app reveals within 3 seconds And no Sentry error is emitted for the timeout ``` ## **Screenshots/Recordings** `~` ### **Before** `~` ### **After** `~` ## **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Observability and timing tweak only; splash fallback behavior and error logging for real hideAsync failures are unchanged. > > **Overview** > **FoxLoader** shortens the splash **animation timeout** from **5s to 3s** so devices where Rive never plays reveal the app sooner on the existing static-fox fallback. > > When that timeout fires and the animation never completed globally, logging is **downgraded from `Logger.error` to `Logger.log`** so expected unsupported-hardware cases stop creating Sentry noise; **`hideAsync` failures** on the same path still use **`Logger.error`**. > > Tests mock **`Logger.log`** and advance fake timers by **3s** to match the new constant. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3c756cd. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** App icons backgrounds are now pure black ## **Changelog** CHANGELOG entry:null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-767 ## **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** https://github.com/user-attachments/assets/42e12a7d-b69a-4771-bc9e-a98e63b37b5b https://github.com/user-attachments/assets/3a9857d1-d447-49b5-bb7b-6d5ce923f738 ### **Before** https://github.com/user-attachments/assets/a3177288-0041-42f6-ae10-7d42f97fd904 ### **After** https://github.com/user-attachments/assets/42e12a7d-b69a-4771-bc9e-a98e63b37b5b https://github.com/user-attachments/assets/3a9857d1-d447-49b5-bb7b-6d5ce923f738 ## **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Asset-only visual change to iOS/Android launcher icons; no auth, networking, or runtime behavior impact. > > **Overview** > Updates **MetaMask home-screen / launcher icon assets** so their backgrounds are **pure black (`#000000`)** instead of the previous non-black treatment (e.g. dark gray or transparent), addressing **TMCU-767**. > > Expect changes in **native image resources**—typically iOS `AppIcon` (and related) asset catalogs under `ios/MetaMask/Images.xcassets/` and Android adaptive launcher layers (`ic_launcher_background` / mipmap PNGs)—with **no application logic** changes. Visual-only: icons should read consistently on the home screen and in app switchers after reinstall or asset refresh. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 12e9f97. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
#30319) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** This PR adopts the breaking messenger contract introduced in `@metamask/ramps-controller` for [TRAM-3502](https://consensyssoftware.atlassian.net/browse/TRAM-3502), which moves the Buy widget API call from unauthenticated to authenticated using a bearer token sourced from `AuthenticationController`. **Why:** The Buy widget endpoint on the ramps API has been gated behind authentication. Without sending an `Authorization: Bearer <token>` header on `getBuyWidgetUrl`, mobile users will be unable to launch the Transak buy flow. **What changed in core (the dependency):** - `RampsService.getBuyWidgetUrl` now fetches a bearer token via `AuthenticationController:getBearerToken` and sends it as an `Authorization` header. - `RampsServiceMessenger`'s `AllowedActions` was widened from `never` to include `AuthenticationController:getBearerToken` — i.e. consumers (this app) **must** delegate that action into the ramps messenger or the call will throw. - See the core PR for the full contract change: `<link-to-core-PR>`. **What this PR does in mobile:** 1. Bumps `@metamask/ramps-controller` to the new major version (currently consuming the preview build `@metamask-previews/ramps-controller@<preview-version>` while the core PR is in review; will switch to `^14.0.0` once published). 2. Delegates `AuthenticationController:getBearerToken` into the `RampsServiceMessenger` at the point where the messenger is constructed in the engine/controller-init layer. 3. Surfaces the new failure modes (wallet locked / user signed out / token fetch failure) to the Buy entry points so the user gets a usable error rather than an unhandled rejection. ## **Changelog** CHANGELOG entry: null <!-- This PR has no end-user-visible UI change on the happy path. The Buy flow behaves identically when the user is signed in; the only user-visible difference is improved error handling on signed-out / locked states, which is captured in the relevant feature changelog by the entry-point change, not here. If release engineering prefers an entry, suggested wording: "Improved Buy widget reliability by authenticating requests to the ramps API." --> ## **Related issues** Fixes: [TRAM-3502](https://consensyssoftware.atlassian.net/browse/TRAM-3502) Depends on (core): `<link-to-core-PR>` — must be merged and released to NPM before this PR can leave draft. ## **Manual testing steps** ```gherkin Feature: Buy widget authentication Scenario: Signed-in user opens the Buy widget Given the user is signed in and the wallet is unlocked And the user has selected a token that supports Transak When the user taps "Buy" and proceeds to the Transak provider Then the Buy widget URL loads successfully And the upstream request to the ramps API includes an "Authorization: Bearer <token>" header And Transak opens in the in-app browser as before Scenario: Wallet-locked user attempts to open the Buy widget Given the wallet is locked When the user taps "Buy" and proceeds to the Transak provider Then the user sees a clear error state (not a silent failure or crash) And no unauthenticated request is sent to the ramps API Scenario: Signed-out user attempts to open the Buy widget Given the user is signed out of profile sync / authentication When the user taps "Buy" and proceeds to the Transak provider Then the user sees a clear error state And no unauthenticated request is sent to the ramps API Scenario: Bearer token call fails transiently Given the AuthenticationController fails to mint a bearer token When the user taps "Buy" and proceeds to the Transak provider Then the failure is surfaced as a user-facing error And retrying after the underlying auth issue is resolved succeeds ``` **How to verify the Authorization header on-device:** - Point a debugging proxy (Charles / mitmproxy) at the device. - Trigger the Buy flow and inspect the request to `https://on-ramp.api.cx.metamask.io/providers/<provider>/buy-widget`. - Confirm an `Authorization: Bearer <jwt>` header is present. ## **Screenshots/Recordings** ### **Before** <!-- Recording of Buy widget on current `main`: request to /buy-widget has no Authorization header. --> ### **After** https://github.com/user-attachments/assets/b45d9a6e-3534-46f1-b51f-1d42637c32d0 <!-- Recording of Buy widget on this branch: same UX, request now includes Authorization: Bearer <token>. Plus recordings of the locked-wallet and signed-out error states. --> ## **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. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **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. [TRAM-3502]: https://consensyssoftware.atlassian.net/browse/TRAM-3502?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [TRAM-3502]: https://consensyssoftware.atlassian.net/browse/TRAM-3502?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Wires bearer-token access into the Buy/ramps path; mis-delegation would break Transak buy, but changes are localized to messenger setup and a dependency bump. > > **Overview** > Upgrades **`@metamask/ramps-controller`** to **^14.0.0** so the Buy widget can call the ramps API with an authenticated bearer token (required by the new controller contract). > > When **`getRampsServiceMessenger`** builds the child messenger, it now **delegates** `AuthenticationController:getBearerToken` from the root messenger into `RampsServiceMessenger`, so `RampsService` can mint tokens without the call failing at runtime. A unit test asserts that delegated call returns the token from the registered handler. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c7e989f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com> Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com> Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com>
…l views (#30069) ## Summary Unifies Segment funnel reporting by emitting a new MetaMetrics event `ASSET_VIEWED` whenever any of these legacy events fire, with the **same properties** plus: - `trade_type`: `Predict` | `Perps` | `Swaps` (mapped from the legacy event) - `implementation_type`: `native` (mobile) Legacy events are **unchanged**; `ASSET_VIEWED` is an additional duplicate for downstream analytics. ## **Changelog** CHANGELOG entry: refactor: update analytic events ## Implementation | Legacy event | Trigger | |--------------|---------| | Predict Feed Viewed | `PredictAnalytics` (`feedViewed` / `trackFeedViewed`) | | Perp Screen Viewed | `usePerpsEventTracking` `track()`; `PerpsOpenOrderCard` geo path (`useAnalytics`) | | Unified SwapBridge Page Viewed | `useTrackSwapPageViewed` | Shared merge helper: `app/core/Analytics/trade-transaction-funnel/assetViewedAnalytics.ts` (exported via `app/core/Analytics/index.ts`). Swap-related AB test mappings include `ASSET_VIEWED` so `enrichWithABTests` applies the same assignments as `Unified SwapBridge Page Viewed`. ## Testing ```bash yarn jest app/core/Analytics/trade-transaction-funnel/assetViewedAnalytics.test.ts \ app/components/UI/Perps/hooks/usePerpsEventTracking.test.ts \ app/components/UI/Predict/controllers/PredictAnalytics.test.ts \ app/components/UI/Bridge/hooks/useTrackSwapPageViewed/index.test.ts \ app/util/analytics/enrichWithABTests.test.ts ``` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Analytics-only duplication of existing events with guarded AB enrichment and one Perps screen-type exclusion; no auth, payments, or transaction logic changes. > > **Overview** > Introduces a unified Segment **`Asset Viewed`** event that fires **in addition to** existing Predict, Perps, and Swaps screen-view events, carrying the same payload plus `trade_type` (`Predict` | `Perps` | `Swaps`) and `implementation_type: native` via **`mergeAssetViewedProperties`**. > > **Swaps:** `useTrackSwapPageViewed` now emits `ASSET_VIEWED` next to `Unified SwapBridge Page Viewed`. Swap numpad and token-selector AB mappings include `ASSET_VIEWED` with **`eventPropertyRequirements`** so `enrichWithABTests` only attaches swap experiments when `trade_type` is `Swaps`. > > **Perps:** `usePerpsEventTracking` mirrors `Perp Screen Viewed` with `ASSET_VIEWED`, except **`cancel_all_orders`** screens (avoids mis-mapping `open_position`). Geo-block cancel flow in **`PerpsOpenOrderCard`** also emits `ASSET_VIEWED`. > > **Predict:** `PredictAnalytics` emits `ASSET_VIEWED` for **feed viewed** and **market details opened**. Explore **`trackExploreSectionSeeAll`** adds Predict funnel `ASSET_VIEWED` for **`predictions_trending`** only. > > Helper normalizes open-position fields to **`open_positions_count`** on Asset Viewed. Tests and integration expectations updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3e5bc2f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Prithpal Sooriya <prithpal.sooriya@gmail.com> Co-authored-by: Prithpal Sooriya <prithpal.sooriya@consensys.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )