[pull] main from MetaMask:main#789
Merged
Merged
Conversation
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
Simplify explore v2 implementation
<!--
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: Simplify explore v2 implementation
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> UI refactor in Trending/Explore only—no auth or payments; minor risk
if removing CryptoMovers search row or Crypto predict visibility changes
analytics or UX subtly.
>
> **Overview**
> Refactors Explore v2 (Trending) by **deduplicating UI and analytics**
across tabs and search.
>
> Adds shared **`formatPercentChange`** and wires **perps** and **crypto
movers** pills to it instead of inline parsing/color logic. Introduces
**`PredictionsCarouselSection`** so **Now, Macro, RWAs, Crypto, and
Sports** reuse one horizontal carousel (header, skeleton,
`trackExploreInteracted`) instead of copy-pasted `renderPredictionItem`
blocks; **Macro/RWAs/Now/Sports** pass **`isEnabled`** from the predict
feature flag (Crypto leaves the default enabled).
>
> **Search** drops the dedicated **`CryptoMoversFeedSearchRow`** export
and routes token/stock rows through **`TokenSearchRowItem`** only;
removes unused **`trackExploreEvent`**.
**`ExploreSectionResultsFullView`** stops passing an unused **`title`**
into list content.
>
> Net effect: less duplicated Explore code with centralized
percent-change and predictions sections; verify Crypto-tab predict
gating and crypto-movers search row analytics if those paths still
matter.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1499bf8. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#30617) <!-- 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** In Unified Buy v2, when a user entered an amount that fell outside one provider's supported range (e.g. below MoonPay's minimum), the payment method picker showed a blanket "No payment methods available" alert and the provider picker silently dropped the affected provider. This was misleading: other providers / payment methods were often still viable, and the user had no way to learn _why_ a given option was unavailable. This PR keeps every payment method and provider visible regardless of quote state, and instead: - **Greys out** rows that have no successful quote (sets `isDisabled` on `ListItemSelect`, suppresses `onPress`). - **Shows the provider's error message** (e.g. "Amount below minimum 25 USD") as the row subtitle, scoped to the row's provider — never bleeding errors across providers. - Falls back to a generic `Quote unavailable.` subtitle when the API does not return an error string. - Suppresses the "Previously used" / "Best rate" / "Most reliable" tag on unavailable provider rows so the failure reason is the dominant signal. - Drops the previous list-level `visiblePaymentMethods` filter, since the disabled-row UX makes silent filtering unnecessary. ## **Changelog** CHANGELOG entry: Fixed a misleading "No payment methods available" error in Buy when entering an amount outside a provider's limits. Unavailable payment methods and providers are now shown greyed out with the specific reason (e.g. "Amount below minimum 25 USD") instead of being hidden. ## **Related issues** Fixes: [TRAM-3556](https://consensyssoftware.atlassian.net/browse/TRAM-3556) ## **Manual testing steps** ```gherkin Feature: Buy payment-method and provider selection error states Scenario: User enters an amount below the selected provider's minimum Given the user is on the Buy amount entry screen And the selected provider is MoonPay When the user enters an amount below MoonPay's minimum (e.g. 1 USD) And the user opens the "Pay with" payment selection modal Then every payment method is still listed And each payment method row is greyed out And each row's subtitle shows the provider's error message (e.g. "Amount below minimum 25 USD") or "Quote unavailable." as a fallback And tapping a greyed-out row does nothing Scenario: User enters an amount supported by only some providers Given the user is on the Buy amount entry screen And the entered amount is supported by Transak but not by MoonPay When the user opens the provider selection modal Then Transak is listed with its quote and tag (e.g. "Best rate") And MoonPay is listed but greyed out And MoonPay's row subtitle shows its error message And MoonPay's tag (e.g. "Previously used") is hidden And tapping MoonPay does not advance the flow Scenario: User enters a valid amount Given the user is on the Buy amount entry screen And the entered amount is supported by every provider/payment method When the user opens either selection modal Then all rows are enabled And each row shows its expected quote and tags And tapping a row selects it and closes the modal as before ``` ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/9b3294a6-a3df-4503-a8af-599d6b758eeb <!-- Payment selection modal showing "No payment methods are available" banner for an amount below MoonPay's minimum, despite other providers being viable. --> ### **After** https://github.com/user-attachments/assets/d6da5ee3-1648-45df-b968-6f1395318b98 <!-- Payment selection modal listing all payment methods greyed out with the provider error message ("Amount below minimum 25 USD") as subtitle; provider selection modal listing MoonPay greyed out with its error subtitle while Transak remains selectable. --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [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. [TRAM-3556]: https://consensyssoftware.atlassian.net/browse/TRAM-3556?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only changes in fiat on-ramp selection modals with expanded unit tests; no auth, payments execution, or backend contract changes. > > **Overview** > Fixes misleading **Buy** UX when quotes fail for some options: payment methods and providers stay visible instead of being hidden or replaced by a blanket “no payment methods” state. > > **Payment selection** stops filtering the list to methods with successful quotes. Rows without a success quote (after quotes finish loading) are **disabled**, show the **selected provider’s** API error or `fiat_on_ramp.quote_unavailable`, and ignore taps. `PaymentMethodListItem` accepts `quoteErrorMessage`, swaps subtitle for that message when present, and uses `ListItemSelect` `isDisabled` / no `onPress` on quote error. > > **Provider selection** treats providers with an error and no matched (non–custom-action) quote as **unavailable**: disabled row, provider-specific error as subtitle (tags like “Previously used” hidden), selection blocked. Providers with a valid matched quote stay selectable even if a stale error exists for that provider. > > Tests cover disabled rows, error scoping, loading behavior, and custom-action quote edge cases. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 30025b4. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com>
## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> This PR tightens Money balance behavior after deposits/withdrawals and on manual refresh so users see accurate state faster and clearer feedback when data is stale or unavailable. It adds tx-confirmed balance invalidation with bounded retries, hooks Money refresh into Wallet pull-to-refresh (when feature-enabled), and updates Money balance UI states to handle loading/retrying/error/feature-disabled/no-account without misleading fallback values. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Improved Money balance refresh reliability after deposits/withdrawals and added clearer unavailable/retry states on Money screens. ## **Related issues** Fixes: - https://consensyssoftware.atlassian.net/browse/MUSD-811 - https://consensyssoftware.atlassian.net/browse/MUSD-831 - https://consensyssoftware.atlassian.net/browse/MUSD-836 - https://consensyssoftware.atlassian.net/browse/MUSD-841 ## **Manual testing steps** ```gherkin Feature: Money balance refresh and unavailable-state handling Scenario: user sees balance refresh after Money deposit or withdrawal confirms Given user has a Money account and submits a deposit or withdrawal When the transaction reaches confirmed Then Money balance data is re-fetched and updates without waiting for the next background poll Scenario: user pull-to-refreshes wallet home with Money enabled Given user is on Wallet home with Money account feature enabled When user pulls to refresh Then wallet balances and Money account balance both refresh in the same interaction Scenario: user sees explicit unavailable state and retry action when Money balance fetch fails Given user is on Money home and the balance fetch fails When the summary renders Then user sees "Balance unavailable" and can tap retry to re-fetch balance Scenario: user does not see misleading Money balance when account/feature is unavailable Given Money account feature is disabled or no primary Money account exists When Money balance components render Then balance/earnings content does not show fake numeric values and a clear unavailable state is shown ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A ### **After** Adding soon ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches balance aggregation, React Query invalidation on tx confirm, and user-visible Money/wallet-home balance UI; broad test coverage limits regression risk but behavior changes affect core Money flows. > > **Overview** > This PR improves **Money balance accuracy and UX** after deposits/withdrawals and when data is missing or stale. > > **Refresh behavior:** `MoneyHomeView` adds pull-to-refresh that calls `refetchBalance`, with error logging on failure. `useMoneyAccountBalance` now exposes `isBalanceFetchError`, `isBalanceFetching`, and `refetchBalance`, and clears formatted totals on fetch errors. On confirmed Money deposit/withdraw transactions, `useRefreshMoneyBalanceOnTxConfirm` invalidates balance queries with exponential backoff until cached values change (wired via `MoneyTransactionMonitor`). Shared `moneyTransactionGuards` dedupe tx classification from toast logic. > > **Display model:** A new `MoneyBalanceDisplayState` union drives `MoneyBalanceSummary` and `MoneyBalanceCard` (feature disabled, no account, loading, retrying, error with retry, unavailable, balance). `useMoneyAccountInfo` centralizes feature flag + primary account. **MoneyEarnings** only renders when `displayState.kind === 'balance'`, avoiding “Balance unavailable” next to projected `$0.00` earnings. `moneyFormatFiat` collapses sub-cent amounts to `$0.00`. > > **Copy:** New strings for balance unavailable, retry, feature disabled, and no account. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6c18e39. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Polish the buy/sell trade markers overlaid on the trader price chart in
the social leaderboard's `TraderPositionView`. The previous dots were
small, used non-token colors (`lightgreen`, `black` stroke), and were
hard to read on top of the chart line.
This PR:
- Resizes the inner colored disk to 16x16.
- Uses `theme.colors.success.default` for buys and
`theme.colors.error.default` for sells, matching the `+$...` / `-$...`
amount colors in the trades list below the chart.
- Adds a 4px ring colored `theme.colors.background.default` so the
marker visually punches through the chart line. The SVG `r` is set to
`innerRadius + strokeWidth / 2` so the ring sits fully outside the inner
disk.
- Adapts automatically to light/dark since both fill and stroke come
from the theme.
Only `TraderPriceChart.tsx` is touched; no API or behavior change beyond
the visual update.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Trader price chart trade markers
Scenario: trader with recorded buys and sells
Given I am viewing a trader position with both buy and sell trades in the visible time window
When the price chart renders
Then a 16px green dot is shown at each buy index, matching the green of the "+$..." amount in the trades list
And a 16px red dot is shown at each sell index, matching the red of the "-$..." amount in the trades list
And each dot is surrounded by a 4px ring matching the chart background
Scenario: theme adaptation
Given a trader position view with trade markers rendered
When I switch between light and dark mode
Then the ring around each dot continues to blend into the chart background
```
## **Screenshots/Recordings**
### **Before**
<img width="1207" height="788" alt="image"
src="https://github.com/user-attachments/assets/5a478fd8-ab80-462e-8e17-541b5aa6da05"
/>
### **After**
<img width="784" height="789" alt="image"
src="https://github.com/user-attachments/assets/6ff57ff5-057b-497f-91a2-2fcbbc64fe2e"
/>
## **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 (existing
`TraderPriceChart.test.tsx` still passes; markers are asserted by
testID, not color)
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
N/A — purely visual change to SVG props on an existing component, no new
operations to trace.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Single-file SVG styling in TraderPriceChart with no API or data-flow
changes.
>
> **Overview**
> Polishes **buy/sell trade markers** on the social leaderboard **trader
price chart** so they read clearly on top of the line.
>
> Markers are **larger** (16px inner disk) with a **4px
background-colored ring**; SVG radius is derived so the ring sits
outside the fill. **Buy/sell colors** now use
`theme.colors.success.default` and `theme.colors.error.default` (aligned
with the trades list), with `theme.colors.background.default` for the
halo instead of `lightgreen` / `black`. The **chart line** always uses
`theme.colors.success.default`, dropping the separate light-mode green
path. **`priceDiff`** is no longer read in the component (import order
cleanup only).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
798663d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
… rule (#30642) ## **Description** After #30590 excluded `x86_64` from the production AAB (to silence Play's 16 KB page-size warning), Play started rejecting the next release with: > This release is not compliant with the Google Play 64-bit requirement. > The following APKs or App Bundles are available to 64-bit devices, but they only have 32-bit native code: 5174 Play's 64-bit rule requires every 32-bit ABI shipped to be paired with its 64-bit equivalent: | 32-bit ABI | Required 64-bit pair | Status before this PR | |---|---|---| | `armeabi-v7a` | `arm64-v8a` | paired | | `x86` | `x86_64` | **unpaired** (x86_64 removed in #30590) | Shipping `x86` without `x86_64` is what triggered the rejection. ### Fix Drop `x86` too, making production ARM-only (`armeabi-v7a` + `arm64-v8a`). This satisfies both: - **64-bit rule** — `armeabi-v7a` is paired with `arm64-v8a`; no unpaired 32-bit ABI remains. - **16 KB rule** — no `x86_64` means no `x86_64 libconceal.so` / `libsecp256k1.so` warnings. `android/app/build.gradle`'s existing `abiFilters(*reactNativeArchitectures())` plumbing automatically picks up the new list, so this is a one-file change. ### User impact Essentially zero. Real Android phones haven't shipped on x86 since ~2016 (the Asus Zenfone 2 era). Any modern Chromebook or emulator that could run x86 is also `arm64-v8a` or `x86_64`-capable, and Play picks one of those instead. `android/gradle.properties.github.dual-versions` (used for BrowserStack real-device runs) has been on `armeabi-v7a,arm64-v8a` all along, so this just brings the main release config in line with the proven-real-devices target set. ### What's NOT changing - `android/gradle.properties` (default, local dev) — still ships all four ABIs for emulator support. - `android/gradle.properties.github` (CI E2E) — still uses `x86_64`. - `android/gradle.properties.github.dual-versions` — already `armeabi-v7a,arm64-v8a`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: Google Play "This release is not compliant with the Google Play 64-bit requirement" rejection introduced by #30590. Follow-up trackers for fixing the underlying 16 KB alignment so we can re-add x86_64 / x86 if ever needed: - #30591 — replace `react-native-fast-crypto` with `react-native-quick-crypto` scrypt - #30592 — drop the Facebook Conceal dependency from `react-native-keychain` ## **Manual testing steps** ```gherkin Feature: Production AAB no longer contains x86 or x86_64 ABIs Scenario: A production release build is generated Given a clean checkout of this branch When the production AAB is built via the standard release workflow (cp android/gradle.properties.release android/gradle.properties before ./gradlew bundleProdRelease) Then `unzip -l app-prod-release.aab | grep '/lib/'` shows only `lib/arm64-v8a/` and `lib/armeabi-v7a/` entries And no `lib/x86/` or `lib/x86_64/` entries appear Scenario: Local dev on x86_64 emulator still works Given default android/gradle.properties (unchanged) is in use When `yarn android` is run Then x86_64 native libs are still produced and the app installs/runs Scenario: CI E2E on x86_64 emulator still works Given android/gradle.properties.github (unchanged) overlays for CI When `./gradlew assembleProdDebug` runs Then the resulting APK contains `lib/x86_64/` and Detox tests pass Scenario: Play Console upload succeeds Given a production AAB built from this branch When the AAB is uploaded to the Play Console Then the 64-bit compliance check passes And no 16 KB page-size warning appears for x86_64 .so files ``` ## **Screenshots/Recordings** ### **Before** Play Console: > Error: This release is not compliant with the Google Play 64-bit requirement. > The following APKs or App Bundles are available to 64-bit devices, but they only have 32-bit native code: 5174 ### **After** 64-bit compliance check passes; 16 KB warning for `x86_64` .so files remains cleared. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable — N/A (build-config change; verification is via the `unzip -l` check on the produced AAB and the Play Console upload) - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable — N/A - [ ] I've applied the right labels on the PR — `team-mobile-platform` #### Performance checks (if applicable) - [x] I've tested on Android — `gradle.properties.github.dual-versions` has been on `armeabi-v7a,arm64-v8a` for BrowserStack real-device runs without issue. - [ ] I've tested with a power user scenario — N/A (no JS behavior change) - [ ] I've instrumented key operations with Sentry traces — N/A ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Single release Gradle property change; default and CI gradle files still ship x86/x86_64 for dev and emulators. > > **Overview** > Production release builds now package **only** `armeabi-v7a` and `arm64-v8a` native ABIs by updating `reactNativeArchitectures` in `android/gradle.properties.release` (removing `x86`). > > That pairs with the earlier removal of `x86_64` so Play’s **64-bit rule** is satisfied—`x86` without `x86_64` was causing rejection—while keeping the **16 KB page-size** workaround (no bundled `x86_64` `.so` from keychain/crypto AARs). Comments in the same file document why both Intel ABIs are omitted; `ndk.abiFilters` in `app/build.gradle` already reads this property, so no Gradle code changes. > > Local dev (`gradle.properties`) and CI E2E (`gradle.properties.github`) are unchanged. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 626b4e5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Cursor <cursoragent@cursor.com>
<!-- 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** https://consensyssoftware.atlassian.net/browse/RWDS-1333 https://consensyssoftware.atlassian.net/browse/RWDS-1330 https://consensyssoftware.atlassian.net/browse/RWDS-1323 Updated VipTierRow background when expanded and collapsed Updated equity allocation view Updated localized text in conjunction with consensys-vertical-apps/va-mmcx-rewards#586 <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-05-26 at 15 53 43" src="https://github.com/user-attachments/assets/2268f9fd-433d-46a0-8265-34c2d3985d39" /> <img width="1179" height="2556" alt="Simulator Screenshot - E2E Test - 2026-05-26 at 15 54 02" src="https://github.com/user-attachments/assets/fc114bfb-c362-4543-a70d-130cd7ce4f7e" /> https://github.com/user-attachments/assets/97582934-8935-4966-8944-9184031bfbd1 <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Wide contract and UI changes across VIP dashboard, tiers, and points; mismatched backend rollout could break copy or allocation display, but scope is rewards UI only with heavy test updates. > > **Overview** > Aligns the mobile VIP rewards experience with an updated rewards API contract and refreshed tier/allocation UI. > > **API & types:** `VipPointsAllocationDto` becomes `VipEquityAllocation` (`max` → `threshold`). `VipLocalizedTextDto` is renamed/restructured (`periodTitle`, equity locked/unlocked copy, `totalPointsTitle`; drops `progressToNextTier`, `statusMessage`, old points-allocation keys). `equityRebateBps` is removed from `VipTierDto`. Mocks/tests across controller, reducer, and UI are updated to match. > > **VIP dashboard (`RewardsVipView`):** Drops the equity-rebate fee carousel tile and tier-resolution IIFE. Tier progress subline is built locally via `rewards.vip.progress_to_next_tier` and `formatCompactValue(remainingPointsToNextTier)`. Volume uses `periodTitle` only (no status line). Points section uses the new equity locked/unlocked localized strings. > > **Points section:** Replaces tier-based equity-rebate radial logic with a threshold gate (`earned >= threshold`) and a single `earned/threshold` ring label; progress stroke clamps at 100% when percent > 100. > > **Tier list (`VipTierRow`):** Adds an animated gold `LinearGradient` overlay on the current tier (fades on collapse while staying mounted). Layout/spacing tweaks; fee tile width 157 → 168. > > **Volume:** Removes the “on track” status row and `status` prop. > > **i18n:** Adds `rewards.vip.progress_to_next_tier`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit be8b0b2. 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: VGR <VanGulckRik@gmail.com>
…#28909) ## **Description** On the confirmation screen for an mUSD conversion, the `GasFeeTokenToast` was overlaying the screen with "You're paying this network fee with mUSD." That notification duplicated information already shown on the confirmation screen and clashed visually with it — and the toast's premise is misleading here anyway, because mUSD conversions are sponsored at the relay level (no network fee is paid by the user). This PR suppresses the toast specifically for `TransactionType.musdConversion`. The toast still fires for every other transaction that uses a non-native gas fee token (e.g. paying gas in USDC on a regular send/swap), where it continues to serve its original reassurance purpose. **Why a type check instead of a token-symbol check:** the suppression is about "this is a relay-sponsored, fee-free flow," not "the selected token is mUSD." Tying it to `TransactionType` keeps the scope correct and extends cleanly if another relay-sponsored flow ships later. ## **Changelog** CHANGELOG entry: Fixed a UI clash on the mUSD conversion confirmation screen where a duplicate network-fee toast was shown. ## **Related issues** Fixes: MUSD-1 ## **Manual testing steps** ```gherkin Feature: mUSD conversion confirmation does not show the gas-fee-token toast Scenario: user opens mUSD conversion confirmation Given the user has a balance in a supported stablecoin (e.g. USDC) And the user is on the Money homepage When the user taps "Convert" and proceeds to the confirmation screen Then no "You're paying this network fee with ..." toast is shown Scenario: regular transaction with non-native gas token still shows the toast Given the user has a transaction that pays gas with a non-native token (e.g. USDC, not as an mUSD conversion) When the confirmation screen loads and the non-native gas token is selected Then the "You're paying this network fee with USDC." toast is shown as before ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding Standards. - [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 format if applicable - [x] I've applied the right labels on the PR #### Performance checks (if applicable) - [ ] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **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** > Confirmation UI-only guard on an existing toast; no auth, payment, or transaction submission logic changes. > > **Overview** > **`GasFeeTokenToast`** no longer shows the “paying network fee with …” toast on **mUSD conversion** confirmations, where relay-sponsored flows already surface fee context and the message was redundant or misleading. > > The component skips its effect when transaction metadata matches **`TransactionType.musdConversion`** via **`hasTransactionType`** and an **`IGNORED_TRANSACTION_TYPES`** list (extensible for other sponsored flows). Other transactions that use a non-native gas fee token still get the toast. A unit test asserts **`showToast`** is not called for mUSD conversion. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit bfc670c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Enables money account keyring to be 7702 upgradeable. ## **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** Already enabled in core: MetaMask/core#8687 ## **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] ``` ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small allowlist and enum addition with a unit test; no auth, payment, or broad transaction-path changes. > > **Overview** > Treats **Money Keyring** accounts as EIP-7702–capable in mobile, matching core support for money-account smart-account upgrades. > > Adds `ExtendedKeyringTypes.money` and includes it in `KEYRING_TYPES_SUPPORTING_7702` so `accountSupports7702` returns true for money accounts (same as HD and simple keyrings). A unit test locks in that behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6124cb1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** ### Why E2E build reuse could select artifacts from a prior workflow run using only the shared `build-source-hash` status on the commit SHA. If multiple runs existed for the same SHA/fingerprint, CI had limited proof that the downloaded app/APKs came from the exact run selected for reuse. For Detox, this matters because the tests must always run against the correct native build. If reuse is wrong, failures can look like flaky E2E tests while the real issue is stale or mismatched build artifacts. ### Before - Reusable E2E builds were matched by fingerprint and artifact names. - The fingerprint status was checked at the commit level, not tied to the candidate workflow run. - Artifact reuse did not validate build metadata before skipping the native build. - Candidate runs still in progress could be considered. ### After - Reusable runs must be completed. - The `build-source-hash` status must match the fingerprint and point to the specific candidate workflow run. - iOS and Android E2E build jobs now publish metadata artifacts. - Reuse now downloads and validates metadata before downloading/reusing native artifacts. - Metadata validation checks: - schema version - fingerprint - platform - build type - MetaMask environment - workflow run id - head SHA - expected artifact names If metadata is missing or does not match, CI falls back to a fresh native build. ## Impact This makes E2E build reuse stricter and safer. First runs after this change will likely rebuild because older artifacts do not have metadata yet. After metadata exists, reuse still works, but only when CI can prove the artifacts match the current E2E build request. <!-- 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 Scenario 1: CI builds fresh artifacts on first run Given the PR has no reusable E2E build artifacts with valid metadata for the current fingerprint When CI runs the Android and iOS E2E build jobs on the current runner Then the jobs fall back to fresh native builds, upload app/APK artifacts, upload build metadata artifacts, and Detox runs against the freshly built artifacts Scenario 2: CI safely reuses artifacts on second run Given a previous completed current-run CI build produced E2E artifacts and matching build metadata for the same fingerprint When CI is re-run without changing native build inputs Then the build jobs find the prior run, validate the metadata, skip the native build, download the matching app/APK artifacts, and Detox runs against those artifacts Scenario 3: CI falls back when metadata is invalid or missing Given a reusable run is found but its E2E build metadata is missing or does not match the current build request When CI evaluates the reusable build Then the metadata validation fails, artifact reuse is skipped, and CI performs a fresh native build ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] 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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes only GitHub Actions reuse logic but directly affects which native binaries Detox runs against; misconfiguration could force extra builds or, worse, reuse wrong artifacts until metadata checks fail. > > **Overview** > Tightens **CI E2E native build reuse** so Detox only skips a full build when artifacts are tied to a specific prior workflow run, not just a matching fingerprint on the commit. > > **`find-reusable-build`** now requires **completed** runs, matches `build-source-hash` via per-status `target_url` pointing at that run (replacing commit-level combined status), and can require a **metadata artifact** alongside app/APK artifacts. > > **Android and iOS E2E build workflows** publish a versioned **build metadata** JSON artifact, download and **jq-validate** it (fingerprint, platform, build type, environment, run id, head SHA, artifact names) before reusing binaries, and fall back to a fresh native build on any mismatch. Reuse decisions are surfaced in **job step summaries**. > > **`ci.yml`** renames the fingerprint job to **`native-build-fingerprint`** and wires E2E builds to its output; **`post-build-source-hash`** gains optional **`post-status`** (skipped on Namespace trial runs while still emitting the fingerprint). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 734d950. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Fixes a Predict market details issue where placing a bet from a large multi-outcome market, such as the World Cup winner market with 64 outcomes, could stall before the transaction-added event appeared. The details screen was keeping broad outcome price work active behind the buy sheet. For 64 outcomes, that meant REST price polling and live price subscriptions for every YES/NO token while the buy flow was also initializing transaction setup. This change exposes buy sheet open state from the preview sheet context and pauses the market details open-outcome price refresh while the buy sheet is mounted. Changes included: - Add `isBuySheetOpen` to `PredictPreviewSheetContext`. - Disable broad open-outcome REST polling and live subscriptions from `PredictMarketDetails` while the buy sheet is open. - Keep existing outcome data available so the selected buy flow still has its market/outcome context. - Add regression coverage for the buy sheet open state and the 64-outcome paused-refresh behavior. ## **Changelog** CHANGELOG entry: Fixed a bug that could delay prediction bet placement from large market details screens. ## **Related issues** Fixes: [PRED-930](https://consensyssoftware.atlassian.net/browse/PRED-930) ## **Manual testing steps** ```gherkin Feature: Predict large market bet placement Scenario: user places a bet from a 64-outcome market details screen Given Predict is enabled And the user opens the World Cup winner market details screen And the market has many open outcomes When the user taps Buy on an outcome And the buy sheet opens Then the market details screen pauses broad open-outcome price polling and live subscriptions When the user proceeds with the bet Then transaction setup should continue without the details screen generating repeated RPC degraded logs from broad outcome refresh work ``` Automated testing run: ```bash node .yarn/releases/yarn-4.14.1.cjs jest app/components/UI/Predict/contexts/PredictPreviewSheetContext.test.tsx --runInBand node .yarn/releases/yarn-4.14.1.cjs jest app/components/UI/Predict/views/PredictMarketDetails/PredictMarketDetails.test.tsx --runInBand git diff --check ``` ## **Screenshots/Recordings** ### **Before** Reporter-provided recording showed bet placement from the World Cup winner market details screen getting stuck before transaction-added logs appeared, followed by repeated RPC degraded logs. ### **After** No after recording captured in this session. Behavior is covered by targeted unit tests for pausing the broad details price refresh while the buy sheet is open. ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [ ] 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. [PRED-930]: https://consensyssoftware.atlassian.net/browse/PRED-930?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Targeted performance fix: toggles existing price hooks off during buy sheet only; no auth, payment, or order logic changes. > > **Overview** > Fixes stalls when placing bets from **large multi-outcome** Predict market details (e.g. 64 teams) by stopping background price work while the buy sheet is open. > > **`PredictPreviewSheetContext`** now exposes **`isBuySheetOpen`** (true while buy preview params are mounted; **`false`** in the navigation fallback outside the provider). **`PredictMarketDetails`** uses it to gate **`useOpenOutcomes`**: broad **REST polling** (~2s) and **live price subscriptions** for every open outcome token pause when the buy sheet is visible and resume on dismiss. **`useOpenOutcomes`** accepts an optional **`enabled`** flag and passes empty queries with polling disabled when off, while still returning cached outcome structure for the buy flow. > > Tests cover buy-sheet open/close state and the 64-outcome pause/resume behavior for **`usePredictPrices`** / **`useLiveMarketPrices`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f55989d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…n Home (MUSD-838) (#30596) ## **Description** The Money Account Home Card was choosing its CTA variant ("Earn" / "Add" / "Get started") from the user's account state, not from whether another primary CTA already exists on Home. As a result, an empty-balance non-new user saw a Primary "Earn" button on Home at the same time the onboarding stepper rendered its primary CTA (two primaries on one screen), and a funded user saw a Secondary "Add" button even when no other primary CTA existed. This change decouples variant from account state. A single derived boolean — `hasOtherPrimaryCtaOnHome`, aliasing the existing `selectWalletHomeOnboardingFlowVisible` selector that already gates the onboarding stepper — drives the variant for every branch. Labels are untouched. ## **Changelog** CHANGELOG entry: Fixed the Money Account Home Card showing two primary CTAs on Home when the onboarding stepper is visible, and showing a non-primary "Add" CTA when no other primary CTA exists. ## **Related issues** Fixes: [MUSD-838](https://consensyssoftware.atlassian.net/browse/MUSD-838) ## **Manual testing steps** ```gherkin Feature: Money Account Home Card CTA variant Scenario: Money CTA is secondary when the onboarding stepper is visible Given a wallet whose onboarding stepper is visible on Home When the user lands on Home Then the Money Account card's button renders as a secondary CTA Scenario: Money CTA is primary when no other primary CTA exists on Home Given a wallet with the onboarding stepper dismissed or completed When the user lands on Home Then the Money Account card's button renders as the primary (black) CTA Scenario: Earn and Add follow the same conditional logic Given a funded Money Account on Home When the onboarding stepper is hidden Then the "Add" button renders as primary When the onboarding stepper is visible Then the "Add" button renders as secondary ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. [MUSD-838]: https://consensyssoftware.atlassian.net/browse/MUSD-838?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only button styling on the Money balance card with regression tests; no auth, data, or navigation logic changes beyond variant selection. > > **Overview** > **MoneyBalanceCard** now picks **Primary vs Secondary** for Earn / Add / Get started from whether another primary CTA is already on Home (`hasOtherPrimaryCtaOnHome`, wired to `selectWalletHomeOnboardingFlowVisible`), instead of hard-coding variants by balance state alone. > > **Empty** and **funded** branches were updated so the card is **Secondary** when the wallet-home onboarding stepper is visible and **Primary** when it is not—fixing duplicate primaries and a funded **Add** that stayed secondary with no competing CTA. New-user label/testID logic is unchanged; only variant selection is unified. Tests assert variant behavior across empty, funded, and new-user cases. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 877baae. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** `Predict Market Details Opened` and `Predict Trade Transaction` had no way to attribute conversions originating from the Explore page — `EXPLORE` was simply missing from `ENTRY_POINT`, and the Explore→Predict navigation never passed one. - Adds `ENTRY_POINT.EXPLORE = 'explore'` to `PredictEventValues` and the `PredictEntryPoint` union (mirrors `SOURCE.EXPLORE` in Perps) - `PredictionCarouselRowItem` and `PredictionSearchRowItem` hardcode `ENTRY_POINT.EXPLORE` — same pattern as `PerpsRowItem` - `SportsTab` sets it on the one direct `PredictMarket` usage - Extracts `useResolvedPredictEntryPoint` hook to centralise the context > prop > trending session > default priority that was duplicated across 5 card components; fixes a pre-existing bug where the session manager could override an explicit prop <!-- 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: add explore entrypoint attribution in predict ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/PRED-929?issueKey=PRED-929&subProduct=jira-software & https://consensyssoftware.atlassian.net/browse/ASSETS-3271 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Analytics and UI wiring only; no auth, payments, or data-handling changes. Behavior change is clearer entry-point attribution and a small priority bugfix. > > **Overview** > Adds **`ENTRY_POINT.EXPLORE`** (`explore`) to Predict analytics types and passes it from **Explore** surfaces: prediction carousel/search rows and **Sports** tab market cards—so market opens and trades can attribute to Explore. > > Introduces **`useResolvedPredictEntryPoint`** to replace duplicated logic across Predict market cards. Resolution order is **context → prop → trending session → `predict_feed` default**. This also fixes a bug where an active trending session could override an **explicit** `entryPoint` prop. > > Card components and related tests are updated to use the hook and to assert that **explicit entry points win over trending**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1c32f7f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Adds the Pay With step to QuickBuy with a token list backed by `sourceTokenOptions`. Also moves the exchange rate tag into the toolbar to match Figma and adds empty-state copy. <img height="800" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-26 at 18 04 46" src="https://github.com/user-attachments/assets/dde60d07-f9a5-4cdc-9cd8-1c32a634466a" /> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes which source token funds a bridge buy and resets amount state on switch; behavior is feature-flagged but affects real swap funding paths when enabled. > > **Overview** > Adds a **Pay With** bottom-sheet step to Top Traders Quick Buy: the footer pill navigates to `payWith`, lists `sourceTokenOptions` with optional multi-chain chips (`PredictChipList`), and selecting a token runs `handleSelectSourceToken` (clears amount/slider) before returning to the amount screen. **`payWithSheet`** is turned on in `TOP_TRADERS_QUICK_BUY_FEATURES`. > > **UI polish:** the exchange rate moves from the amount section into **`QuickBuyToolbar`** (with matching loading skeleton); empty-state strings for no pay tokens / “All” filter are added. > > **`PredictChipList` refactor:** scroll math lives in `calculateChipScrollX` + `useChipScrollList`; chips can show optional icons, custom Tailwind/test IDs, and an optional gesture-handler horizontal scroll for reuse (e.g. chain filter). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 405bd26. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MMQA-1802 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Changes are limited to test infrastructure and a new performance/system spec; production app code is untouched. > > **Overview** > Adds a **Playwright/Appium system test** that logs in, sends a tiny ETH amount via the redesigned send flow, confirms, opens Activity, and waits for on-chain **Confirmed** status (5-minute timeout). > > Extends the **dual-framework test layer** so the same page objects work under Detox and Appium: `PlaywrightGestures.waitAndTap` now accepts an optional **`timeout`** for display/enable waits; send/confirmation/activity/tab-bar flows use **`encapsulatedAction`** with platform-specific locators (e.g. Ethereum network chip + ETH row, iOS recipient `textfield`, numpad keys by XPath on iOS); **`walletSendButton`** is encapsulated and tapped via **`UnifiedGestures`**; Activity tab and confirm footer get Appium paths; **`ActivitiesView.waitForTransactionConfirmed`** polls status text up to ~120s on Appium. > > New send helpers: **`enterAmountViaNumpad`**, **`selectRecipientAccount`**, plus Detox/Appium splits for continue, review, and recipient entry. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8efe346. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ettings Drawer (#30543) ## **Description** Adds a shared `Pressable` primitive (`app/component-library/components-temp/Pressable/`) that replaces `TouchableOpacity`'s full-subtree opacity dim with a token-based background swap on press. Callers pick a semantic variant (`section` / `subsection` / `default` / `muted` / `transparent` / `none`) and the component owns the resting → pressed token pair, so the broader `TouchableOpacity` migration becomes consistent without per-call-site token guessing. Ships RN core + `react-native-gesture-handler` variants (RNGH scroll trees need their own `Pressable` to avoid Android gesture conflicts) and defaults `accessibilityRole="button"` to preserve the implicit role `TouchableOpacity` provided. Migrates `SettingsDrawer` as the first consumer. This fixes the pure-black-mode regression where the previous opacity dim made elevated rows look invisible against the `#000000` backdrop — pressed rows now shift to `background.defaultPressed` instead of dimming. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-790 ## **Manual testing steps** ```gherkin Feature: Settings row press feedback Scenario: user presses a Settings row in light mode Given the app is open in light mode When user navigates to Settings and presses any row Then the row background briefly shifts to the pressed token (no subtree dim) Scenario: user presses a Settings row in pure-black mode Given MM_PURE_BLACK_PREVIEW=true is set in .js.env and the app is rebuilt When user navigates to Settings and presses any row Then the row background briefly shifts to #222226 and remains clearly visible And the row does not appear to "disappear" against the pure-black backdrop ``` ## **Screenshots/Recordings** https://github.com/user-attachments/assets/15251791-a867-4f96-a9d4-7eaca4b1c626 https://github.com/user-attachments/assets/c72bc988-f1e8-4fcd-98d4-91b4a11b5a77 ### **Before** ### Non-Pure Black https://github.com/user-attachments/assets/838a11c1-ad14-4e17-8df3-e43ef906e3e8 ### Pure Black https://github.com/user-attachments/assets/83ae56b1-916a-47e0-b92f-545eab8ff111 ### **After** ### Non-Pure Black https://github.com/user-attachments/assets/a0975b7e-d62c-4c4c-b3e9-9b2a39876d1a ### Pure Black https://github.com/user-attachments/assets/d0d2b706-6b2a-4ac1-8026-21e151adf4f2 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Localized UI/interaction and a single settings row consumer; main follow-up is overriding accessibilityRole where rows are not semantic buttons. > > **Overview** > Introduces a shared **`Pressable`** primitive under `components-temp/Pressable` (plus **`PressableGH`** for RNGH scroll trees) to standardize press feedback: on press it layers **`colors.background.pressed`** over the caller’s style instead of **`TouchableOpacity`** subtree opacity. **`accessibilityRole`** defaults to **`button`**; tests, README, Storybook story, and registry entry are included. > > **`SettingsDrawer`** is migrated as the first consumer—**`TouchableOpacity`** → **`Pressable`**, and the row wrapper no longer sets a resting **`backgroundColor`** on the outer styles (pressed feedback comes from the new overlay). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4260311. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Adds a Primary CTA haptic impact when the user presses the **Trade**
button on a related-asset row in the What's Happening expanded card.
- The Trade button is a primary commit action that opens the Perps
market detail flow. Per the haptics catalog, `ImpactMoment.PrimaryCTA`
is the moment reserved for primary surface commits (Buy/Trade/Save) and
is the correct mapping here.
- The haptic fires only when there is a valid `hlPerpsMarket` symbol
(i.e., the same guard that gates navigation and analytics). If the press
is a no-op, no haptic plays.
- Implemented via the project's `util/haptics` facade (`playImpact` +
`ImpactMoment`), not by importing `expo-haptics` directly — consistent
with the existing eslint rule and the catalog-driven haptics
architecture used elsewhere (e.g. `PerpsSlider`).
## **Changelog**
CHANGELOG entry: Added haptic feedback to the Trade button in the What's
Happening detail card.
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Haptic feedback on What's Happening Trade CTA
Scenario: User taps Trade on a related perps asset
Given the user has opened a What's Happening card with at least one related perps asset
And the device has system haptics enabled
When the user taps the "Trade" button next to a related asset
Then a medium "Primary CTA" haptic impact is felt
And the app navigates to the Perps market details screen
Scenario: Row without a perps market does not render Trade
Given a related asset has no hlPerpsMarket symbol
When the user views the row
Then no Trade button is shown
And no haptic fires
```
## **Screenshots/Recordings**
### **Before**
No haptic on Trade press.
### **After**
Primary CTA haptic fires on Trade press (see attached screenshot of the
affected screen in the PR description).
## **Pre-merge author checklist**
- [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding
Standards.
- [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 format if applicable
- [ ] I've applied the right labels on the PR
#### Performance checks (if applicable)
- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Made with [Cursor](https://cursor.com)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Small UX addition behind existing trade guards; no auth, data, or
navigation logic changes beyond calling the shared haptics helper.
>
> **Overview**
> Adds **Primary CTA** haptic feedback when users tap **Trade** on a
related perps asset row in the What's Happening detail card, using
`playImpact(ImpactMoment.PrimaryCTA)` from `util/haptics`.
>
> The impact runs only inside the existing trade handler after a valid
`hlPerpsMarket` symbol is confirmed—the same guard as navigation and
analytics—so no-op rows never trigger haptics. **Unit tests** mock the
haptics facade and cover both successful Trade press and missing-market
cases.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9f94739. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Co-authored-by: Cursor <cursoragent@cursor.com>
…nts (#30621) ## **Description** The `TradingService` analytics events (`TradeTransaction`, `PositionCloseTransaction`) already read `vipTier` and `vipDiscount` from `trackingData`, but no caller was populating those fields. This PR wires VIP program context through every trading flow: - **`PerpsOrderView`** — adds `vipTier` / `vipDiscount` to the `trackingData` passed to `placeOrder`, so `#trackOrderResult` includes them. - **`PerpsClosePositionView`** — adds the same fields to `closePosition`'s `trackingData`, so `#buildCloseEventProperties` includes them. - **`PerpsFlipPositionConfirmSheet` / `usePerpsFlipPosition`** — extends `handleFlipPosition` to accept `TrackingData` and passes VIP context through to `TradingService.flipPosition`. All three views obtain `vipTier` via the existing `useVipTier()` hook and `vipDiscount` from `feeResults.feeDiscountPercentage`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: VIP tier and discount in trading analytics Scenario: VIP data included in place-order analytics Given user is a VIP program participant with a non-zero tier When user places a new perps order Then the TradeTransaction analytics event includes vip_tier and vip_discount properties Scenario: VIP data included in close-position analytics Given user is a VIP program participant with a non-zero tier When user closes a perps position Then the PositionCloseTransaction analytics event includes vip_tier and vip_discount properties Scenario: VIP data included in flip-position analytics Given user is a VIP program participant with a non-zero tier When user flips a perps position direction Then the TradeTransaction analytics event includes vip_tier and vip_discount properties ``` ## **Screenshots/Recordings** N/A — analytics-only change with no UI impact. ### **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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Analytics-only wiring with no trading, auth, or UI behavior changes; risk is limited to incorrect or missing event properties if hooks return stale values. > > **Overview** > This PR **populates VIP program fields on perps trading analytics** by threading `vipTier` (from `useVipTier()`) and `vipDiscount` (from `feeResults.feeDiscountPercentage`) into `trackingData` for **place order**, **close position**, and **flip position** flows—so downstream `TradeTransaction` / `PositionCloseTransaction` events can emit the properties the service layer already expects. > > **Flip flow:** `usePerpsFlipPosition` now accepts optional `TrackingData` and forwards it to `flipPosition`; the confirm sheet passes fee, market price, and VIP fields. Tests mock `useVipTier` and assert the flip handler receives a tracking payload with `totalFee` and `marketPrice`. > > **Order view:** Only analytics-related edits (VIP fields + `vipTier` in `handlePlaceOrder` deps); some inline comments on `trackingData` were removed. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8c48f12. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adds the shared Predict portfolio data/model hook for PRED-902. This introduces `usePredictPortfolio`, a reusable portfolio-domain hook that centralizes the Predict balance, open positions, claimable positions, claim/deposit/withdraw handlers, loading/error state, and derived portfolio summary values for the homepage portfolio module and future Positions screen. The hook derives: - available Predict balance - active/open positions and actionable claimable positions - portfolio value - open, claimable, and badge counts - claimable amount - total unrealized P&L amount and optional percent - P&L visibility using the one-cent threshold - aggregate and granular loading/error/refetch state Unrealized P&L is calculated from open positions only using summed current value minus summed initial value. Resolved won/lost positions are excluded from unrealized P&L, and the P&L percent is omitted when total initial value is zero. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/PRED-902 ## **Manual testing steps** ```gherkin Feature: Predict portfolio shared data model Scenario: portfolio model derives reusable values for Predict surfaces Given the Predict portfolio hook is rendered with balance, open positions, and claimable positions When the underlying balance or positions query data changes Then the hook returns updated portfolio value, P&L, counts, claimable amount, and loading/error state ``` Manual app QA: N/A. This PR adds a shared data/model hook and unit coverage only; no UI integration is included. ## **Screenshots/Recordings** N/A. No user-facing UI changes are included in this PR. ### **Before** N/A ### **After** N/A ## **Testing** - `NODE_OPTIONS=--max-old-space-size=8192 node .yarn/releases/yarn-4.14.1.cjs jest app/components/UI/Predict/hooks/usePredictPortfolio.test.ts app/components/UI/Predict/hooks/usePredictBalance.test.ts app/components/UI/Predict/hooks/usePredictPositions.test.ts --runInBand --watchman=false --forceExit --silent --coverage=false` - `node .yarn/releases/yarn-4.14.1.cjs lint:tsc` ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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** > Data-layer hook and unit tests only; no UI or payment/auth changes, though derived portfolio/P&L logic will need careful review when integrated. > > **Overview** > Introduces **`usePredictPortfolio`**, a shared Predict data hook that composes balance, active/claimable positions (with live updates on open positions), account state, and claim/deposit/withdraw actions into one **`PredictPortfolioModel`**. > > It **derives** portfolio value (balance + open position value + actionable won claimables), open/claimable/badge counts, claimable amount, unrealized P&L from open positions only (current vs initial value, percent omitted when initial value is zero), and P&L visibility behind a **$0.01** threshold. Won claimables with positive value count toward value and badges; lost claimables do not. Loading, refresh, aggregated/per-source errors, and a combined **`refetch`** are exposed. > > **Exports** the hook from the Predict hooks barrel. **Adds** unit coverage for the portfolio hook and **new tests** that balance and positions refetch when the selected account address changes (with more flexible account mocks). > > No UI wiring in this PR—hook and tests only. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit bd8588a. 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** Updated `app/core/AppConstants.ts` to stop reading `process.env.MM_PORTFOLIO_URL` and always use the portfolio website host directly: - `PORTFOLIO_URL = 'https://portfolio.metamask.io'` This ensures Browser launches from Explore cannot be redirected to an API endpoint URL (which renders as a blank page). ## **Changelog** CHANGELOG entry: fix: explore browser icon opens blank page. ## **Related issues** Fixes: #29048 ## **Manual testing steps** ```gherkin Feature: Open browser from Explore Scenario: Browser icon opens portfolio site when no tabs are open Given MM app browser has no open tabs When user opens Explore and taps the browser icon beside search Then the app opens the portfolio website, not an API URL ``` ## **Screenshots/Recordings** ### **Before** Repro from bug report: browser navigates to `https://portfolio.api.cx.metamask.io/...` and shows blank page. ### **After** Expected navigation target resolves from `AppConstants.PORTFOLIO.URL` to `https://portfolio.metamask.io`. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-5e53fa06-e2dd-4725-837c-cc51d95d3374"><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-5e53fa06-e2dd-4725-837c-cc51d95d3374"><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>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Update the home-screen "How it works" description to match the latest Figma copy ([Figma node 8027-14650](https://www.figma.com/design/XKZ8hRqSn2iTiuzmlQLuYQ/Money-account?node-id=8027-14650&m=dev)). - Before: "Deposit mUSD into your Money account and earn up to 4% APY. Your balance is dollar-backed and ready to spend, trade, or send anytime." - After: "Add mUSD and earn up to 4% APY (variable). Your balance is dollar-backed and ready to spend, trade, or send anytime." The existing component already splits this into i18n `description_prefix` · highlighted APY · `description_suffix`, so only the two locale strings in `locales/languages/en.json` change. Non-English locales come from the localization pipeline. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Updated the Money home "How it works" description copy. ## **Related issues** Fixes: [MUSD-843](https://consensyssoftware.atlassian.net/browse/MUSD-843) ## **Manual testing steps** ```gherkin Feature: Money home — "How it works" copy Scenario: User views the updated description on the Money home screen Given the user has a Money account When user opens the Money home screen Then the "How it works" section reads "Add mUSD and earn up to 4% APY (variable). Your balance is dollar-backed and ready to spend, trade, or send anytime." And the "4% APY" segment is highlighted in the success color ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [MUSD-843]: https://consensyssoftware.atlassian.net/browse/MUSD-843?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Copy-only change in English locale strings and tests; no business logic or security impact. > > **Overview** > Updates the Money home **How it works** copy in English to match Figma: the prefix shifts from depositing into the Money account to **Add mUSD and earn up to**, and the suffix now includes **(variable)** before the dollar-backed balance sentence. > > `MoneyHowItWorks` still composes prefix, highlighted APY, and suffix from i18n—no UI logic changes. Unit tests in `MoneyHowItWorks.test.tsx` were aligned with the new strings. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6f635b7. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
This PR fixes two smoke-test flakes while keeping the tests on the
normal fixture/mock paths.
For the Android swap deeplink failure, the test reached the Swap screen
with `1.0` USDC -> USDT selected, but the quote area stayed in its
loading skeleton until the fee-disclaimer assertion timed out. The
full-parameters deeplink scenario now loads
`tests/smoke/swap/withTokens.json`, matching the regular swap smoke
fixture so USDC contract and balance reads are available before the
bridge quote resolves.
For the linked stake smoke failure, the job was `stake-ios-smoke` and
the app reached wallet home, but `stake-button` never existed. The stake
test already had Accounts API mocks and the framework default
feature-flag mock is aligned with current production defaults, so the
fix keeps Detox synchronization on until the Earn CTA is visible, then
disables sync only for the animated staking flow. It also enables the
Mainnet network map used by the TokensFullView filter, uses the stable
Network Manager row selector for Localhost, and keeps fiat coverage by
asserting the staked ETH row contains the localized label, the expected
`1 ETH` amount, and a fiat balance matching a dollar-value regex. The
combined staked-row assertion lives in the TokensFullView page object,
with row selector constants centralized in
`tests/selectors/Wallet/WalletView.selectors.ts`, so the spec stays
aligned with the E2E page-object/selector guidelines.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: Smoke E2E fixture flakes
Scenario: user opens a full-parameter USDC to USDT swap deeplink
Given the iOS or Android smoke test app is launched with Anvil mainnet chain state
And the Anvil node has preloaded ERC20 token contract and balance state
When user opens the swap deeplink with USDC as the source token, USDT as the destination token, and amount 1000000
Then the Swap screen displays USDC, USDT, and amount 1.0
And the bridge quote resolves
And the fee disclaimer and confirm swap button are visible
Scenario: user starts staking from wallet home
Given the stake smoke test app is launched with mocked Mainnet ETH balance and the framework default feature-flag mock
When user logs in and wallet home renders
Then the token-row Earn CTA is visible
When user taps Earn and stakes 1 ETH
Then the staking deposit activity is confirmed
And the staked ETH asset row is visible with amount 1 ETH and a fiat balance
```
## **Screenshots/Recordings**
N/A - E2E-only test changes.
### **Before**
- Swap deeplink: Android CI recording showed the Swap screen reached
with USDC -> USDT and amount `1.0`, but the quote section remained in a
loading skeleton until the fee-disclaimer assertion timed out.
- Stake: iOS CI recording showed wallet home loading without the
token-row `stake-button`, so the Earn CTA assertion timed out.
### **After**
- Swap deeplink: local iOS prebuilt smoke run reached the quote view and
passed the full-parameters deeplink scenario.
- Stake: local iOS prebuilt smoke run reached the Earn CTA via the
existing Accounts API mocks and framework default feature-flag mock,
completed the staking flow, filtered TokensFullView to Localhost, and
verified the staked ETH row, amount, and fiat balance text matching the
wallet selector regex.
## **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).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
## **Validation**
- `yarn lint:tsc`
- `yarn prettier --check tests/smoke/swap/swap-deeplink-smoke.spec.ts`
- `yarn eslint tests/smoke/swap/swap-deeplink-smoke.spec.ts`
- `yarn prettier --check tests/page-objects/wallet/HomeSections.ts
tests/selectors/Wallet/WalletView.selectors.ts
tests/smoke/stake/stake-action-smoke.spec.ts`
- `yarn eslint tests/page-objects/wallet/HomeSections.ts
tests/selectors/Wallet/WalletView.selectors.ts
tests/smoke/stake/stake-action-smoke.spec.ts`
- `PREBUILT_IOS_APP_PATH="$HOME/Downloads/main-e2e-MetaMask.app" yarn
test:e2e:ios:debug:run --testPathPattern
tests/smoke/swap/swap-deeplink-smoke.spec.ts --testNamePattern "navigate
to bridge view with full parameters"`
- `PREBUILT_IOS_APP_PATH="$HOME/Downloads/main-e2e-MetaMask.app" yarn
test:e2e:ios:debug:run --testPathPattern
tests/smoke/stake/stake-action-smoke.spec.ts --testNamePattern "should
be able to import stake test account with funds"`
- Re-ran the stake command after removing direct controller fixture
seeding and per-test feature-flag overrides; it still passed via the
normal mocked API/default flag paths.
- Re-ran the stake command after restoring the row-scoped fiat balance
assertion; it passed.
- Re-ran the stake command after moving the row-scoped fiat balance
assertion into the TokensFullView page object; it passed.
- Selector-only cleanup after that was validated with `yarn lint:tsc`
and focused Prettier/ESLint; Detox was not rerun for that cleanup.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Changes are limited to Detox smoke tests, selectors, and page objects;
no production app logic.
>
> **Overview**
> Hardens two smoke E2E paths that were timing out in CI.
>
> **Swap deeplink (USDC → USDT):** The full-parameters scenario now
seeds Anvil with `tests/smoke/swap/withTokens.json` (same as other swap
smokes) so ERC20 contract/balance reads finish before the bridge quote
leaves the loading skeleton.
>
> **Stake from Actions:** The fixture enables Mainnet in the
network-enabled map; the Earn CTA is asserted **before** Detox sync is
turned off for the staking animation flow. Post-stake verification uses
`NetworkManager.tapNetwork('eip155:1')` instead of the network list
modal, and a shared **TokensFullView** page object asserts the staked
ETH row (label, `1 ETH`, and a fiat amount matching a dollar regex)
instead of a fixed USD string.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
156bd74. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** - Fix explore search v2 issues: - Cryptos -> Crypto - "View all" wont show in the loading state - "View all" stays on the no_query state - When there is a query: - "View X more" will be shown only if there are more than 3 items - Every section with less than 3 items does not show "View all" - When there are no results we should show the correct empty state with the pills - If there are no results for all sections we do not show "We found these results for "Btcx"" <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: fix explore search v2 issues ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3272 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI and label logic in Explore search with broad test updates; no auth, payments, or security-sensitive paths. > > **Overview** > Explore Search v2 UX fixes: **Crypto** tab copy (was “Cryptos”), smarter **View all / View more** behavior, richer **empty states**, and a **custom search placeholder** overlay. > > **Section actions:** `getViewMoreLabel` now returns `null` when there’s nothing beyond the 3-item cap (with an active query), so headers hide the control instead of showing misleading “View all”. Loading sections skip the button entirely. With **no** query, labels still use **View all**. With a query, **View X more** appears only when counts justify it; tokens without a server total can still fall back to **View all**. > > **Empty results:** When every section is empty, the list shows a global “no results” message, optional **BTC/ETH/SOL** quick pills, and only shows the “other results” line when some sections still have hits (with a `count` in copy). Per-feed empty states keep the feed-specific message. > > **Search bar:** Interactive mode uses an empty native placeholder plus a non-interactive overlay for alignment; tests target `EXPLORE_VIEW_SEARCH_TEXT_INPUT` instead of placeholder text. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 906285a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…#30666) <!-- 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** The pay-with bottom sheet was gated behind the `MM_DEV_PAY_WITH_BOTTOM_SHEET` env variable via the `isPayWithBottomSheetEnabled()` helper. This PR removes the feature flag entirely and enables the pay-with bottom sheet unconditionally: 1. **Removes `isPayWithBottomSheetEnabled()`** from `transaction-pay.ts` 2. **Simplifies navigation** in 4 files (`PayWithRow`, `PerpsPayRow`, `PredictPayWithRow`, `PredictBuyWithAnyToken`) - always navigate to `CONFIRMATION_PAY_WITH_BOTTOM_SHEET` instead of conditionally choosing between the bottom sheet and the old modal 3. **Removes dead code** from `usePredictBalanceTokenFilter` and `usePerpsBalanceTokenFilter` - the synthetic `HighlightedItem` rows (Predict balance / Perps balance) that were only shown in the old modal path are removed along with their unused hooks and imports 4. **Simplifies `PayWithModal`** - removes fiat highlighted actions suppression logic since the bottom sheet handles fiat actions 5. **Updates 7 test files** - removes mocks for the flag, updates navigation assertions, removes tests for old-path behavior > **Note:** `PayWithModal` and its route (`CONFIRMATION_PAY_WITH_MODAL`) are intentionally kept - they are still used as the "Other assets" token picker launched from within the bottom sheet via `usePayWithCryptoSection`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Pay-with bottom sheet Scenario: user opens pay-with token picker from confirmation Given user has a pending transaction confirmation with pay-with row When user taps the pay-with row Then the pay-with bottom sheet opens (not the old full-screen modal) Scenario: user opens pay-with from Perps order view Given user is on the Perps order view with a pay-with row When user taps the pay-with row Then the pay-with bottom sheet opens Scenario: user opens pay-with from Predict buy flow Given user is in the Predict buy-with-any-token flow When user taps Change Payment Method Then the pay-with bottom sheet opens ``` ## **Screenshots/Recordings** ### **Before** ### **After** ### MUSD Conversion https://github.com/user-attachments/assets/fefa8b80-cc81-4876-8221-29d9aed79c86 ### Perps https://github.com/user-attachments/assets/b48cd1bf-4497-464b-94f3-07daea47716b ### Predict https://github.com/user-attachments/assets/362ad188-7724-4e6d-9844-2c80899147a6 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches payment selection navigation across confirmations, Perps, and Predict; behavior change is broad but localized to pay-with UX, not auth or funds signing. > > **Overview** > Removes the **`MM_DEV_PAY_WITH_BOTTOM_SHEET`** gate (`isPayWithBottomSheetEnabled`) and makes the **pay-with bottom sheet** the only entry path from confirmations, Perps, and Predict (always **`CONFIRMATION_PAY_WITH_BOTTOM_SHEET`**). > > **Perps** and **Predict** balance token filters no longer prepend synthetic **Perps balance** / **Predict balance** highlighted rows or wire **Add funds** from those lists—that UI lived on the old modal path. Perps still applies allowlist filtering and clears other tokens’ selection when perps balance is selected. > > **`PayWithModal`** stops prepending fiat highlighted actions and the flag-based suppression; token lists come from filters only. The modal route remains for flows such as **Other assets** from the bottom sheet. > > Tests drop flag mocks and assert bottom-sheet navigation. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit db8b7e4. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
The Money Account confirmation screens did not match the Convert
experience used on mobile home: the Add screen showed "Add money" with
no conversion tooltip, and the Transfer screen showed "Transfer money".
This aligns those screens with MUSD-806:
- **Add → "Add funds" + conversion tooltip** — `MoneyAccountDepositInfo`
now installs its navbar through the new `useMoneyAccountDepositNavbar`
hook, which sets the "Add funds" title and adds an info button that
opens the conversion tooltip (`useMoneyAccountDepositTooltip`). The
tooltip APY is read from `useMoneyAccountBalance().apyPercent`, so the
copy stays in sync with the account's real rate.
- **Transfer → "Transfer funds"** — `MoneyAccountWithdrawInfo` title
string updated.
- **Projected balance** — the deposit amount screen shows the projected
balance via `BalanceProjection`. The copy is unified into a single
parametrised key (`confirm.custom_amount.projected_balance` → "Projected
{{projectedYears}}-year balance:") instead of the year-pinned
`projected_five_year_balance`, and the component takes a
`projectedYears` prop (currently `1`).
Heading copy lives in `en.json` (`money_account_add_money`,
`money_account_transfer_money`) alongside the new tooltip strings
(`deposit_tooltip_title`, `deposit_tooltip_description`).
**Scope:** this is the design-review heading / tooltip / projection-copy
change only. The Deposit funds / Move mUSD routing and the Transfer
destinations belong to the MM Pay / Ramps teams and are tracked
separately.
## **Changelog**
CHANGELOG entry: Updated the Money Account Add and Transfer confirmation
screens with corrected headings ("Add funds" / "Transfer funds"), a
conversion tooltip on the Add screen, and a unified parametrised
projected-balance copy.
## **Related issues**
Fixes:
[MUSD-806](https://consensyssoftware.atlassian.net/browse/MUSD-806)
## **Manual testing steps**
```gherkin
Feature: MM Pay Money Account heading, tooltip and projection
Scenario: user opens the Add screen
Given the user has a Money Account
When the user starts Add money (Convert crypto)
Then the screen heading reads "Add funds"
And tapping the navbar info button shows the conversion tooltip
And the tooltip APY matches the account's current rate
Scenario: projected balance updates with the entered amount
Given the user is on the Add screen
When the user enters an amount
Then a "Projected 1-year balance:" line shows the compounded amount
Scenario: user opens the Transfer screen
Given the user has a Money Account
When the user starts Transfer (Between accounts)
Then the screen heading reads "Transfer funds"
```
## **Screenshots/Recordings**
### **Before**
### **After**
https://github.com/user-attachments/assets/84acc820-5566-4a65-b722-4ff35be3fe6b
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- [x] I've tested with a power user scenario
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
## **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.
[MUSD-806]:
https://consensyssoftware.atlassian.net/browse/MUSD-806?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Projection math and APY source switched from percent-based 5-year
vault data to `apyDecimal` with configurable years—user-visible amounts
can change if APY wiring is wrong; otherwise UI/copy and tests only.
>
> **Overview**
> Aligns Money Account **Add** and **Transfer** confirmation screens
with the Convert mobile experience (MUSD-806): headings become **“Add
funds”** / **“Transfer funds”**, and the Add flow gets a navbar **info**
control that opens an APY conversion tooltip driven by
`useMoneyAccountBalance().apyPercent`.
>
> **Add screen** no longer calls `useNavbar` directly; it uses
**`useMoneyAccountDepositNavbar`**, which sets the title, back button,
and a header info button wired to **`useMoneyAccountDepositTooltip`**
(balance hook only mounts while the modal is open).
>
> **Projected balance** replaces the fixed **5-year**
`ProjectedFiveYearBalance` with **`BalanceProjection`**: a
`projectedYears` prop, copy via
`confirm.custom_amount.projected_balance`, and compounding on
**`apyDecimal`** instead of vault APY as a percent. Money account
deposit shows a **1-year** projection under the amount.
>
> New **`en.json`** strings cover the deposit tooltip and updated
confirm titles; tests cover navbar, tooltip, and projection math.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3ab9509. 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: Matthew Grainger <46547583+Matt561@users.noreply.github.com>
Co-authored-by: Shane T <shane.odlum@consensys.net>
## **Description** Splits the `push-eas-update` job into two parallel jobs, one per platform (iOS and Android), running on separate runners. This avoids LavaMoat serializer contention and mitigates intermittent OTA deployment failures caused by a [known GitHub Actions runner issue](actions/runner#3819 (comment)). The shared EAS update steps have been extracted into a reusable workflow. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: N/A ## **Manual testing steps** | Run | Platform | Result | |-----|----------|--------| | [iOS dry-run](https://github.com/MetaMask/metamask-mobile/actions/runs/26117723683/job/76811308433) | iOS | ✅ Passed — cancelled before EAS upload | | [Android test](https://github.com/MetaMask/metamask-mobile/actions/runs/26119164078) | Android | ✅ Passed | | [Both platforms in parallel](https://github.com/MetaMask/metamask-mobile/actions/runs/26120507757) | iOS + Android | ✅ Both passed | ## **Before/After** ### **Before** Single `push-update` job — iOS bundled first, then Android sequentially on the same runner. ### **After** Two parallel jobs (`push-update-ios`, `push-update-android`) running simultaneously on isolated runners, visible as side-by-side nodes in the Actions run graph. Verified via dry-run dispatch targeting `exp` channel.
## **Description** Fixes two touch gesture issues with the TradingView chart: 1. **iOS back gesture blocked**: Users couldn't swipe from the left edge to navigate back 2. **Vertical scroll hijacked**: Chart was capturing vertical drag gestures, preventing page scrolling ## Changes ### 1. iOS Edge Overlay (`Price.advanced.tsx`, `Price.styles.tsx`) - Added 15px transparent overlay on left edge (iOS only) with `pointerEvents="box-only"` - Prevents chart from capturing touches at screen edge, preserving native back gesture ### 2. Disabled Vertical Touch Drag (`AdvancedChart.types.ts`) - Added `'vert_touch_drag_scroll'` to TradingView's `DEFAULT_DISABLED_FEATURES` - **Fixes vertical scroll hijacking**: Chart no longer prevents page from scrolling vertically ### 3. Removed Unused Touch Tracking (`Price.advanced.tsx`, `Price.advanced.test.tsx`) - Removed `usePriceChart` context integration, `handleTouchStart/End` callbacks - Removed touch event handlers from chart container (`onTouchStart`, `onTouchEnd`, `onTouchCancel`) - Removed 4 obsolete test cases for touch gesture handling - These were intended for scroll coordination but are no longer needed ## Testing **iOS:** - ✅ Swipe from left edge (0-15px) triggers back navigation - ✅ Chart interactions (pan, zoom, crosshair) work normally - ✅ Vertical scrolling works without chart interference **Android:** - ✅ Chart interactions work normally - ✅ Vertical scrolling works without chart interference ## **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: Fixes chart interactions ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3176 ## **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] --> https://github.com/user-attachments/assets/25a220b1-58c1-4c5d-b9c5-b04ed22f7c62 ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches token details chart UX and parent list scrolling; iOS-only overlay may affect edge interactions. No auth or data-path changes. > > **Overview** > Improves **token overview advanced chart** scroll vs pan behavior by stopping the old pattern that flipped `isChartBeingTouched` on every chart touch (which could lock the transactions **FlatList**). > > **`Price.advanced`** no longer wires `onTouchStart` / `onTouchEnd` / `onTouchCancel` or `usePriceChart`. On **iOS**, a narrow left **`edgeOverlay`** (`pointerEvents="box-only"`) sits over the chart so gestures at the screen edge can reach the parent scroll view. > > **TradingView** defaults now disable **`vert_touch_drag_scroll`** so vertical drags in the WebView favor page scroll instead of chart vertical drag. > > Tests for the removed touch → context behavior are dropped. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 616a79d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
Improves the crypto up/down market experience on the feed series card
and market details screen.
These changes are scoped to the existing crypto up/down work behind the
Predict up/down feature flag. They improve release quality for the
upcoming crypto up/down experience, where the current UX is unstable for
users, with minimal regression risk outside the gated feature.
This PR fixes several visible stability issues:
- Prevents Up/Down CTA prices from briefly flickering to stale fallback
prices while live CLOB price subscriptions remount or warm back up.
- Uses a shared buy-price precedence for CTA labels: live WebSocket
`bestAsk` → REST `entry.buy` → static market token price.
- Keeps the details chart anchored to the currently live market so
selecting a future time slot does not interrupt the BTC price stream.
- Keeps the selected time slot independent from the chart market, so
target price/actions can follow the selected slot while the chart
remains continuous.
- Preserves series data during transient series refetches so position
rows and chart sizing do not jump during time-slot changes.
- Keeps crypto up/down chart loading visible until the live chart has
enough renderable points, avoiding a spinner → blank → chart transition.
- Uses Polymarket event `priceToBeat` metadata as the target-line
fallback for hourly/daily crypto up/down markets whose target price API
can be unavailable.
- Preserves the existing group item threshold fallback for crypto
up/down markets that do not provide event `priceToBeat` metadata.
- Improves crypto up/down chart rendering/loading behavior and bottom
padding across larger chart heights/font scales.
- Improves longer-duration countdown/reset copy for hourly/daily/weekly
crypto up/down markets.
- Keeps crypto up/down card routing behind the Predict up/down feature
flag.
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: null
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: Crypto up/down market experience
Scenario: user views the crypto up/down series card while prices update
Given the Predict up/down feature flag is enabled
And a live crypto up/down market is visible in the Predict feed
When live CLOB price updates are received for the Up and Down tokens
Then the Up and Down CTA prices update from the live buy prices
And the CTA prices do not briefly flicker to stale REST or static market prices
Scenario: user opens crypto up/down market details and changes time slots
Given the user is on a live crypto up/down market details screen
And the market series includes a future time slot
When user selects the future time slot
Then the selected time slot updates
And the chart remains anchored to the live market price stream
And the Up and Down actions use the selected time slot market
And the current price display remains stable while the target price loads
Scenario: user waits for the crypto up/down chart to load
Given the user is on a crypto up/down market details screen
And live chart data has not produced at least two renderable points
When the initial chart request finishes
Then the chart loading state remains visible
And the screen does not briefly show an empty chart area before the live line renders
Scenario: user views hourly or daily crypto up/down target lines
Given an hourly or daily crypto up/down market has Polymarket event price to beat metadata
And the crypto target price API is unavailable
When the market card or market details screen is rendered
Then the target line uses the event price to beat metadata
And the existing group item threshold fallback is still available if event metadata is missing
Scenario: user views longer-duration crypto up/down markets
Given a crypto up/down market has an hourly, daily, or weekly recurrence
When the market card or time slot picker is rendered
Then the countdown and reset copy use readable longer-duration formatting
```
## **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**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches live pricing, chart anchoring, and controller fallbacks across
Predict crypto up/down flows, but scope is largely behind the up/down
feature flag with broad test coverage.
>
> **Overview**
> This PR tightens the **gated** crypto up/down Predict experience (feed
card, details, and routing) so prices, charts, and target lines stay
stable during live updates and time-slot changes.
>
> **Pricing & live data:** Buy CTAs now share `getPredictBuyPrice` (live
`bestAsk` → REST `entry.buy` → token price). `useLiveMarketPrices`
caches recent updates so remounts do not flash stale REST/static prices.
Chart loading stays active until at least two renderable points exist;
current price can still propagate while loading.
>
> **Details screen:** The chart stays on the **live** series market
while the picker only changes the selected slot (target line, Up/Down
actions, share). Series markets are held in a ref during refetch so
positions/chart height do not jump. Target/current summaries use
`resolveCryptoTargetPrice` with skeletons when appropriate; chart bottom
padding scales with height and font scale.
>
> **Target price & Polymarket:** Event `priceToBeat` is parsed onto
markets; `PredictController` and UI fall back through fetched price →
event metadata → `groupItemThreshold`. Hourly recurrence is supported in
duration helpers.
>
> **UX polish:** Longer countdowns use `H:MM:SS` when ≥1 hour; reset
copy uses readable hour/day/week strings. Up/down feed cards require
`selectPredictUpDownEnabledFlag` in addition to `isCryptoUpDown`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
31cc179. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…are (#30622) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Bump for assets-controller with latest fixes for solana and non-evm asset imports already added to extension. No changelog as the flag is not enabled yet and the feature is not fully implemented. ## **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/ASSETS-3270 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [X] I've included tests if applicable - [X] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [X] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Dependency bump (assets-controller 7→8) plus changes to token hide logic and non-EVM import paths that touch AssetsController and MultichainAssetsController; feature-flagged unify state limits exposure but asset state can be wrong if regressions slip in. > > **Overview** > Upgrades **`@metamask/assets-controller`** to **^8.0.1** (and **`@metamask/assets-controllers`** to **^108.1.0**) to pick up Solana / non-EVM fixes already on extension, and wires mobile to match unified assets behavior. > > **Hide / show tokens:** `useAssetVisibility` no longer treats “custom” vs “has balance” as exclusive when hiding. For visible tokens it can call **`removeCustomAsset`** and **`hideAsset`** together so a user-added token that also has a balance entry does not stay visible after hide. > > **Add token search:** With **assets unify** enabled, non-EVM imports still use **`MultichainAssetsController.addAssets`**, but now also register each asset via **`AssetsController.addCustomAsset`** (same pattern as EVM), with tests updated. > > **Engine messenger:** **`getAssetsControllerMessenger`** uses the package **`AssetsControllerMessenger`** action/event types, drops the large local allow-list and unsafe cast, and delegates **`SnapController:snapInstalled`**. Init imports the messenger type from **`@metamask/assets-controller`** instead of the local re-export. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9c6ae62. 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: salimtb <salim.toubal@consensys.net>
## **Description** Updates the Money account legal copy to align with the latest Figma source for MUSD-833. Touches: - Onboarding animation disclaimer footer on all four steps (`step1`–`step4_footer_text`). - "How it works" body copy on both the home preview (`how_it_works.description_*`) and the dedicated How It Works view (`how_it_works_page.description_1`), including the verb change `Deposit → Add`. - "What you get" benefit row — appends `(variable)` next to the APY value, gated by `isPositiveNumber(apy)` so it never renders orphaned. - "Earn on your crypto" tooltip sheet wording (`earn_crypto_info_sheet.body`). - Link MetaMask Card subtitle — adds `(variable)` next to APY in `card.link_subtitle` (bullet `card.link_bullet_apy` intentionally unchanged to match Figma). - `MoneyOnboardingView` wiring: surfaces the new `step3_footer_text` / `step4_footer_text` strings on the onboarding step config. Copy-only and `en.json`-only — non-English locales come from the localization pipeline. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [MUSD-833](https://consensyssoftware.atlassian.net/browse/MUSD-833) ## **Manual testing steps** ```gherkin Feature: Money account legal copy Scenario: User sees the updated disclaimer on each onboarding step Given the Money account onboarding has not been seen When the user advances through the 4 onboarding steps Then step 1 shows "APY is variable and not guaranteed." And step 2 shows "Money account uses Veda infrastructure." And step 3 shows "Includes Steakhouse Financial monitoring." And step 4 shows "Powered by Monad." Scenario: User views the updated How it works copy on Money home Given the user has a Money account with a positive APY When the user opens the Money home view Then the How it works section reads "Add mUSD to your Money account and earn up to {APY}% APY (variable). Your balance is dollar-backed and ready to spend, trade, or send anytime." Scenario: User views the Earn on your crypto tooltip Given the user is on the Money home view When the user taps the Earn on your crypto info icon Then the bottom sheet body reads "Illustration assumes {APY}% Annual Percentage Yield (APY) remains unchanged for one year. APY is variable and is not guaranteed. No guarantee of return." Scenario: User views the dedicated How it works view Given the user is on the Money home view When the user taps into the How it works section Then description_1 reads "Add mUSD into your Money account and earn up to {APY}% APY (variable) automatically. Funds go into a DeFi vault, administered by Veda with risk monitoring by Steakhouse Financial. The rate is generated by third-party DeFi platforms that deploy funds in blockchain protocols. No staking, no claiming, no lock-ups." Scenario: User views the Link MetaMask Card section Given the user has not yet linked a MetaMask Card When the user views the Link MetaMask Card section on Money home Then the subtitle includes "up to {APY}% APY (variable) on your balance" And the "Earn up to {APY}% APY" bullet stays unchanged (matches Figma) ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. [MUSD-833]: https://consensyssoftware.atlassian.net/browse/MUSD-833?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Copy and conditional text rendering only; no changes to balances, vault logic, or authentication. > > **Overview** > Updates **Money account** user-facing legal and marketing copy in **`en.json`** (MUSD-833): onboarding step footers on all four steps, **How it works** home and full-page text (**Deposit → Add**, Veda/Steakhouse/DeFi disclaimers), **Earn on your crypto** tooltip, and **Link MetaMask Card** subtitle with **(variable)** next to APY. > > **UI behavior** changes alongside copy: **`MoneyOnboardingView`** shows new **`step3_footer_text`** / **`step4_footer_text`**; **`MoneyHowItWorks`** only shows the highlighted APY block when APY is a **positive** number (not zero/loading/missing), otherwise **`description_no_apy`**; **`MoneyWhatYouGet`** appends **(variable)** next to the APY label only when **`isPositiveNumber(apy)`** so it is not orphaned. > > Tests are updated to match the new strings and APY display rules. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a257c53. 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: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Co-authored-by: Shane T <shane.odlum@consensys.net>
…ask/perps-controller (#30507) ## **Description** The perps controller source of truth moved to the core monorepo as `@metamask/perps-controller` ([core PR #8871](MetaMask/core#8871)). This PR removes the in-tree copy and switches mobile to consume the published npm package. Changes: - Delete `app/controllers/perps/` — all source, tests, types, utils (~82k lines) - Remove local aliases from `tsconfig.json`, `babel.config.js`, `metro.config.js` - Add `@metamask/perps-controller@^6.3.0` to `package.json` - Add `tsconfig` path mappings for subpath imports (`constants/*`, `types`, `utils/*`) — needed until mobile moves to `Node16` module resolution - Stub `MYXProvider` in Metro resolver — the provider is excluded from the published dist (extension-only); babel's `dynamicImportToRequire` rewrites the dynamic `import()` to `require()`, causing Metro to resolve it statically - Widen cronjob slice storage type to `Record<string, unknown>` — breaks a `TS2589` deep-recursion cycle between `@metamask/snaps-controllers`' `Json` types and reduxjs-toolkit's `WritableDraft` mapper when the published perps-controller types are in scope ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: TAT-3187 ## **Manual testing steps** ```gherkin Feature: Perps trading after controller migration Scenario: app boots and perps screens render Given mobile depends on @metamask/perps-controller@^6.3.0 from npm When the user opens the Perps tab Then markets, positions, orders, and account state render without errors Scenario: place a trade end-to-end Given the user is on testnet with a funded account When the user opens a market position on BTC Then the order submits and the position appears in the positions list ``` ## **Screenshots/Recordings** ### **Before** N/A — refactor with no visual surface change. ### **After** N/A — refactor with no visual surface change. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). #### Performance checks (if applicable) - [ ] I've tested on Android - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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 lint/import policy and removes generated controller action types tied to perps trading; runtime behavior depends on the full npm migration elsewhere in the PR. > > **Overview** > Removes **in-tree Perps controller lint and import fences** now that mobile consumes **`@metamask/perps-controller`** from npm instead of `app/controllers/perps/`. > > **ESLint (`.eslintrc.js`):** Drops the Core-alignment override that targeted `app/controllers/perps/**` and perps `*-method-action-types` (keeps the generic `app/**/*-method-action-types*` rule). Removes the perps test `no-duplicate-imports` exception and all **`no-restricted-imports`** patterns that blocked relative imports into `**/controllers/perps/**`, plus perps exclusions from the default import-fence override. > > **Deleted file:** Removes the auto-generated **`PerpsController-method-action-types.ts`** (~1k lines) from the repo; messenger action types for `PerpsController` now come from the published package (aligned with the broader PR that deletes `app/controllers/perps/` and wires Engine/UI to `@metamask/perps-controller@^6.3.0`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d23cd7b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Reverts the architecture-narrowing changes from #30590 and #30642 that were rushed in to silence Google Play's 16 KB page-size warning for `base/lib/x86_64/libconceal.so` and `base/lib/x86_64/libsecp256k1.so`. Google Play **extended their compliance deadline**, so we have time to fix the underlying 4 KB alignment issue properly instead of shipping fewer ABIs as a workaround. The structural fixes are tracked separately: - #30591 — replace `react-native-fast-crypto` with `react-native-quick-crypto` scrypt (drops `libsecp256k1.so`). - #30592 — drop the Facebook Conceal dependency from `react-native-keychain` (drops `libconceal.so`). Once those land, both `.so` files disappear for **every** ABI (including arm64-v8a), which is the real fix Play actually cares about. ### What this PR restores | File | After this PR (= pre-#30590 state) | |---|---| | `android/gradle.properties.release` | `reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64` | | `android/app/build.gradle` | `reactNativeArchitectures()` back to its original one-liner; `ndk.abiFilters(*reactNativeArchitectures())` block removed from `defaultConfig` | ### Why revert rather than keep `abiFilters` for safety? The `abiFilters` plumbing isn't harmful when paired with all four ABIs (it would just resolve to all four), but keeping it adds non-obvious build behavior tied to a workaround we're abandoning. Cleaner to fully revert and re-introduce when (if) we narrow ABIs again as a deliberate decision. ### Untouched (already untouched by the original PRs) - `android/gradle.properties` (default, local dev) - `android/gradle.properties.github` (CI E2E) - `android/gradle.properties.github.dual-versions` (BrowserStack real-device runs) - `scripts/build.sh` `-PreactNativeArchitectures=...` CLI overrides ## **Changelog** CHANGELOG entry: null ## **Related issues** Reverts: #30590, #30642 Tracking the proper fixes: #30591, #30592 ## **Manual testing steps** ```gherkin Feature: Production AAB ships all four ABIs again Scenario: A production release build is generated Given a clean checkout of this branch When the production AAB is built via the standard release workflow (cp android/gradle.properties.release android/gradle.properties before ./gradlew bundleProdRelease) Then `unzip -l app-prod-release.aab | grep '/lib/'` shows `lib/arm64-v8a/`, `lib/armeabi-v7a/`, `lib/x86/`, and `lib/x86_64/` entries Scenario: Local dev unchanged Given default android/gradle.properties (unchanged) When `yarn android` is run on an x86_64 emulator Then app installs and runs as before Scenario: CI E2E unchanged Given android/gradle.properties.github overlay When E2E build runs Then x86_64 APK is produced and Detox tests pass ``` ## **Screenshots/Recordings** ### **Before** Production AAB ships only `armeabi-v7a` + `arm64-v8a`. Play 16 KB warning cleared (workaround), but the underlying 4 KB-aligned `.so` files still ship for arm64-v8a. ### **After** Production AAB ships all four ABIs again, restoring full device coverage (including Chromebook ARC++ on x86_64). Play 16 KB warning returns for x86_64, but the warning is informational under the extended deadline and the structural fixes (#30591, #30592) are the real path forward. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable — N/A (build-config revert; verification is via the `unzip -l` check on the produced AAB) - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable — N/A - [ ] I've applied the right labels on the PR — `team-mobile-platform` #### Performance checks (if applicable) - [x] I've tested on Android — restores the pre-#30590 known-good behavior used in production for the prior release. - [ ] I've tested with a power user scenario — N/A (no JS behavior change) - [ ] I've instrumented key operations with Sentry traces — N/A ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes only release packaging/architecture selection but increases shipped native surface (x86/x86_64) and may re-expose Play 16 KB alignment warnings until dependency fixes land. > > **Overview** > Reverts the Play Store **16 KB page-size workaround** that limited production native builds to ARM only. **Release** `gradle.properties.release` again sets `reactNativeArchitectures` to all four ABIs (`armeabi-v7a`, `arm64-v8a`, `x86`, `x86_64`), so production AABs regain x86/x86_64 coverage (e.g. Chromebooks). > > In `app/build.gradle`, the **`ndk.abiFilters(*reactNativeArchitectures())`** block is removed from `defaultConfig`, so packaging no longer forces ABI filtering at the NDK layer. `reactNativeArchitectures()` is collapsed back to a single ternary that reads the property or falls back to the four default ABIs. > > **Trade-off:** Google Play’s x86_64 16 KB alignment warning may return until follow-up work replaces misaligned third-party `.so` files; that is intentional per the extended compliance timeline. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 61f5095. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )