[pull] main from MetaMask:main#829
Merged
Merged
Conversation
… 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> <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> </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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )