chore: release: 7.74.0#28948
Conversation
## **Description** Rename the `CONTROLLER_MESSENGERS` constant to `MESSENGER_FACTORIES` to reflect that it provides messenger factories for all messenger clients (controllers + services). 3 files changed. **PR 2 of 4** — depends on PR 1 (#28610). - ~~PR 1: Core type renames (`Controller` → `MessengerClient`, etc.) (#28610)~~ - **PR 2 (this):** `CONTROLLER_MESSENGERS` → `MESSENGER_FACTORIES` - PR 3: `initModularizedControllers` → `initMessengerClients` + utils/Engine.ts renames - PR 4: Property renames (`controller` → `messengerClient`, `getController` → `getMessengerClient`) in all init files + tests Relates to [WPC-916](https://consensyssoftware.atlassian.net/browse/WPC-916). ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/WPC-916 ## **Manual testing steps** ```gherkin Feature: Messenger client init system Scenario: App builds and runs normally Given the app is built from this branch When user opens the app Then the app behaves identically to main (no runtime behavior change) ``` ## **Screenshots/Recordings** N/A — no UI changes. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [WPC-916]: https://consensyssoftware.atlassian.net/browse/WPC-916?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Low behavioral risk (rename-only) but touches engine initialization typing/lookup and includes a huge `default-fixture.json` update that could affect test expectations and increase review surface. > > **Overview** > Renames the modularized messenger lookup constant from `CONTROLLER_MESSENGERS` to `MESSENGER_FACTORIES` and updates engine types/utilities to reference the new name (including generic return-type mappings used during messenger-client initialization). > > Updates `tests/framework/fixtures/json/default-fixture.json`, removing legacy `ComplianceController` fields and significantly expanding `PerpsController` cached market/user data, plus adding a few new persisted fields (e.g., onboarding consent backfill, rewards `ondoCampaignActivity`, and preferences `tokenOverviewChartType`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit cf8987a. 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: MetaMask Bot <metamaskbot@users.noreply.github.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Transitioning from default settings to each individual tab is not working correctly https://github.com/user-attachments/assets/21b9940a-68b9-4c40-a10b-aba54b7996d7  ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: fix default settings navigation ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UI/navigation configuration change; could subtly affect onboarding stack visuals (background/header) and transition behavior but does not touch business logic or data handling. > > **Overview** > Fixes the broken transition from `DefaultSettings` into the individual onboarding settings screens by moving background/header styling into `Stack.Navigator`-level `screenOptions` for `OnboardingSuccessFlow`, and removing per-screen overrides. > > Also standardizes `OnboardingNav` card background via navigator `screenOptions` (dropping redundant per-screen `cardStyle`) to keep transitions visually consistent. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 25a8f51. 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 the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This fixes SWAPS-4336, where swap deeplinks targeting supported but disabled networks could fall back to the default Bridge pair and show an unexpected network-added toast. The deeplink flow now checks swap support first, enables already-known networks in the background, auto-adds supported missing EVM networks from `PopularList`, and consumes one-shot toast suppression correctly so deeplink and Bridge token-selector adds stay silent while normal manual add/remove toasts still behave as expected. ## **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 swap deeplinks on supported disabled networks so the requested chain opens without an extra network-added toast. ## **Related issues** Refs: [SWAPS-4336](https://consensyssoftware.atlassian.net/browse/SWAPS-4336) ## **Manual testing steps** ```gherkin Feature: open swap deeplinks on supported disabled networks Scenario: deeplink adds a supported disabled network without showing an add toast Given Sei is disabled in the wallet When the user opens a swap deeplink for "SEI -> USDC" on Sei Then Bridge opens with "SEI -> USDC" selected on Sei And no "network added" toast is shown Scenario: manual re-add still shows the add toast after deeplink suppression is consumed Given Sei was added by deeplink and then disabled again When the user adds Sei back manually Then a "network added" toast is shown When the user removes Sei again Then a "network removed" toast is shown Scenario: bridge token selection adds a missing supported network silently Given a supported EVM network from the Bridge token selector is disabled When the user selects a token on that network in Bridge Then the network is added in the background And no "network added" toast is shown ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> [SWAPS-4336]: https://consensyssoftware.atlassian.net/browse/SWAPS-4336?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes deeplink-driven network enablement and auto-add behavior for Bridge/Swaps, which can affect navigation, network configuration state, and user-facing toasts. Risk is moderated by added unit tests, but failures could still cause incorrect chain selection or missing/extra notifications. > > **Overview** > Fixes swap deeplinks so supported-but-disabled (or missing) source/dest chains are made available before `BridgeView` mounts, instead of falling back to default params. > > Adds one-shot suppression for *network-added* toasts via `networkToastSuppression`, wires `Main`'s add/remove network toast logic through `shouldShowNetworkListToast`, and uses the suppression when Bridge token selection or swap deeplinks auto-add EVM networks from `PopularList` (clearing suppression on failures). > > Extends `handleSwapUrl` to verify swap support (`ALLOWED_BRIDGE_CHAIN_IDS`), best-effort enable known chains, auto-add supported missing EVM networks, and drop unsupported/unavailable dest tokens; expands tests to cover these scenarios. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b3efc14. 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 the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Adds a Positions/Outcomes tab bar to the game details screen, gated behind the `extendedSportsMarketsLeagues` feature flag per league. **What changed:** - **`useGameDetailsTabs` hook** — New hook that reads the `extendedSportsMarketsLeagues` remote flag, computes tabs (Positions + Outcomes when user has positions, Outcomes-only otherwise), manages active tab state, and determines sticky header indices. - **`PredictGameDetailsContent`** — Fetches positions as a single source of truth and passes them to both the hook (for tab logic) and `PredictGameDetailsTabsContent` (for rendering). Renders `PredictMarketDetailsTabBar` as a direct `ScrollView` child for sticky behavior. - **`PredictGameDetailsTabsContent`** — New component with three rendering paths: - Flag off + has positions → "Your picks" title + `PredictPicks` - Flag off + no positions → `null` - Flag on + has positions → tabbed view (Positions/Outcomes tabs with sticky header) - Flag on + no positions → outcomes placeholder directly (no tab bar) - **`PredictPicks`** — Refactored to accept `positions` and `claimablePositions` as required props instead of fetching internally. Removed "Your picks" title (now owned by parent). Removed internal empty-state check (parent controls visibility). - **`PredictMarketDetailsTabBar`** — Added optional `tabTwStyle` prop to allow consumers to override individual tab styling (game details passes `flex-1` for 2-tab even distribution). ## **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 Positions and Outcomes tab bar to sports game detail screens ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/PRED-802 ## **Manual testing steps** ```gherkin Feature: Game details Positions/Outcomes tab bar Scenario: User views game details with positions (flag-enabled league) Given the user has open positions on a game in an enabled league And the extendedSportsMarketsLeagues flag includes that league When the user navigates to the game detail screen Then a sticky tab bar appears below the chart with "Positions" and "Outcomes" tabs And the "Positions" tab is selected by default And the user's pick items are displayed When the user taps the "Outcomes" tab Then the outcomes placeholder is displayed Scenario: User views game details without positions (flag-enabled league) Given the user has no positions on a game in an enabled league And the extendedSportsMarketsLeagues flag includes that league When the user navigates to the game detail screen Then no tab bar is shown And the outcomes placeholder is displayed directly below the chart Scenario: User views game details on a non-enabled league Given the extendedSportsMarketsLeagues flag does not include the game's league When the user navigates to the game detail screen Then no tab bar is shown And if the user has positions, the "Your picks" title and pick items are displayed And if the user has no positions, nothing is shown below the chart Scenario: Tab bar stickiness Given the user is on a game detail screen with the tab bar visible When the user scrolls down past the chart Then the tab bar sticks to the top of the screen And the tab content scrolls underneath ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** https://github.com/user-attachments/assets/e5fec3d6-b0e7-4aa9-8910-d940b8d623a6 ### **After** https://github.com/user-attachments/assets/26ed73c2-b77b-4da0-b449-c3ddaca6726b ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk: changes game details rendering flow and how positions data is fetched/prop-drilled to drive tabbed UI (including sticky header behavior), gated by a remote feature flag but still impacts a user-facing screen. > > **Overview** > Adds a feature-flagged **Positions/Outcomes** tab experience to the Predict game details screen, including a sticky `PredictMarketDetailsTabBar` when the user has positions in an enabled league and an outcomes placeholder when they don’t. > > Refactors `PredictPicks` to be purely presentational by requiring `positions`/`claimablePositions` props (no internal fetching or header), and introduces `useGameDetailsTabs` + `PredictGameDetailsTabsContent` to centralize tab state/visibility and conditionally render picks vs outcomes content. Updates/expands tests accordingly and removes the prior snapshot test. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8bf539c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ity via the money account homepage so that i can see card deposit and other activity (#28632) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** **Reason:** Money account users need visibility into card, deposit, and other Money-related activity from the Money home experience, with a path to a dedicated list for review and filtering. **Solution:** This PR adds a **Recent activity** (or equivalent) section on `MoneyHomeView` when there are transactions, backed by `useMoneyAccountTransactions` and new UI (`MoneyActivityList`, `MoneyActivityItem`). Users can open a full **Money Activity** screen (`MoneyActivityView`) via the stack route `Routes.MONEY.ACTIVITY`, with date-grouped sections and filters (All / Deposits / Transfers). Transaction rows reuse and extend `MultichainTransactionListItem` for consistent display and fiat formatting via `moneyActivityFiat` and `useMoneyTransactionDisplayInfo`. Row and “View all” taps on activity items still surface an **under construction** alert until detail flows ship. Activity data is driven by remote feature flag `moneyActivityMockDataEnabled` (or `MM_MONEY_ACTIVITY_MOCK_DATA_ENABLED` for local/dev); when mock data is off, lists stay empty until a dedicated Money transactions source is wired in. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Added Money account activity preview on the Money home screen and a full activity list with filters when enabled by feature flags ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-440 Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-429 ## **Manual testing steps** ```gherkin Feature: Money account activity (home and full screen) Background: Given Money home and Money activity are enabled for the build And remote flag moneyActivityMockDataEnabled is on (or MM_MONEY_ACTIVITY_MOCK_DATA_ENABLED=true for local QA) Scenario: user sees activity on Money home and opens full activity Given I am on the Money home screen And mock Money transactions are available Then I should see a Money activity section with recent rows When user taps "View all" (or the section header shortcut) Then I should land on the full Money Activity screen with a back affordance Scenario: user filters activity on the full screen Given I am on the full Money Activity screen When user selects the Deposits filter Then only deposit-type rows should appear When user selects the Transfers filter Then only transfer-type rows should appear When user selects All Then the full merged list should appear Scenario: user taps an activity row (placeholder) Given I am on the Money home activity section or the full Money Activity screen When user taps a transaction row Then an under construction alert should be shown ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** https://www.loom.com/share/48b54c51745d4d03947ab4a48bc0fe99 <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds new Money activity UI, navigation route, and fiat-display logic driven by a new remote/env feature flag; while mostly additive, it touches transaction formatting/conversion and navigation paths that could affect Money screens. > > **Overview** > Adds a **Money Activity** experience: a recent-activity preview on `MoneyHomeView` (with a "View all" CTA) and a new full-screen `MoneyActivityView` that groups transactions by date and supports **All / Deposits / Transfers** filtering. > > Introduces new shared UI + data plumbing for activity rows: `MoneyActivityList` (5-item preview), `MoneyActivityItem` (row rendering + optional network badge), `useMoneyTransactionDisplayInfo` and `moneyActivityFiat` for token/fiat line formatting, and `moneyActivityFilters`/`activityStyles` helpers. > > Wires the screen into navigation by adding `Routes.MONEY.ACTIVITY` and registering it in the Money stack (with themed `cardStyle` background), and gates mock activity data behind a new `moneyActivityMockDataEnabled` remote flag (with `MM_MONEY_ACTIVITY_MOCK_DATA_ENABLED` fallback). Includes comprehensive unit tests and new `en.json` strings for activity and transaction labels. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a1b8842. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…other flows cp-7.73.0 (#28685) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> A user reported that the "Pay with" token selector on `PredictBuyWithAnyToken`wasn't allowing to select a different token. A transaction is needed to that work and the current logic could pick up pending approvals from unrelated flows (bridge, swap, send, etc.), allowing them to select tokens from the wrong transaction context. **Root cause:** `initPayWithAnyToken()` calls `addTransactionBatch()` directly without first rejecting existing pending approvals — unlike the standalone `predictDeposit` flow which goes through `useConfirmNavigation` and rejects all unapproved transactions before creating its own. When stale approvals existed, `useApprovalRequest()` returned the first (wrong) approval, and `PredictPayWithRow` enabled token selection based on a generic `transactionMeta` truthiness check. **Fix (defense-in-depth):** 1. **`usePredictBuyActions`** — added `rejectPendingTransactions()` in the `transitionEnd` handler before `initPayWithAnyToken()`, mirroring the cleanup pattern from `useConfirmNavigation`. 2. **`PredictPayWithRow`** — replaced the generic `transactionMeta` truthiness check with `hasTransactionType(transactionMeta, [TransactionType.predictDepositAndOrder])`, so the selector only enables for the correct transaction type. This branch also includes prior commits that handle no-quotes blocking alerts in the buy flow and disable the pay-with selector until transaction metadata is ready. ## **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: Predict buy-with-any-token token selector isolation Scenario: token selector stays disabled when a non-predict approval is pending Given user has an unconfirmed swap or bridge transaction pending And user navigates to a Predict market buy screen When the buy screen finishes loading Then the "Pay with" row does not show an arrow icon And tapping the "Pay with" row does not open the token selection modal Scenario: token selector enables after deposit-and-order batch is created Given user has no pending transactions And user navigates to a Predict market buy screen When the buy screen finishes loading and initPayWithAnyToken completes Then the "Pay with" row shows the arrow icon And tapping the "Pay with" row opens the token selection modal Scenario: stale approvals are rejected on buy screen entry Given user has an unconfirmed transaction from another flow And user navigates to a Predict market buy screen When the screen transition completes Then the stale unconfirmed transaction is rejected And a new deposit-and-order batch is created as the only pending approval ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches transaction/approval handling in the Predict buy flow by programmatically rejecting unapproved transactions and tightening when the pay-with selector is enabled; regressions could affect in-flight approvals or block token selection. > > **Overview** > Prevents the `PredictBuyWithAnyToken` pay-with token selector from latching onto stale approvals from other flows. > > On screen entry, `usePredictBuyActions` now rejects all `unapproved` transactions before calling `initPayWithAnyToken`, and `PredictPayWithRow` only enables navigation/UI affordances when the current `transactionMeta` is a `TransactionType.predictDepositAndOrder` (otherwise it disables press, hides the arrow, and removes the muted background). The buy flow also propagates *blocking* pay alerts (insufficient balance / no quotes) via `usePredictBuyInfo` into `usePredictBuyConditions` and `usePredictBuyError` to disable placing bets and surface the correct blocking message, with updated tests. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 69b5397. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
Fix perps and short transition
<!--
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**
https://github.com/user-attachments/assets/c922da17-10ce-4ed4-b1c0-7690cbe8471b
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches React Navigation screen options for the perps confirmation
flow, which can affect modal presentation/transition behavior and header
visibility across routes.
>
> **Overview**
> Adjusts the perps `RedesignedConfirmations` screen options to
explicitly return `StackNavigationOptions` and always use `presentation:
'transparentModal'`, while keeping the conditional perps header
behavior.
>
> This is intended to fix the perps/short transition behavior by
ensuring confirmations are presented with a consistent transparent modal
configuration.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ccdf1f4. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…27898) ## **Description** Implements [TAT-2761](https://consensyssoftware.atlassian.net/browse/TAT-2761): remove the PerpsHome cold-start skeleton caused by empty controller caches. **What changed:** - `PerpsAlwaysOnProvider` now owns `startMarketDataPreload()`, so preload runs from the wallet root in both wallet layouts. - Perps hooks seed first render from live stream snapshots before falling back to controller cache, eliminating remount flashes for positions, orders, account, and markets. - `MarketDataChannel.clearCache()` now preserves valid global market cache on account-only clears. - `PerpsController` persists successful preload market/user snapshots to MMKV and hydrates them synchronously on startup, including multi-provider payloads. - `docs/perps/perps-caching-architecture.md` updated to match the actual disk write and hydration paths. **Benchmark (iOS simulator, April 1 2026):** - Clean perps disk cache → first PerpsHome market data: `3908ms` - Same-session reopen of PerpsHome → first market data: `0ms` - After JS reload → controller hydrated `286` markets in `9ms`, first PerpsHome market data: `0ms` ## **Changelog** CHANGELOG entry: Added persistent disk-backed caching for Perps so the trading screen opens instantly without loading skeletons ## **Related issues** Fixes: [TAT-2761](https://consensyssoftware.atlassian.net/browse/TAT-2761) ## **Manual testing steps** ```gherkin Feature: Perps cold-start caching Scenario: user opens Perps after a fresh app launch Given the user has previously visited the Perps trading screen When user relaunches the app and navigates to Perps Then the trading screen displays market data immediately without loading skeletons Scenario: user reopens Perps after JS reload Given the user is on the Perps trading screen When user triggers a JS reload and navigates back to Perps Then cached market data is hydrated instantly from disk And no skeleton loading state is shown Scenario: user switches accounts while on Perps Given the user has Perps open with cached market data When user switches to a different account Then global market cache is preserved And only user-specific data (positions, orders) is refreshed ``` ## **Screenshots/Recordings** ### **Before** Loading skeletons shown on every PerpsHome open (cold start and JS reload). ### **After** Market data renders instantly from disk cache; no skeleton flash on reopen or JS reload. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [TAT-2761]: https://consensyssoftware.atlassian.net/browse/TAT-2761?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [TAT-2761]: https://consensyssoftware.atlassian.net/browse/TAT-2761?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes Perps data seeding, cache invalidation, and persistence behavior across app restarts and reconnects; bugs could surface as stale/incorrect positions/markets or missing invalidations during account/provider switches. > > **Overview** > Enables *instant Perps home rendering on cold start* by adding a disk-backed cache layer and seeding hooks from synchronous stream snapshots before falling back to controller preload caches. > > `PerpsController` now **hydrates market/user caches from disk at construction time** and persists successful REST preloads back to disk, with support for aggregated multi-provider payloads and a new `skipTTL` option to serve disk-hydrated data on first paint. > > `PerpsStreamManager` adds `getSnapshot()` to channels and **persists live market/user snapshots to disk (throttled)**, preserves global market cache on account-only clears, and resets/invalidates disk cache on reconnect/account/provider changes. Preload ownership moves from `Wallet/index.tsx` to `PerpsAlwaysOnProvider`, and tests/mocks/docs are updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ed83a41. 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: Racitores <ramon.acitores@consensys.net>
…7.73.0 (#28622) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> We're experiencing an issue where the SafeAreaView top padding gets recalculated upon component mount, which results in bad UI. This PR reduces the blast radius of the changes by consolidating all SafeAreaView imports to `react-native-safe-area-context`. We then create a shim for the module, which handles applying top insets via style instead. Changes also includes: - Consolidate safe area context mocks in test setup file - Remove unused safe area mocks within test files - Update snapshots ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches SafeAreaView usage across many screens, so incorrect inset/edge handling could cause widespread layout regressions on iOS/Android despite being mostly mechanical changes. > > **Overview** > Standardizes `SafeAreaView` usage by switching many components from `react-native` to `react-native-safe-area-context` (including adding explicit `edges` in a few places) to avoid incorrect top-inset recalculation on mount. > > Refactors navigation/header configuration for `DeFiProtocolPositionDetails` by moving `setOptions` logic out of the component and into `MainNavigator` options via `getDeFiProtocolPositionDetailsNavbarOptions` (now explicitly sets `headerShown: true`). > > Cleans up tests by removing per-file safe-area mocks in favor of the centralized jest mock in `testSetupView.js`, and updates snapshots/expectations accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f88a0cf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…et test (#28708) ## **Description** Fix Prettier formatting violations and eslint errors in `SafeAreaViewWithHookTopInset.test.tsx` introduced by #28622. These break lint checks on any unrelated PR that touches this file. **Changes:** - Reformat JSX to match Prettier config - Extract inline styles to `StyleSheet.create` to fix `react-native/no-inline-styles` - Replace `require()` with `jest.requireActual()` in `jest.mock` factory to fix `@typescript-eslint/no-require-imports` ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes lint/formatting regressions from #28622 ## **Manual testing steps** ```gherkin Feature: SafeAreaViewWithHookTopInset test lint compliance Scenario: lint and tests pass on the test file Given the file app/shims/SafeAreaViewWithHookTopInset.test.tsx When running eslint on the file Then zero errors are reported When running jest on the file Then all 20 tests pass ``` ## **Screenshots/Recordings** N/A — no visual changes, formatting and lint fixes only. ### **Before** 6 eslint errors on `main`: - 2x `@typescript-eslint/no-require-imports` — `require()` inside `jest.mock` factory - 4x `react-native/no-inline-styles` — inline style objects in test assertions ### **After** 0 eslint errors, 0 eslint-disable comments, all 20 tests passing. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: changes are confined to a Jest test file and only adjust mocks/style declarations to satisfy linting/formatting, without touching runtime code paths. > > **Overview** > Cleans up `SafeAreaViewWithHookTopInset.test.tsx` to pass lint/format checks by switching `jest.mock` factories from `require()` to typed `jest.requireActual()` and tightening ref typings in the mock `SafeAreaView`. > > Replaces inline style objects used in tests with a shared `StyleSheet.create` (`testStyles`) and applies minor Prettier-driven JSX/line-wrap formatting changes, leaving test coverage/behavior unchanged. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 00a20c7. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Add app lifecycle actions (`app_background`, `app_foreground`,
`app_restart`) to the agentic tooling with platform-aware
implementations (iOS `simctl` + Android `adb`). Enable multi-device CDP
target discovery so `status` probes all targets across both platforms.
Fix preflight to reuse a healthy Metro instance (curl /status check) and
warn on platform mismatch instead of failing. Add `--input key=value`
flag to `validate-recipe.js`.
Also fixes switch/end nodes bypassing `when` guards (caused TypeError on
default config), and adds automatic `run.log` capture for every recipe
execution.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Agentic lifecycle actions and multi-device support
Scenario: run app-lifecycle recipe in dry-run mode
Given the agentic tooling is available
When user runs validate-recipe with app-lifecycle.json --dry-run
Then recipe parses and validates without errors
Scenario: CDP bridge status shows multiple targets
Given both iOS simulator and Android emulator are running
When user runs cdp-bridge.js status
Then both platform targets are listed
Scenario: lifecycle actions execute per platform
Given the app is running on iOS simulator
When user triggers app_background action
Then the app moves to background via simctl
```
## **Screenshots/Recordings**
### **Before**
N/A — new tooling feature
### **After**
- `node validate-recipe.js recipes/app-lifecycle.json --dry-run` —
parses OK
- Lifecycle actions validated on both iOS simulator and Android emulator
- Multi-device target discovery working across platforms
## **Validation Recipe**
<details><summary>app-lifecycle.json (20 nodes — short background, long
background, restart)</summary>
```json
{
"title": "App Lifecycle — validate data survives background, long background, and restart",
"description": "Reference recipe demonstrating three lifecycle stress levels: short background (within WS grace period), long background (exceeds grace period, forces full WS reconnection), and full app restart. Use as a template for PR recipes that need lifecycle validation.",
"inputs": {
"symbol": { "type": "string", "default": "BTC" },
"short_background_ms": { "type": "number", "default": 5000 },
"long_background_ms": { "type": "number", "default": 30000 },
"test_short_background": { "type": "boolean", "default": true },
"test_long_background": { "type": "boolean", "default": true },
"test_restart": { "type": "boolean", "default": false }
},
"validate": {
"workflow": {
"pre_conditions": ["wallet.unlocked", "perps.feature_enabled"],
"entry": "nav-market-list",
"nodes": {
"nav-market-list": { "action": "navigate", "target": "PerpsTrendingView", "next": "wait-markets" },
"wait-markets": { "action": "wait_for", "assert": { "operator": "gt", "field": "count", "value": 0 }, "next": "baseline-price" },
"baseline-price": { "action": "eval_async", "description": "Baseline — confirm markets and price data loaded", "next": "short-background" },
"short-background": { "action": "app_background", "when": "test_short_background", "duration_ms": "{{short_background_ms}}", "next": "short-foreground" },
"short-foreground": { "action": "app_foreground", "next": "wait-post-short" },
"wait-post-short": { "action": "wait_for", "next": "verify-post-short" },
"verify-post-short": { "action": "eval_async", "description": "Confirm markets + price survive short background", "next": "long-background" },
"long-background": { "action": "app_background", "description": "Exceeds WS grace period", "duration_ms": 30000, "next": "long-foreground" },
"long-foreground": { "action": "app_foreground", "next": "wait-post-long" },
"wait-post-long": { "action": "wait_for", "next": "verify-post-long" },
"verify-post-long": { "action": "eval_async", "description": "Confirm markets + DEXs recover after WS reconnection", "next": "restart-app" },
"restart-app": { "action": "app_restart", "when": "test_restart", "next": "detect-post-restart" },
"...": "remaining restart/unlock/verify nodes",
"done": { "action": "end", "status": "pass" }
}
}
}
}
```
</details>
## **Validation Logs**
Command:
```bash
node scripts/perps/agentic/validate-recipe.js \
scripts/perps/agentic/teams/perps/recipes/app-lifecycle.json
```
<details><summary>Full output (11/17 passed, 6 skipped — iOS)</summary>
```
Running recipe: App Lifecycle — validate data survives background, long background, and restart
Team: perps
Pre-conditions: wallet.unlocked, perps.feature_enabled
Workflow nodes: 20
Pre-conditions: PASS
[nav-market-list] navigate to PerpsTrendingView
result: {"navigated":"PerpsTrendingView",...}
PASS
[wait-markets] wait for condition
result: {"count":291}
PASS
[baseline-price] Baseline — confirm markets and price data loaded
result: {"found":true,"price":"$71,046"}
PASS
[short-background] Short background — within WS grace period, cache should be preserved
backgrounded for 5000ms
PASS
[short-foreground] foreground app
foregrounded (io.metamask.MetaMask)
PASS
[wait-post-short] wait for condition
result: {"count":291}
PASS
[verify-post-short] Confirm markets + price survive short background
result: {"found":true,"price":"$71,058"}
PASS
[long-background] Long background — exceeds WS grace period, forces full reconnection
backgrounded for 30000ms
PASS
[long-foreground] foreground app
foregrounded (io.metamask.MetaMask)
PASS
[wait-post-long] wait for condition
result: {"count":291}
PASS
[verify-post-long] Confirm markets + DEXs recover after full WS reconnection
result: {"markets":291,"dexs":9,"price":"$71,039"}
PASS
[restart-app] restart app
[SKIPPED - when condition did not match]
[detect-post-restart] Detect login vs wallet after restart
[SKIPPED - when condition did not match]
[check-needs-unlock] evaluate branch
[SKIPPED - when condition did not match]
[nav-after-restart] navigate to PerpsTrendingView
[SKIPPED - when condition did not match]
[wait-post-restart] wait for condition
[SKIPPED - when condition did not match]
[verify-post-restart] Confirm markets reload cleanly after full restart
[SKIPPED - when condition did not match]
----------------------------------------
Results: 11/17 passed, 6 skipped
Recipe: PASS
```
</details>
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Adds new workflow actions that spawn `xcrun`/`adb` processes and
changes CDP target selection/reporting, which can affect automation
reliability across devices. Also introduces automatic log
capture/redaction and new CLI flags that alter runner behavior.
>
> **Overview**
> **Agentic workflows can now exercise app lifecycle events.** The
recipe runner adds new actions (`app_background`, `app_foreground`,
`app_restart`) implemented via a new `lib/app-lifecycle.js` that uses
`simctl`/AppleScript on iOS and `adb` on Android, and documents these
actions plus a new `teams/perps/recipes/app-lifecycle.json` reference
recipe.
>
> **CDP and preflight scripts now better support multi-device setups.**
`cdp-bridge.js status` probes *all* discovered Hermes targets (via new
`discoverAllTargets`) and returns either a single object or an array;
`preflight.sh` reuses an already-healthy Metro instance by probing
`/status` and loosens the platform check to a warning when the expected
platform target isn’t found.
>
> **Recipe execution UX improved.** `validate-recipe.js` adds `--input
key=value` for overriding recipe inputs, `--no-log` to disable logging,
captures console output to `run.log` with basic redaction, and fixes
`when` guards to apply to `switch`/`end` nodes (skipping them safely
instead of executing).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b3948ed. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## **Description**
Removed the scheduled cron trigger from
`.github/workflows/run-e2e-regression-tests-android.yml` so this
workflow no longer runs every 3 hours.
The workflow can still be run manually via `workflow_dispatch`.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: Android regression workflow trigger behavior
Scenario: workflow can be manually triggered only
Given the GitHub Actions workflow file `run-e2e-regression-tests-android.yml`
When I inspect the `on` section
Then it contains `workflow_dispatch` inputs
And it does not contain a `schedule` cron trigger
```
## **Screenshots/Recordings**
Not applicable (CI workflow configuration change only).
### **Before**
N/A
### **After**
N/A
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a
href="https://cursor.com/agents/bc-6074cff0-b322-43a4-898b-b8b12af5bb28"><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-6074cff0-b322-43a4-898b-b8b12af5bb28"><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>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cmd-ob <cmd-ob@users.noreply.github.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Fix design of mush deposit page. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1173 ## **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** <img width="395" height="853" alt="Screenshot 2026-04-10 at 4 22 11 PM" src="https://github.com/user-attachments/assets/584fab12-a80f-4092-a57e-6ec0e662dabd" /> ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I've included tests if applicable - [X] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UI/prop change limited to the confirmations custom amount view and mUSD conversion flow; main risk is unintended layout/row visibility regressions when `hidePayTokenAmount` is enabled. > > **Overview** > Updates `CustomAmountInfo` to **remove `overrideContent`** and introduce `hidePayTokenAmount`, which hides the default `PayTokenAmount` (and the associated extra content block) while keeping `PayWithRow` rendering logic consistent. > > Simplifies `MusdConversionInfo` by deleting the bespoke override UI (output tag + embedded `PayWithRow`) and instead passing `hidePayTokenAmount` to `CustomAmountInfo`; tests are updated accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3c829f9. 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 the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Speed up and cancel failures no longer open a blocking **Retry** modal. Users see a **toast** with a clear title and, when available, a short error description—including a friendlier message when the failure is due to **“nonce too low”** (already confirmed). **Changes** - Removed `RetryModal` and related state (`retryIsOpen`, `errorMsg`, `toggleRetry`, `retry`) from the legacy **Transactions** screen and **UnifiedTransactionsView**. - On failure, **legacy** `Transactions` uses `ToastService.showToast` with shared options from `getTransactionUpdateErrorToastOptions`. - **Unified** flow uses `ToastContext` in `useUnifiedTxActions` to show the same toast shape. - Centralized toast config in `app/util/confirmation/transactions.ts` (variant, icon, colors, transparent background, copy) so both entry points stay in sync. - Added `resolveTransactionUpdateErrorMessage` to map raw errors to user-facing strings where we special-case known cases. <!-- 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: Redesigned speed-up/cancel retry modal with error toasts ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1076 ## **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** [toast failed.webm](https://github.com/user-attachments/assets/3baec8fe-8513-4e99-ad14-f36c16a72043) <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UX refactor that changes how speed-up/cancel failures are surfaced (toast instead of a blocking modal) without altering transaction update logic; main risk is missing toast context/service wiring in some views. > > **Overview** > Speed-up/cancel failures no longer open a blocking **Retry** modal; they now show an **error toast** in both the legacy `Transactions` list (via `ToastService`) and the unified flow (via `ToastContext`). > > Adds shared helpers `resolveTransactionUpdateErrorMessage` and `getTransactionUpdateErrorToastOptions` in `util/confirmation/transactions.ts`, including a friendlier message for *“nonce too low”* (already confirmed), and updates tests/mocks accordingly. Locale strings are migrated from `transaction_update_retry_modal` to `transaction_update_toast` across supported languages. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d49b050. 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 the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This updates the A/B testing documentation to make the implementation path much easier for a new engineer to follow. The guide now starts with a quickstart and definition of done, consolidates the implementation guidance into one end-to-end example, and moves agent-specific workflow details to an appendix so they do not interrupt the main onboarding flow. ## **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** N/A ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill -->
…8724) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Using alert system for money account related errors. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1182 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** NA ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I've included tests if applicable - [X] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes how `moneyAccountDeposit` “no funds” is surfaced by introducing a new blocking alert and wiring it into the shared pending-amount alert pipeline, which can affect confirm-button enablement and user flow. Risk is limited to confirmations/UX and is covered by added unit tests. > > **Overview** > Moves the `moneyAccountDeposit` “no funds” state into the confirmations *alert system* by introducing a new blocking `AccountNoFunds` alert (with metrics mapping) and feeding it through `usePendingAmountAlerts`. > > Removes the old inline “no funds” red text from `CustomAmountInfo`, updates tests to assert alert-driven rendering, and adds new i18n under `alert_system.account_no_funds` while deleting the legacy `confirm.no_funds_use_different_account` string. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c92ce45. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This PR syncs the stable branch to main for version 7.74.0. *Synchronization Process:* - Fetches the latest changes from the remote repository - Resets the branch to match the stable branch - Attempts to merge changes from main into the branch - Handles merge conflicts if they occur *File Preservation:* Preserves specific files from the stable branch: - CHANGELOG.md - bitrise.yml - android/app/build.gradle - ios/MetaMask.xcodeproj/project.pbxproj - package.json Indicates the next version candidate of main to 7.74.0
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
Wires up the Social Leaderboard to live data from the Social API.
Integrate the social-controllers (SocialService + SocialController) into
the Engine, adds useTopTraders hook using useQuery from
@metamask/react-data-query to fetch leaderboard data through the Data
Services pattern.
Also adds the homepage TopTradersSection (horizontal card carousel) and
the full TopTradersView (ranked list) with skeleton loading states.
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Adds a new Social data service/controller to the Engine and wires UI
screens to fetch live leaderboard data from a new `SOCIAL_API_URL`,
which could impact app startup/state persistence and introduce new
network failure modes.
>
> **Overview**
> Adds live Social Leaderboard integration by introducing Engine-managed
`SocialService` and `SocialController` (new messengers, init wiring,
persisted state, and data-service registration) and configuring a new
`SOCIAL_API_URL` build/env constant.
>
> Updates the homepage `TopTradersSection` to fetch and render the top 3
traders (cards + skeleton loading, refresh via ref, hide when empty/flag
off) and upgrades `TopTradersView` to display the full ranked list with
a network filter entry point and follow toggles.
>
> Includes new UI components (`TopTraderCard`, `TraderRow`, skeletons,
`NetworkFilterButton`), a `formatPnl` formatter, the `useTopTraders`
hook built on `@metamask/react-data-query`, plus expanded unit tests and
updated mocks/strings.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5881e59. 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 the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** https://consensyssoftware.atlassian.net/browse/RWDS-1163 ### Leaderboard tier selector - Replaced TabsBar with a Pressable trigger that opens a RewardsSelectSheet bottom sheet for tier selection - Created RewardsSelectSheet -- a generic, reusable select bottom sheet registered as a transparentModal in MainNavigator.js at Routes.MODAL.REWARDS_SELECT_SHEET. Accepts title, options, selectedValue, and onSelect callback - Default tier is the user's projected tier (from leaderboard position) when available, otherwise the top tier (last in list) ### Stats summary - Added CampaignStatsSummary component displaying Return, Market Value, Rank, and Tier in a 2x2 grid with loading skeletons and error banners ### Leaderboard neighbor display (preview mode) - When maxEntries is set and the user's tier matches the selected tier: - If user rank is within visible range: highlights their row with bg-background-muted - If user rank is outside visible range: shows top 3 entries + dot separator + neighbor entries (rank-1, user, rank+1) - Handles edge cases: first/last in tier (1-2 neighbors), tier mismatch, no position data ### Pending tag / Qualified tag - Add `qualified` and `qualifiedDays` to CampaignLeaderboardEntry and CampaignLeaderboardPositionDto - Display `Pending` Tag if qualified: false, `Qualified` tag if true ### Activity view - Group activity rows by date ### Prize pool - Add prize pool progress bar according to hardcoded breakpoints given by PRD - Fetch total deposit volume from new endpoint Get(':campaignId/stats/deposits') <!-- 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* ### Pending <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-09 at 17 59 47" src="https://github.com/user-attachments/assets/bfdcec83-6f2b-4c29-b416-35b1c3275be9" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 15 05" src="https://github.com/user-attachments/assets/500d7428-f0bc-40f1-ace7-c7048b38e23f" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 15 41" src="https://github.com/user-attachments/assets/a0af5d73-a265-4c0b-b8c7-d9f928cc10e3" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 18 33" src="https://github.com/user-attachments/assets/c695d664-4465-4f07-9027-668ae1d2fd7d" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 18 40" src="https://github.com/user-attachments/assets/a1a0da1a-31ed-4207-bf4f-379485655cb5" /> ### Qualified <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 20 27" src="https://github.com/user-attachments/assets/29b8def5-4d08-4cf0-9e2f-3272ecdf93c2" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 20 31" src="https://github.com/user-attachments/assets/9e0c3c85-7a10-4f50-8418-8d40b5f29afb" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 23 10" src="https://github.com/user-attachments/assets/19f2ab07-f255-4767-b90a-e07dc8265c08" /> ### Activity view <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 15 28 48" src="https://github.com/user-attachments/assets/e8b42158-b6ff-47e9-b44d-ab23ba87ecc1" /> ### Prize pool <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 17 24 02" src="https://github.com/user-attachments/assets/ac0b1219-2252-41ed-bd26-656f188076eb" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 17 29 36" src="https://github.com/user-attachments/assets/6f47ff55-db28-4318-919d-ce50319d0010" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-04-10 at 17 29 58" src="https://github.com/user-attachments/assets/c4d64e3a-aa0d-44bf-bd50-8f9703986acf" /> * <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Moderate UI/behavior changes in Rewards campaign flows plus a new data fetch (`getOndoCampaignDeposits`) and updated leaderboard rendering, which could affect navigation and correctness of displayed stats/tier selection. > > **Overview** > Updates Ondo campaign rewards UI to support **tier-based leaderboards** via a new reusable `RewardsSelectSheet` modal (registered in `MainNavigator`) and localized tier display names. > > Reworks campaign details/leaderboard presentation by replacing `OndoLeaderboardPosition` with a new `CampaignStatsSummary` (return/market value/rank/tier, pending/qualified tags, SWR-style loading/error handling), adding a `OndoPrizePool` progress section backed by a new `useGetOndoCampaignDeposits` hook, and enhancing `OndoLeaderboard` with preview mode (`maxEntries`), current-user highlighting, and neighbor/split-view rendering. > > Refactors the portfolio activity view to be **activity-only**, grouped by date headers, and updates activity rows to support `timeOnly`, signed USD formatting, and external outflow address shortening; tests are updated/added accordingly. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ecd1e4b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…-3331] (#28337) ## **Description** When selecting a token in the UB2 Buy flow, a quick error ("We've encountered an error") flashes on the amount input screen before the correct "Powered by [provider]" text appears. The root cause is a provider ID mismatch: the quotes API can return provider IDs in a prefixed format (`/providers/transak`) while the controller state stores them without the prefix (`transak`). This caused `selectedQuote` to resolve to `null`, briefly rendering the error banner. The fix normalizes provider IDs on both sides of the comparison using `normalizeProviderCode()` and switches from array destructuring to `.find()` so all returned quotes are searched. ## **Changelog** CHANGELOG entry: Fixed Buy amount screen sometimes showing a generic error when quotes returned for the selected provider but provider id strings differed in format. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3331 Based on draft PR #27779 ## **Manual testing steps** ```gherkin Feature: Token selection in Buy flow Scenario: user selects a token and navigates to amount input Given user is on the token selection screen in the Buy flow When user selects a token (e.g. ETH) Then the amount input screen shows "Powered by [provider]" without any error flash ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> N/A. Reason: This is an extremely rare race condition. It doesn't happen often, and after several changes on main, it's even less common. Nevertheless, we still want to solve this logical condition via this PR. ### **After** <!-- [screenshots/recordings] --> N/A. Reason: This is an extremely rare race condition. It doesn't happen often, and after several changes on main, it's even less common. Nevertheless, we still want to solve this logical condition via this PR. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches Buy flow quote-selection and payment-method loading state; small logic changes but in a user-critical conversion path and could affect when errors/continue button appear. > > **Overview** > Prevents the Buy amount input screen from briefly showing the generic *no quotes* error by updating `BuildQuote` to **normalize provider IDs** (handling `/providers/...` vs short codes) and to **search all returned quotes** via `.find()` when deriving `selectedQuote`. > > Tightens `useRampsPaymentMethods` loading behavior so `isLoading` stays true while auto-selecting a payment method when the previously selected method is no longer present, avoiding UI flashes of stale selection. Adds targeted tests covering provider-ID matching scenarios, empty/mismatched quote responses, continue-button disabled state, and the stale-selection loading fallback. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2d4d9d7. 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: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…saction confirmation (#28040) ## Summary - Fixes a race condition in `Toast.showToast` where rapid successive calls (e.g., transaction approved + confirmed in the same tick on Linea) cause the success toast to persist indefinitely - Tracks pending `setTimeout` with a ref so only the latest `showToast` call wins, ensuring the success toast renders with its proper auto-dismiss animation - Adds test coverage for the rapid successive `showToast` scenario https://github.com/user-attachments/assets/12064e1e-3beb-4d36-82e3-3237b2045eb6 ## Test plan - [x] Toast unit tests pass (`yarn jest app/component-library/components/Toast/Toast.test.tsx`) - [x] Manual: trigger a Max DAI→mUSD conversion on Linea and verify the success toast auto-dismisses after ~3s - [x] Verify normal (non-rapid) toast transitions still work correctly <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches toast display timing/animation logic; small but could regress toast sequencing or dismissal behavior if timer clearing interacts with existing transitions. > > **Overview** > Fixes a race in `Toast.showToast` where back-to-back calls could leave multiple queued `setTimeout` updates, causing the wrong toast state/timeout behavior (e.g., a success toast persisting). > > `Toast` now tracks and clears any pending `setTimeout` via a ref so only the latest `showToast` call applies. Adds a unit test asserting rapid successive calls leave a single pending timer and only the latest toast renders. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 111df6d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Bringing the following changes to the client: ```markdown ## [1.25.2] ### Fixed - Relax Trongrid `internal_transactions` validation to avoid sync failures on sparse legacy payloads ([#289](MetaMask/snap-tron-wallet#289)) - Handle TRC10 token identifiers correctly in the current Trongrid account-history transaction flow, without mis-parsing endpoint-specific `asset_name` formats ([#289](MetaMask/snap-tron-wallet#289)) - Decouple assets and transactions synchronization so one failure does not prevent the other from completing ([#289](MetaMask/snap-tron-wallet#289)) ``` ## **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** n/a ## **Manual testing steps** n/a ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** n/a ### **After** n/a ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk dependency bump confined to the Tron snap package; behavior changes are limited to Tron sync handling and should not affect unrelated wallet flows. > > **Overview** > Bumps `@metamask/tron-wallet-snap` from `^1.25.1` to `^1.25.2`, updating both `package.json` and `yarn.lock` resolution/checksum. > > This pulls in upstream fixes around Tron sync robustness (more permissive Trongrid `internal_transactions` validation, correct TRC10 token identifier handling, and separating asset vs transaction sync so one failure doesn’t block the other). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 235931c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…nd update result properties (#28645) ## **Description** Rename `initModularizedControllers` to `initMessengerClients`, drop `existingControllersByName`, rename `controllerInitFunctions` to `initFunctions`, and update return type to `messengerClientsByName`. Update all consumers in `Engine.ts`, `utils.test.ts`, and test utility functions. 80 files changed. **PR 3 of 4** — depends on PR 2 (#28641). - ~~PR 1: Core type renames (`Controller` → `MessengerClient`, etc.) (#28610)~~ - ~~PR 2: `CONTROLLER_MESSENGERS` → `MESSENGER_FACTORIES` (#28641)~~ - **PR 3 (this):** `initModularizedControllers` → `initMessengerClients` + utils/Engine.ts renames - PR 4: Property renames (`controller` → `messengerClient`, `getController` → `getMessengerClient`) in all init files + tests Relates to [WPC-916](https://consensyssoftware.atlassian.net/browse/WPC-916). ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/WPC-916 ## **Manual testing steps** ```gherkin Feature: Messenger client init system Scenario: App builds and runs normally Given the app is built from this branch When user opens the app Then the app behaves identically to main (no runtime behavior change) ``` ## **Screenshots/Recordings** N/A — no UI changes. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [WPC-916]: https://consensyssoftware.atlassian.net/browse/WPC-916?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Refactors the Engine’s initialization wiring for all controller/messenger clients, so mistakes could break startup order or dependency resolution despite being a rename-focused change. > > **Overview** > **Renames and reshapes the Engine init helper** by replacing `initModularizedControllers` with `initMessengerClients`, renaming `controllerInitFunctions` to `initFunctions`, and returning `messengerClientsByName`. > > **Simplifies initialization state** by dropping support for `existingControllersByName` and updating the dependency lookup helper/error messaging to `getMessengerClientOrThrow`. > > Updates `Engine.ts` wiring and a large set of controller init tests to use the new request mock helper (`buildMessengerClientInitRequestMock`) and the new result property names. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 80bf6e1. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
This PR polishes the Money feature so the patterns for Headers, List,
Sections, Filtering and Spacing are visually cohesive.
## **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: Money account activity and hub layout polish
Scenario: User opens Money activity from the Money hub
Given the user is logged in with a Money account that can show activity
And the user is on the Money hub (home) screen
When the user navigates to Money activity (Activity)
Then the activity screen loads with the expected header and back affordance
And activity is grouped and readable (date sections and list items render without layout overlap)
Scenario: User filters Money activity by type
Given the user is on the Money activity screen
And there is activity data available for more than one filter category
When the user changes the activity filter (e.g. All / Deposits / Transfers as applicable)
Then the list updates to match the selected filter
And section headers and row content remain correctly aligned and legible
Scenario: User reviews Money hub summary and quick actions after layout updates
Given the user is on the Money hub (home) screen
When the user views the balance summary and the primary action buttons row
Then balances and labels use the updated typography and spacing (no clipped text or misaligned controls)
And primary actions remain tappable with expected labels and icons
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<img width="1462" height="680" alt="Screenshot 2026-04-13 at 4 30 22 PM"
src="https://github.com/user-attachments/assets/38255e3a-a6c7-4ada-9a5b-7a0b5406eba0"
/>
### **After**
<img width="1442" height="643" alt="Screenshot 2026-04-13 at 4 30 37 PM"
src="https://github.com/user-attachments/assets/5bf37578-baf5-4b7f-8391-2a9611bb11c1"
/>
## **Pre-merge author checklist**
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk visual-only tweaks to layout, spacing, and typography within
Money screens; main risk is minor UI regressions like
truncation/clipping on edge device sizes.
>
> **Overview**
> Improves visual cohesion across Money hub and activity screens by
adjusting padding/spacing, alignment, and typography in headers, section
headers, lists, and filter buttons.
>
> Updates action buttons and activity rows to better handle sizing and
truncation (larger icons/avatars, centered/stretch layouts,
`min-w-0`/`shrink` Tailwind classes), and lightly refines secondary text
weights and button container padding for consistency.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5ae2126. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Feature Flag Registry Drift Report Feature flag drift was detected between E2E tests and production. Download the [`drift-report` artifact](https://github.com/MetaMask/metamask-mobile/actions/runs/24060043070) for the full report. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Priya <priya.narayanaswamy@consensys.net>
## **Description** New: Campaign Stats Screen A dedicated screen showing the user's personal performance in the campaign — their current return (positive in green, negative in red), total portfolio value, rank, tier (Bronze, Silver, Platinum), net deposit amount, days held, and whether they're Qualified or Pending. New: Tier-based Leaderboard The leaderboard now lets users filter by tier (Bronze, Silver, Platinum). Each entry shows rank, referral code, and return percentage. Users see their own position highlighted, plus a count of total participants in that tier. New: "Qualify for this rank" & "You're qualified" cards - If a user is pending, they see a card telling them exactly how much more they need to deposit and how many more days to hold to qualify. - Once they meet the requirements, the card flips to "You're qualified." New: After-Hours Trading popup When a user tries to swap an asset outside market hours, a popup appears explaining that trading is closed, shows a countdown to when markets reopen, and warns about wider price spreads. New: Eligibility warning popup If there aren't enough days left in the campaign to meet the holding requirement, a warning popup tells the user their new position won't count toward the campaign, with options to cancel or proceed anyway. New: "Entries closed" state If the campaign has ended and the user never opted in, the join button is locked and shows "Entries closed." Tapping it shows a message explaining they missed the opt-in window. Updated: Portfolio section Now shows each deposited asset with its current value, shares owned, and profit/loss percentage. Users can tap a position to swap it for a different asset, or tap a link to view their full activity history. Updated: Prize pool display Shows the current prize pool size and how much additional volume is needed to unlock the next reward tier. ## **Changelog** CHANGELOG entry: ondo campaign rewards - stats page ## **Screenshots/Recordings** - Active Campaign - Opted in Negative return but qualified <img width="952" height="1763" alt="negative-qualified" src="https://github.com/user-attachments/assets/0e27784a-f5ce-4033-b338-e2916a259427" /> <img width="952" height="1763" alt="negative-qualified-2" src="https://github.com/user-attachments/assets/d07d0535-b2a1-4603-b4b4-4be694dc33c7" /> Positive return but pending <img width="1025" height="1799" alt="positive-pending-1" src="https://github.com/user-attachments/assets/b4e231a0-a0af-45db-90a8-572551c8322d" /> <img width="1025" height="1799" alt="positive-pendin-2-leaderboard-bottom-20" src="https://github.com/user-attachments/assets/14e37219-9605-466b-b788-507527fce233" /> Leaderboard top 5 (in others its 18th position) <img width="943" height="539" alt="leaderboard-top-5" src="https://github.com/user-attachments/assets/55c98e89-0c94-494d-882b-b02516ef6731" /> Prize pool variants <img width="962" height="324" alt="prize-pool-fully-reached" src="https://github.com/user-attachments/assets/c154f79a-723b-4fa8-ba9b-5885b3fd541b" /> <img width="962" height="324" alt="prize-pool-unlock" src="https://github.com/user-attachments/assets/da6f91f0-d12c-4654-a87d-680412769d4d" /> Leaderboard page (positive return pending) <img width="1025" height="1799" alt="positive-pending" src="https://github.com/user-attachments/assets/636d6806-c6ee-4635-bd07-6e2761919db0" /> Stats page positive but pending <img width="952" height="1763" alt="positive-pending" src="https://github.com/user-attachments/assets/6d5c8d1f-e519-47b6-9b43-e26a4df7c8dc" /> Stats page positive & qualified <img width="951" height="1830" alt="positive-qualified-complete" src="https://github.com/user-attachments/assets/570f8f11-1d4e-415f-ab48-a0e70a747b47" /> Stats page but negative return and cashed out <img width="952" height="1763" alt="negative-qualified-cashed-out" src="https://github.com/user-attachments/assets/9298e079-30ff-4625-8ac1-eec3890df4fb" /> Open position or swap position but outside of market hours <img width="957" height="845" alt="open-position-market-hours" src="https://github.com/user-attachments/assets/52accff5-3d36-4e0b-af50-a2062fb58b78" /> Open position but can't qualify for tier treshold anymore <img width="1156" height="701" alt="not eligible" src="https://github.com/user-attachments/assets/b67d484a-0977-4d63-bec5-f4f414273ca4" /> - Not Opted in <img width="916" height="1813" alt="Screenshot from 2026-04-13 15-32-09" src="https://github.com/user-attachments/assets/afc04260-729d-4867-bdd8-7caad4db9527" /> <img width="916" height="1813" alt="Screenshot from 2026-04-13 15-32-12" src="https://github.com/user-attachments/assets/12cb1a91-c999-4f38-b535-e8aa8a6b6c4a" /> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds new rewards navigation routes, screens, and bottom sheets with updated Ondo campaign eligibility/pending logic and new `minDeposit` data plumbing; mistakes could impact campaign UX and leaderboard/stats rendering but do not touch security-critical flows. > > **Overview** > Introduces a dedicated **Ondo campaign Stats** screen (`RewardsOndoCampaignStats`) and wires it into the rewards navigator, including navigation from the campaign details stats header. > > Adds new bottom sheets for **Pending** (`RewardsOndoPendingSheet`), **After-hours trading** (`OndoAfterHoursSheet`), and **Not eligible** (`OndoNotEligibleSheet`), and updates campaign details/portfolio/CTA flows to gate swaps/position actions when the user can no longer meet the `ONDO_GM_REQUIRED_QUALIFIED_DAYS` requirement. > > Extends Ondo leaderboard tier data with `minDeposit` and updates `OndoLeaderboard`/`CampaignStatsSummary` to show qualify messaging, open the pending sheet from pending tags/cards, unify stats error handling, and tweak prize pool/max-tier copy and various UI text/icon styles (including ET→EST strings). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a7be45e. 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: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: sophieqgu <sophieqgu@gmail.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->
## **Description**
This branch finishes the Card Home migration to `CardController` and
fixes the behavior regressions introduced while moving card auth,
cardholder state, wallet data, and spending-limit flows away from the
old SDK/React Query orchestration.
The motivation for the change was to make `CardController` the source of
truth for Card state, instead of splitting responsibility across the
Redux `card` slice, SDK helpers, and deleted React Query hooks like
`useLoadCardData` / `useGetCardExternalWalletDetails`.
Key changes in this branch:
- **Card authentication and session state now come from
`CardController`**
- `CardAuthentication` uses `useCardAuth`.
- UI now reads controller-backed selectors such as
`selectIsCardAuthenticated`, `selectIsCardholder`,
`selectCardholderAccounts`, and `selectCardUserLocation`.
- Logout and session validation are handled through
`Engine.context.CardController`.
- Legacy auth verification helpers and side-effect flows were removed.
- **Card Home was migrated to controller-backed data and split into
smaller hooks/components**
- `CardHome.tsx` was refactored heavily into focused components and
hooks like `useCardHomeActions`, `useCardHomeAnalytics`, and
`useCardProvisioning`.
- Snapshot-based tests touched by this work were removed in favor of
explicit assertions.
- **Push provisioning was aligned with the new controller/provider
architecture**
- Provisioning eligibility was moved into the provider layer.
- The old Galileo-specific adapter path was removed in favor of the
controller adapter.
- US-only provisioning restrictions and provider-specific feature-flag
behavior were preserved.
- **Unauthenticated cardholder UX was added**
- Cardholders who are not authenticated now see teaser actions on Card
Home instead of a blocking login-required warning.
- Teaser actions route to Card authentication.
- Card authentication now shows an informational auth prompt banner for
those entry points.
- Terms and Conditions / Contact support remain visible in that state
while Logout stays hidden.
- **Spending Limit / delegation flows broken by the migration were
restored**
- Card Home now passes the full spending-limit payload again
(`priorityToken`, `allTokens`, `delegationSettings`,
`externalWalletDetailsData`) instead of only `{ flow }`.
- `CardHomeData` now carries `delegationSettings`.
- Supported tokens are enriched with `delegationContract`, which fixes
the `"Missing token configuration"` delegation failure.
- Spending Limit can pre-select the priority asset again and the token
picker no longer stalls on an infinite spinner.
- After successful delegation, `useSpendingLimit` now calls
`CardController.fetchCardHomeData()` so the updated
wallet/priority-token state appears automatically without requiring a
manual refresh.
- **Additional follow-up fixes and test coverage**
- Added/updated controller, provider, Card Home, Spending Limit,
provisioning, authentication, and utility tests.
- Replaced touched card snapshot tests with explicit assertions where
applicable.
## **Changelog**
CHANGELOG entry: Fixed MetaMask Card authentication, unauthenticated
cardholder actions, and spending limit/delegation refresh flows after
the CardController migration.
## **Related issues**
Fixes:
<!-- Add issue links if applicable -->
## **Manual testing steps**
```gherkin
Feature: Card controller migration and follow-up flow fixes
Background:
Given I have a build from this branch
And I have access to a MetaMask Card test account
Scenario: Card authentication uses controller-backed session state
Given I am logged out of Card
When I open Card and log in with a valid account
Then Card Home should load successfully
And authentication state should be preserved by CardController
When I log out from Card
Then CardController should clear the card session
And I should return to the logged-out Card state
Scenario: Unauthenticated cardholder sees teaser actions and auth prompt
Given I am a cardholder but I am not currently authenticated
When I open Card Home
Then I should see teaser actions for card management
And I should see Terms and Conditions and Contact support
And I should not see Logout
When I tap Manage limit
Then the Card authentication screen should open
And I should see the informational auth prompt banner
Scenario: Spending Limit opens with delegation-ready token data
Given I am authenticated on Card Home
And I have supported card assets available
When I tap Manage limit
Then the Spending Limit screen should open
And the priority asset should be pre-selected
When I open the Token selector
Then the asset list should load without an infinite spinner
Scenario: Delegation refreshes Card Home automatically
Given I am authenticated on Card Home
And I open Spending Limit for a token that is not yet enabled
When I complete delegation successfully
Then I should return to Card Home
And the token list and current priority token should refresh automatically
And I should not need to pull to refresh manually
Scenario: Push provisioning still respects provider/controller rules
Given I am authenticated on Card Home with a supported eligible card
When I review add-to-wallet availability
Then provisioning eligibility should reflect the provider response
And provider-specific feature flags should still be respected
```
## **Screenshots/Recordings**
### **Before**
N/A
### **After**
N/A
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Large refactor of `CardHome` data-flow and interaction handlers to
rely on `CardController`/new hooks, plus navigation/auth gating changes;
regressions are possible in card setup, spending-limit, and sensitive
actions (PIN/details/freeze). Mostly UI-layer changes but they touch
session/logout behavior and several user flows.
>
> **Overview**
> **Card Home is migrated to controller-backed state and decomposed into
smaller units.** `CardHome` now renders from `useCardHomeData()` and
`CardController` selectors/capabilities, with UI split into components
like `CardAlertSection`, `CardActionsButtons`, `CardImageSection`,
`CardBalanceDisplay`, `ManageCardOptions`, and `CardHomeFooter`, plus
extracted hooks for actions/analytics/provisioning.
>
> **Unauthenticated cardholder UX is changed from “blocked” to “teaser”
actions.** Manage options (view details/PIN, freeze toggle, cashback,
travel, manage card, etc.) can appear while unauthenticated but now
route to `Routes.CARD.AUTHENTICATION` with `showAuthPrompt: true`;
logout stays hidden.
>
> **Auth + location handling is adjusted in `CardAuthentication`.** The
screen reads `showAuthPrompt` from route params to show a new info
banner (`CardMessageBoxType.AuthPrompt`), and location selection is now
local state (`selectedLocation`) used during login rather than
immediately calling `CardController.setUserLocation`.
>
> **Behavioral/test updates.** Tests are updated to mock `useRoute`,
validate new teaser/navigation behavior, switch `CardHome` tests to
`useCardHomeData`, align freeze with separate `freeze/unfreeze`
mutations, update spending-limit copy expectations, and tighten
analytics expectations (don’t emit without a formatted balance).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3baa77b. 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 the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This change **bumps the build version once** in a dedicated job that calls **`update-latest-build-version.yml`**, then triggers **iOS and Android** through **`runway-ota-build-core`** in **parallel**. Both jobs use **`skip_version_bump: true`** and **`source_branch`** set to the **version-bump commit SHA** so both builds use the same tree. Downstream steps (PR comment + Slack) now require **both** platform jobs to succeed. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-521 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
… markets (#28696) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> The Predict Picks section (used in game details) currently renders `PredictPickItem` — a simple row showing "Picked [outcome] at $X" with PnL. For sports markets with extended market types (spreads, totals, player props), we need the richer `PredictPositionDetail` component that already exists on the regular market details screen, which includes icons, real-time preview values, percentage PnL, privacy mode support, and a full-width cash-out button. This PR conditionally renders `PredictPositionDetail` instead of `PredictPickItem` inside `PredictPicks` when the market's league is in the `extendedSportsMarketsLeagues` feature flag — following the same flag pattern used by `useGameDetailsTabs`. When the flag is disabled (or the market has no game/league), the existing `PredictPickItem` rendering is preserved. Also includes a minor cleanup: removes an unnecessary `useEffect` in `useGameDetailsTabs` that was resetting `activeTab` when tabs changed. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/PRED-803 ## **Manual testing steps** ```gherkin Feature: PredictPositionDetail in sports prediction picks Scenario: user views positions for an extended sports market Given the user has open positions on a sports market with a league in extendedSportsMarketsLeagues (e.g. NBA) When user navigates to the game details screen Then positions are displayed using the rich PredictPositionDetail component And each position shows an icon, title, shares info, real-time current value, and percentage PnL And each open position has a full-width "Cash out" button Scenario: user views positions for a non-extended sports market Given the user has open positions on a sports market whose league is NOT in extendedSportsMarketsLeagues When user navigates to the game details screen Then positions are displayed using the original PredictPickItem component And each position shows "Picked [outcome] at $X" format with PnL value Scenario: user views positions for a non-sports market Given the user has open positions on a non-sports prediction market (no game property) When user navigates to the market details screen Then positions are displayed using the original PredictPickItem component ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** https://github.com/user-attachments/assets/6f09c287-4371-4f4f-859c-7dbb69a673d8 ### **After** https://github.com/user-attachments/assets/a5790c3f-f276-4428-b604-a8aaed2a1ddd ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes conditional rendering for the Picks list and adjusts tab state behavior; also removes polling on active positions, which could affect UI freshness and user interaction flows in game details. > > **Overview** > **Game details picks rendering is upgraded for extended sports markets.** `PredictPicks` now checks `selectExtendedSportsMarketsLeagues` and, when the market’s `game.league` is enabled, renders `PredictPositionDetail` (including forcing `CLOSED` status for claimable positions) instead of `PredictPickItem`. > > **Behavioral tweaks and coverage.** `useGameDetailsTabs` no longer resets `activeTab` when the tab set changes, tests were updated/added for the new picks rendering and tab behavior, and `PredictGameDetailsContent` stops polling active positions by removing the `refetchInterval` option. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f8c9faa. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Summary Merges `stable` into the `release/7.74.00` line after [#29233](#29233) landed **7.73.2** on `stable`, so [#28948](#28948) (`release/7.74.00` → `stable`) can merge without mass conflicts. CHANGELOG entry: null <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it updates release CI gating and modifies Predict trading feature-flag resolution/analytics plus onboarding auth/marketing-consent flows, which can impact build automation and user-facing trading/login behavior. > > **Overview** > Merges `stable` changes into the `release/7.74.0` line, including updates to the auto RC build workflow to gate version bumps/build triggers/commenting on a label check and to simplify the RC comment step (shallower checkout and removal of test plan JSON upload/AI key envs). > > Predict trading changes include new CLOB v2/legacy-host flag plumbing (controller + selectors), refactoring order analytics emission to build regular vs sensitive properties, and several buy-with-any-token UX/flow tweaks (pay-with row visibility, suppressing pay-token alerts while editing, init/cleanup behavior). > > Also updates onboarding/auth flows (wallet deletion resets newer onboarding state fields, OAuth rehydration now awaits marketing opt-in sync, removes legacy iOS Google warning saga/state/selectors), adjusts Token Details analytics to include A/B test attribution and ensures swaps navigation resets scroll, and includes assorted test/snapshot updates, ramps selector coverage for non-EVM addresses, and localization/changelog/version metadata updates. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b11b7c9. 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: metamaskbot <metamaskbot@users.noreply.github.com> Co-authored-by: runway-github[bot] <73448015+runway-github[bot]@users.noreply.github.com> Co-authored-by: Caainã Jeronimo <caainaje@gmail.com> Co-authored-by: infiniteflower <139582705+infiniteflower@users.noreply.github.com> Co-authored-by: sahar-fehri <sahar.fehri@consensys.net> Co-authored-by: Prithpal Sooriya <prithpal.sooriya@users.noreply.github.com> Co-authored-by: Prithpal Sooriya <prithpal.sooriya@gmail.com> Co-authored-by: António Regadas <antonio.regadas@consensys.net> Co-authored-by: George Marshall <george.marshall@consensys.net> Co-authored-by: tommasini <tommasini15@gmail.com> Co-authored-by: TylerC <tyler.chong@consensys.net> Co-authored-by: ieow <4881057+ieow@users.noreply.github.com> Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com> Co-authored-by: Wei Sun <wei.sun@consensys.net> Co-authored-by: Cal-L <cal.leung@consensys.net> Co-authored-by: Michal Szorad <michal.szorad@consensys.net> Co-authored-by: Bryan Fullam <bryan.fullam@consensys.net> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com> Co-authored-by: Vince Howard <vincenguyenhoward@gmail.com> Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com> Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Co-authored-by: Matthew Grainger <matthew.grainger@consensys.net> Co-authored-by: Xiaoming Wang <7315988+dawnseeker8@users.noreply.github.com> Co-authored-by: Arafet (CN - Hong Kong) <52028926+arafetbenmakhlouf@users.noreply.github.com> Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com> Co-authored-by: Gaurav Goel <grvgoel19@gmail.com> Co-authored-by: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com> Co-authored-by: geositta <matthew.denton@consensys.net> Co-authored-by: Javier Garcia Vera <javier.vera@consensys.net> Co-authored-by: Luis Taniça <matallui@gmail.com>
This comment has been minimized.
This comment has been minimized.
… CardController (#29376) - fix(card): update feature flag listener on CardController (#29350) <!-- 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 branch refreshes **card home data and Baanx configuration** when **remote card feature flags** change, and fixes a **race** where a slow **unauthenticated** `fetchCardHomeData` could overwrite state **after** successful **submitCredentials**. **Feature flags** - [`app/selectors/featureFlagController/card/index.ts`](app/selectors/featureFlagController/card/index.ts): exports **`defaultCardFeatureFlag`** and **`resolveCardFeatureFlag`** (empty remote payload → defaults). **`selectCardFeatureFlag`** now uses **`resolveCardFeatureFlag`** so the same resolution rules apply in Redux selectors and Engine. **BaanxProvider / init** - [`BaanxProvider.ts`](app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts): accepts optional **`getCardFeatureFlag`** (lazy) in addition to legacy **`cardFeatureFlag`**. A private getter resolves **`cardFeatureFlag`** on each read so URLs/constants track the latest remote flags without recreating the provider. - [`card-controller/index.ts`](app/core/Engine/controllers/card-controller/index.ts): passes **`getCardFeatureFlag`** from **`RemoteFeatureFlagController:getState`** + **`resolveCardFeatureFlag`** into **`BaanxProvider`**. **CardController** - Subscribes to **`RemoteFeatureFlagController:stateChange`** with a **selector** that serializes **`remoteFeatureFlags.cardFeature`** so only meaningful card-flag updates run the handler. - **`#handleCardFeatureFlagChange`**: if an EVM address is selected, **`invalidateFetch()`**, clears **`cardHomeData`** / sets **`cardHomeDataStatus`** to **`idle`**, then refetches card home data. - **`#fetchCardHomeDataWithLogging`**: centralizes **`fetchCardHomeData`** + **`Logger.error`** for account switch, feature-flag refresh, **`submitCredentials`**, and **`validateAndRefreshSession`**. - **`#triggerCardholderCheck`** (accounts API URL path): uses **`resolveCardFeatureFlag`** instead of ad-hoc casting. - **`submitCredentials`**: sets **`cardHomeData`** to **`null`** and status **`idle`**, calls **`invalidateFetch()`**, then fetches—so in-flight unauthenticated responses cannot win over authenticated data. **Messenger / types** - [`card-controller-messenger/index.ts`](app/core/Engine/messengers/card-controller-messenger/index.ts): allows event **`RemoteFeatureFlagController:stateChange`**. - [`types.ts`](app/core/Engine/controllers/card-controller/types.ts): **`CardControllerAllowedEvents`** includes **`RemoteFeatureFlagControllerStateChangeEvent`**. **Tests** - [`CardController.test.ts`](app/core/Engine/controllers/card-controller/CardController.test.ts): subscription to remote feature-flag state; handler clears state and refetches; **`drops in-flight unauthenticated card home data after successful auth`**. - [`BaanxProvider.test.ts`](app/core/Engine/controllers/card-controller/providers/BaanxProvider.test.ts): **`getCardFeatureFlag`** read **lazily** during **`getOnChainAssets`**. ## **Changelog** CHANGELOG entry: Card — **`CardController`** listens for **`RemoteFeatureFlagController:stateChange`** and refetches card home data when **`cardFeature`** changes; **`BaanxProvider`** resolves card feature flags lazily; shared **`resolveCardFeatureFlag`**; **`submitCredentials`** invalidates in-flight fetches and resets card home state to avoid stale unauthenticated data after login. ## **Related issues** Fixes: #29348 <!-- Add GitHub issue link when available, e.g. Fixes #12345 --> ## **Manual testing steps** ```gherkin Feature: Card home and Baanx flags stay in sync with remote card feature flags Scenario: Remote card feature flag updates while card tab is open Given the user is on an EVM account with card session and card home loaded When remote `cardFeature` changes (e.g. rollout or config update) Then card home data is cleared to idle and refetched And Baanx-backed calls use the updated flag-derived config on subsequent requests Scenario: Login while an unauthenticated card home fetch is still in flight Given an unauthenticated card home fetch has not completed When the user completes submitCredentials successfully Then authenticated card home data wins and a late unauthenticated response does not overwrite it Scenario: Card feature flag change with no selected EVM address When RemoteFeatureFlagController emits a card-related change but no EVM address is selected Then the handler returns early without refetch errors ``` ## **Screenshots/Recordings** <!-- Optional: behavior is mostly data-layer; attach if you verify on device after a forced remote flag change. --> ### **Before** <!-- Card home could stay stale until manual refresh; rare stale data after fast login during slow unauthenticated fetch. --> ### **After** <!-- Card home refetches when `cardFeature` changes; submitCredentials path drops stale in-flight unauthenticated results. --> ## **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 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] > **Medium Risk** > Updates card state refresh triggers and fetch invalidation logic around auth and feature-flag changes; risk is moderate due to new event subscriptions and potential for extra network calls or missed updates if selectors are wrong. > > **Overview** > **Card home data now refreshes when remote `cardFeature` flags change.** `CardController` subscribes to `RemoteFeatureFlagController:stateChange`, clears `cardHomeData`/status back to `idle`, invalidates any in-flight fetch, and refetches. > > **Fixes a race where slow unauthenticated fetches could overwrite authenticated state.** After successful `submitCredentials`, the controller resets home data, bumps the fetch generation, and refetches via a shared `#fetchCardHomeDataWithLogging` helper (also used by account-switch and session refresh paths). > > **Feature-flag resolution and consumption were tightened.** Adds `resolveCardFeatureFlag` (and exports `defaultCardFeatureFlag`) to normalize empty remote payloads to defaults; `BaanxProvider` can now read flags lazily via a `getCardFeatureFlag` callback wired in `cardControllerInit`, and the card-controller messenger/types allow the new remote-flag stateChange event. > > Tests add coverage for the new subscription behavior, the stale-fetch drop after auth, and lazy flag reads in `BaanxProvider`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 0d9863b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [890ac4a](890ac4a) Co-authored-by: Bruno Nascimento <brunonascimentodev@gmail.com>
🚀 RC Builds Ready for Testing
More Info
AI Test Plan
Executive SummaryRelease Focus: Major architectural refactor of Card, Perps, Predict, and Charts features alongside significant new Money hub components and advanced charting capabilities Key Changes:
Critical Areas: Card feature - complete architectural overhaul with removed hooks (useGetPriorityCardToken, useLoadCardData, useCardProviderAuthentication) replaced by new data layer, Perps compliance gate integration - new gate() wrapper around order placement could block trades unexpectedly, Perps transaction history - pagination, deduplication, and withdrawal merging logic is new and complex, Predict controller refactor - analytics separated into PredictAnalytics class, method actions auto-generated, withTrace wrapper added, AdvancedChart WebView - major chartLogic.js rewrite (+3278 lines), layout-settle skeleton, TradingView link interception Overall Risk: HIGH Recommendation: No-go without targeted regression on Card home screen actions, Perps order placement with compliance gate, and Perps transaction history pagination. The Card feature removed 6+ major hooks and 2000+ lines of logic in favor of a new data layer - any regression in freeze/unfreeze, PIN view, card details, or asset selection could break core card functionality for existing cardholders. Perps compliance gate wrapping order placement is a critical path change. Recommend full manual regression on Card, Perps trading flow, and Predict buy flow before release. Release Scenarios (24)High Risk Scenarios (16)1. Card - Home Screen ActionsRisk Level: HIGH Why This Matters: CardHome.tsx was reduced from ~1500 lines to ~222 lines by extracting all business logic into useCardHomeActions (464 lines, new file) and useCardHomeData (111 lines, new file). Six major hooks were deleted entirely (useGetPriorityCardToken, useLoadCardData, useCardProviderAuthentication, useCardholderCheck, useGetCardExternalWalletDetails, useGetLatestAllowanceForPriorityToken). Any regression in the data flow from the new controller-based approach could silently break card actions. Preconditions:
Test Steps:
Expected Outcomes:
2. Card - Asset Selection Bottom SheetRisk Level: HIGH Why This Matters: AssetSelectionBottomSheet.tsx was reduced from 363 lines to 63 lines. The entire data fetching approach changed from SDK calls (useCardSDK, useAssetBalances, useUpdateTokenPriority) to reading from Redux state via useCardHomeData. The new getAssetBalanceKey utility and useUpdateFundingPriority hook replace complex allowance-based logic. If the new data layer doesn't populate correctly, the asset selection sheet will show empty or incorrect token lists. Preconditions:
Test Steps:
Expected Outcomes:
3. Card - Push Provisioning (Apple Wallet)Risk Level: HIGH Why This Matters: GalileoCardAdapter.ts (118 lines) was completely deleted and replaced with ControllerCardAdapter.ts (99 lines). The pushProvisioning/adapters/card/index.ts now exports ControllerCardAdapter instead of GalileoCardAdapter. AppleWalletAdapter.ts (187 lines) was added as a new wallet adapter. This is a complete replacement of the provisioning infrastructure. Preconditions:
Test Steps:
Expected Outcomes:
4. Perps - Order Placement with Compliance GateRisk Level: HIGH Why This Matters: PerpsMarketDetailsView.tsx now wraps the entire handleTradePress callback in gate() from useComplianceGate hook. The compliance gate is a new async wrapper that could silently block order placement if the compliance check fails or times out. The refactor changed from a direct function to an arrow function returning gate(async () => {...}), which changes the execution context and could affect error handling. Preconditions:
Test Steps:
Expected Outcomes:
5. Perps - Transaction History PaginationRisk Level: HIGH Why This Matters: usePerpsTransactionHistory.ts was significantly refactored (+250 lines, -128 lines). New pagination logic with fundingCursorRef, fetchGenerationRef, and PAGE_WINDOW_MS/MAX_LOOKBACK_MS constants was added. Two new deduplication functions (deduplicateById, deduplicateByTxHash) were introduced. Withdrawal transactions are now tracked separately from deposits. The startTime/endTime parameters were removed from the hook interface. Any bug in the cursor-based pagination or deduplication could result in missing or duplicate transactions. Preconditions:
Test Steps:
Expected Outcomes:
6. Perps - WebSocket Stream ManagerRisk Level: HIGH Why This Matters: PerpsStreamManager.tsx was massively expanded (+189 lines, -28 lines) and PerpsConnectionManager.ts gained significant new logic (+67 lines). New mock provider was added for testing. usePerpsLiveAccount, usePerpsLiveOrders, and usePerpsLivePositions all received updates. The stream architecture is critical for real-time trading data and any regression could show stale prices or positions. Preconditions:
Test Steps:
Expected Outcomes:
7. Perps - Withdraw FlowRisk Level: HIGH Why This Matters: useWithdrawTokens.ts was reduced from 46 to 12 lines (major simplification). usePerpsWithdrawToastRegistrations.tsx is a new 148-line file. usePerpsWithdrawStatus.ts received updates. The withdrawal flow touches multiple refactored components and the new toast registration system. Preconditions:
Test Steps:
Expected Outcomes:
8. Token Overview - Advanced Chart (Price.advanced.tsx)Risk Level: HIGH Why This Matters: Price.tsx was reduced from 146 lines to 59 lines and now acts as a router between PriceAdvanced and PriceLegacy. Price.advanced.tsx (437 lines) and Price.legacy.tsx (215 lines) are new files. PriceChart.tsx was significantly refactored with new chartRowWidth state, NoDataOverlay integration, and changed color logic. The chart color now uses LIGHT_MODE_SUCCESS_GREEN regardless of price direction (removed up/down color logic). Any regression here affects all token detail screens. Preconditions:
Test Steps:
Expected Outcomes:
9. AdvancedChart - WebView Chart RenderingRisk Level: HIGH Why This Matters: AdvancedChart.tsx gained 76+ lines of new logic including layoutSettling state, LAYOUT_SETTLE_FALLBACK_MS timer, TradingView link interception with InAppBrowser, and ohlcvSeriesStaleSnapshotRef. chartLogic.js/chartLogicString.ts had +3278 lines added. These are complex WebView-JavaScript bridge changes that could cause chart rendering failures, stuck skeletons, or broken external link handling. Preconditions:
Test Steps:
Expected Outcomes:
10. Predict - Buy Flow with Preview SheetRisk Level: HIGH Why This Matters: PredictController.ts was reduced from 1060 to 570 lines with analytics extracted to PredictAnalytics class and method actions auto-generated in PredictController-method-action-types.ts. PredictPreviewSheetContext.tsx (254 lines) is entirely new. Routes/index.tsx changed significantly. usePredictBuyActions.ts gained 96 lines. Any regression in the controller refactor could break order placement. Preconditions:
Test Steps:
Expected Outcomes:
11. Predict - Polymarket WebSocket Live UpdatesRisk Level: HIGH Why This Matters: WebSocketManager.ts (285 lines) is entirely new. PolymarketProvider.ts gained 147 lines. utils.ts gained 167 lines with new parsing logic. This is a complete new real-time data infrastructure for Predict. Any bug in WebSocket message parsing or connection management could show stale or incorrect market prices. Preconditions:
Test Steps:
Expected Outcomes:
12. Predict - Sell/Cash Out FlowRisk Level: HIGH Why This Matters: PredictSellPreview.tsx was significantly refactored (180 lines changed). usePredictCashOut.ts (76 lines) is a new hook. PredictAnalytics.ts (236 lines) is a new class that now handles all analytics previously inline in PredictController. The separation of analytics from controller logic could cause events to not fire if the new class isn't properly initialized. Preconditions:
Test Steps:
Expected Outcomes:
13. Card - Onboarding / Sign Up FlowRisk Level: HIGH Why This Matters: SignUp.tsx gained 112 lines of changes. WaitlistFormModal.tsx (180 lines) is entirely new. OnboardingNavigator.tsx received updates. The card onboarding is a critical user acquisition flow and any regression would prevent new users from getting a card. Preconditions:
Test Steps:
Expected Outcomes:
14. Compliance Gate - Access Restricted ModalRisk Level: HIGH Why This Matters: useComplianceGate.ts (126 lines) is a new hook replacing useWalletCompliance.ts (deleted). It's now integrated into PerpsMarketDetailsView as a gate() wrapper around order placement. Even with complianceEnabled disabled, the hook is still instantiated and gate() is called on every trade button press. If the hook has initialization errors or gate() throws when compliance is disabled, it would block all Perps trading. Preconditions:
Test Steps:
Expected Outcomes:
15. Navigation - Main Navigator ChangesRisk Level: HIGH Why This Matters: MainNavigator.js gained 69 lines and MainNavigator.test.tsx (168 lines) is new. App.tsx gained 59 lines. Multiple route files were updated (Card routes/index.tsx, Predict routes/index.tsx, Money routes/index.tsx). Navigation is the backbone of the app and any regression could make features inaccessible. Preconditions:
Test Steps:
Expected Outcomes:
16. Earn - mUSD Claim BonusRisk Level: HIGH Why This Matters: AssetOverviewClaimBonus.tsx gained 235 lines of new logic including cross-chain balance aggregation (mainnetMusdAsset + lineaMusdAsset), new TagBase bonus tag, lifetimeBonusClaimed display, and onRefetchReady callback. The cross-chain balance calculation is new and complex - if selectAsset selectors don't return correct data for both chains, the bonus estimate will be wrong. Preconditions:
Test Steps:
Expected Outcomes:
Medium Risk Scenarios (8)1. Money Hub - Activity ViewRisk Level: MEDIUM Why This Matters: MoneyHomeView.tsx gained 106 lines. Eight new Money components were added (MoneyEarnings, MoneyConvertStablecoins, MoneyOnboardingCard, MoneyProgressBar, MoneyMusdTokenRow, MoneyWhatYouGet, MoneyActivityItem, MoneyActivityList). MoneyWhyMetaMaskMoney and MoneyYourPosition were deleted. This is a significant UI restructuring of the Money hub. Preconditions:
Test Steps:
Expected Outcomes:
2. Snaps - Collapsible Section UIRisk Level: MEDIUM Why This Matters: SnapUICollapsibleSection.tsx (73 lines) and collapsible-section.ts (27 lines) are entirely new Snap UI components. SnapUIAccountSelector.tsx gained 49 lines. SnapUIFooterButton.tsx was refactored. The Snap UI renderer index.ts now exports collapsible-section. Any regression could break Snap UIs that use these components. Preconditions:
Test Steps:
Expected Outcomes:
3. DeFi Positions ListRisk Level: MEDIUM Why This Matters: DeFiPositionsList.tsx gained 69 lines and lost 21 lines - significant logic changes to the positions display. This affects users with DeFi positions who rely on this view for portfolio tracking. Preconditions:
Test Steps:
Expected Outcomes:
4. Permission Approval FlowRisk Level: MEDIUM Why This Matters: PermissionApproval.tsx gained 9 lines of changes. This is a security-critical flow - any regression could cause incorrect permissions to be granted or denied. Preconditions:
Test Steps:
Expected Outcomes:
5. Ramp - Buy/Sell FlowRisk Level: MEDIUM Why This Matters: Multiple Ramp view snapshots were deleted (BuildQuote, Checkout, OrderDetails, OrdersList, Quotes, SendTransaction, Settings) indicating significant test refactoring. BuildQuote.test.tsx gained 71 lines. The snapshot deletions suggest UI changes that need visual verification. Preconditions:
Test Steps:
Expected Outcomes:
6. Account Right Button / Account SwitcherRisk Level: MEDIUM Why This Matters: AccountRightButton/index.tsx gained 15 lines and index.test.tsx gained 63 lines. AccountRightButton.types.ts has a new type. This is a frequently used UI element that appears on the main wallet screen. Preconditions:
Test Steps:
Expected Outcomes:
7. Toast NotificationsRisk Level: MEDIUM Why This Matters: Toast.tsx gained 9 lines and Toast.test.tsx gained 35 lines. Toast is used extensively by the new useCardHomeActions hook for freeze/unfreeze/PIN success messages. Any regression in toast rendering would affect user feedback for card operations. Preconditions:
Test Steps:
Expected Outcomes:
8. Network Multi-SelectorRisk Level: MEDIUM Why This Matters: NetworkMultiSelector.tsx lost 52 lines and gained 8 - significant simplification. NetworkMultiSelectorUtils.ts (84 lines) is a new utility file. The component was likely refactored to use the new utility functions, which could change behavior. Preconditions:
Test Steps:
Expected Outcomes:
Teams Sign-off Status (21/21)Signed off: Accounts Framework, Assets, Card, Confirmations, Core Extension UX, Core Platform, Design System, Earn, Engagement, Mobile Platform, Mobile UX, Money Movement, Networks, Onboarding, Perps, Predict, Rewards, Social AI, Swaps And Bridge, Transactions, Wallet Integrations Excluded Features - Feature Flags Disabled (59)The following features are disabled via feature flags and should NOT be tested:
Generated by AI Test Plan Analyzer (claude-sonnet-4-6) at 2026-04-27T19:51:23.381Z AI generated test plan (JSON): test-plan-7.74.00.json |
This PR updates the change log for 7.74.0-ota.0. (Hotfix - no test plan generated.) --------- Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com> Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com> Co-authored-by: Wei Sun <wei.sun@consensys.net> Co-authored-by: chloeYue <chloe.gao@consensys.net> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - base branch is not main or a release branch (base: stable) All E2E tests pre-selected. |
|


🚀 v7.74.0 Testing & Release Quality Process
Hi Team,
As part of our new MetaMask Release Quality Process, here’s a quick overview of the key processes, testing strategies, and milestones to ensure a smooth and high-quality deployment.
📋 Key Processes
Testing Strategy
Conduct regression and exploratory testing for your functional areas, including automated and manual tests for critical workflows.
Focus on exploratory testing across the wallet, prioritize high-impact areas, and triage any Sentry errors found during testing.
Validate new functionalities and provide feedback to support release monitoring.
GitHub Signoff
Issue Resolution
Cherry-Picking Criteria
🗓️ Timeline and Milestones
✅ Signoff Checklist
Each team is responsible for signing off via GitHub. Use the checkbox below to track signoff completion:
Team sign-off checklist
This process is a major step forward in ensuring release stability and quality. Let’s stay aligned and make this release a success! 🚀
Feel free to reach out if you have questions or need clarification.
Many thanks in advance
Reference
Note
Medium Risk
Touches release/CI automation (runner images, new composite action, smart E2E selection behavior) and Android test dependencies/Braze push handling, which can affect build stability and E2E reliability despite limited product-code changes.
Overview
Bumps the app to v7.74.0 (Android
versionName/versionCode) and adds the7.74.0release notes + updated compare links inCHANGELOG.md.Reworks release/CI automation: introduces a local composite action
setup-e2e-env, switches most iOS jobs to Cirrusmacos-runner:tahoe+ Xcode26.3, updates Smart E2E selection to skip AI and force full E2E onrelease/*PRs, adds new smoke suites forSmokeSeedlessOnboarding, and updates RC auto-builds to trigger whenever a release branch has an open PR and to post an AI-generated test plan (removing the oldgenerate-rc-test-planworkflow). Also adds a temporarytemp-bitrise-ios-e2ePOC workflow plus ause_bitrise_runnertoggle for iOS E2E jobs.Tightens testing/tooling and ownership: bans external Jest snapshots (
toMatchSnapshot()), migrates several component tests away from snapshot assertions and deletes.snapfiles, updates ESLint rules (including banning the JSinoperator in perps/core-sync-relevant paths), adds CODEOWNERS entries for Social/AI, and adds an agent skill doc for syncing perps controller to core.Makes a few platform/build fixes: pins/excludes Espresso deps from Detox androidTest to avoid incompatibilities, adjusts a Braze yarn patch to prevent debug deps leaking to consumers, and updates Android
MainActivity/Braze config to populate push payload and allow automatic push deep link handling.Reviewed by Cursor Bugbot for commit 4fcf97c. Bugbot is set up for automated code reviews on this repo. Configure here.