Skip to content

[pull] main from MetaMask:main#829

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

[pull] main from MetaMask:main#829
pull[bot] merged 11 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Jun 12, 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 : )

jpuri and others added 11 commits June 12, 2026 06:59
… balance (#31569)

<!--
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 designs of money account deposit page when account as not crypto
balance.

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

## **Manual testing steps**
NA

## **Screenshots/Recordings**
<img width="399" height="848" alt="Screenshot 2026-06-11 at 4 05 42 PM"
src="https://github.com/user-attachments/assets/7aceaad9-6529-4e2d-a8a4-135e4df43828"
/>

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Confirmation-screen UI and copy changes for the no-funds deposit path;
no auth, payment execution, or backend logic changes.
> 
> **Overview**
> Improves the **money account deposit** confirmation when the selected
account has **no crypto balance** (and no fiat path): users still see
payment UI to pick another account/token instead of only a buy prompt.
> 
> **Alert presentation:** `AlertMessage` is now a muted error **banner**
with a left accent bar and default text color (replacing centered
error-colored text). The account-no-funds alert uses a dedicated
**title** (`Insufficient funds`) plus the existing body copy.
> 
> **Deposit flow:** `custom-amount-info` treats “account no funds” like
having a payment option—**Pay with** row and deposit keyboard stay
visible; **Buy** section is hidden when that alert is active.
`PayWithRow` shows a **“Select token”** empty state (still tappable to
open the picker) instead of a loading skeleton, via shared
`PayWithRowLayout` refactor across interactive, fiat, money-account, and
empty variants.
> 
> **Wiring:** `useAccountNoFundsAlert` is included in
`useConfirmationAlerts` for transactions; tests and copy keys
(`confirm.label.select_token`) updated accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
feaeb5f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…rt (MUSD-927) (#31558)

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

`MoneyTransferSheet` previously kept two separate option arrays
(`activeOptions` and `disabledOptions`) with two separate render paths.
On top of being duplicative, this meant the Perps and Predictions
options always rendered as active-looking, tappable rows even when their
feature flags were off — the press handlers just silently no-oped.

This PR unifies them into a single `Option[]` list supporting `disabled:
boolean` (and `comingSoon: boolean` for the "Coming soon" rows),
mirroring the pattern already established in the sibling
`MoneyAddMoneySheet`:

- Perps and Predictions options are now rendered as disabled (muted
icon, alternative text color, non-tappable) when `useMoneyPerpsDeposit`
/ `useMoneyPredictDeposit` report their flags as disabled.
- The flag guards move from inside the press handlers to the element
itself (`disabled` prop + `onPress` gating), so the disabled state is
also exposed to accessibility tools.
- Enabled options are ordered before disabled ones, same as
`MoneyAddMoneySheet`.
- "Send to external account" and "Withdraw to bank" keep their "Coming
soon" tag rendering, unchanged.

All testIDs and analytics payloads are unchanged.

## **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: Disabled the Perps and Predictions options in the Money
Account transfer sheet when their features are unavailable, instead of
showing active options that did nothing.

## **Related issues**

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

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

## **Manual testing steps**

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

```gherkin
Feature: Transfer money sheet flag-gated options

  Scenario: user opens the transfer sheet with Perps/Predict flags disabled
    Given the Perps and Predict MM Pay feature flags are disabled

    When user opens the Money Account transfer sheet
    Then the "Perps account" and "Predictions account" options render greyed out and are not tappable

  Scenario: user opens the transfer sheet with Perps/Predict flags enabled
    Given the Perps and Predict MM Pay feature flags are enabled

    When user taps the "Perps account" or "Predictions account" option
    Then the sheet closes and the corresponding deposit flow starts, as before

  Scenario: user views the coming soon rows
    Given the transfer sheet is open

    When user looks at "Send to external account" and "Withdraw to bank"
    Then both still render with a "Coming soon" tag and are not tappable
```

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

### **After**

<!-- [screenshots/recordings] -->
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)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI refactor in Money sheets with behavior aligned to existing
add-money patterns; deposit/withdraw flows unchanged aside from clearer
disabled Perps/Predict rows when flags are off.
> 
> **Overview**
> Introduces a shared **`MoneySheetOptionsList`** component that renders
Money bottom-sheet rows with optional **`disabled`** / **`comingSoon`**
handling, muted styling, and **enabled options listed before disabled
ones**.
> 
> **`MoneyAddMoneySheet`** and **`MoneyTransferSheet`** drop their
inline row UI and styles in favor of this list. Add-money folds
**Receive external** into the same options array (no separate static
row). Transfer merges former **active** vs **disabled** lists into one
**`MoneySheetOption[]`**: Perps and Predictions rows use **`disabled:
!isPerpsEnabled` / `!isPredictEnabled`** instead of looking tappable
with no-op handlers; send-external and withdraw-to-bank stay **coming
soon** via flags.
> 
> Adds unit tests for **`MoneySheetOptionsList`** and transfer-sheet
cases for disabled/enabled Perps and Predictions options.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
202b6d6. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Replace the letter-initial avatar fallback with a Maskicon (MetaMask's
deterministic mask-shaped account art) across the three trader-avatar
surfaces — Top Traders carousel, leaderboard list rows, and the trader
profile header. Falls back consistently with how wallet accounts render
elsewhere in the app.

Three components previously rendered a single-letter `AvatarBase` (`S`
for swisscheese, `D` for dutchiono, etc.) when no profile image URL was
present. They now render a Maskicon seeded by the trader's wallet
address:

  - `TopTraderCard` — 60px Xl avatar in the homepage carousel
  - `TraderRow` — 40px Lg avatar in the leaderboard list
  - `ProfileHeader` — 40px Lg avatar on the trader detail screen

  **Detecting Clicker's "default" image URL**

Verified empirically: Clicker returns a generic placeholder
(`daylight-images.s3.us-east-1.amazonaws.com/ens-fallback.png`) for
every `.eth` trader without a real profile picture. Before this PR, a
naive `trader.avatarUri ? <Image> :
<Maskicon>` check would render that shared placeholder as an `Image`
since the field is non-null, defeating the fallback for many traders
(aparjey.eth, jakey.eth, stakedao.eth, etc.).

Added a small `hasRealAvatar()` helper that returns false for null/empty
*and* for known shared placeholder URLs. The list lives in
`app/components/Views/Homepage/Sections/TopTraders/utils/avatarFallback.ts`
and is easy to extend if we discover more defaults (Farcaster, Twitter,
etc.).

  ## **Changelog**

CHANGELOG entry: Updated traders without a profile picture to render a
Maskicon (matching the wallet identity art elsewhere in the app) instead
of a single-letter avatar.

  ## **Related issues**

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

  ## **Manual testing steps**

  ```gherkin
  Feature: Trader avatar Maskicon fallback

    Scenario: Trader with a real Clicker-hosted profile image
Given the user opens any leaderboard surface (Top Traders carousel,
list, or profile)
      When a trader has a real Clicker-hosted avatar URL
      Then the avatar renders as before (no visible change)

    Scenario: Trader with no profile image at all
      Given a trader has no avatar URL
      When the trader's row, card, or profile is rendered
      Then a Maskicon seeded by their wallet address is shown
And the Maskicon is clipped to a circle, matching the real avatar
styling

    Scenario: Trader using Clicker's ENS placeholder
      Given a .eth trader has Clicker's generic ENS placeholder URL
      When the trader's row, card, or profile is rendered
Then the Maskicon fallback is shown (the placeholder image is not used)

    Scenario: Top-3 ranked trader retains the podium decoration
      Given a top-3 ranked trader has no profile image
Then their Maskicon renders inside the existing TopRankAvatar gradient
ring and crown
  ```

  ## **Screenshots/Recordings**

  ### **Before**
<img width="447" height="974" alt="Screenshot 2026-06-11 at 10 17 51 PM"
src="https://github.com/user-attachments/assets/17597728-b219-4a2a-b0f2-001b0eb53ec7"
/>

  ### **After**
<img width="447" height="974" alt="Screenshot 2026-06-11 at 10 13 05 PM"
src="https://github.com/user-attachments/assets/1664ab7d-c35a-472c-8c23-1f802c8b18c3"
/>


  ## **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 per
the docs.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI-only changes on social leaderboard surfaces with unit tests; no
auth, data, or API behavior changes.
> 
> **Overview**
> Replaces **letter-initial** `AvatarBase` fallbacks with **Maskicon**
`AvatarAccount` art (seeded by wallet address) on Top Traders carousel
cards, leaderboard rows, and trader profile headers—aligned with wallet
identity elsewhere in the app.
> 
> Adds **`hasRealAvatar()`** so avatars render as `Image` only for real
per-user URLs, not for missing/empty values or Clicker’s shared ENS
placeholder (`ens-fallback.png`). That placeholder previously slipped
through a truthy `avatarUri` check and blocked the fallback for many
`.eth` traders.
> 
> Tests are updated to expect Maskicon instead of the first-letter
fallback.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
448c0c2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Swap `ButtonHero` for the themed `Button` (`Primary` variant) on the
trader position Buy CTA.

`ButtonHero` locks itself to light-theme colors regardless of the app's
theme, so the Buy button renders as MetaMask blue even in dark mode and
looks inconsistent with every other button on the screen. The Follow
button on
`TraderProfileView` already uses `Button` with `ButtonVariant.Primary`;
this brings the Buy CTA in line.

Single-file change in `TraderPositionView.tsx`. `testID`, `isFullWidth`,
and `onPress` props are identical across both components, so all
existing button tests (which query by `testID`) pass unchanged.

  ## **Changelog**

CHANGELOG entry: Fixed the Buy button on the trader position screen
rendering with light-theme colors in dark mode.

  ## **Related issues**

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

  ## **Manual testing steps**

  ```gherkin
  Feature: Trader position Buy button respects app theme

    Scenario: Buy button in dark mode
      Given the app is in dark mode
      When the user opens a trader's position screen
      Then the Buy button uses the dark-themed primary color
And it visually matches the Follow button on the trader profile screen

    Scenario: Buy button in light mode
      Given the app is in light mode
      When the user opens a trader's position screen
Then the Buy button continues to render correctly (no visual regression)

    Scenario: Buy action still works
      Given the user is on a trader position screen
      When the user taps the Buy button
      Then the Quick Buy flow opens as before
  ```

  ## **Screenshots/Recordings**

  ### **Before**
<img width="447" height="974" alt="Screenshot 2026-06-11 at 9 37 33 PM"
src="https://github.com/user-attachments/assets/bf8e1ba1-3ae4-45a8-9043-bfde4dc40f50"
/>

  ### **After**
<img width="447" height="974" alt="Screenshot 2026-06-11 at 9 44 06 PM"
src="https://github.com/user-attachments/assets/2e69940c-fbc6-4b47-9baa-fa4171452359"
/>

  ## **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]
> **Low Risk**
> Single-component styling swap with no logic, navigation, or testID
changes.
> 
> **Overview**
> Replaces the trader position screen **Buy** CTA from `ButtonHero` to
the design-system **`Button`** with `ButtonVariant.Primary` and
`ButtonSize.Lg`, so the control follows the active app theme instead of
fixed light-theme styling.
> 
> **`testID`**, **`isFullWidth`**, **`onPress`**, and label behavior are
unchanged, so Quick Buy and existing tests that target the buy button by
test ID should behave the same—only appearance should align with other
primary actions (e.g. Follow on trader profile).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
187d9b3. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Polish pass on the trader profile positions list. Three coordinated
changes:

  **1. PositionRow redesign for open and closed positions.**
- **Open rows:** top-right shows position value (unchanged);
bottom-right now shows unrealized `+$X (+Y%)` colored by PnL sign (was
just `+Y%`).
- **Closed rows:** top-right now shows signed colored realized $ PnL
(was the gross sold amount); bottom-right shows the magnitude `Y%` in
gray with a colored `▲` (gain) or `▼` (loss) triangle. For break-even
closes a gray U+2212 minus
  replaces the triangle.

**2. `30D P&L` headline relabel to `30D Return`.** The Clicker field
surfacing this number (`pnl30d`) includes both realized PnL on trades
inside the window *and* unrealized mark-to-market change on positions
held during the window. "P&L"
implied "realized only" to most readers; "Return" is the financially
accurate name for a 30-day wealth-change metric. Verified empirically
against a live trader: realized closes accounted for ~88% of the
headline, the residual was unrealized
appreciation on still-open positions. If the team decides they actually
want realized-only here, that's a Clicker schema ask (separate ticket);
the label is honest about what's currently being shown either way.

**3. Closed positions fetch: `sort: 'latest'` + `limit: 100`.**
Clicker's default sort on `/positions/closed` is value-descending, so at
the default `limit=20` you'd see top high-value closes from any time
rather than recent activity. Mobile
now requests recency-first and asks for the max page size. Open
positions also bump to `limit: 100` (the v2 endpoint doesn't accept a
sort param, so client-side sort handles ordering there).

  Small follow-on changes that fall out of the above:
  - New `formatSignedUsd` helper for explicit-sign $ display.
- `sortPositions` closed "value" sort tracks `realizedPnl` (the visible
top-right number) instead of `soldUsd` so the order matches what users
see.
- Color logic in `PositionRow` derives from the dollar value's sign, not
the percent's sign. Fixes an edge case where `boughtUsd === 0` (null
percent, non-zero realized PnL) would render a positive value in red.

  ## **Changelog**

CHANGELOG entry: Updated the trader profile positions list with a
clearer PnL design (signed dollar amounts plus directional triangles for
closed positions, unrealized dollar amounts on open positions) and
renamed the headline 30D stat to "30D Return".

  ## **Related issues**

  Refs: https://consensyssoftware.atlassian.net/browse/TSA-690

  ## **Manual testing steps**

  ```gherkin
  Feature: Trader profile positions list with refreshed PnL design

Scenario: Open positions show unrealized dollar PnL alongside percent
Given the user is on a trader's profile with at least one open position
      When the Open tab is selected
Then each row shows the current position value top-right (unchanged)
And the bottom-right shows "+$X.XX (+Y%)" or "-$X.XX (-Y%)" colored
green or red

Scenario: Closed positions show signed realized PnL with a direction
triangle
Given the user is viewing a closed position with a non-zero realized PnL
Then the top-right shows the signed realized $ PnL in green (gain) or
red (loss)
And the bottom-right shows an unsigned percent next to a colored ▲ or ▼
triangle

    Scenario: Break-even closed position shows neutral styling
Given the user is viewing a closed position with exactly zero realized
PnL
      Then the top-right shows "$0.00" in neutral gray
And the bottom-right shows "0%" next to a gray minus glyph instead of a
triangle

    Scenario: Headline reads "30D Return" instead of "30D P&L"
      Given the user is on a trader profile
      Then the 30-day stat label reads "30D Return"

    Scenario: Closed positions tab shows most-recent closes first
      Given the user opens the Closed tab on an active trader
      Then the most recent closes appear at the top
      And the "Recent" sort indicator is active
  ```

  ## **Screenshots/Recordings**

  ### **Before**
<img width="447" height="974" alt="Screenshot 2026-06-11 at 4 32 44 PM"
src="https://github.com/user-attachments/assets/3c89e13d-2dd2-49d0-8e56-e89517cdf910"
/>
<img width="447" height="974" alt="Screenshot 2026-06-11 at 4 32 29 PM"
src="https://github.com/user-attachments/assets/3da09de0-92d2-410a-8db9-f2128f0350c0"
/>


  ### **After**

https://www.loom.com/share/29dfee2ac93a41f8a5a1c8e5bd4f1bc6

  ## **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]
> **Low Risk**
> Social leaderboard UI, formatting, and read-only position query
parameters only; no auth, payments, or persistence changes.
> 
> **Overview**
> Polishes the **trader profile** positions list so PnL reads more
clearly and closed history matches what users expect.
> 
> **Position rows:** Open positions still show **position value**
top-right; bottom-right now shows **signed unrealized dollars with
percent** (e.g. `+$1,059.96 (+182%)`), with color driven by dollar sign.
**Closed** rows show **signed realized $ PnL** top-right (replacing
gross **sold** amount), with **unsigned percent**, colored **▲/▼** (or a
neutral minus at break-even). A new **`formatSignedUsd`** helper backs
the dollar formatting; PnL coloring follows the **dollar** sign so edge
cases like zero `boughtUsd` don’t mis-color.
> 
> **Copy & data:** The headline stat label changes from **30D P&L** to
**30D Return** (`en.json`). **`useTraderPositions`** requests **`limit:
100`** for open and closed, and **`sort: 'latest'`** for closed so
recent closes aren’t buried by value-desc defaults. Client **closed
“value” sort** now uses **`realizedPnl`** so ordering matches the
visible top-right number.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4ab37f7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ypto flow (MUSD-945) (#31574)

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

The Convert Crypto (Add funds) flow shows the live vault APY label on
the zero state and a projected 1-year balance once an amount is entered,
but neither line explains what those figures mean.

This PR adds an info icon to both states of `BalanceProjection` on the
`moneyAccountDeposit` confirmation screen:

- Zero state ("Earn X% APY") — opens the "Annual Percentage Yield (APY)"
bottom sheet (`MoneyApyInfoSheet`) with a new `deposit` variant showing
the single-paragraph copy from the design, passing the live `apyPercent`
- Amount-entered state ("Projected 1-year balance: $X") — opens the
"Projected 1-year balance" bottom sheet (`MoneyEarnCryptoInfoSheet` with
a `deposit` variant title; other surfaces keep "Earn on your crypto")

Both presses are tracked via `trackTooltipClicked` with `screen_name:
money_deposit`, mirroring the Money home screen handlers. The zero-state
label copy is aligned with the design ("Earn X% APY" instead of "Earn up
to X% APY"). APY values remain fully dynamic — sourced from
`useMoneyAccountBalance`, the same hook backing the Money Account home
screen; no APY is hard-coded.

Per design, the info tooltip button in the screen header is removed (the
in-content icons replace it); the now-unused
`useMoneyAccountDepositTooltip` hook and its locale keys are deleted.
The "Earn on your crypto" sheet body is also aligned with the Figma
copy.

## **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: Added APY and projected balance info tooltips to the
Money Account convert crypto flow

## **Related issues**

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

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

## **Manual testing steps**

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

```gherkin
Feature: Convert Crypto APY and projected balance tooltips

  Scenario: user opens the APY tooltip on the zero state
    Given the user is on the Money Account home screen
    And the user opens Add funds > Convert crypto

    When the user taps the info icon next to the "Earn X% APY" label
    Then the "Annual Percentage Yield (APY)" bottom sheet opens with the live APY value

  Scenario: user opens the projected balance tooltip
    Given the user is on the Convert crypto screen

    When the user enters an amount
    Then the projected 1-year balance updates as the user types

    When the user taps the info icon next to the projected balance
    Then the "Earn on your crypto" bottom sheet opens
```

## **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/5c99a9e2-13a9-4ddc-8beb-df75ea5564ef


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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI-only Money deposit flow changes with analytics and navigation to
existing sheets; no auth, payments, or transaction logic changes beyond
import paths.
> 
> **Overview**
> Adds **in-line info icons** on the Money convert-crypto deposit flow’s
`BalanceProjection` row: one on the zero-state APY pitch and one beside
the projected balance when an amount is entered. Taps fire **money
deposit analytics** and open existing bottom sheets via a new
**`deposit` variant** (shorter APY copy; earn-crypto sheet uses
**“Projected 1-year balance”** as the title).
> 
> **`BalanceProjection`** moves under `UI/Money`, gains navigation +
tooltip handlers, and the APY label string drops **“up to”** (`Earn
{{percentage}}% APY`). The **header info tooltip** on add funds is
removed (`useMoneyAccountDepositNavbar` /
`useMoneyAccountDepositTooltip` deleted); the deposit screen navbar is
only title + back button. Locale keys for the old header tooltip are
removed; new deposit-specific sheet strings are added.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8f1fdd9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Inline async effects and call `Authentication` directly so
`useAuthCapabilities` and `useSyncSRPs` follow React Compiler–friendly
patterns without behavior changes.

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

Refactors two hooks to follow React Compiler–friendly patterns (see
`docs/performance/react-compiler.md`) without changing runtime behavior:

**`useAuthCapabilities`**
- Removes the `useCallback` → `useEffect` indirection and calls
`Authentication.getAuthCapabilities` directly instead of via
`useAuthentication()` (which returns a new object every render).
- Inlines the async fetch inside `useEffect` with deps `[osAuthEnabled,
allowLoginWithRememberMe]` only.

**`useSyncSRPs`**
- Replaces the async IIFE inside `useEffect` with a named async function
(`syncSRPs`), matching the pattern used in `useAuthCapabilities`.

No API or consumer changes. Existing unit tests cover loading lifecycle,
re-fetch on selector changes, and error handling.

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

Refs: N/A — internal React Compiler compatibility refactor

## **Manual testing steps**

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

N/A — behavior-preserving refactor; covered by existing unit tests:

```bash
yarn jest app/core/Authentication/hooks/useAuthCapabilities.test.ts
yarn jest app/components/hooks/useSyncSRPs.test.ts
```

## **Screenshots/Recordings**

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

N/A — no UI changes

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit c6e4415. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Cursor <cursoragent@cursor.com>
…_target (MUSD-959) (#31590)

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

`MoneyBalanceCard`'s Add button (and the mUSD row Add button on Money
home, which shares the same routing hook) used to preselect mUSD as the
payment token and redirect to the Ramp Buy flow when the wallet held no
mUSD.

Per MUSD-959, the Add press now always opens the MM Pay deposit screen
with no explicit preselection. MM Pay already implements both acceptance
criteria in `useAutomaticTransactionPayToken`: it auto-selects the
highest-balance crypto token when the user has tokens, and auto-selects
a fiat payment method when the user has none (`autoSelectFiatPayment ||
tokens.length === 0`). Duplicating a "has tokens" check on our side
would only risk diverging from MM Pay's authoritative token filtering
(disabled tokens, minimum balances, hardware-wallet rules).

`useMoneyAccountAddRouting` therefore collapses to a single
`routeAddMoney` that calls `initiateDeposit()`; the now-dead `moveMusd`,
`depositFunds`, `convertCrypto`, and `hasMusdBalance` members are
removed (no remaining consumers).

The event properties part: both call sites fired `trackButtonClicked`
with a predictive `redirect_target` (`hasMusdBalance ? money_deposit :
ramp_buy`) computed before routing, which no longer matched where the
user actually landed. Both now report the constant `money_deposit`.

## **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 wallet home balance card Add button to always
open the deposit screen, preselecting fiat payment when the wallet holds
no tokens

## **Related issues**

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

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

## **Manual testing steps**

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

```gherkin
Feature: MoneyBalanceCard add money routing

  Scenario: user with crypto tokens presses Add on the balance card
    Given the wallet holds at least one crypto token

    When user presses Add on the wallet home balance card
    Then the MM Pay deposit screen opens with the highest-balance crypto token preselected as the payment token

  Scenario: user without tokens presses Add on the balance card
    Given the wallet holds no tokens

    When user presses Add on the wallet home balance card
    Then the MM Pay deposit screen opens with a fiat payment method preselected
    And the user is not redirected to the Ramp Buy flow

  Scenario: user presses Add on the mUSD row of Money home
    Given the user is on the Money home screen

    When user presses Add on the MetaMask USD row
    Then the MM Pay deposit screen opens
    And the Button Clicked event reports redirect_target money_deposit
```

## **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/3bed6e97-b9ca-446f-a598-af5d9e5ba249


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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes core add-money navigation and removes Ramp fallback for
zero-mUSD users; deposit flow behavior now depends entirely on MM Pay
auto-selection.
> 
> **Overview**
> **Add money** on wallet home (`MoneyBalanceCard`) and Money home’s
**mUSD row** no longer branches on mUSD balance or sends users to Ramp
Buy. Both call **`initiateDeposit()`** with no options so MM Pay owns
token/fiat preselection.
> 
> The **`useMoneyAccountAddRouting`** hook and its tests are **removed**
(Ramp `goToBuy`, `moveMusd` preselection, etc.).
**`SCREEN_NAMES.RAMP_BUY`** is dropped from Money analytics constants.
> 
> **Analytics** `redirect_target` for those Add/Earn actions is always
**`money_deposit`** instead of a pre-routing `ramp_buy` vs
`money_deposit` guess. Deposit failures are **logged** via
`Logger.error` on the balance card and mUSD row.
> 
> Tests are updated accordingly; Money home gains coverage for
**condensed info card** navigation/actions.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3d0ef79. 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**

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

Re-enables three skipped Perps smoke E2E tests that were disabled after
CI failures
([MMQA-1936](https://consensyssoftware.atlassian.net/browse/MMQA-1936)).

**Root cause:** navigation relied on **Explore crypto**
(`tapExploreCryptoIfVisible`), which was clipped / not tappable on CI
while ETH is already available on the Perps home watchlist.

**Changes (E2E only, no app changes):**
- Add `PerpsMarketListView.selectMarketAndTapOrderSide()` — selects a
watchlist market and taps Long/Short with `executeWithRetry`.
- Update `openPosition` / add `navigateToPerpsOrderEntry` in
`perps.flow.ts` to use the watchlist path (no Explore crypto).
- Re-enable `perps-position-liquidation`, `perps-position`, and
`perps-position-stop-loss` specs.
- Align `perps-limit-long-fill` with the same navigation helper.
- Pre-grant notification permission on fresh installs (`permissions: {
notifications: 'YES' }`) when `restartDevice: true`, so the OS push
prompt does not block login.

## **Changelog**

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

CHANGELOG entry: null

## **Related issues**

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

Fixes:
[MMQA-1936](https://consensyssoftware.atlassian.net/browse/MMQA-1936)

## **Manual testing steps**

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

```gherkin
Feature: Perps position smoke E2E

  Scenario: open a long ETH position from the Perps home watchlist
    Given a logged-in wallet with Perps mocks on Arbitrum
    And notification permission is pre-granted on app launch

    When the test navigates to Perps from the wallet home
    And selects ETH from the watchlist and taps Long
    Then the order entry screen is shown without tapping Explore crypto

  Scenario: liquidation smoke verifies position closes when mark price triggers liquidation
    Given an open long ETH position
    When the mock mark price moves to a non-liquidating level
    Then the close position control remains visible
    When the mock mark price moves to a liquidating level
    Then the close position control is no longer visible
```

**Local run (use package.json scripts so
`NODE_OPTIONS=--experimental-vm-modules` is set for Anvil):**

```bash
# Single spec (CI prebuilt app)
PREBUILT_IOS_APP_PATH=build/MetaMask.app yarn test:e2e:ios:main:ci -- tests/smoke/perps/perps-position-liquidation.spec.ts

# All affected specs (local debug build)
yarn test:e2e:ios:debug:run -- \
  tests/smoke/perps/perps-position.spec.ts \
  tests/smoke/perps/perps-position-stop-loss.spec.ts \
  tests/smoke/perps/perps-position-liquidation.spec.ts \
  tests/smoke/perps/perps-limit-long-fill.spec.ts
```

## **Screenshots/Recordings**

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

N/A — E2E test-only change; validation is via Detox smoke runs and CI
artifacts.

### **Before**

CI smoke failures on Perps navigation (Explore crypto not tappable);
three specs skipped.

### **After**

Specs re-enabled; navigation uses watchlist selection with retry.

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

[MMQA-1936]:
https://consensyssoftware.atlassian.net/browse/MMQA-1936?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Changes are limited to Detox/page objects and smoke specs; no
production app code is modified.
> 
> **Overview**
> **Re-enables three skipped Perps smoke E2E specs** by fixing CI-flaky
navigation that depended on tapping **Explore crypto** when ETH is
already on the Perps home watchlist.
> 
> **Navigation refactor (tests only):** `PerpsMarketListView` gains
`scrollToMarketRow` (scrolls Perps home watchlist or market list until a
row is visible) and `selectMarketAndTapOrderSide` (market pick +
Long/Short with `executeWithRetry`). `perps.flow.ts` adds
`navigateToPerpsOrderEntry` and routes `openPosition` through it instead
of `PerpsHomeView.tapExploreCryptoIfVisible`.
> 
> **Spec updates:** `perps-position`, `perps-position-stop-loss`, and
`perps-position-liquidation` are un-skipped; `perps-limit-long-fill` and
the others use `navigateToPerpsOrderEntry('ETH', 'long')`. Fixtures with
`restartDevice: true` now pass `permissions: { notifications: 'YES' }`
so the OS push prompt does not block login.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d936495. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

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

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## **Description**

Appium smoke CI jobs were skipping the **Upload failure screen
recordings** step when tests failed, so no `appium-smoke-videos-*`
artifact was produced for debugging (e.g. [Appium Smoke Tests (iOS) run
#6, job
appium-accounts-ios-smoke](https://github.com/MetaMask/metamask-mobile/actions/runs/27402029386/job/80983538947)).

**Why:** GitHub Actions skips subsequent steps after a failed step
unless their `if` condition includes a job status function (`always()`,
`failure()`, etc.). The recording upload only checked
`steps.run-tests-*.outcome == 'failure'`, which is not sufficient on its
own.

**Fix:** Add `always() &&` to both Namespace and current runner upload
conditions in `run-appium-e2e-workflow.yml`, matching the pattern
already used for the Playwright HTML report upload in the same workflow.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A (CI workflow bug observed in Actions run 27402029386)

## **Manual testing steps**

```gherkin
Feature: Appium failure screen recording artifact upload

  Scenario: CI uploads recordings when Appium smoke tests fail
    Given an Appium smoke workflow job where Run Appium smoke tests fails
    When the job reaches the Upload failure screen recordings step
    Then the step is not skipped
    And the appium-smoke-videos-<suite-name> artifact is available when MP4 files were saved during the run
```

Post-merge verification: re-run a failing Appium smoke job (or trigger a
known-failing test) and confirm the upload step executes and the video
artifact appears.

## **Screenshots/Recordings**

N/A — CI workflow-only change; no user-facing UI impact.

### **Before**

Upload step skipped after test failure; no failure recording artifact on
the run.

### **After**

Upload step runs on test failure; failure recordings available when
saved to `tests/test-reports/appium-smoke-videos/<suite>/`.

## **Pre-merge author checklist**

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

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

<div><a
href="https://cursor.com/agents/bc-929e305b-924d-4955-bfeb-626434c644fa"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-929e305b-924d-4955-bfeb-626434c644fa"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: cmd-ob <cmd-ob@users.noreply.github.com>
## **Description**

Updates `locales/languages/en.json` to replace "Monthly Top Traders"
with "Weekly Top Traders" in two places:
- `social_leaderboard.top_traders_view.title` — full-screen leaderboard
title
- `top_traders` — home widget label

The UI labels said "Monthly" but the leaderboard reflects a weekly
timeframe, causing a mismatch between the copy and the actual data
shown.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A — copy-only fix identified via visual inspection of the app

## **Manual testing steps**

```gherkin
Feature: Weekly Top Traders label

  Scenario: user views the Top Traders section
    Given the app is open on the home screen

    When user scrolls to the Top Traders widget
    Then the widget title reads "Weekly Top Traders"

    When user taps the widget to open the full leaderboard
    Then the screen title reads "Weekly Top Traders"
```

## **Screenshots/Recordings**

### **Before**

Monthly Top Traders (as seen in UI)

### **After**

Weekly Top Traders

## **Pre-merge author checklist**

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Copy-only change in English locale plus test expectation updates; no
logic, API, or navigation changes.
> 
> **Overview**
> Renames the Top Traders copy to **Weekly Top Traders** so the home
widget and full leaderboard title match the weekly timeframe of the
data.
> 
> `locales/languages/en.json` updates
`social_leaderboard.top_traders_view.title` and
`homepage.sections.top_traders`. Component code is unchanged; tests in
`TopTradersSection.test.tsx` and `TopTradersView.test.tsx` now assert
the new label when tapping the section header and on the leaderboard
screen.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b953ca2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jun 12, 2026
@pull pull Bot added the ⤵️ pull label Jun 12, 2026
@pull
pull Bot merged commit 9e90ec5 into Reality2byte:main Jun 12, 2026
0 of 11 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.

7 participants