Skip to content

[pull] main from MetaMask:main#838

Merged
pull[bot] merged 23 commits into
Reality2byte:mainfrom
MetaMask:main
Jun 16, 2026
Merged

[pull] main from MetaMask:main#838
pull[bot] merged 23 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Jun 16, 2026

Copy link
Copy Markdown

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 : )

Matt561 and others added 23 commits June 16, 2026 11:40
…PI (#31724)

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**
Updated `MoneyOnboardingView` to use latest Rive animation and API
syntax.
<!-- mms-check: type=text required=true -->

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

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
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 MoneyOnboardingView to use latest Rive
animation and API syntax

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: [MUSD-996: Update MoneyOnboardingView to use latest Rive
animation and
API](https://consensyssoftware.atlassian.net/browse/MUSD-996)

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Updated Rive Money Onboarding Flow

  Scenario: user can access latest onboarding flow
    Given user has not already seen the onboarding flow

    When user clicks the Money balance card on Wallet home **or** the Money navbar button
    Then latest Money onboarding flow is rendered

  Scenario: user can navigate forward using the continue button
    Given user has not already seen the onboarding flow

    When user taps the continue button
    Then user moves forward to the next onboarding step

  Scenario: user can navigate backwards and forwards through the onboarding flow
    Given user has not already seen the onboarding flow

    When user taps the left (forward) or right (backward) edge of the screen
    Then onboarding flow navigates in the correct direction

  Scenario: user can exit out of the onboarding flow
    Given user has not already seen the onboarding flow

    When user taps the close "X" button
    Then user is redirected to Money Home
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

<!-- [screenshots/recordings] -->
N/A - Old Rive animation file
### **After**

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


https://github.com/user-attachments/assets/c9e507bc-c10b-4ba3-9355-90d71baff3f1

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

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

Do not mark it as "Ready for review" until 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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

The snap management tests (disable, enable, remove) were failing at
times in the pipeline because `tapSettings()` has a nested retry loop
that fights itself under `disableSynchronization: true`— once the
account menu overlay opens, the tab bar is hidden, and retries can never
recover.
                                                           
Replaced with a step-by-step navigation helper that uses explicit waits
between each tap.

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

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes:

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

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

<!-- mms-check: type=screenshot required=true -->

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

<!-- mms-check: type=checklist required=true -->

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

- [ ] 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.
… prices cp-7.82.0 (#31801)

## **Description**

This PR fixes severe JS-thread performance degradation on the Predict
market details screen (`PredictMarketDetails` /
`PredictGameDetailsContent`). When opening a market with a live price
feed — most noticeably a live soccer game — the JS thread FPS would
collapse to near 0, making the screen unusable.

**Reason for the change:** The live Polymarket WebSocket price stream
drives high-frequency updates. The code was (1) doing an
`O(subscriptions × tokens)` `new Set(key.split(','))` allocation on
*every* incoming price message, and (2) re-rendering the entire details
screen on every single message because nothing was throttled or
memoized. Profiling showed `performWorkOnRoot` (React render) consuming
~70% of the trace, with `new Set()`/`Object.assign`/`JSON.stringify`
allocation churn dominating self-time.

**Improvements:**

- **`WebSocketManager`**
- Precompute the parsed `Set<tokenId>` per subscription once at
subscribe time instead of rebuilding it (`new Set(key.split(','))`) on
every message. This removes the single largest self-time hotspot.
- Coalesce/throttle price emission with a leading + trailing edge
(250ms, mirroring the existing orderbook throttle) so subscribers are
notified at most ~4×/sec instead of at the full WebSocket message rate.
- Clean up the new timer/buffer/Set state on disconnect and full
cleanup.
- **`useLiveMarketPrices`** — skip the state update entirely when an
incoming tick carries no actual value change
(`price`/`bestBid`/`bestAsk`), preventing redundant re-renders.
- **`usePredictPrices`** — memoize the per-render
`JSON.stringify(queries)` so it only runs when the queries change.
- **`useOpenOutcomes`**
- Disable the live price subscription for game markets, where its result
is never rendered (the game branch runs its own subscriptions). Removed
a redundant full-screen re-render source.
- Preserve object identity for outcomes/tokens whose computed price did
not change, so only rows that actually changed get a new reference.
- **`PredictMarketDetails`** — memoize
`handleBackPress`/`handleBuyPress`/`handleClaimPress` so stable
callbacks no longer defeat child memoization.
- **`PredictGameDetailsContent`** and **`PredictMarketOutcome`** — wrap
in `React.memo` so a parent re-render no longer re-renders these
subtrees/rows when their props are unchanged.

**Result:** JS-thread FPS went from ~0 → mid-50s on live game events,
and regular markets from ~25–35 → comparable smoothness, with re-renders
now scoped to the components whose data actually changed.

## **Changelog**

CHANGELOG entry: Fixed severe performance degradation on the Predict
market details screen for markets with live price updates.

## **Related issues**

Fixes:
[PRED-1014](https://consensyssoftware.atlassian.net/browse/PRED-1014)

## **Manual testing steps**

```gherkin
Feature: Predict market details performance with live prices

  Scenario: user opens a live game market
    Given a live soccer game market is available in Predict
    And the JS-thread FPS monitor / performance overlay is enabled
    When the user opens the PredictGameDetailsContent screen
    Then the screen remains responsive
    And the JS-thread FPS stays in a healthy range (not collapsing toward 0)

  Scenario: user opens a regular market with live prices
    Given a regular open market with live price updates is available in Predict
    When the user opens the PredictMarketDetails screen
    Then the outcomes list updates live without re-rendering unchanged rows
    And the JS-thread FPS stays in a healthy range

  Scenario: live prices still update correctly
    Given the user is on a market details screen
    When the underlying token prices change over the WebSocket feed
    Then the displayed prices/odds update to reflect the new values
```

## **Screenshots/Recordings**

### **Before**

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


https://github.com/user-attachments/assets/1cc444f5-a693-4584-80f8-072305a3147c



### **After**

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


https://github.com/user-attachments/assets/1fe95b3c-1fb4-4fa0-a794-8450cbe08f88


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

- [ ] 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-1014]:
https://consensyssoftware.atlassian.net/browse/PRED-1014?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
…cy regions (#31763)

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

Cardholders whose residency falls in a geo-restricted region must not be
able to link their Money Account to the MetaMask Card. Previously the
linkage flow had no residency gating, so users in blocked
countries/states could attempt (and surface UI for) Money Account card
linkage.

This PR adds residency-based blocking for Money Account ↔ card linkage:

- **Residency capture**: `BaanxProvider` now maps `countryOfResidence`
and `usState` from the `/v1/user` KYC payload onto `CardAccountStatus`
(normalized to uppercase), and these fields are added to the
`CardAccountStatus` type.
- **Residency utils** (`app/components/UI/Card/util/residency.ts`):
`buildCardResidencyRegion` derives a region code, using the `US-{STATE}`
pattern (e.g. `US-CA`) for US residents so blocked lists can target
specific states. `isCardResidencyInBlockedRegions` matches a region
against a blocked list and **fails open** when residency is unknown.
- **Selectors** (`app/selectors/cardController.ts`): adds
`selectCardCountryOfResidence`, `selectCardUsState`,
`selectCardResidencyRegion`, and `selectIsCardResidencyBlocked`, reusing
the existing mUSD conversion blocked-region flag
(`selectMusdConversionBlockedCountries`). `selectCardAvailableTokens`
now suppresses Money Account placeholder funding entries when residency
is blocked (active funding rows are preserved).
- **Linkage hook** (`useMoneyAccountCardLinkage`): exposes
`isResidencyBlocked`, forces `canLink=false`, and fails closed across
`openLinkCardSheet`, `startLinkFlow`, the post-auth pending-link effect,
and `confirmLinkInBackground`. Each blocked path tracks
`CARD_MONEY_ACCOUNT_LINKING_FAILED` with the new `RESIDENCY_BLOCKED`
reason.
- **UI**: `MoneyHomeView` hides the card section (link/upsell) when
residency is blocked while still showing `manage` mode for
already-linked cards. `MoneyOnboardingCard` auto-completes/skips the
card step when residency is blocked and the card is not already linked.

## **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: Blocked Money Account to MetaMask Card linkage for
cardholders in geo-restricted residency regions.

## **Related issues**

Fixes: CARD-413

## **Manual testing steps**

```gherkin
Feature: Money Account card linkage residency blocking

  Scenario: Cardholder in a blocked region cannot link their Money Account
    Given a cardholder whose KYC residency is in a blocked region (e.g. country "GB" or state "US-CA")
    And the blocked region is present in the mUSD conversion blocked-region list
    When the user opens the Money home screen
    Then the MetaMask Card link/upsell section is hidden
    And the Money Account funding placeholder is not shown in the card funding list

  Scenario: Blocked cardholder attempting to link fails closed
    Given a cardholder whose residency is blocked
    When the user triggers the link card flow
    Then no navigation or delegation occurs
    And an error toast is shown
    And a CARD_MONEY_ACCOUNT_LINKING_FAILED event is tracked with reason "RESIDENCY_BLOCKED"

  Scenario: Already-linked card remains manageable in a blocked region
    Given a cardholder whose residency is blocked
    And the card is already linked to the Money Account
    When the user opens the Money home screen
    Then the card section is shown in "manage" mode

  Scenario: Cardholder in an allowed region can link normally
    Given a cardholder whose residency is not in any blocked region
    When the user opens the Money home screen and starts the link flow
    Then the link flow proceeds as before
```

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

#### 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`.
-->

- [ ] 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 -->
)

## **Description**

<!-- mms-check: type=text required=true -->

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

The Money balance card on the wallet home screen used to alternate its
CTA between **Earn** (when the money-account balance was 0) and **Add**
(when funded). Because the balance is resolved asynchronously from cache
on startup, the button visibly flipped from "Earn" to "Add" as the
cached balance loaded.

Per the accepted solution in MUSD-987, this collapses the CTA to a
single, stable **Add** button regardless of balance state.
`buttonLabelKey`/`buttonTestId` are now constants and the state branches
only decide the button variant and container testID
(error/unavailable/empty/new-user/funded are unchanged). Dead code left
behind by the change is removed: the `EARN_BUTTON` testID and the
unreferenced `homepage.sections.money_empty_state` /
`money_filled_state` locale blocks (`en.json` only — other locales flow
from the localization pipeline).

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

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

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

CHANGELOG entry: Fixed the Money balance card CTA flipping from "Earn"
to "Add" on startup by always showing a single "Add" button.

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-987

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Money balance card CTA

  Scenario: user with no money balance opens the wallet home
    Given the user has a money account with a 0 balance
    When the wallet home screen loads
    Then the Money balance card shows a single "Add" button
    And the button does not change from "Earn" to "Add" as the balance resolves

  Scenario: user with a money balance opens the wallet home
    Given the user has a money account with a balance greater than 0
    When the wallet home screen loads
    Then the Money balance card shows the "Add" button
    And pressing it starts the deposit flow
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

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

The CTA rendered "Earn" for a 0 balance and flipped to "Add" once the
cached balance resolved (see attached recording on MUSD-987).

### **After**

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

<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/2a9ee5c3-18f0-4ecd-a90d-566fd50a09cd"
/>


The CTA always renders "Add".

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
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.
…oney pages (MUSD-968) (#31735)

## **Description**

Balances, the percentage/APY value, and the primary action button row
sat at different vertical positions on the **Home** page and the **Money
account** page, producing a visible layout shift ("jumping") when
navigating between the two screens.

This aligns the Money account page's content rhythm to the Home page
(Home left untouched as the source of truth):

- `MoneyBalanceSummary`: normalized the top offset and tightened the
balance→APY gap to match Home's balance block.
- `MoneyActionButtonRow`: content-size the action buttons by removing
the `ButtonBase` `min-height`/`h-full`/stretch hack, so **Add / Send /
Card** share the same height and top position as Home's **Buy / Swap /
Send / Receive** buttons.

The balance, APY/percentage value, and action-button row now hold their
vertical position across both screens.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

CHANGELOG entry: Fixed inconsistent vertical alignment of the balance,
APY/percentage, and action buttons between the Home and Money account
pages.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-968

## **Manual testing steps**

```gherkin
Feature: Consistent alignment between Home and Money account pages

  Scenario: Balance, APY and action buttons stay in place when switching pages
    Given I am on the Home page
    And I note the vertical position of the balance, the percentage value, and the action button row

    When I navigate to the Money account page
    Then the balance, the APY value, and the action button row are at the same vertical positions
    And the action buttons are the same height as on the Home page
    And there is no visible vertical jump when switching between the pages
```

## **Screenshots/Recordings**

### **Before**

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

### **After**

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



https://github.com/user-attachments/assets/8cec1f1e-21c2-4701-a833-ec6cfec5f783



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

- [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.
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**


This PR integrates the Extension Activity adapter prototype into Mobile
using a temporary vendored implementation, while preparing the code for
a future shared `@metamask/activity-adapters` package.
The change normalizes Mobile activity data sources into a common
`ActivityListItem` shape:

- Accounts API EVM transactions are mapped with `mapApiEvmTransactions`
- Local EVM transactions are mapped with `mapLocalTransaction`
- Non-EVM keyring transactions are mapped with `mapKeyringTransaction`

Mobile then renders normalized activity rows with `ActivityListItemRow`,
while preserving Mobile-specific behavior such as Figma-specific row
copy/styling, legacy transaction-details navigation, pending local EVM
speed up/cancel handling, account/network filtering, token-poisoning
protection, and bridge/token enrichment.

A key part of this PR is the `ActivityAdapterEnvironment` boundary.
Adapter internals no longer directly depend on hidden Mobile/Extension
shims for host-specific utilities. Instead, dependencies such as
`toAssetId`, native asset lookup, token metadata, calldata parsing,
wrapped-token configuration, status constants, and ERC-20 transfer log
topics are passed through an explicit environment object. This makes the
current vendored implementation closer to the shape needed for
externalization.

This PR also includes the scaffold for the redesigned Activity screen
from TMCU-854. The redesigned screen is fully gated behind the remote
feature flag `tmcuActivityRedesignEnabled`, which defaults to `false` in
E2E feature-flag mocks. When the flag is disabled, `ActivityView`
renders the existing legacy Activity implementation. When the flag is
explicitly enabled, `ActivityView` lazy-loads and renders the new
`ActivityScreen`.
The feature-flag boundary was hardened so that only
`tmcuActivityRedesignEnabled === true` enables the redesigned screen.
The redesigned screen is lazy-loaded, so its component tree and
dependencies are not evaluated on the flag-off path.

To preserve existing Activity E2E behavior while the flag is off, the
adapter-backed legacy Activity path keeps the existing row test
contract:

- Activity rows expose `transaction-item-${index}`
- Activity statuses expose `transaction-status-${index}`
- Swap and bridge rows use the richer legacy Activity titles where
bridge history is available, e.g. `Swap ETH to
- USDC` and `Bridge to Optimism`

Follow-up externalization work should move `app/util/activity-adapters`
into a shared package, keep `ActivityAdapterEnvironment` as the host
dependency contract, provide Mobile and Extension environment
implementations, move parity fixtures into the package test suite, and
replace Mobile vendored imports with package imports once published.

Follow-up redesign work should keep new Activity UI/data wiring scoped
under `app/components/Views/ActivityScreen/**` or redesign-only hooks
until the feature flag is intentionally enabled for rollout.



## **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:
Refs:
- https://consensyssoftware.atlassian.net/browse/TMCU-797
- https://consensyssoftware.atlassian.net/browse/TMCU-854

## **Manual testing steps**

```gherkin
Feature: Activity adapters and Activity redesign feature flag isolation
  Scenario: legacy Activity remains active when redesign flag is disabled
    Given tmcuActivityRedesignEnabled is disabled or missing
    When the user opens the Activity tab
    Then the legacy Activity view is rendered
    And existing transaction rows expose transaction-item-* test IDs
    And existing transaction statuses expose transaction-status-* test IDs
  Scenario: redesigned Activity screen renders when redesign flag is enabled
    Given tmcuActivityRedesignEnabled is true
    When the user opens the Activity tab
    Then the redesigned Activity screen is rendered
    And the legacy Activity transaction tab UI is not rendered
  Scenario: adapter-backed Activity rows preserve legacy swap and bridge titles
    Given the user has swap or bridge activity with bridge history available
    When the user opens the Activity tab with tmcuActivityRedesignEnabled disabled
    Then swap rows show the rich swap title
    And bridge rows show the rich bridge destination title
```

## **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**
> Touches transaction list merging, deduplication, and
navigation/speed-up-cancel flows where regressions could hide or
mislabel activity; mitigated by heavy test coverage and flag-gated
redesign entry (per PR description).
> 
> **Overview**
> Introduces a **unified Activity stack** on top of shared
`ActivityListItem` adapters: **`ActivityList`** merges paginated
Accounts API EVM history, enriched local EVM txs, and non-EVM keyring
activity (chain enablement, hash/nonce dedup, malicious-token filtering,
bridge rows), then renders most rows via new **`ActivityListItemRow`**
(localized titles/statuses, token + fiat amounts, network badge, legacy
swap/bridge title overrides). Pending locals still use
**`TransactionElement`**; non-EVM bridges use
**`MultichainBridgeTransactionListItem`**, with
**`useUnifiedTxActions`** for speed-up/cancel (incl. Ledger/QR).
> 
> Adds **`ActivityScreen`** scaffold (animated header, search
placeholder, type/network filter chips + sheets,
**`ActivityEmptyState`** CTAs) wired to **`ActivityList`**, plus
supporting hooks (`useTransactionsQuery`, `useLocalActivityItems`,
`useTransactionAutoScroll`) and API **`normalizeTransaction`** /
transformation helpers, with broad unit tests.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7510782. 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: vinnyhoward <vincenguyenhoward@gmail.com>
Co-authored-by: Ramon Acitores <ramon.acitores@consensys.net>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Ramon AC <36987446+racitores@users.noreply.github.com>
## **Description**

<!-- mms-check: type=text required=true -->

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

Addresses the design-review polishes for the Money account screens
(MUSD-993):

1. **Add funds sheet** — renamed the fiat row to **Debit card or Apple
Pay** (Card icon) and added a coming-soon **Bank account** row, matching
the design. The Debit card or Apple Pay row is always active and opens
the MM Pay deposit flow.
2. **APY tooltip** — updated the variability copy (Veda / Steakhouse
Financial) and added "Money account is powered by Monad."
3. **How it works FAQ** — the supported no-fee deposit tokens are now
derived from the `earnMoneyDepositNoFeeTokens` remote flag (with a
bundled per-chain fallback so the list is never empty) instead of a
hard-coded list. Chain ids resolve to friendly network names; mUSD shows
in the per-chain "which tokens can I deposit" list but is excluded from
the inline "converts to mUSD" sentence.
4. **Yield FAQ** — appended the APY-variability / Veda–Steakhouse
disclaimer.
5. **Deposit FAQ** — limited the funding-methods sentence to "debit
card, credit card, or Apple Pay".
6. **Money home layout** — the "Add funds" CTA now renders once at the
bottom (previously a misplaced mid-list instance in the empty state),
and a divider separates every content section.
7. **What you get** — "Send" instead of "Transfer".

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
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: Polished the Money account screens — refreshed the Add
funds payment options, APY and FAQ copy, made the supported-token list
dynamic, and fixed the home layout spacing and Add funds button
placement.

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-993

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Money account design review polishes

  Scenario: Add funds sheet payment options
    Given I am on the Money account home screen
    When I tap "Add"
    Then I see "Convert crypto", "Debit card or Apple Pay", the mUSD amount, "Bank account" (Coming soon) and "External address" (Coming soon)
    And tapping "Debit card or Apple Pay" opens the MM Pay deposit flow

  Scenario: How it works FAQ tokens are dynamic
    Given I open the "How it works" page
    When I expand "Which tokens can I deposit into the Money Account?"
    Then the per-chain token list reflects the no-fee remote config with friendly network names

  Scenario: Money home layout
    Given I am on the Money account home screen
    Then the "Add funds" button appears once at the bottom
    And each content section is separated by a divider
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

<!-- 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/663f7d86-1858-4384-809c-1bae4111f24e

<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/0de9e1c5-e634-472f-b028-86528978168a"
/>
<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/cf27a558-6400-48e1-aa09-6fc6f07fdcc8"
/>
<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/68b26e87-bc8a-4c78-b599-77da2c0f4116"
/>
<img width="1206" height="2622" alt="image"
src="https://github.com/user-attachments/assets/f0c492ac-9ab7-4263-afe7-38d3cd81c737"
/>

_Screenshots to be attached during review — UI polish; reference designs
are in the Figma links on the MUSD-993 ticket._

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

Unifies PnL abbreviation across the three Social Leaderboard surfaces
(homepage carousel, leaderboard list, trader profile headline) so the
same value renders identically everywhere. The trader profile's 30D
Return previously showed
un-abbreviated values (e.g. `+$117,166.82`); the leaderboard rows used a
K-only formatter that produced `+$1,200K` for million-dollar values. Now
all three use one shared formatter:

- **Sub-$1K** renders the actual value with 2 decimal places (e.g.
`+$500.24`, `+$0.50`)
- **≥$1K** abbreviates with K/M/B/T tier suffixes and 1 decimal trimmed
(e.g. `+$5.1K`, `+$117.2K`, `+$1.2M`, `+$1M`)
  - Zero renders as `$0.00` with no sign
- Tier-boundary rounding promotes correctly: `999_999` → `+$1M` (not
`+$1000K`)

  **What changed**

- New `formatSignedAbbreviatedUsd` in
`SocialLeaderboard/utils/formatters.ts` is the single source of truth.
Co-located helpers (`shortenAbsCurrency`, `renderBucket`,
`CURRENCY_BUCKETS`) live in the same file.
- `StatsRow` (profile 30D Return) drops its local `formatPnlWithCents` +
`formatWithThreshold` import in favor of the shared formatter.
- `TopTraderCard` + `TraderRow` (homepage carousel and leaderboard list)
import the shared formatter directly via the existing cross-route
`eslint-disable` pattern.
- The thin `formatPnl` wrapper in
`Homepage/Sections/TopTraders/utils/formatPnl.ts` and its test file are
deleted. Two consumers updated.
- Tests in `formatters.test.ts`, `StatsRow.test.tsx`,
`TraderProfileView.test.tsx`, `TopTraderCard.test.tsx`, and
`TraderRow.test.tsx` updated to assert the new format.

  **Visible behavior changes**

- Trader profile 30D Return: `+$117,166.82` → `+$117.2K`. The PM-driven
request that started this work.
- Homepage carousel + leaderboard list PnL: rows over `$1M` now
correctly promote to M (`+$1.2M`) instead of staying in K (`+$1,200K`).
Sub-$1M rows gain one decimal of precision (`+$963K` → `+$963.1K`).
- Zero PnL: no longer shows a `+` sign (was `+$0` in old `formatPnl`,
now `$0.00`). Consistent with how the profile view renders zero.

  ## **Changelog**

CHANGELOG entry: Unified the PnL number formatting on the social
leaderboard so the same value renders the same way everywhere (trader
profile, leaderboard list, homepage carousel). Large values now
abbreviate to K/M/B/T with one decimal
  (e.g. $1.2M); sub-$1K values keep two decimal places.

  ## **Related issues**

Refs: N/A — surfaced during TSA-628 / social leaderboard polish work.
PM-driven request: trader profile 30D Return needed to abbreviate
($1.2M) for parity with the rest of the surfaces. Filing as a follow-up
to the perps rollout work.

  ## **Manual testing steps**

  ```gherkin
  Feature: Unified PnL abbreviation across the social leaderboard

Scenario: Trader profile 30D Return shows abbreviated value for large
numbers
Given the user opens a trader profile whose 30D return is $1,170,000
Then the headline reads "+$1.2M" (not "+$1,170,000.00" or "+$1,170K")

Scenario: Leaderboard list row abbreviates million-dollar PnL correctly
      Given a leaderboard trader with $1,200,000 PnL
      When the leaderboard list renders
      Then the row reads "+$1.2M" (not "+$1,200K")

Scenario: Homepage Top Traders carousel matches the leaderboard format
      Given the same trader appears in the homepage Top Traders carousel
Then the carousel card renders the same "+$1.2M" string as the
leaderboard list

    Scenario: Sub-$1K values keep two decimal places
      Given a trader profile with a 30D return of $500.236
      Then the headline reads "+$500.24" (not "+$500" or "+$500K")

    Scenario: Zero PnL renders neutrally with no sign
      Given a trader profile with a 30D return of exactly $0
      Then the headline reads "$0.00" (no leading + or -)
  ```

  ## **Screenshots/Recordings**

  ### **Before**
<img width="450" height="973" alt="Screenshot 2026-06-15 at 10 14 43 PM"
src="https://github.com/user-attachments/assets/eb6dbf7a-f688-4749-b6c2-08c2bf2e445b"
/>
<img width="446" height="973" alt="Screenshot 2026-06-15 at 10 14 33 PM"
src="https://github.com/user-attachments/assets/0be54128-0bd2-443c-8b12-25bf416be40b"
/>


  ### **After**
<img width="446" height="973" alt="Screenshot 2026-06-15 at 10 12 41 PM"
src="https://github.com/user-attachments/assets/ecb18b8c-f45b-4ac5-ac2f-f7aa4d2245e7"
/>
<img width="446" height="973" alt="Screenshot 2026-06-15 at 10 12 27 PM"
src="https://github.com/user-attachments/assets/fd50cbfe-04e4-4f59-8d6f-bb42996e2a79"
/>


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

- [ ] 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.
## **Description**

<!-- mms-check: type=text required=true -->

Bringing the following changes to the client:

```markdown
## [1.26.0]

### Added

- Add `signProofOfOwnership` client request method ([#327](MetaMask/snap-tron-wallet#327))
  - This method silently signs `metamask:proof-of-ownership:<nonce>:<address>` messages with the account's secp256k1 key via TronWeb's `signMessageV2`
- Add support for `keyring_createAccounts` method to enable batch account creation ([#308](MetaMask/snap-tron-wallet#308)).
```

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

CHANGELOG entry: null

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

n/a

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

n/a

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

<!-- mms-check: type=checklist required=true -->

<!--
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.
…1803)

## **Description**

Migrates `import-srp` and `delete-account` from Detox
(`SmokeWalletPlatform`) to Appium (`SmokeAccounts`) as part of the
ongoing smoke-test framework migration.

Changes include:
- New Appium specs under `tests/smoke-appium/accounts/`
- Removal of the Detox counterparts from `tests/smoke/wallet/` and
`tests/smoke/multichain-accounts/`
- Cross-framework fixes in `ImportSrpView` (replaces
`device.getPlatform()` with `PlatformDetector`, adds Appium iOS
seed-phrase input handling)
- New `iosAppiumXPath` selector variant in `resolve()` for
platform-specific iOS locators

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: Detox-to-Appium SmokeAccounts migration — test infrastructure only

## **Manual testing steps**

```gherkin
Feature: SmokeAccounts Appium account flows

  Scenario: import SRP account on Android
    Given a device with the Appium smoke test runner
    When I run the import-srp Appium spec on Android
    Then the test imports an SRP and verifies Account 1 is selected

  Scenario: delete account on iOS
    Given a device with the Appium smoke test runner
    When I run the delete-account Appium spec on iOS
    Then the test deletes the imported account and verifies it is removed from the account list
```

## **Screenshots/Recordings**

### **Before**

N/A — E2E test migration only; no user-facing UI changes.

### **After**

N/A — E2E test migration only; no user-facing UI changes.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Style](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/coding-style.md)
- [x] I've completed the PR template and read the [Ready for
review](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/ready-for-review.md)
guide
- [x] I've included tests if applicable and/or updated snapshots
- [x] I've documented my code with [JSDoc](https://jsdoc.app/) if
applicable
- [x] I've applied the right labels for this PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md))

#### Performance checks (if applicable)

- [x] I tested on an Android device or emulator and timing performance
was acceptable
- [x] I tested this change with the `power user` performance scenario
and timing performance was acceptable
- [x] I instrumented this change with Sentry traces if applicable

## **Pre-merge reviewer checklist**

- [ ] I've followed the [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Style](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/coding-style.md)
- [ ] I've read the [How to review a MetaMask Mobile
PR](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/reviewing.md)
guide
- [ ] I've checked what automated tests report, and I've considered
whether this change should have caused any failures to resolve
differently
- [ ] I've manually tested the change, following the manual testing
steps in the pull request description, and that what's being tested
reflects the user's perspective, not the presence of the change itself
- [ ] I've checked that any documentation linked from this PR, or that I
expect to update from this change, is accurate and up to date

Made with [Cursor](https://cursor.com)
## **Description**

The price change percentage shown on the Token Details page frequently
diverges from the Trending page percentage, sometimes dramatically. This
PR addresses the client-side root causes.

### Fix 1 — Defensive sort for historical prices
(`useTokenHistoricalPrices.ts`)

The historical-prices API occasionally returns data in reverse
chronological order (newest-first). Since the client uses `prices[0]` as
the 24h-ago baseline, reverse-sorted data makes the baseline equal the
*current* price, yielding 0% or near-0% change. A defensive sort ensures
`prices[0]` is always the oldest entry.

### Fix 2 — Use spot-prices percentage for legacy chart instead of
deriving from historical prices (`useTokenPrice.ts`,
`exchange-rates.ts`)

The legacy chart derived its percentage from `currentPrice -
historicalPrices[0]`. For newly-listed or volatile tokens, the
`historical-prices` API can return incomplete data (e.g. only 10 hours
of data when 24 hours is requested), causing inaccurate percentages.

The spot-prices API (`v3/spot-prices`) already returns pre-computed
percentage changes (`pricePercentChange1d`, `pricePercentChange7d`,
`pricePercentChange30d`, `pricePercentChange1y`); the same values the
Trending page displays. However, these fields were being discarded:

- **EVM path**: The core `fetchTokenContractExchangeRates` function
fetched full market data but stripped everything except `.price` in its
final reduce
- **Non-EVM path**: `fetchTokenExchangeRates` called the same API but
only extracted `.price`, discarding percentage fields

**What changed:**

- **Core (`@metamask/assets-controllers`)**: Added optional
`includeMarketData` parameter to `fetchTokenContractExchangeRates`. When
`true`, returns full `MarketDataDetails` (including percentage changes)
instead of price-only. Defaults to `false` for backward compatibility.
([core PR #9042](MetaMask/core#9042))
- **Mobile (`exchange-rates.ts`)**: Added `includeMarketData` flag to
`fetchTokenExchangeRates` and `getTokenExchangeRate`. Non-EVM branch now
preserves the full API response when the flag is set. Removed the
redundant `getTokenSpotPriceWithMarketData` function.
- **Mobile (`useTokenPrice.ts`)**: Single `useEffect` now calls
`getTokenExchangeRate({ includeMarketData: true })` to get both the
price and percentage data in one API call. For supported time ranges
(1D, 1W, 1M, 1Y), the spot-prices percentage overrides the
historical-prices-derived one. For imported tokens, reads percentage
from Redux (already available via `TokenRatesController`). Unsupported
ranges (3M, 3Y, All) fall back to the historical-prices derivation.

### Fix 3 — Tighten "no data" overlay for legacy chart with insufficient
time coverage (`useTokenHistoricalPrices.ts`, `PriceChart.tsx`)

Previously the chart only checked if the API returned at least 5 data
points before rendering. This meant a 1D request that returned only 10
hours of data (many data points but covering less than half the
requested period) would still render a misleading chart.

**What changed:**

- **`useTokenHistoricalPrices.ts`**: Added a
`hasInsufficientTimeCoverage()` check that compares the actual time span
of returned data against the expected duration for each time period (1D
= 24h, 1W = 7d, etc.). If the data covers less than **95%** of the
expected duration, the hook sets `hasInsufficientCoverage: true`. HTTP
204 (no content) responses also set the flag.
- **`PriceChart.tsx`**: The "no data" overlay now also shows when
`hasInsufficientCoverage` is true, even if there are 5+ data points.
- The flag is threaded through `useTokenPrice` → `TokenDetails` →
`AssetOverviewContent` → `Price` → `PriceLegacy`/`PriceAdvanced` →
`PriceChart`.

## Example

SpaceX on Base — Reverse-sorted historical data (Fix 1) + Incomplete
historical data (Fix 2)

**Trending page shows:** `+98,964%`

**Token Details (legacy chart) before fix:** `-80%` (or `-0.00%` with
reverse-sorted data)

The `historical-prices` API returned only ~10 hours of data for this
newly-listed token, starting after the major pump. Using
`historicalPrices[0]` as the baseline gave a post-pump price, making the
percentage wildly incorrect.

**After fix:** Uses `pricePercentChange1d` from the spot-prices API
(same source as Trending page) → `+98,720%` ✅

## **Changelog**

CHANGELOG entry: Fixed percentage mismatch between Trending page and
Token Details page caused by reverse-sorted historical price data,
discarded spot-prices percentage fields for both EVM and non-EVM tokens,
and added 95% time-coverage check to show "no data" overlay for
incomplete historical data

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Token Details percentage accuracy

  Scenario: Legacy chart percentage matches trending page for newly-listed tokens
    Given user is on the Trending page and sees a newly listed token (e.g. on Base chain)
    When user taps into Token Details and the legacy chart loads
    Then the displayed percentage should closely match the trending percentage
    And the amount change should be consistent with the percentage

  Scenario: Non-EVM token percentage matches trending page
    Given user is on the Trending page filtered to Solana
    When user taps a trending Solana token into Token Details
    Then the displayed 1D percentage should match the trending percentage

  Scenario: Switching time ranges works correctly
    Given user is on Token Details for any token
    When user switches between 1D, 1W, 1M, 1Y time ranges
    Then each range should show the spot-prices-derived percentage
    And 3M, 3Y, All should fall back to historical-prices-derived percentage

  Scenario: Insufficient time coverage shows no-data overlay
    Given the historical-prices API returns less than 95% of the requested time period
    When user is on Token Details for a newly-listed token on 1D
    Then the chart should show the "No chart data" overlay instead of a partial chart

  Scenario: Stable tokens remain unaffected
    Given user is on the Trending page and sees a major token (e.g. SOL, ETH)
    When user taps into Token Details
    Then the percentage should remain within 0-2% of the trending percentage (unchanged behavior)
```

## **Screenshots/Recordings**

### **Before**

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

### **After**

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



## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [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**

- [ ] 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 pricing UX across legacy/advanced charts and
exchange-rate fetching; incorrect coverage or spot-% override could
still mislead users, but behavior is guarded by tests and falls back to
historical derivation for unsupported ranges.
> 
> **Overview**
> Aligns Token Details price-change % and legacy chart behavior with
Trending by fixing historical-price handling and using spot-prices
market data.
> 
> **Historical prices:** `useTokenHistoricalPrices` now sorts API
results chronologically, exports `hasInsufficientTimeCoverage()` (95% of
the requested period), sets `hasInsufficientCoverage` on short spans and
HTTP 204, and threads that flag through `useTokenPrice` → `PriceChart`,
which shows the insufficient-data overlay even when there are enough
points.
> 
> **Spot-prices %:** `fetchTokenExchangeRates` / `getTokenExchangeRate`
gain optional `includeMarketData`; `useTokenPrice` fetches full market
data for non-imported tokens (with a fetch-id guard on token switch) and
overrides `priceDiff` / `comparePrice` from Redux or API fields
(`pricePercentChange1d`, etc.) for 1D/1W/1M/1Y. Bridge Redux only stores
numeric rates when the payload is a number.
`@metamask/assets-controllers` bumps to **^109.1.0**.
> 
> **Tests:** Coverage for coverage math, chart overlay, exchange-rate
call signatures, stale fetch clearing, and advanced-chart OHLCV mocks
aligned to **prevBar** baseline.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f1665a5. 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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

Fix percentage buttons when withdrawing from predict into money account.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

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

## **Manual testing steps**
NA

## **Screenshots/Recordings**
NA

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

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

Do not mark it as "Ready for review" until 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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

QuickBuy treated USD as the canonical fiat unit, with
inconsistent/mislabeled conversions (a `€` symbol rendered on a USD
number, `currencyExchangeRate` meaning different things on EVM vs
non-EVM, hardcoded `$` headlines). This makes the user's display
currency the single canonical fiat unit across state, slider, balances,
and totals. Deriving USD only at the analytics boundary, where the
schema contractually requires `amount_usd`.


https://github.com/user-attachments/assets/05701682-8392-4f63-8304-2420a488a061

<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-06-16
at 10 06 26"
src="https://github.com/user-attachments/assets/a82f96e8-cd60-4526-9c75-a07a37312c3c"
/>
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-06-16
at 10 13 52"
src="https://github.com/user-attachments/assets/1b773a6e-e77e-4c8e-a51e-41103d803cd8"
/>
<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-06-16
at 10 06 59"
src="https://github.com/user-attachments/assets/a7b7ad4c-a533-483c-9471-18afa3652a80"
/>

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/TSA-633

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

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

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

NA

### **After**

NA

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
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
- [ ] 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.

---------

Co-authored-by: Xavier Brochard <xavier.brochard@consensys.net>
Co-authored-by: Cursor <cursoragent@cursor.com>
After BrowserStack session enrichment, extract the installed app size
from profiling data and publish it to Sentry as an `app_size_mb`
measurement (unit: megabyte), using the same publisher and DSN as the
per-test timing metrics.

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

This PR extends the E2E performance reporting pipeline to track
installed app size over time in Sentry.

After a BrowserStack session is enriched with profiling data, the
`app_size` metric (in MB) is extracted from the profiling summary and
published to Sentry as an `app_size_mb` measurement with `megabyte`
unit. It reuses the existing `publishPerformanceScenarioToSentry`
publisher and DSN, so no new infrastructure is needed.

Changes:
- `types.ts`: add `app_size` to `ProfilingData` metrics; `appSizeMb` to
`ProfilingSummary`
- `PerformanceTracker.ts`: add optional `appSizeMb` field to
`MetricsOutput`
- `BrowserStackEnricher.ts`: extract `app_size` into
`profilingSummary.appSizeMb`
- `PerformanceSentryPublisher.ts`: add `app_size_mb` measurement
(megabyte unit); allow publishing when only `appSizeMb` is set and
`steps` is empty
- `PerformanceReporter.ts`: call `publishAppSizeToSentry()` after
enrichment
- `PerformanceSentryPublisher.test.ts`: 3 new tests covering
`app_size_mb`

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

CHANGELOG entry: null

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Refs: https://consensyssoftware.atlassian.net/browse/MMQA-1974

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

This is a CI/test-infrastructure-only change (files under
`tests/reporters/`). There is no UI or runtime app behaviour to test
manually.

To verify:
1. Merge and let a nightly BrowserStack E2E run complete.
2. Open the Sentry project used for E2E performance metrics.
3. In Discover / Performance, query `measurements.app_size_mb` — values
should appear for each test session that has profiling data.

Unit tests covering the new behaviour can be run locally:
```bash
yarn jest tests/reporters/providers/sentry/PerformanceSentryPublisher.test.ts
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

N/A — no UI changes. Sentry data will only be visible after a CI run
with the merged branch.

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

- [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.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## **Description**

<!-- mms-check: type=text required=true -->

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

The "Earn on your crypto" screen (`MoneyPotentialEarningsView`) was
registered inside the Money tab stack, so it rendered with the bottom
tab navigation bar still visible and the CTA sitting above it — it was
not a true full-page screen as per the design.

This PR promotes `MoneyPotentialEarningsView` from the Money tab stack
(`MoneyTabScreenStack`) to a top-level native stack route in
`MainNavigator`, mirroring the existing Money confirmations/onboarding
pattern. As a result the bottom tab navigation bar is no longer rendered
on this screen and the "Convert your crypto" CTA sits at the true bottom
edge of the screen with safe-area padding. No changes were needed to the
view itself or to the navigation calls (the route name resolves to the
new top-level registration).

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
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: Changed the "Earn on your crypto" screen to a full-page
layout, removing the bottom navigation bar.

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-994

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Earn on your crypto full-page screen

  Scenario: user opens Earn on your crypto from the Money home screen
    Given the user is on the Money home screen
    And the "Earn on your crypto" section shows eligible tokens

    When the user taps the section header or "View all"
    Then the "Earn on your crypto" screen opens as a full page
    And the bottom tab navigation bar is not visible
    And the "Convert your crypto" CTA is pinned to the bottom of the screen with padding
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

<!-- 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/0dbe0051-1d6c-4c4e-b875-dfa38dd1e8cf


## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
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.
…31740)

## **Description**

When the `assetsUnifyState` feature flag is enabled, the active fiat
currency shown across the UI is read from
`AssetsController.selectedCurrency` (via `selectCurrentCurrency` ->
`getCurrencyRateControllerCurrentCurrency`). However, the General
Settings "Base currency" picker only wrote the selection to
`CurrencyRateController.setCurrentCurrency`. Nothing ever wrote
`AssetsController.selectedCurrency`, and the controller does not
auto-sync from `CurrencyRateController`.

As a result, with the flag on, tapping a currency closed the picker but
the selection silently no-opped and the displayed currency stayed on
`USD`. With the flag off the UI reads
`CurrencyRateController.currentCurrency`, so the bug did not reproduce.

This PR contains two changes:

1. `selectCurrency` now also calls
`AssetsController.setSelectedCurrency(currency)`, so the selection
applies regardless of the flag state. `setSelectedCurrency` updates
`selectedCurrency` and triggers a price refetch in the new currency.
2. Migration `143` copies `CurrencyRateController.currentCurrency` into
`AssetsController.selectedCurrency`. Migration `139` had defaulted
`selectedCurrency` to `'usd'` without preserving the user's existing
currency, so without this, enabling the flag would silently reset
existing non-USD users to USD.

## **Changelog**

CHANGELOG entry: Fixed a bug where changing the base currency in General
Settings had no effect.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Base currency selection in General Settings

  Scenario: user changes the base currency with assetsUnifyState enabled
    Given the assetsUnifyState feature flag is enabled
    And the user is on Settings > General
    When the user opens the "Base currency" picker
    And the user selects "EUR - Euro"
    Then the selected base currency updates to EUR
    And fiat values across the app are displayed in EUR

  Scenario: existing non-USD user upgrades with assetsUnifyState enabled
    Given a user had previously selected EUR as their base currency
    When the app upgrades and runs migration 143
    And the assetsUnifyState feature flag is enabled
    Then the user's base currency remains EUR (not reset to USD)
```

## **Screenshots/Recordings**

### **Before**

<!-- Selecting a currency closed the picker but it remained USD -->

### **After**

<!-- Selecting a currency now applies and persists -->

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…31765)

## **Description**

Mobile half of TSA-702. The deeplink contract change (see paired
social-api PR) renames the `notification_event` query param on
`social-trader-position` URLs to `notification_subtype` for parity with
NAAP. This PR updates the mobile deeplink
handler to parse the new name, forwards the value through navigation to
`TraderPositionView`, and includes it on the
`SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED` analytics event so
click-attribution can distinguish spot vs perp opens in
  analytics.

  **What changed**

- `handleSocialTraderPositionUrl.ts` — parses `notification_subtype`
(was `notification_event`), fires the existing
`SOCIAL_FOLLOW_TRADING_NOTIFICATION_CLICKED` event with the new property
key, and forwards `notificationSubtype` as a
  navigation param to `TraderPositionView`.
- `TraderPositionView.tsx` — reads `notificationSubtype` from route
params and includes it on the
`SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED` event when present.
- `socialLeaderboardEvents.ts` — adds `NOTIFICATION_SUBTYPE:
'notification_subtype'` as an analytics property key.
- `NavigationService/types.ts` — adds optional `notificationSubtype` to
both `TraderPositionViewParams` union branches.

  **Backwards compatibility**

Missing `notification_subtype` does not break navigation — the analytics
property is omitted via a spread guard when absent. Routes that don't
originate from a notification tap (in-app row taps, deeplinks without a
subtype) work unchanged.

  **Paired PR**

This depends on the social-api rename ([PR
#89](consensys-vertical-apps/va-mmcx-social-api#89))
landing for the new param name to appear on real deeplinks. Until both
ship, notification-tap analytics will be missing the subtype property —
but routing/destination behavior is unchanged.

  ## **Changelog**

  CHANGELOG entry: null

  ## **Related issues**

  Fixes: https://consensyssoftware.atlassian.net/browse/TSA-702

  ## **Manual testing steps**

  ```gherkin
  Feature: Notification deeplink forwards subtype through to analytics

    Scenario: Tap a notification with a spot subtype
Given the user taps a social-trader-position deeplink with
notification_subtype=follow_newtrade_buy
      When the deeplink handler runs
      Then the user lands on TraderPositionView for the given position
And the SOCIAL_FOLLOW_TRADING_NOTIFICATION_CLICKED event fires with
notification_subtype=follow_newtrade_buy
And once the screen renders, SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED
fires with notification_subtype=follow_newtrade_buy

    Scenario: Tap a notification with a perp subtype
Given the user taps a social-trader-position deeplink with
notification_subtype=follow_newtrade_perp_long
      When the deeplink handler runs
Then navigation and analytics propagate
notification_subtype=follow_newtrade_perp_long end-to-end

    Scenario: Legacy deeplinks without a subtype still work
Given the user taps a social-trader-position deeplink with no
notification_subtype query param
      When the deeplink handler runs
      Then navigation completes normally
And the SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED event fires WITHOUT a
notification_subtype property
  ```

  ## **Screenshots/Recordings**

  N/A — analytics-only change, no visible UI.

  ### **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)

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

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

Do not mark it as "Ready for review" until 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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

Fix broken perps section headers in Explore

<!-- mms-check: type=text required=true -->

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

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
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 broken perps section headers in Explore

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

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

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

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

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

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

### **After**



https://github.com/user-attachments/assets/ce6366fb-b54e-4c6b-be49-7219327f3250



## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
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.
<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

Display card transactions as mUSD rather than vmUSD
Also remove the linked requirement before fetching card transactions,
since you can still fetch them even if you are logged out.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

CHANGELOG entry: display money card transactions as mUSD

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: N/A

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: money account card transactions

  Scenario: user looks at activity list
    Given you have a money account with at least one card transaction

    When you look at the activity item in the list
    Then the token shown in the row will be mUSD 
```

## **Screenshots/Recordings**

### **Before**
<img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e -
2026-06-16 at 16 27 11"
src="https://github.com/user-attachments/assets/7da817b3-91ea-4852-837d-b3c4a01e008a"
/>

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

### **After**

<!-- [screenshots/recordings] -->
<img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e -
2026-06-16 at 16 27 19"
src="https://github.com/user-attachments/assets/0a6c71bd-9439-40a1-8870-38ebabe6834e"
/>

## **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.
…31822)

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

Batch sell was reporting smart transactions (STX) as disabled on all
networks except Ethereum mainnet and Sepolia, even when STX was enabled
for the user and the Sentinel liveness API returned `smartTransactions:
true` for chains like BSC, Base, and Polygon.

Unified Swap/Bridge already refreshes STX liveness on entry via
`useRefreshSmartTransactionsLiveness`, which calls
`SmartTransactionsController.fetchLiveness` and populates
`livenessByChainId` in Redux. Batch sell never triggered that fetch, so
only the controller defaults (mainnet + sepolia) were present and
`selectSmartTransactionsEnabled` returned false for every other chain.

This change adds the same liveness refresh to the first batch sell
screen (`BatchSellTokenSelect`), keyed off the active source chain
(`activeChainId`), matching the BridgeView pattern. When the user
switches chain pills, liveness is refetched for the newly selected
chain.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes: #31821

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Batch sell smart transaction liveness

  Scenario: STX is enabled on a non-Ethereum batch sell network
    Given smart transactions are opted in in Settings > Advanced
    Given the wallet has tokens on BSC (or Base / Polygon / Arbitrum / Linea)
    When the user opens Batch sell token select
    And selects the non-Ethereum network pill
    And proceeds through review to fetch quotes
    Then quote requests include stx_enabled true (when other STX gates pass)
    And batch sell submission passes isStxEnabled true

  Scenario: STX liveness refreshes when switching batch sell networks
    Given the user is on Batch sell token select with multiple eligible networks
    When the user switches between network pills
    Then liveness is fetched for each selected chain (verify via Redux livenessByChainId or network inspector)
```

Additional verification:
- Confirm Ethereum mainnet and Sepolia batch sell behavior is unchanged.
- Confirm batch sell still respects STX opt-out (Settings toggle off →
STX false).

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

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

<img width="1047" height="418" alt="Screenshot 2026-06-16 at 11 27
20 AM"
src="https://github.com/user-attachments/assets/97164095-a6e6-464c-abac-4c486f4202b0"
/>


### **After**

<!-- [screenshots/recordings] -->
<img width="1641" height="574" alt="Screenshot 2026-06-16 at 11 22
41 AM"
src="https://github.com/user-attachments/assets/d8d54a76-160d-443b-aef0-1ca7024ecdf7"
/>



## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

- [ ] 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.
…#31751)

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

Adds currentPriceLineColorOverride prop to AdvancedChart

- Adds currentPriceLineColorOverride?: string to AdvancedChartProps and
the ChartFeatures template interface, baking it into
window.CONFIG.theme.currentPriceColor at HTML creation time
- Updates createLastPriceLine (candle chart) and createLineLastPriceLine
(line chart) in chartLogic.js to read currentPriceColor || successColor
so the override applies without touching candle up-colors, volume, or
line-chart series color
- Consumers that don't pass the prop get an empty string → falsy →
existing successColor fallback; no visual change to the token detail
chart
- Fixes a race condition in the initial*ColorRef hot-swap pattern: the
three color-override refs (initialLineColorRef, initialSuccessColorRef,
initialErrorColorRef) are now snapshotted synchronously inside useMemo
rather
than in a post-render useEffect. This prevents SET_THEME_COLORS from
seeing "colors already match" and skipping a needed hot-swap when a
theme change and a color override change land in the same render cycle.

Motivation

The current-price horizontal line currently uses successColor (green),
which is
also used for candle up-colors and volume. A per-consumer override is
needed so
Perps can render a white price line without changing candle colors
globally.

Test plan

- [ ] All existing AdvancedChart unit tests pass (yarn jest
app/components/UI/Charts/AdvancedChart/)
- [ ] Token detail chart: current-price line unchanged (still
green/successColor) — no currentPriceLineColorOverride passed
- [ ] After this merges, the Perps migration PR adds
currentPriceLineColorOverride={colors.text.default} to
PerpsAdvancedChart and verifies the price line renders white (dark mode)
/ near-black (light mode) without affecting candle colors

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

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

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Advanced chart current price color

  Scenario: chart colors update after live price direction changes
    Given the token details chart is loaded with a custom current price line color

    When live price data changes the token chart direction from positive to negative
    Then the chart updates its line and candle colors without rebuilding the WebView
    And the current price horizontal line keeps the custom current price line color
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**
N/A
<!-- [screenshots/recordings] -->

### **After**
N/A
<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

We aren’t permitted to render Money account UI elements when users are
geo-blocked.

This PR uses the new feature flag `moneyAccountGeoBlockedCountries` and
hides
- Money balance card on home, instead showing money hub (as it does when
money account is disabled)
- Money navbar button, instead restoring the activity buton
- Wallet home Contentful banners are not shown

## **Changelog**

CHANGELOG entry: geo-block money account in unavailable regions

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-828

## **Manual testing steps**
Feature: Money geo-blocking
```
  Background:
    Given the Money account feature flag is enabled

  Scenario: User in a blocked country sees no Money UI
    Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"]
    And the detected geolocation is "GB"
    When the user opens the app
    Then the Money balance card is not rendered on the wallet home screen
    And the bottom nav shows the Activity tab instead of the Money tab
    And the Activity clock icon is not rendered in the wallet header
    And the growth banners are not rendered on the wallet home screen

  Scenario: User in an unblocked country sees all Money UI
    Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"]
    And the detected geolocation is "US"
    When the user opens the app
    Then the Money balance card is visible on the wallet home screen
    And the bottom nav shows the Money tab
    And the Activity clock icon is visible in the wallet header
    And the growth banners are visible on the wallet home screen

  Scenario: Growth banners are visible when Money is disabled entirely
    Given the Money account feature flag is disabled
    And the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"]
    And the detected geolocation is "GB"
    When the user opens the app
    Then the growth banners are visible on the wallet home screen

  Scenario: Empty blocked regions list allows all users through
    Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions []
    And the detected geolocation is "GB"
    When the user opens the app
    Then the Money balance card is visible on the wallet home screen
    And the bottom nav shows the Money tab

  Scenario: Country-region code is matched by country prefix
    Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"]
    And the detected geolocation is "GB-ENG"
    When the user opens the app
    Then the Money balance card is not rendered on the wallet home screen
    And the bottom nav shows the Activity tab instead of the Money tab

  Scenario: Default blocklist applies when no remote flag is configured
    Given the "moneyAccountGeoBlockedCountries" remote flag is not set
    And the MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES env var is not set
    And the detected geolocation is "GB"
    When the user opens the app
    Then the Money balance card is not rendered on the wallet home screen
    And the bottom nav shows the Activity tab instead of the Money tab

  Scenario: Env var blocklist is used when remote flag is absent
    Given the "moneyAccountGeoBlockedCountries" remote flag is not set
    And the MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES env var is set to "US"
    And the detected geolocation is "US"
    When the user opens the app
    Then the Money balance card is not rendered on the wallet home screen
    And the detected geolocation is "GB"
    When the user opens the app
    Then the Money balance card is visible on the wallet home screen
```

## **Screenshots/Recordings**


### **Before**
<img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e -
2026-06-16 at 14 04 01"
src="https://github.com/user-attachments/assets/eabba171-2235-46d5-98c9-aced14e5f0de"
/>


### **After**
<img width="1170" height="2532" alt="Simulator Screenshot - iPhone 16e -
2026-06-16 at 14 00 13"
src="https://github.com/user-attachments/assets/48c2f31c-7560-4342-97cb-0558f440f075"
/>


## **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`.
-->

- [ ] 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.
@pull pull Bot locked and limited conversation to collaborators Jun 16, 2026
@pull pull Bot added the ⤵️ pull label Jun 16, 2026
@pull
pull Bot merged commit dc704c5 into Reality2byte:main Jun 16, 2026
1 of 8 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.