release: 7.82.0#31598
Conversation
## **Description**
Adds missing `@deprecated` JSDoc tags to legacy local components that
now have confirmed equivalents in
`@metamask/design-system-react-native`.
This documents the migration path for the remaining matching components
in `app/component-library` and adds the requested deprecation tag to
`app/components/UI/Box`.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: Design system deprecation JSDoc coverage
Scenario: component deprecation tags are documented
Given the local component library contains legacy components that match design-system-react-native exports
When the component files are inspected
Then matching legacy components include @deprecated JSDoc pointing to @metamask/design-system-react-native
```
Validation performed:
- `rg "@deprecated" app/component-library/components-temp/HeaderRoot
app/component-library/components-temp/HeaderStandardAnimated
app/component-library/components-temp/SectionHeader
app/component-library/components/Select/SelectButton
app/component-library/components-temp/Skeleton
app/component-library/components/Tags/Tag
app/component-library/components-temp/TitleStandard
app/component-library/components-temp/TitleSubpage
app/components/UI/Box`
- Exact-name audit against installed
`@metamask/design-system-react-native` exports
- `yarn lint:tsc`
## **Screenshots/Recordings**
### **Before**
N/A - documentation-only JSDoc update.
### **After**
N/A - documentation-only JSDoc update.
## **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**
> JSDoc-only changes with no behavioral impact; may surface IDE
deprecation warnings for existing imports.
>
> **Overview**
> Adds **`@deprecated` JSDoc** on legacy local UI wrappers so IDEs and
docs steer imports toward **`@metamask/design-system-react-native`** for
components that already have same-named package exports.
>
> Coverage spans **`components-temp`** (`HeaderRoot`,
`HeaderStandardAnimated`, `useHeaderStandardAnimated`, `SectionHeader`,
`Skeleton`, `TitleStandard`, `TitleSubpage`), **`component-library`**
(`SelectButton`, `Tag`), and **`app/components/UI/Box`**. Each tag names
the matching design-system symbol; existing descriptions (e.g.
`SectionHeader` interim v1 note, `useHeaderStandardAnimated` hook docs)
are preserved where present.
>
> **No runtime, styling, or export changes**—documentation-only
migration hints aligned with an export-name audit.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e656c2b. 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 Agent <cursoragent@cursor.com>
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
## **Description** Adds a focused headless-session dismissal hook for the Ramp headless buy host. `HEADLESS_HOST` remains mounted at the base of the Ramp stack while native-flow screens such as EnterEmail, BasicInfo, KycProcessing, and KycWebview are pushed or reset above it. When a user backs out of one of those screens, the transparent host can be revealed again without unmounting, so the existing unmount and `beforeRemove` cleanup paths do not fire. This change arms dismissal only after the same `headlessSessionId` has blurred, then closes the live session and dismisses the headless modal if the host regains focus. The hook defers the close by one tick and re-checks focus/session identity to avoid treating transient `navigation.reset` focus blips as user dismissal. The `nativeFlowError` path disables this user-dismissal heuristic so auth failures continue to close through `failSession`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3630 ## **Manual testing steps** ```gherkin Feature: Headless buy native-flow dismissal Scenario: user backs out of a native-flow screen in headless buy Given a headless buy session is active and has navigated from RampHeadlessHost to a native-flow screen such as EnterEmail When the user taps the screen back button or performs a native stack back action Then the headless session is closed with reason "user_dismissed" And the RampHeadlessEntry modal is dismissed instead of revealing a transparent RampHeadlessHost with a live session ``` ## **Screenshots/Recordings** N/A — this is a headless lifecycle fix with no visible UI change. Validation evidence is in unit test output and static checks. ## **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) N/A — this change adds a small lifecycle hook and does not introduce performance-sensitive rendering, data loading, or production instrumentation paths. The checklist below was consciously assessed as not applicable for this PR. - [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 ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. ## Validation - `node_modules/.bin/prettier --check app/components/UI/Ramp/Views/HeadlessHost/HeadlessHost.tsx app/components/UI/Ramp/headless/useHeadlessSessionFocusDismissal.ts app/components/UI/Ramp/headless/useHeadlessSessionFocusDismissal.test.ts` — passed - `NODE_OPTIONS=--max-old-space-size=8192 node_modules/.bin/eslint app/components/UI/Ramp/Views/HeadlessHost/HeadlessHost.tsx app/components/UI/Ramp/headless/useHeadlessSessionFocusDismissal.ts app/components/UI/Ramp/headless/useHeadlessSessionFocusDismissal.test.ts` — passed - `node_modules/.bin/jest app/components/UI/Ramp/headless/useHeadlessSessionFocusDismissal.test.ts app/components/UI/Ramp/Views/HeadlessHost/HeadlessHost.test.tsx --runInBand --forceExit` — both suites printed `PASS`, but the local Jest process hung after reporting results and had to be terminated; the same behavior reproduced with the bundled Node runtime. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes headless buy session lifecycle and navigation edge cases (OTP return vs user back-out); mistakes could close sessions early or leave stale sessions, but behavior is heavily unit-tested. > > **Overview** > Adds **`useHeadlessSessionFocusDismissal`** so a headless buy session closes with `user_dismissed` when **`HEADLESS_HOST`** becomes focused again after the user backs off a native-flow screen (the host stays mounted at the stack base, so unmount/`beforeRemove` alone did not run). > > **HeadlessHost** wires the hook and turns it off when **`nativeFlowError`** or **`suppressFocusDismissal`** is set. **OtpCode** sets **`suppressFocusDismissal: true`** on successful OTP when routing back to the host without amount/currency/assetId, so programmatic refocus is not treated as dismissal; failures still use **`nativeFlowError`** only. > > Unit tests cover the hook, host wiring, and OTP navigation paths. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3bc79e8. 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: saustrie-consensys <270766059+saustrie-consensys@users.noreply.github.com>
## **Description** The headless Transak buy flow could issue a quote request with no `paymentMethod`. Transak's `/api/v2/lookup/quotes` endpoint requires the parameter and rejects the request with HTTP 400 (`"paymentMethod is required parameter"`). The root cause is the payment-method resolution chain degrading to an empty string when the quote's payment method isn't found in the loaded catalog and no explicit `paymentMethodId` override is passed: 1. `HeadlessHost` resolved `paymentMethodId ?? catalog.find(...)?.id` — `undefined` on a catalog miss. 2. `useContinueWithQuote.continueNative` then computed `ctx.paymentMethodId ?? selectedPaymentMethod?.id ?? ''` — `''` because the headless flow never seeds `selectedPaymentMethod` when the lookup misses. 3. `TransakService.getBuyQuote` silently drops `paymentMethod` from the query when it's falsy → 400. ### Solution - **Forward the quote's own payment method** (`HeadlessHost.tsx`): when the catalog membership check misses, fall back to `quote.quote.paymentMethod` — the method the quote was actually priced with. Transak normalizes the `/payments/...` id. - **Fail fast** (`useContinueWithQuote.ts`): if no payment method resolves, throw a reported error instead of issuing a request that can never succeed, so this can't silently regress. ## **Changelog** CHANGELOG entry: null <!-- Developer-only headless buy flow; not end-user-facing yet. --> ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3631 ## **Manual testing steps** ```gherkin Feature: Headless buy quote fetch Scenario: user starts a headless Transak buy without an explicit paymentMethodId Given a quote whose paymentMethod is not in the loaded payment-method catalog When the headless buy flow fetches the Transak quote Then the request includes the quote's paymentMethod And Transak returns a quote instead of HTTP 400 ``` ## **Screenshots/Recordings** Walkthrough from Amitabh's integrated `test-money-account` TestFlight build, which stacks the headless PRs (#31045, #31046, #31109) plus the money-account deposit layer and exercises this change end-to-end: - Part I → https://www.loom.com/share/3af06e801b57484d92e3bb9565e2d932 - Part II → https://www.loom.com/share/da47c43b3c544e2f85d2538fc5426443 ## **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) N/A — this is a headless payment-method resolution fix (network request only) with no performance-sensitive rendering, data loading, or production instrumentation paths. The checklist below was consciously assessed as not applicable for this PR. - [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 ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes native Transak quote request inputs in the headless buy flow; behavior is gated on `headlessSessionId` with new tests, but incorrect resolution could still break headless deposits. > > **Overview** > Fixes the headless Transak buy path sending quote requests **without** `paymentMethod`, which Transak rejects with HTTP 400. > > **`HeadlessHost`** now resolves payment method as: session override → catalog membership → **`quote.quote.paymentMethod`** when the quote’s method isn’t in the loaded catalog (stale quote, filters, or load race). Previously a catalog miss left `paymentMethodId` unset and the native flow degraded to an empty value on the wire. > > **`useContinueWithQuote.continueNative`** adds a **headless-only** fail-fast: when `ctx.headlessSessionId` is set and no payment method resolves, it reports and throws before `getBuyQuote`, instead of issuing a doomed request. The standard BuildQuote (UB2) path is unchanged because it never sets `headlessSessionId`. > > Tests cover catalog-miss fallback, the headless guard, and that UB2 still proceeds without the guard. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 34492f2. 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: saustrie-consensys <270766059+saustrie-consensys@users.noreply.github.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- 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 blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> Migrates unowned usages of the deprecated mobile component-library `Text` component to `Text` from `@metamask/design-system-react-native`. This follows the MMDS Text migration guidance by updating import paths, variant casing, color names, and weight-specific text variants to `fontWeight`. Files with CODEOWNERS ownership were intentionally excluded to avoid requiring review from other teams. The migration keeps legacy `TextVariant` / `TextColor` aliases only where the receiving component is still legacy and typed against the component-library enums, such as `SensitiveText`, `Input`, `TagColored`, and `TextWithTooltip`. Style-only `getFontFamily(...)` usage in the touched unowned files was removed rather than replaced with new font-family definitions. ## **Changelog** <!-- mms-check: type=changelog required=true --> CHANGELOG entry: null ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: N/A ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> N/A - this is a mechanical design-system migration with no intended user-facing behavior change. Validation performed: ```bash yarn lint:tsc yarn jest app/components/UI/AssetElement/index.test.tsx git diff --check ``` Additional verification: ```bash # Confirm changed files have no CODEOWNERS owners # Confirm no unowned file still default-imports deprecated component-library Text # Confirm touched style-file set has no getFontFamily/fontFamily leftovers ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> N/A - visual output should be unchanged. ### **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) - [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=9d1e1e1-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** > Broad but mechanical design-system import and prop renames with no intended behavior change; regression risk is limited to subtle typography/color mismatches on affected screens. > > **Overview** > Mechanically migrates **unowned** screens and shared UI from the deprecated component-library `Text` to `Text` from `@metamask/design-system-react-native`, scoped to files without CODEOWNERS so other teams are not pulled in. > > Across approvals (install snap flows, snap account naming), wallet/settings modals, browser chrome, permissions, simulation details, and related views, imports and props are updated to MMDS conventions: **Pascal/camel variant names** (e.g. `BodyMd`), **renamed colors** (e.g. `TextDefault`, `PrimaryDefault`), and **weight-specific variants** replaced with `fontWeight` where needed. Legacy `TextVariant` / `TextColor` are kept only where a child still expects component-library types (e.g. `TagColored`, `TextWithTooltip`). Touched style code drops `getFontFamily` tied to the old Text API; one test mock extends the design-system package to include `Text`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit fd197fc. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…e picker copy (#31137) <!-- 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 blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** Addresses two bugs in the MM Pay payment picker bottom sheet: **1. Swipe-to-dismiss freeze on "Select token" modal** When the user opens the "Other assets" token selection modal from the Pay With bottom sheet and swipes down to dismiss it, the page freezes. The root cause: the legacy `BottomSheet` wrapping `PayWithModal` has `shouldNavigateBack={false}` (needed to avoid double-pop when a token is selected with `dismissOnSelectCount=2`), but swipe/overlay/back-button dismissals bypass the `handleClose` callback entirely — they go through the gesture handler → `onCloseDialog()` directly. Without `shouldNavigateBack` and without a `postCallback`, no navigation occurs, leaving the modal screen in the navigation stack with its invisible overlay capturing all touch events. The fix adds an `onClose` handler that navigates back only when no `postCallback` was set (i.e., swipe/overlay/back-button dismiss), avoiding double-pop for programmatic dismissals (X button, token selection). **2. "Perps account" / "Predict account" → "Perps balance" / "Predict balance"** The payment picker rows display "Perps account" and "Predict account" but the correct copy is "Perps balance" and "Predict balance". <!-- mms-check: type=text required=true --> <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- mms-check: type=changelog required=true --> <!-- 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 a bug where dismissing the token selection modal by swiping down would freeze the Pay With screen, and corrected label in the payment picker ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1502 and https://consensyssoftware.atlassian.net/browse/CONF-1505 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Pay With bottom sheet Scenario: user swipes down to dismiss token selection modal Given the user is on a transaction confirmation with the Pay With bottom sheet open When user taps "Other assets" to open the token selection modal And user swipes down on the token selection modal to dismiss it Then the Pay With bottom sheet is visible and interactive (no freeze) Scenario: user verifies Perps balance label Given the user is on a Perps deposit confirmation When user opens the Pay With bottom sheet Then the Perps section row displays "Perps balance" (not "Perps account") Scenario: user verifies Predict balance label Given the user is on a Predict deposit confirmation When user opens the Pay With bottom sheet Then the Predict section row displays "Predict balance" (not "Predict account") ``` ## **Screenshots/Recordings** https://github.com/user-attachments/assets/96515bed-f816-4b3d-8b24-62385c7e8cf3 <!-- mms-check: type=screenshot required=true --> <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Targeted navigation on gesture dismiss and string-key renames in confirmations UI; no auth or payment logic changes. > > **Overview** > Fixes a **freeze** when users swipe to dismiss the **Other assets** token picker opened from Pay With with `dismissOnSelectCount > 1`. In that case `shouldNavigateBack` is off to avoid double-pop on token select, but swipe/overlay dismiss never ran navigation—`PayWithModal` now **`onClose`** calls `navigation.goBack()` only when there is **no** pending post-close callback (`hasCallback` false). > > **Copy:** Pay With rows for Perps and Predict now use **"Perps balance"** / **"Predict balance"** (new `confirm.pay_with_bottom_sheet.perps_balance` and `predict_balance` strings), with hooks and tests updated to match. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 754cdec. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…1168) <!-- 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 blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** Fixes issues with custom token import and also provides smart image fallbacks for tokens. <!-- mms-check: type=text required=true --> <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- mms-check: type=changelog required=true --> <!-- 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: feat: support UAC custom asset import and dynamic image fallbacks ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: N/A ## **Manual testing steps** 0. Make sure the setting to show zero balance tokens is enabled 1. Add custom network 2. Add token on custom network 3. EXPECTED - you should see that token added for that custom network ## **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** <img width="394" height="793" alt="Screenshot 2026-06-05 at 18 59 24" src="https://github.com/user-attachments/assets/658d6575-6d5f-454d-b2e6-338f1d0d4ef6" /> ## **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] > **Medium Risk** > Touches custom asset persistence and import flows across multiple entry points; logo fallback uses module-global dead-URL state but is UI-only with broad test coverage. > > **Overview** > **Asset logos** now use design-system `AvatarToken` with a **smart image fallback** chain: primary `asset.image`, then MetaMask static token icon URLs (lowercase and checksummed). Failed loads are tracked in a bounded rotating set and skipped on retry; `onError` advances to the next URL. > > **Unified assets (UAC) import** now passes **`PendingTokenMetadata`** into `AssetsController.addCustomAsset` from `useAssetVisibility`, with a default **`iconUrl`** from `createCaipAssetImageUrl` when missing. **Add custom token** and **search token autocomplete** flows supply symbol, name, decimals, chainId, and address for EVM and non-EVM (including CAIP-19 addresses as asset IDs). > > API test mocks add **HEAD** success for `static.cx.metamask.io` token icon PNGs. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8b1ff70. 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 Agent <cursoragent@cursor.com>
## **Description**
`CampaignOptInCta` is the canonical component for the "not opted in" CTA
flow in Rewards campaign detail pages. It handles geo-restriction
detection (`useCampaignGeoRestriction`), the geo-locked "Check
eligibility" button, the geo-loading state, and the opt-in sheet — but
it only checked geo at the campaign level (`excludedRegions`) or via a
custom country-code set.
This PR extends the abstraction with feature-level geo-restriction
support so that campaigns backed by a product with its own eligibility
API (Perps, Predict) can signal ineligibility through the same
component.
**Changes:**
- **`useCampaignGeoRestriction`** — accepts a new optional
`isFeatureGeoRestricted` param. When `true`, it short-circuits to
`isGeoRestricted: true` before any campaign-level geo checks, without
affecting `isGeoLoading`.
- **`CampaignOptInCta`** — accepts a new optional
`isFeatureGeoRestricted` prop and forwards it to
`useCampaignGeoRestriction`.
- **`PerpsTradingCampaignCTA`** — refactored to delegate the
not-opted-in path entirely to `CampaignOptInCta` with
`isFeatureGeoRestricted={!isPerpsEligible}`, removing ~65 lines of
duplicated geo-locked/join UI logic.
- **`PredictThePitchCampaignCTA`** — uses `usePredictEligibility()` and
passes `isFeatureGeoRestricted={!isPredictEligible}` to
`CampaignOptInCta`, so Predict geo-blocking now surfaces the same locked
CTA as Perps.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: Campaign CTA should block geo-restricted users from opting in
## **Manual testing steps**
```gherkin
Feature: Geo-restricted campaign CTA
Scenario: user is geo-blocked from Perps and views the Perps campaign
Given the user is in a Perps-restricted region (isPerpsEligible = false)
When the user opens the Perps Trading campaign detail page
Then a "Check eligibility" button with a lock icon is shown
When the user taps the button
Then a toast appears saying the campaign is not available in their region
And the opt-in sheet does NOT open
Scenario: user is geo-blocked from Predict and views the Predict campaign
Given the user is in a Predict-restricted region (isEligible = false from usePredictEligibility)
When the user opens the Predict The Pitch campaign detail page
Then a "Check eligibility" button with a lock icon is shown
When the user taps the button
Then a toast appears saying the campaign is not available in their region
Scenario: eligible user views the Perps campaign
Given the user is eligible for Perps
When the user opens the Perps Trading campaign detail page and is not yet opted in
Then a "Join Campaign" button is shown
When the user taps it
Then the opt-in sheet opens
```
## **Screenshots/Recordings**
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-06-08 at 18 25 06"
src="https://github.com/user-attachments/assets/b4745575-19ca-4b92-9026-46cf43d32533"
/>
### **Before**
### **After**
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [x] I've tested on Android
- [x] I've tested with a power user scenario
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
## **Pre-merge reviewer checklist**
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes who can open campaign opt-in (product eligibility + removal of
dev geo bypass); localized to Rewards campaign CTAs with solid test
coverage.
>
> **Overview**
> Adds **feature-level geo restriction** to the shared campaign opt-in
flow so Perps/Predict eligibility blocks joining through the same
**"Check eligibility"** UI as campaign geo rules.
>
> `useCampaignGeoRestriction` now accepts optional
`isFeatureGeoRestricted`: when true it treats the user as restricted
immediately, skips campaign geo resolution, and returns `isGeoLoading:
false`. **`CampaignOptInCta`** forwards a new `isFeatureGeoRestricted`
prop into that hook.
>
> **Perps** and **Predict** campaign CTAs delegate the not-opted-in path
to `CampaignOptInCta` with `isFeatureGeoRestricted={!isPerpsEligible}` /
`{!isPredictEligible}` (Predict now uses `usePredictEligibility`),
removing duplicated geo-locked/join sheet logic in Perps. Tests cover
hook behavior, prop wiring, and Predict’s geo-locked CTA.
>
> Also removes the prior `__DEV__` early return that always allowed geo
in development builds.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0a31a17. 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: Rik Van Gulck <vangulckrik@gmail.com>
…sell receive list (TSA-642) (#31235) ## **Description** In QuickBuy Sell mode the user sells the fixed position token and chooses which token to **receive**. The Receive picker (`useReceiveTokens`) only listed stablecoins (mUSD/USDC/USDT), so native tokens were never offered. This PR extends the Receive candidate set to always include the native token of every chain already covered by the stablecoin candidates, so natives and stablecoins are always visible regardless of balance. Natives are built via the existing Bridge helper `getNativeSourceToken(chainId)` and enriched through the same `enrichTokenBalance` path (the `isNativeAddress` branch already handles native balance/pricing), so no controller changes were needed. Candidates are ordered stablecoin-before-native within each chain group and the position chain is sorted first, which keeps a stablecoin as the default selection (`sellDestTokenOptions[0]`). ## **Changelog** CHANGELOG entry: Fixed QuickBuy sell flow so native tokens are always shown alongside stablecoins in the "Receive" token list. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TSA-642 ## **Manual testing steps** ```gherkin Feature: QuickBuy sell receive token list Scenario: user opens the Receive picker when selling a position Given I am on a trader position and open QuickBuy And I switch to Sell mode When I open the "Receive" token picker Then the list shows the native token and stablecoins for each supported chain And the position chain's stablecoin is selected by default And tokens I do not hold still appear with a $0.00 balance ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only expansion of receive picker options using existing bridge token helpers and enrichment; no auth or controller changes. > > **Overview** > QuickBuy **Sell** mode’s **Receive** picker now lists **native tokens** (ETH, POL, etc.) in addition to stablecoins, fixing cases where natives were never offered. > > `useReceiveTokens` builds one native per chain already covered by stablecoin candidates via `getNativeSourceToken`, merges them into the picker list, and keeps **stablecoins before natives** within each chain group so the default receive token (`sellDestTokenOptions[0]`) stays a stablecoin. Non-stable ERC-20s like WETH remain excluded. Comments on `QuickBuyReceiveScreen` were updated to describe stablecoin-or-native receive options; behavior is unchanged aside from the expanded list from the hook. > > Tests cover natives in the list, zero-address natives, preferred-chain ordering, and stablecoin-first within the preferred chain. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a02ec0d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Cursor <cursoragent@cursor.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- 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 blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> Fixes multiple issues in the MMPay fiat payment flow for `moneyAccountDeposit` transactions: 1. **Upgraded `@metamask/transaction-pay-controller` to `^23.3.0`** — Picks up the fiat `moneyAccountDeposit` fixes released in core (release/1025.0.0). 2. **Fixed fiat deposit calldata population** — For fiat deposits, `updateTokenAmount()` is now called during `handleDone` to populate nested calldata (approve + deposit) with approximate amounts at UI time, so the transaction is valid at submit time. Core re-encodes with exact amounts after settlement. 3. **Fixed buy amount calculation** — Replaced `amountFiat` with `totals.total.usd` minus `providerFiat` fees as the amount passed to `startHeadlessBuy`. This ensures the Ramps order covers relay fees in addition to the user's intended deposit amount, without double-counting the on-ramp provider fee. 4. **Suppressed no-funds alert when fiat is available** — `useAccountNoFundsAlert` now checks `useIsFiatPaymentAvailable` and skips the blocking "no funds" alert when fiat payment is an option for `moneyAccountDeposit`. 5. **Simplified fee tooltip logic** — Refactored the `Tooltip` component in `bridge-fee-row` to use a lookup map instead of chained `if`/`hasTransactionType` calls, and added `moneyAccountDeposit` to the tooltip map. 6. **Added `getAmountData` callback** — New `amount-data-callback.ts` module provides the `getAmountData` callback using `buildMoneyAccountDepositBatch` for client-side calldata re-encoding, wired into `TransactionPayController` init. ## **Changelog** <!-- mms-check: type=changelog required=true --> CHANGELOG entry: null ## **Related issues** <!-- mms-check: type=issue-link required=true --> Refs: MetaMask/core#8987 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Fiat money account deposit Scenario: user completes a fiat deposit after on-ramp settlement Given the app is running with @metamask/transaction-pay-controller@23.3.0 And the user has a connected account with no token balance When user initiates a moneyAccountDeposit flow with fiat payment Then no "insufficient funds" alert is shown And the confirmation screen shows correct fee breakdown with tooltip And the buy amount sent to Ramps equals total minus providerFiat fee And the deposit completes successfully without errors Scenario: user initiates moneyAccountDeposit without fiat payment available Given the app is running with @metamask/transaction-pay-controller@23.3.0 And the user has no tokens and no fiat payment method When user views the moneyAccountDeposit confirmation Then a blocking "no funds" alert is displayed ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> N/A — dependency version change and logic fixes only, no UI changes. ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [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. --------- Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…e component (#30800) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Fixes a race where users who import an SRP with existing funds could get stuck on the fund step of the wallet-home post-onboarding checklist. Restarting the app usually fixed it because balance data had time to settle and auto-advance could run. Root cause: skipInitialBalanceWait shows the fund step immediately after onboarding, but auto-advance depended on hasBalanceFetched + accountGroupBalance > 0. After import, balances often aren’t ready on first paint (completedOnboarding was set late, token balances still syncing). The fund step has no Skip button, so users appeared stuck until a relaunch. **Solution:** - useWalletHomeOnboardingFundStepBalanceGate — separate gate for fund-step auto-advance: - Re-evaluates on selector updates (no engine event subscriptions) - Debounces positive balance (300ms) to avoid stale positive→zero flashes - Keeps accepting updates for up to 10s when initial reading is zero/null - AccountGroupBalance — uses the new hook, improves hasBalanceFetched when accountGroupBalance catches up after groupBalance, and triggers a one-shot refreshBalance() on fund step entry when skipInitialBalanceWait is true - Authentication.dispatchLogin — sets completedOnboarding(true) at login/restore so balance controllers can fetch earlier (not only after Main mounts) - skipInitialBalanceWait behavior is unchanged: fund step still shows immediately; we just wait for a settled positive balance before auto-advancing. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed post-onboarding checklist sometimes staying on the fund step after importing a wallet that already had a balance ## **Related issues** Fixes: Refs: https://consensyssoftware.atlassian.net/browse/TMCU-851 ## **Manual testing steps** ```gherkin Feature: Post-onboarding fund step auto-advance after SRP import Scenario: Imported wallet with existing funds auto-advances from fund step Given a clean app install And homepage sections v1 and wallet-home onboarding steps are enabled When user imports an SRP for an account that already has mainnet token balance And user completes onboarding success and lands on wallet home Then the fund step is shown immediately (no loading shell) And within a few seconds the checklist auto-advances to the trade step without app restart Scenario: Truly empty imported wallet stays on fund step Given a clean app install When user imports an SRP for an account with zero mainnet balance And user lands on wallet home post-onboarding checklist Then the fund step remains visible And the user can tap Add funds to open on-ramp Scenario: App relaunch while on fund step still auto-advances when funded Given user is on fund step (step 0) with a positive balance that was not yet detected When user kills and relaunches the app Then balance loads and checklist auto-advances to trade step Scenario: Stale positive balance flash does not auto-advance Given user is on fund step with initial aggregate balance reading of zero When balance briefly flashes positive then returns to zero before settling Then checklist does not auto-advance to trade step ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes wallet-home onboarding auto-advance timing and dispatches completedOnboarding earlier at login, which can affect balance fetch timing and checklist UX across import/restore flows. > > **Overview** > Fixes imported wallets with existing funds getting **stuck on the wallet-home post-onboarding fund step** when `skipInitialBalanceWait` shows the checklist before balances settle. > > **`AccountGroupBalance`** no longer owns inline fetch timers; it uses **`useAccountGroupBalanceFetchState`** (extracted 3s timeout + faster “fetched” when aggregate balance catches up) and replaces the old `hasBalanceFetched && balance > 0` auto-advance check with **`useWalletHomeOnboardingFundStepBalanceGate`** (300ms debounce on positive aggregate, 10s grace while zero/null, no advance after grace if balance turns positive late). On fund step with skip-wait, **`useWalletHomeOnboardingBalanceRefreshEffect`** triggers a **one-shot `refreshBalance()`**. > > **`Authentication.dispatchLogin`** now dispatches **`setCompletedOnboarding(true)`** at login/restore so balance fetching can start earlier than Main mount. Tests were updated/split for the new hooks and design-system `SensitiveText` import. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7e9c499. 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 blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> Animates the Quickbuy mode toggle so that it slides nicely when picking the option. https://github.com/user-attachments/assets/44004018-1bd9-4d1b-85f2-91325f25df49 <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- mms-check: type=changelog required=true --> <!-- 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** Refs: TSA-607 <!-- mms-check: type=issue-link required=true --> Fixes: ## **Manual testing steps** N/A — simple change ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> n/a <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** n/a <!-- [screenshots/recordings] --> ### **After** n/a <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [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** > UI-only change in Quick Buy with no trade logic or API changes; minor layout-measurement edge cases on first render are the main regression risk. > > **Overview** > The Social Leaderboard **Quick Buy** buy/sell mode control no longer toggles a static `bg-muted` highlight on each segment. It now uses a single **sliding pill** (`Animated.View`) that springs between Buy and Sell, sized from `onLayout` on each option. > > **Selection feedback** adds `playSelection()` haptics when the mode changes, and the active background comes from `useTheme()` (`colors.background.muted`) instead of per-segment Tailwind classes. Sell stays disabled with reduced opacity when there is no sellable balance; font weight still reflects the selected mode. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f3601c7. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…es (#31210) ## **Description** `BridgeController.updateBatchSellTrades` accepts an `isSmartTransaction` boolean as its second argument to determine whether trade parameters should be built for smart transactions. The mobile implementation in `useBatchSellQuoteData` was calling the method without this argument, so STX-eligible users would always have their trades built without STX support, regardless of their opt-in status or network eligibility. This change reads the `isSmartTransaction` flag via `selectShouldUseSmartTransaction` (the same selector already used by `useBatchSellQuoteRequest` for the quote request side) and forwards it to `updateBatchSellTrades`, aligning mobile with the extension implementation in `ui/ducks/batch-sell/actions.ts`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: https://consensyssoftware.atlassian.net/browse/SWAPS-4586 ## **Manual testing steps** ```gherkin Feature: Batch Sell smart transactions flag propagation Scenario: user with STX disabled submits batch sell trades Given the user has STX disabled or is on an unsupported network When the batch sell review screen finishes loading quotes Then updateBatchSellTrades is called with isSmartTransaction=false Scenario: user with STX enabled submits batch sell trades Given the user has STX opted-in and is on a supported network (e.g. Mainnet) When the batch sell review screen finishes loading quotes Then updateBatchSellTrades is called with isSmartTransaction=true ``` ## **Screenshots/Recordings** N/A — no UI changes, logic-only fix. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example <!-- For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). --> ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes how batch-sell trades are built (STX vs standard) based on per-chain eligibility; scope is limited to bridge hooks but affects the transaction submission path. > > **Overview** > Batch Sell on mobile now resolves **smart transaction (STX) eligibility per source chain** and threads that flag through quote and trade flows, matching extension behavior. > > `useBatchSellQuoteData` passes **`isSmartTransaction`** as the second argument to `BridgeController.updateBatchSellTrades`, so trade params are built with STX when the user is opted in and the network qualifies. `useBatchSellQuoteRequest` no longer calls `selectShouldUseSmartTransaction` without a chain: both hooks normalize the first source token’s chain via new **`getMaybeHexChainId`** (`app/util/bridge`) before reading STX state. > > **`@metamask/bridge-controller`** is bumped to **^74.0.0** (lockfile updated). Unit tests cover STX true/false, chain ID normalization, and empty source-token edge cases. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a739475. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…1128) <!-- 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 blocks the PR check. 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? --> Bumping `@metamask/network-controller` to `^32.0.0` and `@metamask/controller-utils` to `^12.1.0`: ```markdown ## [32.0.0] ### Changed - **BREAKING:** Remove Sei, MegaETH, Avalanche, and ZKSync from list of default networks ([#8767](MetaMask/core#8767)) - You will need to add them as network configurations first before switching to them. - Bump `@metamask/controller-utils` from `^12.0.0` to `^12.1.0` ([#8774](MetaMask/core#8774)) ``` ## **Changelog** <!-- mms-check: type=changelog required=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 --> Closes: https://consensyssoftware.atlassian.net/browse/WPN-1239 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> - Onboard as new user on a fresh install - Observe that zkSync, Avalanche, and MegaETH are not enabled by default ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A <!-- [screenshots/recordings] --> ### **After** <!-- [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`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > The breaking default-network removal can affect users or flows that relied on Avalanche, ZKSync, MegaETH, or Sei being preconfigured; otherwise this is primarily a dependency and test-fixture alignment change. > > **Overview** > Bumps **`@metamask/network-controller`** to **32.0.0** and **`@metamask/controller-utils`** to **12.1.0** (including `package.json` resolutions and `yarn.lock`). > > That **breaking** network-controller release drops **Sei, MegaETH, Avalanche, and ZKSync** from built-in default EVM networks, so fresh installs no longer ship those chain configs unless users add them manually. > > Test fixtures are aligned: **`initial-background-state.json`** no longer seeds MegaETH, ZKSync, or Avalanche mainnet entries, and **`AddressSelector.test.tsx`** updates the expected EVM-only network list to match. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a8aa9b6. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Updates Mobile to consume `@metamask/transaction-controller` v67
directly and removes the stale local patch for v66. The patched
behaviour (extra-transaction `isInternal` flagging) is now included
upstream in v67.
Transaction Controller v67 performs gas fee estimation, transaction
signing, EIP-1559 compatibility checks, and network state/registry
lookups through its controller messenger. This PR delegates those
runtime actions on the TransactionController messenger and removes
constructor callbacks that are no longer part of the v67 options
surface.
Hook construction is extracted to `app/util/transactions/hooks`,
mirroring the pattern used in the extension bump. Init stays focused on
controller construction; Predict, MetaMask Pay, 7702 delegation, Smart
Transaction, and batch publish behaviour lives in hook-specific tests.
Hook wiring uses messenger calls and adapters rather than direct
controller instances.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: Transaction Controller v67 dependency bump
Scenario: Standard ETH transaction reaches a terminal state
Given the app is running with TC67
When a user sends a standard ETH transaction
Then the transaction confirms or fails without unhandled errors
Scenario: Smart transactions flow completes
Given the app is running with TC67 and Smart Transactions enabled
When a user sends a transaction via the STX path
Then the publish hook resolves and the transaction reaches a terminal state
```
## **Screenshots/Recordings**
N/A
### **Before**
### **After**
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [x] I've tested on Android
- [x] I've tested with a power user scenario
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- mms-check directive vocabulary — read by .github/scripts/shared/pr-template-checks.ts at module load to build the validation plan. Directives are invisible in rendered markdown and must NOT be removed or edited without updating the validator registry. type=text Section must contain non-placeholder prose. type=changelog Section must have a valid CHANGELOG entry: line. type=issue-link Section must have a Fixes:/Closes:/Refs: line with a value. type=manual-testing Section must have real testing steps or an explicit N/A. type=screenshot Section must have evidence (image/URL) or an explicit N/A. type=checklist Section must have all checkboxes consciously checked. required=true|false Whether a missing/invalid section blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** Removes the completed `stickyButtonsAbTest` A/B test that compared "Swap" vs "Convert" labels on the Token Details sticky footer. The experiment has been deployed to 100%, and we are keeping **Swap** as the permanent label. This change removes all related feature flag wiring, analytics attribution, and test coverage for the experiment, and hardcodes the swap button to use `asset_overview.swap`. The unused `asset_overview.convert` locale key was also removed from all language files. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- mms-check: type=changelog required=true --> <!-- 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: emove sticky buttons AB test "Swap" vs "Convert" ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3077 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> Check that the button says Swap instead of Convert ## **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** There was a FF ### **After** There is no FF ## **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 label cleanup and experiment teardown only; swap/buy behavior and other AB tests are unchanged. > > **Overview** > Removes the finished **`stickyButtonsAbTest`** experiment that compared **Swap** vs **Convert** on the Token Details sticky footer. The swap CTA is now always **`asset_overview.swap`** via `TokenDetailsStickyFooter` (no `useABTest`). > > Cleanup spans **`abTestConfig`**, **`abTestAnalyticsRegistry`**, the **`stickyButtonsAbTest`** entry in **`feature-flag-registry`**, and sticky-footer attribution in **`useSubmitBridgeTx`**. Tests drop A/B mocks and variant cases; bridge submit tests no longer mock a fourth `useABTest` call for this flag. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 16d2abf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
… up deposit navigation (MUSD-898) (#31084) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Clicking `Add` from a token row on the Money Account home screen navigated to the deposit confirmation. Two issues made this feel slow/janky (MUSD-898): 1. **~1s delay on subsequent `Add` taps.** Initiating a deposit creates an unapproved transaction batch. The navbar back button rejects it, but leaving via the iOS swipe gesture or the Android hardware back button does **not** — so the unapproved batch lingers in state. On the next `Add` tap, `useConfirmNavigation` detects the stale pending transaction and takes a reject-then-defer path: it rejects the old batch and only navigates after the rejection round-trips through `ApprovalController` → Redux → re-render. That serialized round-trip is the ~1s. 2. **Layout jump on first load.** The projected-balance line rendered `null` while the vault APY was loading, then popped in once loaded, pushing content down. This PR reuses the existing `useClearConfirmationOnBackSwipe` machinery (already used by Predict deposit) to reject the lingering money-account deposit/withdraw batch on gesture/hardware back-out. With no stale transaction left behind, the `useConfirmNavigation` detour is skipped and navigation is instant. It also reserves the projected-balance line height with a skeleton while the APY loads, so the line fills reserved space instead of growing the layout. No `useConfirmNavigation` reorder was made: a literal navigate-first approach would briefly flash the stale confirmation (`useApprovalRequest` returns the first pending approval), so the existing reject-then-navigate path is kept as the correct guard for the rare back-out-then-immediate-retap race — it is simply no longer hit in the normal flow. ## **Changelog** CHANGELOG entry: Fixed sluggish navigation and a layout shift when adding money to a Money Account. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-898 ## **Manual testing steps** ```gherkin Feature: Money Account deposit navigation Scenario: user opens the Add money screen repeatedly Given the user is on the Money Account home screen When the user taps "Add" on a token row And the user leaves via the swipe-back or hardware-back gesture And the user taps "Add" again Then the deposit confirmation opens immediately without the ~1s delay And the projected balance line does not cause the layout to jump ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/552a5b61-f960-4ca5-9093-4714ade4b1ed ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Confirmation UX and loading placeholder only; reuses existing back-swipe reject hook with added transaction types and no auth or payment logic changes. > > **Overview** > Fixes sluggish **Add money** navigation and a layout jump on the Money Account deposit confirmation screen. > > **`CustomAmountInfo`** now treats money account **deposit** and **withdraw** like Predict deposit for back navigation: `useClearConfirmationOnBackSwipe` rejects the pending batch on swipe-back and hardware back, not only on the navbar. That clears unapproved batches that previously lingered and forced a slow reject-then-navigate path on the next **Add** tap. Predict-only `onBeforeReject` (clear pending predict deposit) is unchanged. > > **`BalanceProjection`** shows a fixed-size **skeleton** while vault APY is loading instead of rendering nothing, so the projected balance line no longer pops in and shifts layout once APY arrives. > > Tests cover the new back-swipe behavior for money account flows and the loading skeleton. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4e25e4c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** This PR uuseHwBatchSignTracker which orchestrates hardware-wallet signing for multi-transaction bridge/swap batches by detecting pending approvals from the ApprovalController, queuing them, and driving sequential device confirmation. It anchors a batchId from the first approved transaction, tracks signing progress through transactionStatusUpdated events, and exposes a cancelCurrentBatch function that aborts all in-flight txs, rejects pending approvals, wipes failed tx nonces to prevent gaps, and resets internal state for retry. A generation counter and stale-batch-ID set ensure that late events from cancelled or retried batches are ignored, while special handling covers smart-transaction (STX) submission failures that arrive after signing succeeds. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Refs: https://consensyssoftware.atlassian.net/browse/MUL-1718 ## **Manual testing steps** N/A — Cannot be tested. its not wired up. ## **Screenshots/Recordings** Cannot be tested. its not wired up. <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [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] > **Medium Risk** > New transaction/approval orchestration with cancel, wipe, and STX edge cases is complex and security-adjacent, but the hook is not wired to production flows yet and behavior is heavily unit-tested. > > **Overview** > Adds **`useHwBatchSignTracker`**, a new hook that wires hardware-wallet signing to multi-step bridge/swap **transaction batches** (not yet integrated into the swaps UI per the PR). > > When enabled for a `fromAddress`, it listens to **TransactionController** and **ApprovalController** events, maps bridge/swap batch txs to **`updateHardwareWalletsSwaps`** events (Signing / Signed / Rejected / TransactionFailed), tracks **`confirmationTxId`**, and exposes **`cancelCurrentBatch`** to abort in-flight signing, reject scoped pending approvals, drop only pre-broadcast txs, wait for terminal statuses, and **`wipeTransactions`** on related chains so failed nonces do not block retries. **Stale-batch** and **`retryGenerationRef`** guards ignore late events from cancelled or retried flows; the approval queue runs through **`executeHardwareWalletOperation`** with special handling for device-not-ready retries, Keystone cancel, and **STX** `STX_NO_HASH_ERROR** after sign. > > **`executeHardwareWalletOperation`** gains optional **`showConfirmation`** (skip awaiting-confirmation UI while still running readiness + execute) and exports **`HardwareWalletOperationType`**. Coverage is a large new **`useHwBatchSignTracker.test.ts`** suite plus small **`executeHardwareWalletOperation`** tests for `showConfirmation: false`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ebee541. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…lder→AnalyticsEventBuilder (assets files) (#31251) ## **Description** Migrates assets-related test files from the legacy analytics system (`useMetrics`, `MetricsEventBuilder`, `addTraitsToUser`) to the new system (`useAnalytics`, `AnalyticsEventBuilder`, `identify`). Part of the analytics migration cleanup series. All changes are in files owned by the assets team. Files migrated: `DeFiPositionsListItem.test.tsx`, `TokenList.test.tsx`, `TokenListItem.test.tsx`, `NftDetails.test.ts`. Note: `TokenListItem.test.tsx` has a pre-existing test failure on `main` unrelated to this change (tracked by #31019). ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — analytics-only refactor, no behaviour change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Changes are limited to test mocks and import paths; runtime wallet/assets behavior is unchanged. > > **Overview** > Updates **assets-team unit tests** so mocks and assertions match the new analytics API—no production code changes. > > **DeFi / token list tests** swap `MetricsEventBuilder` for `AnalyticsEventBuilder` (imports and `jest.requireActual` paths under `util/analytics`). DeFi navigation analytics expectations now build events with `AnalyticsEventBuilder.createEventBuilder`. > > **TokenList.test.tsx** extends the `useAnalytics` mock with `identify` and a default `isDataRecorded` implementation so it mirrors the current hook surface. > > **TokenListItem.test.tsx** loads `MetaMetricsEvents` from `core/Analytics` instead of the legacy `useMetrics` path for mUSD CTA event assertions. > > **NftDetails.test.ts** aligns the `useAnalytics` mock with the new API (`identify`; drops unused legacy mock fields like `addTraitsToUser` / `isDataRecorded` where no longer needed). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e33ebdf. 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>
…n TransactionField test (engagement) (#31254) ## **Description** Migrates the `TransactionField` notification test from `MetricsEventBuilder` to `AnalyticsEventBuilder`. Part of the analytics migration cleanup series. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — test-only change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Test-only import and assertion updates with no runtime or production impact. > > **Overview** > Updates **`TransactionField.test.tsx`** so notification copy analytics expectations use **`AnalyticsEventBuilder`** from `util/analytics` instead of **`MetricsEventBuilder`** from `core/Analytics`, including the import, the `useAnalytics` mock’s `createEventBuilder`, and the asserted event built in the copy-button test. > > No production code changes; behavior under test is unchanged aside from aligning with the analytics migration (#26686). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5981942. 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>
…Menu test (core-ux) (#31253) ## **Description** Removes the stale `MetricsEventBuilder` mock reference from the `AccountsMenu` test file. The component was already migrated to `AnalyticsEventBuilder`; this cleans up the leftover mock. Part of the analytics migration cleanup series. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — test-only change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Test-only cleanup with no production or runtime behavior changes. > > **Overview** > Removes the unused **`jest.mock` for `MetricsEventBuilder`** from `AccountsMenu.test.tsx` as part of analytics migration cleanup. > > Analytics in these tests is already covered by the **`useAnalytics`** mock (`trackEvent`, `createEventBuilder`); the old core builder mock was redundant and no longer referenced. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c1de9c1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Cursor <cursoragent@cursor.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- 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 blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> This is a follow-up refinement to the native fiat deposit gating introduced in #31209. `useHasNativeFiatProvider` previously returned `true` whenever **any** native provider merely existed in the user's region (`providers.some((p) => p.type === 'native')`). That is not the condition that actually determines the deposit experience. Headless fiat deposit (MM Pay / Money Account, Perps, Predict) is native-only for v0, but `RampsController` resolves the **currently selected (preferred) provider** first (see `resolveProviderIdsForQuote`) rather than relying on the headless quote's `restrictToKnownOrNativeProviders` auto-selection. As a result, an aggregator preferred provider — carried over from order history, or the aggregator `/providers/transak` matched by the loose `"transak"` name check in `determinePreferredProvider` — could run a **non-native** deposit experience even though the gate said a native provider was available. This change gates on the **selected** provider's type instead (`selectedProvider?.type === 'native'`), so the flow is correctly blocked whenever the preferred provider is an aggregator or no native provider is selected. The hook remains read-only — it never mutates provider selection or controller state, so the standalone Buy flows are unaffected. The accompanying unit test was updated to assert against the selected-provider behavior. ## **Changelog** <!-- mms-check: type=changelog required=true --> CHANGELOG entry: null <!-- Internal refinement of an unreleased v0 gating hook (follow-up to #31209); no user-visible change on its own. If release engineering would rather track it, swap to: CHANGELOG entry: Fixed native fiat deposit gating to key off the selected provider, so the cash deposit option no longer appears when an aggregator provider would handle the deposit. --> ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3615 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Native fiat deposit gating Scenario: Preferred provider is an aggregator Given the user's region resolves a native provider And the user's selected/preferred provider is an aggregator (e.g. carried over from a previous order) When the user opens the cash deposit / add money flow (MM Pay, Money Account, Perps or Predict) Then the native fiat deposit option is not offered Scenario: Preferred provider is native Given the user's selected/preferred provider is a native provider (e.g. Transak Native) When the user opens the cash deposit / add money flow Then the native fiat deposit option is offered Scenario: No provider selected Given the user has no selected provider When the user opens the cash deposit / add money flow Then the native fiat deposit option is not offered ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> N/A — logic-only change to a read-only gating hook; there is no visual change beyond whether the existing option is offered. Behavior is covered by `app/components/UI/Ramp/hooks/useHasNativeFiatProvider.test.ts`. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [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 money/deposit UX gating logic; wrong behavior could hide or show fiat deposit incorrectly, but the hook stays read-only and scope is limited to one boolean gate. > > **Overview** > **`useHasNativeFiatProvider`** no longer treats “a native provider exists in the region” as sufficient for headless fiat deposit (MM Pay, Money Account, Perps, Predict). It now returns **`true` only when the selected/preferred provider’s `type` is `native`**, matching how `RampsController` resolves quotes so aggregator preferences (e.g. from order history or loose Transak matching) do not incorrectly expose the deposit path. > > Unit tests were reworked to mock **`selectedProvider`** (not just the provider list), including the case where a native provider is available but an aggregator is selected. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1e01e31. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com>
…n transaction controller metrics (confirmations) (#31252) ## **Description** Migrates the transaction controller event handler from the legacy `MetricsEventBuilder` to `AnalyticsEventBuilder`. Also removes the `setSaveDataRecording` call which was part of the now-removed data-recording chain. Part of the analytics migration cleanup series. All changes are in files owned by the confirmations team. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — analytics-only refactor, no behaviour change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Analytics-only refactor with no user-facing behavior change; main nuance is omitting saveDataRecording on tracked events until the analytics-controller types align. > > **Overview** > Transaction controller metrics now build events with **`AnalyticsEventBuilder`** instead of legacy **`MetricsEventBuilder`**, including **`generateEvent`** in `utils.ts` and the handlers in `metrics.ts`. > > Tracking no longer calls **`setSaveDataRecording`** when forwarding events to **`AnalyticsController:trackEvent`**. A temporary **`initMessenger` cast** works around a type mismatch until `@metamask/analytics-controller` drops **`saveDataRecording`** from its event type. > > Tests use a **single mocked `AnalyticsEventBuilder`** and assert against that builder for all transaction metric handlers. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b1d9f07. 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>
## **Description** Delegates MetaMask agent skills sync/setup to the shared `@metamask/skills` CLI instead of keeping repo-local sync/postinstall wrappers. Default install behavior stays conservative: `metamask-skills postinstall` refreshes the public `MetaMask/skills` cache best-effort, but generated local skills are only regenerated when developers run `yarn skills` or opt in with `SKILLS_AUTO_UPDATE=1`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: MetaMask/skills#24 Refs: MetaMask/decisions#162 (ADR 57) ## **Manual testing steps** ```gherkin Feature: Agent skills setup Scenario: Manual sync uses the shared package Given the shared @metamask/skills CLI is installed When a developer runs yarn skills Then Mobile skills are synced through metamask-skills sync Scenario: Default install does not regenerate local skills Given SKILLS_AUTO_UPDATE is unset When the skills postinstall hook runs Then it refreshes the public skills cache without regenerating local skill outputs Scenario: Opt-in install regenerates local skills Given SKILLS_AUTO_UPDATE=1 When the skills postinstall hook runs Then it refreshes the public skills cache and runs sync best-effort ``` ## **Screenshots/Recordings** N/A — developer tooling only, no UI changes. ### **Before** N/A ### **After** N/A ## **Validation** Validated against the published `@metamask/skills@0.1.0`: - `yarn install` resolves `@metamask/skills@npm:0.1.0` and links the `metamask-skills` bin - `yarn skills:postinstall` (`metamask-skills postinstall`) runs clean (exit 0) and is a no-op without opt-in - `metamask-skills --help` exposes `list/search/describe/sync/postinstall/install` - packed CLI `sync`/`postinstall --dry-run` with `SKILLS_AUTO_UPDATE=1` and `METAMASK_SKILLS_TARGET_REPO=metamask-mobile` ## **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. ## **How to use** Run manual sync: ```bash yarn skills ``` To opt into best-effort regeneration during install/setup, add this to `.skills.local` or your shell: ```bash SKILLS_AUTO_UPDATE=1 ``` Optional filters work through the shared installer: ```bash SKILLS_DOMAINS=testing,coding SKILLS_INCLUDE=agentic/recipe-harness ``` Use `METAMASK_SKILLS_TARGET_REPO` locally for forks or unusual remotes that should use the canonical `metamask-mobile` overlays.
## **Description**
This pull request improves the handling and display of long network
names across several UI components to ensure they are visually
constrained and do not overflow or wrap undesirably. The changes
introduce line limits and styling adjustments for text elements, and add
corresponding tests to verify this behavior.
**UI improvements for long network names:**
* The `MultichainAddressRow` component now truncates long network names
to a single line by setting `numberOfLines={1}` on the relevant `Text`
element, with a new test to confirm this behavior.
* The `NetworkConnectionBanner` component limits the primary message
(which includes the network name) to two lines, and a test is added to
ensure this.
**Styling and layout enhancements:**
* Both `NetworkMultiSelectorList` and `NetworkSelector` components now
render network names in a single line (`numberOfLines={1}`) and apply a
flex style to prevent overflow, with new or updated styles and tests
verifying correct rendering.
**Test and import adjustments:**
* Test files are updated to reflect the new styles and props, including
mock style objects and import corrections.
These changes ensure that long network names are consistently displayed
in a user-friendly manner throughout the app.
## **Changelog**
<!-- mms-check: type=changelog required=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 network name length label when too long
## **Related issues**
<!-- mms-check: type=issue-link required=true -->
Fixes: network name label is rendering too long
## **Manual testing steps**
<!-- mms-check: type=manual-testing required=true -->
```gherkin
Prerequisites
- Use a build with gasFeesSponsoredNetwork feature flag enabled for at least one network (e.g. Monad Mainnet)
- Add a custom network with a very long name (e.g. "Monad Mainnet YOYOMI OK.OK.OK.OK.OK.OK.OK.OK.OK").
- Or alternatively change a current network name with a very long name.
---
NetworkSelector (Network pill sheet)
1. From Wallet home, go to tokens menu then Popular networks.
2. Verify the sponsored network name truncates to 1 line with ellipsis next to the "No network fee" pill.
MultichainAddressRow (Receiving address screen)
3. From Wallet home, tap Receive → verify the long network name truncates to 1 line with ellipsis.
NetworkConnectionBanner
4. Add a custom network with a very long name and a broken/unreachable RPC URL.
5. Wait ~30 s and verify the "Unable to connect to …" banner appears capped at 2 lines.
```
## **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**
<img width="200" height="400" alt="BEFORE-receiving address"
src="https://github.com/user-attachments/assets/f23413e9-3c9d-4be9-910c-1a784b5655b8"
/>
### **After**
<img width="200" height="400" alt="network name ellipsis"
src="https://github.com/user-attachments/assets/71073596-8934-45f1-9f05-6f08c4704cbf"
/>
<img width="200" height="400" alt="AFTER-receiving address"
src="https://github.com/user-attachments/assets/3beeb8f3-e3f0-477a-9c6c-2e0317967689"
/>
<img width="200" height="400" alt="connection error network wrapped"
src="https://github.com/user-attachments/assets/2127b329-58c2-4cb2-95ab-360e4f085035"
/>
## **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**
> Display-only text truncation and flex layout tweaks with matching
tests; no networking, auth, or data logic changes.
>
> **Overview**
> Long custom network names no longer blow out list rows, receive
screens, or connection banners.
>
> **`MultichainAddressRow`** caps the network label at **one line**
(`numberOfLines={1}`). **`NetworkConnectionBanner`** caps the primary
status string (which embeds the network name) at **two lines**. In
**`NetworkSelector`** and **`NetworkMultiSelectorList`**, gas-sponsored
rows now use a single-line name with **`flex: 1` / `minWidth: 0`** so
ellipsis works beside the “No network fee” tag, and the title row uses
**`items-center`** for alignment.
>
> Unit tests assert the new `numberOfLines` and flex styles where the
title is a custom React node (plain string titles in cells are
unchanged).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
60c83a1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…r→AnalyticsEventBuilder, addTraitsToUser→identify (unowned files) (#31249) ## **Description** Migrates the remaining unowned files from the legacy analytics system (`useMetrics`, `MetricsEventBuilder`, `addTraitsToUser`) to the new system (`useAnalytics`, `AnalyticsEventBuilder`, `identify`). This is part of the analytics migration cleanup series. These files have no CODEOWNERS entry, so this PR can be reviewed and merged by any mobile-platform contributor. Files migrated: - `DeleteWalletModal/index.tsx` — `useMetrics` → `useAnalytics` - `AccountStatus/index.tsx` — `useMetrics` → `useAnalytics` - `backupUtils.ts` — `addTraitsToUser` → `identify` - Various test files — updated mocks and stale mock removal ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — analytics-only refactor, no behaviour change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Refactor-only import and API renames with test mock updates; no intended change to analytics payloads or user-facing behavior. > > **Overview** > Finishes analytics cleanup for **unowned** files by swapping legacy **`MetricsEventBuilder`** / **`useMetrics`** usage for **`AnalyticsEventBuilder`** (`util/analytics`) and **`useAnalytics`**, with onboarding flows still going through **`trackOnboarding`**. > > **Production:** `DeleteWalletModal`, `AccountStatus`, and `backupUtils` now build events via **`AnalyticsEventBuilder.createEventBuilder`** instead of the core metrics builder (same events and properties). > > **Tests:** Perf/unit tests mock **`useAnalytics`** instead of **`useMetrics`**; several suites adopt **`createMockUseAnalyticsHook`** / **`createMockEventBuilder`**; **`NetworksManagementView`** mock uses **`identify`** instead of **`addTraitsToUser`**; **`TrendingView`** drops **`withMetricsAwareness`** from the mock. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 97a1919. 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>
…nd useMetrics→useAnalytics (web3auth/onboarding files) (#31250) ## **Description** Migrates all web3auth and onboarding files from the legacy analytics system (`useMetrics`, `MetricsEventBuilder`) to the new system (`useAnalytics`, `AnalyticsEventBuilder`). Part of the analytics migration cleanup series. All changes are in files owned by the web3auth/onboarding team. Files migrated: - `AccountBackupStep1`, `AccountBackupStep1B`, `ManualBackupStep1-3`, `ImportFromSecretRecoveryPhrase`, `Onboarding`, `ChoosePassword`, `WalletCreationError/SRPErrorScreen` ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — analytics-only refactor, no behaviour change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Mechanical import/API rename across onboarding analytics with no wallet or auth logic changes; main risk is test/mock drift if event payloads diverge from the legacy builder. > > **Overview** > This PR continues the analytics migration in **web3auth/onboarding** screens by swapping **`MetricsEventBuilder`** for **`AnalyticsEventBuilder`** (`util/analytics`) everywhere onboarding events are built before `trackOnboarding`. > > Touched flows include account backup steps, manual backup, import-from-SRP, choose password, onboarding root, and wallet-creation error. **Runtime behavior is intended to stay the same**—same events, properties, and `trackOnboarding` wiring; only the builder import and class name change. > > **Tests** are aligned with the new stack: mocks target `AnalyticsEventBuilder` instead of `MetricsEventBuilder`, legacy **`MetaMetrics` singleton** mocks are dropped where **`useAnalytics`** already covers the surface, and **`addTraitsToUser`** expectations become **`identify`**. Onboarding tests drop **`withMetricsAwareness`** HOC wiring in favor of the **`useAnalytics`** mock. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 33d3acd. 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>
…ken held (#31393) ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> On the Token Details screen, the Swap button and the QuickBuy (lightning/flash) icon were both gated on `selectHasEligibleSwapSource`, which the footer called with the currently-viewed token **excluded**. As a result, **a user whose only funded asset was the token they were viewing (e.g. holding only ETH, on the ETH page) saw neither control, and only the fiat Buy fallback was shown**. This is incorrect: the swap handler (`useHandleOnSwap`) already swaps the held token *away* when the user holds it, and QuickBuy's sell mode operates on the position token. So holding only the viewed token is a perfectly valid reason to surface Swap and QuickBuy. The fix calls the selector with no exclusion args in `useStickyTokenActions`, so the viewed token counts as a fundable/swappable asset. The selector's optional `excludedChainId` / `excludedAddress` parameters are intentionally retained for any future caller that genuinely needs "any funded asset except X". Behavioral delta: for a held token that is not fiat-buyable and with no other holdings, the Buy on-ramp fallback no longer shows; Swap is shown instead. For buyable tokens (e.g. ETH) both still show. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed the Swap and Quick Buy buttons not appearing on the token details screen when the only funded asset was the token being viewed. ## **Related issues** Fixes: Issue where the Swap button wouldn't show, preventing me from swapping a token I actually hold. ## **Manual testing steps** ```gherkin Feature: Token details trade actions for a single-asset wallet Scenario: User holding only the viewed token sees Swap and Quick Buy Given my wallet holds a positive balance of only one token (e.g. ETH) And I have no other funded assets When I open the Token Details screen for that token Then the Swap button is visible And the Quick Buy (lightning) icon is visible And tapping Quick Buy opens the QuickBuy sheet where I can sell the token ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="1440" height="805" alt="image" src="https://github.com/user-attachments/assets/4e58144c-218a-473c-ad91-88c06c01499a" /> ### **After** <img width="694" height="919" alt="image" src="https://github.com/user-attachments/assets/b095e246-7584-41c1-a19f-01492669cd16" /> ## **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** > Localized change to swap-eligibility gating and footer visibility on Token Details; no auth, payments, or data-layer changes. > > **Overview** > Fixes Token Details **Swap** and **Quick Buy** staying hidden when the user’s only funded asset is the token on screen. > > `useStickyTokenActions` no longer passes the viewed token into `selectHasEligibleSwapSource` as an exclusion. **`selectHasEligibleSwapSource`** is simplified to a state-only check: any asset with positive fiat balance counts, including the current token, since that balance is a valid swap source. > > Tests now assert the hook uses the selector without exclusions and that a single funded “viewed” token yields eligibility **true**. For wallets with only one non–fiat-buyable holding, the footer may show **Swap** instead of the Buy on-ramp fallback when swap eligibility is true. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5722fd1. 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>
…st (earn) (#31255) ## **Description** Renames `addTraitsToUser` to `identify` in the `EmptyStateCta` earn test mock, completing the migration to the new analytics API. Part of the analytics migration cleanup series. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: #26686 ## **Manual testing steps** N/A — test-only change. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Test-only mock renames with no runtime or analytics behavior changes. > > **Overview** > Updates the **`useAnalytics` mock** in `EmptyStateCta.test.tsx` so it matches the migrated analytics API: **`addTraitsToUser` → `identify`**, **`getMetaMetricsId` → `getAnalyticsId`**, and drops **`isDataRecorded`** from the mock shape. > > No production or component behavior changes—test setup only, as part of the broader analytics migration cleanup (refs #26686). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9e52538. 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>
…noise on first heartbeat timeout (#31387) ## **Description** The RTDS WebSocket (Polymarket crypto price feed) had two bugs in its heartbeat/reconnect path, surfaced by Sentry issue [METAMASK-MOBILE-5XNQ](https://metamask.sentry.io/issues/METAMASK-MOBILE-5XNQ/). **Bug 1 — Infinite reconnect loop** `MAX_RECONNECT_ATTEMPTS` was bypassed entirely for heartbeat-triggered reconnects because `rtdsReconnectAttempts` resets to `0` on every successful `onopen`. If the RTDS server accepts TCP connections but stops sending data (or responding to pings), the heartbeat would fire → close the socket → `onclose` → `scheduleRtdsReconnect` → successful `onopen` → reset to 0 → repeat indefinitely. Fix: added a separate `rtdsHeartbeatTimeouts` counter that accumulates across reconnects and gates `scheduleRtdsReconnect` independently. **Bug 2 — Noisy Sentry errors for transient blips** `Logger.error()` was called on the very first heartbeat timeout. The Sentry event showed `sinceLastMessageMs: 15341` — only 341 ms over the 15 000 ms threshold — consistent with a brief network blip that auto-recovers on reconnect. Fix: the first timeout logs to `DevLogger` only; only repeated timeouts (counter `> 1`, i.e. the problem persists after a reconnect) escalate to `Logger.error` with a `heartbeatTimeouts` count in context. **Counter lifecycle:** | Event | `rtdsHeartbeatTimeouts` | |---|---| | First heartbeat timeout | +1 (= 1, DevLogger only) | | Reconnects but still stale | +1 (≥ 2 → Sentry) | | Counter `> MAX_RECONNECT_ATTEMPTS` (5) | Stops reconnecting | | `disconnectRtds()` / `reconnectAll()` | Reset to 0 | ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://metamask.sentry.io/issues/METAMASK-MOBILE-5XNQ/ ## **Manual testing steps** ```gherkin Feature: RTDS WebSocket heartbeat resilience Scenario: user opens Predict with crypto markets visible Given the Predict feature is enabled and crypto markets are loaded When the RTDS WebSocket connection goes briefly silent (< 30 s) Then the app silently reconnects without logging a Sentry error Scenario: RTDS server is reachable but consistently non-responsive Given the RTDS WebSocket connects successfully (TCP open) When no messages arrive for 15 s across multiple reconnect cycles Then a Sentry error is logged after the second stale timeout And reconnection stops after MAX_RECONNECT_ATTEMPTS heartbeat timeouts ``` ## **Screenshots/Recordings** N/A — this is an internal error-handling and Sentry-noise fix with no visible UI change. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### 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 ## **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** > Localized Predict Polymarket WebSocket resilience and observability; no auth or payment paths, with unit tests covering the new behavior. > > **Overview** > Hardens **RTDS** (Polymarket crypto price) WebSocket heartbeat handling in `WebSocketManager`. > > A new **`rtdsHeartbeatTimeouts`** counter survives successful reconnects so **`scheduleRtdsReconnect`** stops after the same cap as TCP failures when the server stays open but silent—fixing a loop where **`rtdsReconnectAttempts`** reset on every **`onopen`**. > > On stale detection, the **first** timeout only **`DevLogger`** logs and still forces reconnect; **`Logger.error`** (Sentry) runs only when timeouts persist after reconnect (**`> 1`**), with **`heartbeatTimeouts`** in context. The counter resets on **`disconnectRtds()`** and when **`reconnectAll()`** reconnects RTDS. > > Tests split “no Sentry on first blip” vs structured **`Logger.error`** on repeated stale timeouts. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c490554. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Make a pilot migration for `TabEmptyState` component. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-283 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/2e122b89-a5f9-410c-a4de-ee526666a9f6" /> ### **After** <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/369671e4-1ab1-4601-b3fd-f8b12fd6f5ca" /> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk UI-only change that swaps the `TabEmptyState` import source and updates the unit test mock; primary risk is minor styling/prop-behavior differences from the new design-system version. > > **Overview** > Migrates the `CollectiblesEmptyState`, `DefiEmptyState`, and `TokensEmptyState` components to import `TabEmptyState`/`TabEmptyStateProps` from `@metamask/design-system-react-native` instead of the local `component-library/components-temp` implementation. > > Updates `TokensEmptyState.test.tsx` to mock `TabEmptyState` from the design-system package (while preserving other exports via `jest.requireActual`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit df95f16. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This PR updates the change log for 7.82.0. (Hotfix - no test plan generated.) --------- Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com> Co-authored-by: tommasini <tommasini15@gmail.com> Co-authored-by: sleepytanya <104780023+sleepytanya@users.noreply.github.com> Co-authored-by: sleepytanya <sleepytanya@gmail.com>
🚀 RC Builds Ready for Testing
More Info
🛡️ Build Environment
API URLs & Details
Build Flags:
🍒 What's in this RCCherry-picks (21 commits)
Changelog (3 commits from main at RC cut)
AI Test Plan
Executive SummaryRelease Focus: Major feature expansion across Rewards (PredictThePitch campaign, VIP Referee program), Perps (products/watchlist redesign), Money (card transactions, analytics), and a significant navigation stack migration from Stack to NativeStack throughout MainNavigator. Key Changes:
Critical Areas: MainNavigator NativeStack migration - all navigation transitions, modal presentations, and screen animations across the entire app, Hardware wallet swap/bridge batch signing flow, Rewards Navigator refactoring - deeplink handling moved, subscription guard logic changed, Notification settings preferences persistence and optimistic updates, Money card transaction merging with existing activity feed Overall Risk: HIGH Recommendation: Conditional go - the NativeStack migration touches every navigation path in the app and the Rewards Navigator deeplink/subscription logic was significantly restructured; these two areas require thorough regression before release. Hardware wallet batch signing is new and untested in production. Recommend focused regression on navigation, hardware wallet flows, and Rewards entry/exit before shipping. Release Scenarios (16)High Risk Scenarios (9)1. Navigation - MainNavigator NativeStack MigrationRisk Level: HIGH Why This Matters: MainNavigator.js replaced all Stack.Navigator/Stack.Screen with NativeStack.Navigator/NativeStack.Screen. Key prop changes: cardStyle→contentStyle, animationEnabled:false→animation:'none', and screenOptions structure changed. Any missed migration or incompatible prop would cause visual regressions or crashes across the entire app navigation. Preconditions:
Test Steps:
Expected Outcomes:
2. Hardware Wallet - Batch Signing for Swaps/BridgeRisk Level: HIGH Why This Matters: useHwBatchSignTracker.ts is a brand new 1261-line file implementing complex state machine for hardware wallet batch signing. It handles TransactionStatus transitions, LOCALLY_DROPPABLE_CANCEL_STATUSES, TERMINAL_CANCEL_STATUSES, 30s timeout for cancel wait, and 1s retry delay for device-not-ready. This is entirely new production code with no prior release history. Preconditions:
Test Steps:
Expected Outcomes:
3. Rewards Navigator - Entry, Deeplinks, and Subscription GuardRisk Level: HIGH Why This Matters: RewardsNavigator.tsx migrated from createStackNavigator to createNativeStackNavigator. The subscription guard logic was restructured - previously checked subscriptionId to navigate to dashboard, now dismisses the flow when subscriptionId is lost. Deeplink handling was moved from RewardsNavigator to RewardsDashboard. The getInitialRoute function was removed. These are significant behavioral changes to the Rewards entry flow. Preconditions:
Test Steps:
Expected Outcomes:
4. Notification Settings - Preferences PersistenceRisk Level: HIGH Why This Matters: useNotificationStoragePreferences.ts was significantly refactored - renamed types (NotificationStoragePreferences→NotificationPreferences), added useOptimisticToggleValue hook, new NotificationPreferenceSectionUpdater pattern, and changed the update flow. The optimistic update pattern is new and could cause state inconsistencies if the API call fails. AccountsList.tsx also had significant changes (+43/-7 lines). Preconditions:
Test Steps:
Expected Outcomes:
5. Money - Card Transaction Activity FeedRisk Level: HIGH Why This Matters: MoneyHomeView.tsx added useMoneyAccountCardTransactions hook and mergeMoneyActivity function to combine card and blockchain transactions. New MoneyCardTransactionDetailsSheet component added. The merging logic (mergeMoneyActivity) is new and could produce duplicates or incorrect ordering. showCardActivityLoading logic has a mock data guard that could suppress real loading states. Preconditions:
Test Steps:
Expected Outcomes:
6. Swaps/Bridge - Post-Trade Bottom SheetRisk Level: HIGH Why This Matters: PostTradeBottomSheet is a brand new component (247 lines) with its own usePostTradeTxStatus hook (132 lines) and abTestConfig. The postTradeNotifications utility is also new. These are entirely new user-facing flows that have not been in production before. Preconditions:
Test Steps:
Expected Outcomes:
7. Perps - Watchlist and Market List RedesignRisk Level: HIGH Why This Matters: PerpsTabControlBar was completely deleted (0 lines remaining from 238+732 test lines). PerpsWatchlistMarkets was heavily rewritten (+262/-42 lines). New usePerpsCategories, useHasNewMarkets, usePerpsWatchlistActions hooks added. PerpsHomeView had major changes (+235/-70 lines). These are significant structural changes to the Perps UI. Preconditions:
Test Steps:
Expected Outcomes:
8. NFT - CollectibleModal RemovalRisk Level: HIGH Why This Matters: CollectibleModal was completely deleted (CollectibleModal.tsx, CollectibleModal.test.tsx, CollectibleModal.styles.ts, CollectibleModal.types.ts, index.ts all removed - 0 lines remaining). CollectibleContractInformation was also deleted. MainNavigator.js removed the CollectiblesDetails import. Any remaining reference to these deleted components would cause a crash. Preconditions:
Test Steps:
Expected Outcomes:
9. Ramp/Buy - Native Flow and Headless SessionRisk Level: HIGH Why This Matters: Ramp routes.tsx was restructured (+28/-36 lines). New useHeadlessSessionFocusDismissal hook (75 lines) added for session management. useRampsBuyLimits is a new hook (71 lines). HeadlessHost.tsx changed significantly. BuildQuote.tsx had changes in both Aggregator and Views versions. These changes affect the critical buy flow. Preconditions:
Test Steps:
Expected Outcomes:
Medium Risk Scenarios (7)1. Account Management - Multichain Address SharingRisk Level: MEDIUM Why This Matters: ShareAddress.tsx (+37/-12 lines) and ShareAddressQR.tsx (+56/-18 lines) had significant changes. AddressList.tsx (+32/-3 lines) added new functionality. MultichainTransactionsView.tsx (+12/-0 lines) added filtering. These changes affect how users share and view their multichain addresses. Preconditions:
Test Steps:
Expected Outcomes:
2. Snap Settings and PermissionsRisk Level: MEDIUM Why This Matters: SnapSettings.tsx was significantly updated (+37/-17 lines) with new ALLOWED_CAPABILITIES export used directly in MainNavigator.js. SnapsSettingsList.tsx changed (+25/-17 lines) with new constants. messenger.ts added (11 lines). KeyringAccountListItem.tsx added new rendering logic. The ALLOWED_CAPABILITIES export is a new pattern that could break if not correctly imported. Preconditions:
Test Steps:
Expected Outcomes:
3. Predict - Feed Config and NavigationRisk Level: MEDIUM Why This Matters: PredictTabView was completely deleted (102 lines removed). PredictHome is entirely new (158 lines). PredictFeedView is new (303 lines). PredictSearchOverlay is new (234 lines). usePredictFeedConfig is new (367 lines). feedConfig.ts is new (309 lines). The entire Predict navigation structure was rebuilt - any routing error would leave users on blank screens. Preconditions:
Test Steps:
Expected Outcomes:
4. Network Selector and ManagementRisk Level: MEDIUM Why This Matters: NetworkSelector.tsx (+8/-2 lines) and NetworkSelector.styles.ts (+4 lines) changed. NetworkMultiSelectorList.tsx (+19/-9 lines) had logic changes. DeprecatedNetworkModal.tsx (+16/-19 lines) was refactored. NetworkVerificationInfo.tsx (+23/-15 lines) changed. These affect core network management flows. Preconditions:
Test Steps:
Expected Outcomes:
5. Security Settings - Reveal Private CredentialRisk Level: MEDIUM Why This Matters: RevealPrivateCredential.tsx had changes (+7/-1 lines). SecuritySettings.tsx changed (+6/-10 lines). TurnOffRememberMeModal.tsx changed (+4/-5 lines). SRPListItem.tsx changed (+16/-11 lines). These touch sensitive security flows where any regression could expose or fail to protect user credentials. Preconditions:
Test Steps:
Expected Outcomes:
6. Transaction History and Activity ViewRisk Level: MEDIUM Why This Matters: TransactionElement/index.js (+9/-10 lines) and utils.js (+13/-9 lines) changed. TransactionDetails/index.js (+14/-0 lines) added new fields. UnifiedTransactionsView.tsx (+28/-2 lines) added new functionality. Transactions/index.js (+19/-0 lines) added new exports. ActivityView/index.js (+3/-1 lines) changed. These collectively affect how all transaction history is displayed. Preconditions:
Test Steps:
Expected Outcomes:
7. Deep Link HandlingRisk Level: MEDIUM Why This Matters: DeepLinkModal.tsx changed (+12/-11 lines). Root/index.tsx changed significantly (+22/-7 lines). The platformNewLinkHandlerSystem flag is disabled, meaning the legacy link handler is active. Any regression in deep link handling could break wallet connect flows, dapp connections, and notification-driven navigation. Preconditions:
Test Steps:
Expected Outcomes:
Teams Sign-off Status (21/21)Signed off: Accounts, Assets, Bots Team, Card, Confirmations, Core Platform, Delegation, Design System, Earn, Engagement, Mobile Platform, Mobile UX, Money Movement, Networks, Onboarding, Perps, Predict, Rewards, Social & AI, Swaps and Bridge, Wallet Integrations Excluded Features - Feature Flags Disabled (74)The following features are disabled via feature flags and should NOT be tested:
Generated by AI Test Plan Analyzer (claude-sonnet-4-6) at 2026-06-19T22:49:31.872Z AI generated test plan (JSON): Available as artifact |
|
policy-bot: approve |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## stable #31598 +/- ##
==========================================
+ Coverage 81.50% 83.27% +1.76%
==========================================
Files 4621 5748 +1127
Lines 121060 148971 +27911
Branches 26604 34786 +8182
==========================================
+ Hits 98671 124055 +25384
- Misses 15451 16561 +1110
- Partials 6938 8355 +1417 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - PR targets a release or stable branch (release/* or stable) All E2E tests pre-selected. |
|



🚀 v7.82.0 Testing & Release Quality Process
Hi Team,
As part of our new MetaMask Release Quality Process, here’s a quick overview of the key processes, testing strategies, and milestones to ensure a smooth and high-quality deployment.
📋 Key Processes
Testing Strategy
Conduct regression and exploratory testing for your functional areas, including automated and manual tests for critical workflows.
Focus on exploratory testing across the wallet, prioritize high-impact areas, and triage any Sentry errors found during testing.
Validate new functionalities and provide feedback to support release monitoring.
GitHub Signoff
Issue Resolution
Cherry-Picking Criteria
🗓️ Timeline and Milestones
✅ Signoff Checklist
Each team is responsible for signing off via GitHub. Use the checkbox below to track signoff completion:
Team sign-off checklist
This process is a major step forward in ensuring release stability and quality. Let’s stay aligned and make this release a success! 🚀
Feel free to reach out if you have questions or need clarification.
Many thanks in advance
Reference