Skip to content

release: 7.82.0#31598

Open
metamaskbotv2[bot] wants to merge 321 commits into
stablefrom
release/7.82.0
Open

release: 7.82.0#31598
metamaskbotv2[bot] wants to merge 321 commits into
stablefrom
release/7.82.0

Conversation

@metamaskbotv2

@metamaskbotv2 metamaskbotv2 Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

🚀 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

  • Developer Teams:
    Conduct regression and exploratory testing for your functional areas, including automated and manual tests for critical workflows.
  • QA Team:
    Focus on exploratory testing across the wallet, prioritize high-impact areas, and triage any Sentry errors found during testing.
  • Customer Success Team:
    Validate new functionalities and provide feedback to support release monitoring.

GitHub Signoff

  • Each team must sign off on the Release Candidate (RC) via GitHub by the end of the validation timeline (Tuesday EOD PT).
  • Ensure all tests outlined in the Testing Plan are executed, and any identified issues are addressed.

Issue Resolution

  • Resolve all Release Blockers (Sev0 and Sev1) by Tuesday EOD PT.
  • For unresolved blockers, PRs may be reverted, or feature flags disabled to maintain release quality and timelines.

Cherry-Picking Criteria

  • Only critical fixes meeting outlined criteria will be cherry-picked.
  • Developers must ensure these fixes are thoroughly reviewed, tested, and merged by Tuesday EOD PT.

🗓️ Timeline and Milestones

  1. Today (Friday): Begin Release Candidate validation.
  2. Tuesday EOD PT: Finalize RC with all fixes and cherry-picks.
  3. Wednesday: Buffer day for final checks.
  4. Thursday: Submit release to app stores and begin rollout to 1% of users.
  5. Monday: Scale deployment to 10%.
  6. Tuesday: Full rollout to 100%.

✅ Signoff Checklist

Each team is responsible for signing off via GitHub. Use the checkbox below to track signoff completion:

Team sign-off checklist

  • 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

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

georgewrmarshall and others added 30 commits June 8, 2026 22:24
## **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 -->
@tommasini tommasini requested review from a team as code owners June 19, 2026 18:32
@tommasini tommasini marked this pull request as draft June 19, 2026 18:40
@sleepytanya sleepytanya added rc-freeze Freeze auto release candidate builds and removed rc-freeze Freeze auto release candidate builds labels Jun 19, 2026
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>
@sleepytanya sleepytanya added the rc-freeze Freeze auto release candidate builds label Jun 19, 2026
@sleepytanya sleepytanya marked this pull request as ready for review June 19, 2026 22:01
sleepytanya
sleepytanya previously approved these changes Jun 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚀 RC Builds Ready for Testing

Platform Link Version
iOS TestFlight Go to TestFlight and download build 5618
Android Download from CI RC 7.82.0 (5618) — download APK artifact from the linked run
More Info
  • Version: 7.82.0
  • iOS Build Number: 5618
  • Android Build Number: 5618
  • Build Pipeline: View Pipeline

🛡️ Build Environment

Setting Value
Environment rc
Build Type main
Remote Feature Flag Env rc
Remote Feature Flag Distribution main
Ramps Environment production
API URLs & Details
API URL
Rewards API https://rewards.api.cx.metamask.io
Portfolio API https://portfolio.api.cx.metamask.io
Portfolio API (alt) https://portfolio.api.cx.metamask.io
Security Alerts API https://security-alerts.api.cx.metamask.io

Build Flags:

  • Build Name: main-rc
  • HAS_TEST_OVERRIDES: false
  • RAMP_DEV_BUILD: false
  • BRIDGE_USE_DEV_APIS: false
---

🍒 What's in this RC

Cherry-picks (21 commits)
Commit Description
efc9191acf release: release-changelog/7.82.0 (#31599)
6b40dbeb4a chore(runway): cherry-pick fix(rewards): update VIP referee dashboard (#32056)
0b1e142675 chore(runway): cherry-pick chore: remove obsolete localized message test (#32084)
44c2aa5021 Cherry-picking commits from cherry-pick-7-82-0-01dd067 to release/7.82.0 for PR #31610 (#32049)
e1ff0f0467 chore(runway): cherry-pick ci: update sonarcloud org id (#32092)
cca18fe4f2 chore(runway): cherry-pick fix: Restore support for percentage before placeholder in localized messages (#32027)
132246e98d chore(runway): cherry-pick fix(predict): keep live sport scoreboard data in sync across feed and event page cp-7.82.0 (#32038)
2291a4ca29 chore(runway): cherry-pick feat(rewards): add priority support entry point to VIP referee page (#32036)
292ddfa14d chore(runway): cherry-pick refactor(explore): standardize Explore homepage section layout cp-7.82.0 (#32015)
e2ee21a206 chore(runway): cherry-pick fix(rewards): apply bottom safe-area inset on VIP dashboard views (Android) (#32025)
12652426d0 fix(money): restore Money Home files broken by release merge (#32033)
ba5723fe8e chore: remove ota version (#32009)
64a63af9b0 chore(runway): cherry-pick fix(predict): exclude child markets from World Cup feed cp-7.82.0 (#31963)
0fe9a5a39c Cherry-picking commits from main to release/7.82.0 for PR #31555 (#31653)
46fd878b27 Cherry-picking commits from main to release/7.82.0 for PR #31505 (#31652)
e767347ab9 chore(runway): cherry-pick fix(rewards): navigation predict the pitch cp-7.82.0 (#31960)
d740ecfe67 Cherry-picking commits from main to release/7.82.0 for PR #31646 (#31663)
a22c52436c Cherry-picking commits from main to release/7.82.0 for PR #31759 (#31767)
a19863c008 Cherry-picking commits from main to release/7.82.0 for PR #31822 (#31835)
96d44efa62 Cherry-picking commits from main to release/7.82.0 for PR #31943 (#31959)
adc57f2fc3 merge release/7.82.0 and solve conflicts

Changelog (3 commits from main at RC cut)
Commit Description
2c82210ef4 Release/7.81.2 (OTA) (#31926)
b95589a3f8 release: 7.81.1 (OTA) (#31737)
3c77e046c0 release: 7.81.0 (#31100)
---

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Teams Signed Off
66/100 9 7 1,589 21/21
Executive Summary

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

  • MainNavigator migrated from @react-navigation/stack to @react-navigation/native-stack with NativeStack.Navigator/Screen replacements, affecting all app navigation transitions and screen options
  • New PredictThePitch campaign system added to Rewards with leaderboard, portfolio, stats, winning views, and position rows with animated SVG border effects
  • Hardware wallet batch signing tracker (useHwBatchSignTracker) added for swap/bridge approval flows on Ledger/Keystone devices
  • Money feature expanded with card transaction merging, MoneyAnalytics hooks, MoneyTabPressTracker, and MoneyAddMoneySheet pending transaction handling
  • Notification storage preferences refactored with optimistic toggle values, new section updater pattern, and useOptimisticToggleValue hook

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 Migration

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

  • Fresh app install or cleared navigation state
  • User has an existing wallet with at least one account
  • At least one custom network added
  • App is on the home/wallet screen

Test Steps:

  1. Launch app and unlock wallet - verify home screen loads without blank/white flash or animation glitch
  2. Navigate to Settings > Security & Privacy - verify slide-in transition is smooth and header renders correctly with back button
  3. Navigate to Send flow: tap Send, enter recipient address, tap Next - verify each screen transition uses correct animation (no card-style push where native slide is expected)
  4. Navigate to Swap: tap Swap, select tokens, proceed to confirmation - verify modal presentation style is correct (not full-screen push where modal is expected)
  5. Navigate to Buy/Ramp flow - verify all nested screens within the Ramp NativeStack render correctly and back navigation returns to correct screen
  6. Open a browser tab, navigate to a dapp, trigger a transaction approval - verify the approval modal appears correctly over the browser without layout issues
  7. Switch networks via the network selector - verify the network selector modal opens and closes correctly with proper animation
  8. Navigate to NFT details, then use hardware back button (Android) or swipe back (iOS) - verify navigation stack pops correctly to previous screen

Expected Outcomes:

  • All screen transitions animate smoothly without visual artifacts
  • Modal screens present as modals, not full-screen pushes
  • Back navigation always returns to the correct previous screen
  • contentStyle backgroundColor replaces cardStyle backgroundColor without white flash
  • animation: 'none' screens (previously animationEnabled: false) show no transition animation

2. Hardware Wallet - Batch Signing for Swaps/Bridge

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

  • Ledger or Keystone hardware wallet connected and paired with MetaMask Mobile
  • Hardware wallet account has sufficient ETH for gas and an ERC-20 token with balance
  • App is on Ethereum mainnet or a supported testnet
  • Swap feature is accessible for the hardware wallet account

Test Steps:

  1. Select the hardware wallet account as the active account
  2. Navigate to Swap and set up a swap requiring an approval transaction (e.g., ERC-20 to ETH) - verify the swap quote loads
  3. Tap Confirm/Submit swap - verify the hardware wallet signing prompt appears for the approval transaction first
  4. Sign the approval on the hardware device - verify the app transitions to waiting for the swap transaction signing prompt
  5. Sign the swap transaction on the hardware device - verify both transactions are submitted and status updates correctly
  6. During the signing flow, simulate cancellation by rejecting on the hardware device - verify the batch is cancelled cleanly, no orphaned transactions remain in pending state
  7. Attempt a bridge transaction with the hardware wallet account requiring approval - verify the same two-step signing flow works for bridge approval + bridge trade types
  8. Check transaction history after completion - verify both approval and swap/bridge transactions appear with correct statuses

Expected Outcomes:

  • Approval transaction is signed first, then trade transaction without user needing to manually re-trigger
  • Cancellation on device cleanly aborts the batch without leaving stuck pending transactions
  • KEYSTONE_TX_CANCELED error is handled gracefully with user-facing message
  • STX_NO_HASH_ERROR is handled without crash
  • Analytics events fire correctly for batch signing steps

3. Rewards Navigator - Entry, Deeplinks, and Subscription Guard

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

  • User has an active Rewards subscription (subscriptionId is set in Redux)
  • App is installed with a valid wallet
  • Rewards tab is accessible

Test Steps:

  1. Navigate to the Rewards tab - verify RewardsDashboard loads correctly as the entry point
  2. From RewardsDashboard, navigate into a campaign details view - verify the NativeStack push animation works correctly
  3. While on a Rewards sub-page, switch accounts to one without a subscription - verify the flow dismisses and returns to the Rewards tab without crash
  4. Navigate to Rewards tab with a version-blocked state (simulate via Redux) - verify the update-required screen shows instead of the dashboard
  5. Open the app via a deeplink to a specific campaign (e.g., ondo campaign) - verify navigation lands on the correct campaign details screen
  6. Navigate to Rewards > VIP section if VIP program data is available - verify VIP Referee view loads with correct data
  7. Navigate back from a deeply nested Rewards screen using the hardware back button (Android) - verify each back press pops one screen correctly
  8. Navigate to PredictThePitch campaign details if campaign data is available - verify leaderboard, portfolio, and stats sub-views are accessible

Expected Outcomes:

  • Rewards tab always shows dashboard for subscribed users
  • Account switch while in Rewards flow dismisses the flow without crash or blank screen
  • Deeplinks navigate to correct screens
  • Version-blocked state shows update screen
  • NativeStack transitions are smooth throughout Rewards flow

4. Notification Settings - Preferences Persistence

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

  • User has notifications enabled in MetaMask
  • User is logged into MetaMask with a valid account
  • Navigate to Settings > Notifications

Test Steps:

  1. Open Settings > Notifications - verify the notification preferences load correctly without error
  2. Toggle a notification category (e.g., 'Received ETH') off - verify the toggle updates immediately (optimistic update) and the change persists after navigating away and back
  3. Toggle the main notification toggle off - verify all sub-toggles reflect the disabled state
  4. Toggle the main notification toggle back on - verify sub-toggles restore to previous state
  5. Rapidly toggle multiple notification preferences in quick succession - verify no race conditions cause incorrect final state
  6. Toggle a preference while offline/poor network - verify the optimistic update shows, and on reconnection the state is correctly reconciled
  7. Navigate away from Notifications settings mid-toggle and return - verify the preference state is consistent
  8. Check that account-specific notification settings persist correctly when switching between accounts

Expected Outcomes:

  • Optimistic toggle updates show immediately without waiting for API response
  • Preferences persist correctly after navigation away and back
  • No duplicate API calls from rapid toggling
  • Error states are shown when persistence fails
  • Account list in notification settings shows correct accounts with correct toggle states

5. Money - Card Transaction Activity Feed

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

  • User has a MetaMask Money account (moneyHomeScreenEnabled flag must be enabled for this to be visible - skip if not available)
  • User has at least one completed card transaction
  • App is on the Money/Home tab

Test Steps:

  1. Navigate to the Money home screen - verify the activity feed loads without error or infinite loading state
  2. Verify card transactions appear merged with regular blockchain transactions in the activity list, sorted by date
  3. Scroll through the activity list - verify no duplicate transactions appear (mergeMoneyActivity deduplication)
  4. Tap on a card transaction in the activity list - verify MoneyCardTransactionDetailsSheet opens with correct transaction details
  5. Pull to refresh the activity feed - verify both card transactions and blockchain transactions refresh correctly
  6. Verify the loading state (MoneyActivityLoading skeleton) appears while card transactions are fetching
  7. Navigate away from Money tab and return - verify activity feed state is preserved or refreshes correctly
  8. Verify the MoneyBalanceCard shows correct combined balance information

Expected Outcomes:

  • Card transactions and blockchain transactions appear in a unified, correctly sorted list
  • No duplicate entries in the merged activity feed
  • MoneyCardTransactionDetailsSheet shows correct card transaction details
  • Loading skeleton appears during data fetch
  • Balance card reflects accurate totals

6. Swaps/Bridge - Post-Trade Bottom Sheet

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

  • User has sufficient token balance to complete a swap
  • App is on Ethereum mainnet or supported network
  • Swap feature is accessible

Test Steps:

  1. Complete a swap transaction successfully - verify the PostTradeBottomSheet appears after transaction submission
  2. Verify the PostTradeBottomSheet shows correct transaction status (pending/confirmed/failed)
  3. Wait for transaction confirmation - verify the bottom sheet updates to confirmed state
  4. Dismiss the PostTradeBottomSheet - verify navigation returns to the correct previous screen
  5. Complete a bridge transaction - verify PostTradeBottomSheet also appears for bridge transactions
  6. Simulate a failed transaction - verify PostTradeBottomSheet shows error state correctly
  7. Verify post-trade notifications are triggered correctly via postTradeNotifications utility
  8. Check that the A/B test config (abTestConfig.ts) for PostTradeBottomSheet does not cause crashes when variant is not assigned

Expected Outcomes:

  • PostTradeBottomSheet appears after every swap/bridge submission
  • Transaction status updates in real-time within the sheet
  • Dismissal navigates correctly without leaving orphaned navigation state
  • Post-trade notifications fire for completed transactions
  • No crash when A/B test variant is undefined

7. Perps - Watchlist and Market List Redesign

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

  • Perps feature is accessible (not behind a disabled flag)
  • App is on the Perps tab or accessible via navigation
  • At least one market is available in the Perps market list

Test Steps:

  1. Navigate to the Perps tab - verify PerpsHomeView loads with the new layout (PerpsProducts component visible if applicable)
  2. Navigate to the market list - verify PerpsMarketListView renders correctly with the new usePerpsMarketListView hook
  3. Interact with market category filters (PerpsMarketFiltersBar) - verify filtering works and selected state is correct
  4. Add a market to the watchlist - verify PerpsWatchlistMarkets updates correctly
  5. Remove a market from the watchlist - verify it is removed without crash
  6. Navigate to PerpsMarketDetailsView for a specific market - verify market details load correctly
  7. Check PerpsMarketCategoryBadge renders for different category types including new categories
  8. Verify PerpsTabView renders correctly without the removed PerpsTabControlBar component

Expected Outcomes:

  • Perps home loads without crash after PerpsTabControlBar removal
  • Market list filters work correctly with new usePerpsCategories hook
  • Watchlist add/remove operations complete without errors
  • Market category badges display correct icons for all categories
  • New PerpsProducts component renders without crash if visible

8. NFT - CollectibleModal Removal

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

  • User has at least one NFT in their wallet
  • App is on the NFTs tab or wallet home with NFTs visible

Test Steps:

  1. Navigate to the NFTs section of the wallet - verify NFTs display correctly
  2. Tap on an NFT to view details - verify NftDetails screen opens (CollectibleModal was deleted, NftDetails.tsx was modified)
  3. Verify NFT details show correctly: image, name, description, contract info
  4. Tap on NFT options (three dots or options button) - verify NftOptions sheet opens correctly
  5. Navigate to CollectibleOverview - verify it renders correctly with the updated index.js (+21/-3 lines)
  6. Verify no navigation routes reference the deleted CollectibleModal component
  7. Test NFT display in the Homepage NFTs section - verify NFTsSection.tsx renders correctly after its changes
  8. Verify ShowDisplayNFTMediaSheet and ShowIpfsGatewaySheet open correctly from NFT details

Expected Outcomes:

  • No crash when navigating to NFT details (CollectibleModal fully removed)
  • NFT details display all information correctly via NftDetails component
  • NFT options sheet opens and all options function correctly
  • No orphaned navigation routes pointing to deleted CollectibleModal
  • CollectibleOverview renders without errors

9. Ramp/Buy - Native Flow and Headless Session

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

  • User is on a supported region for buying crypto
  • App has network connectivity
  • User is on the wallet home screen

Test Steps:

  1. Tap Buy button on wallet home - verify Ramp flow opens correctly with the updated routes.tsx
  2. Select a provider and proceed to quote - verify BuildQuote screen renders correctly after its changes
  3. If a native flow provider is available, proceed through OTP code entry - verify OtpCode.tsx renders the new accessibility additions
  4. Proceed to checkout - verify HeadlessHost.tsx handles session correctly with the new useHeadlessSessionFocusDismissal hook
  5. Minimize the app during a headless session and return - verify the session is dismissed correctly per useHeadlessSessionFocusDismissal logic
  6. Complete a buy order - verify OrderDetails screen shows correct information
  7. Test the ProviderSelectionModal opens and closes correctly
  8. Verify useRampsBuyLimits hook correctly enforces buy limits in the BuildQuote screen

Expected Outcomes:

  • Ramp flow opens and navigates correctly through all steps
  • OTP code screen renders and accepts input
  • Headless session dismisses when app is backgrounded
  • Buy limits are enforced and shown to user
  • Order details display correctly after purchase

Medium Risk Scenarios (7)

1. Account Management - Multichain Address Sharing

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

  • User has a multichain account (account with addresses on multiple chains)
  • App is on the accounts list or account details screen

Test Steps:

  1. Navigate to account details for a multichain account
  2. Tap Share Address - verify ShareAddress sheet opens with the updated layout
  3. Verify all chain addresses are displayed correctly in the AddressList
  4. Tap on a specific chain address to view QR code - verify ShareAddressQR sheet opens with correct address
  5. Verify the QR code displays the correct address for the selected chain
  6. Copy an address from the ShareAddress sheet - verify clipboard receives correct address
  7. Navigate to MultichainTransactionsView - verify transactions load correctly with the new filtering additions
  8. Verify MultichainTransactionDetailsSheet opens correctly for a transaction

Expected Outcomes:

  • ShareAddress sheet shows all chain addresses correctly
  • ShareAddressQR shows correct QR for selected chain
  • Address copy works for all chain types
  • Multichain transaction list loads and filters correctly
  • Transaction details sheet shows complete information

2. Snap Settings and Permissions

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

  • At least one Snap is installed in the wallet
  • User navigates to Settings > Snaps

Test Steps:

  1. Navigate to Settings > Snaps - verify SnapsSettingsList renders correctly with the new constants
  2. Tap on an installed Snap - verify SnapSettings screen opens with the updated layout
  3. Verify Snap permissions are displayed correctly in the updated SnapSettings.tsx
  4. Check that ALLOWED_CAPABILITIES export from SnapSettings is accessible (used in MainNavigator)
  5. Verify the messenger.ts additions work correctly for Snap settings actions
  6. Navigate to a Snap that has keyring accounts - verify KeyringAccountListItem renders correctly with new additions
  7. Test Snap removal flow if available - verify it completes without crash
  8. Navigate back from Snap settings - verify navigation returns to SnapsSettingsList correctly

Expected Outcomes:

  • Snaps list loads all installed snaps correctly
  • Individual Snap settings page shows all permissions and options
  • ALLOWED_CAPABILITIES is correctly exported and used by MainNavigator
  • Keyring account list items render correctly within Snap settings
  • Navigation within Snap settings works correctly

3. Predict - Feed Config and Navigation

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

  • Predict feature is accessible (not behind a disabled flag that is currently off)
  • App has network connectivity to fetch market data
  • User is on the Predict tab or can navigate to it

Test Steps:

  1. Navigate to the Predict section - verify PredictHome loads correctly (new component, 158 lines)
  2. Verify the Live Now section renders with correct market data (PredictLiveNowSection is new)
  3. Navigate to a specific feed (e.g., sports, crypto) via PredictMarketListRoute - verify feed loads with correct config
  4. Switch between tabs within a feed - verify tab switching works and filter chips update
  5. Select a filter chip - verify the market list updates to show filtered results
  6. Navigate to a market details page from the feed - verify PredictMarketDetailsView opens correctly
  7. Use the search overlay (PredictSearchOverlay is new, 234 lines) - verify search results appear
  8. Navigate back through the Predict navigation stack - verify each back press returns to correct screen

Expected Outcomes:

  • PredictHome renders all sections (Live Now, Popular Today, Trending, Categories)
  • Feed navigation works correctly for all feed IDs
  • Tab and filter switching updates market list without crash
  • Search overlay opens, accepts input, and shows results
  • Navigation stack is correct throughout Predict flow

4. Network Selector and Management

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

  • User has multiple networks configured
  • App is on the wallet home screen
  • At least one custom network has been added

Test Steps:

  1. Tap the network selector on the wallet home - verify NetworkSelector opens with the new styles (NetworkSelector.styles.ts +4 lines)
  2. Switch to a different network - verify the switch completes and wallet home updates
  3. Navigate to Settings > Networks - verify NetworksManagementView loads correctly
  4. Add a new custom network - verify the add flow works with updated RpcUrlInput
  5. Open NetworkMultiSelector - verify multi-network selection works with the updated component
  6. Test NetworkMultiSelectorList - verify list renders correctly with new styles and test additions
  7. Verify DeprecatedNetworkModal shows correctly for deprecated networks
  8. Test NetworkVerificationInfo displays correctly for unverified networks

Expected Outcomes:

  • Network selector opens and closes correctly
  • Network switching updates all relevant UI components
  • Custom network addition flow completes successfully
  • Multi-network selector works for permission flows
  • Deprecated network modal shows with correct messaging

5. Security Settings - Reveal Private Credential

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

  • User has an existing wallet with a known password
  • User navigates to Settings > Security & Privacy

Test Steps:

  1. Navigate to Settings > Security & Privacy - verify SecuritySettings renders correctly after its changes
  2. Tap 'Reveal Secret Recovery Phrase' - verify the quiz/warning flow appears
  3. Complete the quiz - verify RevealPrivateCredential.tsx opens with the updated code (+7/-1 lines)
  4. Enter the correct password - verify the SRP is revealed correctly
  5. Test 'Show Private Key' for an account - verify the same flow works for private key reveal
  6. Verify the SRPList and SRPListItem render correctly with their updated test/component changes
  7. Test the 'Turn Off Remember Me' modal - verify TurnOffRememberMeModal.tsx works correctly after its changes
  8. Navigate back from reveal credential screen - verify navigation returns correctly

Expected Outcomes:

  • Security settings page loads without error
  • SRP reveal flow completes with correct credential display
  • Private key reveal works correctly
  • Turn off remember me modal functions correctly
  • All security flows require password confirmation before revealing sensitive data

6. Transaction History and Activity View

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

  • User has at least 5 completed transactions in history
  • App is on the wallet home or activity tab

Test Steps:

  1. Navigate to the Activity/Transactions view - verify ActivityView loads correctly with the updated index.js
  2. Scroll through transaction history - verify TransactionElement renders correctly with updated index.js and utils.js
  3. Tap on a transaction to view details - verify TransactionDetails opens with the new additions (+14/-0 lines)
  4. Verify transaction details show correct information including block explorer link
  5. Navigate to UnifiedTransactionsView - verify it loads with the new additions (+28/-2 lines)
  6. Check MultichainTransactionDetailsSheet opens correctly for non-EVM transactions
  7. Verify Notifications > Transaction field renders correctly after its test changes
  8. Test BlockExplorerFooter in notification details - verify block explorer link opens correctly

Expected Outcomes:

  • Transaction list loads and scrolls smoothly
  • Transaction details show all relevant information
  • Block explorer links open correctly
  • Unified transactions view shows all transaction types
  • Multichain transaction details work for non-EVM chains

7. Deep Link Handling

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

  • App is installed and wallet is set up
  • Test device can receive deep links
  • App is in background or closed state

Test Steps:

  1. Send a deep link to open the app to the wallet home - verify app opens to correct screen
  2. Send a deep link to a specific token details page - verify TokenDetails opens correctly
  3. Send a deep link while app is in foreground - verify DeepLinkModal.tsx handles it correctly after its changes (+12/-11 lines)
  4. Send a deep link to the Ramp/Buy flow - verify the flow opens at the correct step
  5. Test a deep link with an invalid/malformed URL - verify graceful error handling without crash
  6. Send a deep link while on a modal screen - verify the modal is dismissed and deep link destination is shown
  7. Verify Root/index.tsx handles deep links correctly after its changes (+22/-7 lines)
  8. Test deep link to a network-specific page - verify correct network is selected

Expected Outcomes:

  • All valid deep links navigate to correct destinations
  • Invalid deep links are handled gracefully
  • Deep links work from both background and closed app states
  • Deep links correctly dismiss any open modals before navigating
  • Network-specific deep links switch to correct network

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:

  • agentic_cli_notifications_enabled
  • aiSocialLeaderboardEnabled
  • aiSocialLeaderboardPerpsEnabled
  • assetsGlobalWatchlistV1
  • bitcoinTestnetsEnabled
  • brazeBannerHome
  • brazeBannerHomeMinVersion
  • brazeSegmentForwarding
  • configRegistryApiEnabled
  • confirmations_pay_hardware
  • coreMCU589AbtestHubPageDiscoveryTabs
  • earnFeatureFlagTemplate
  • earnMoneyFirstTimeDepositAnimationEnabled
  • earnMusdConversionRewardsUiEnabled
  • earnPooledStakingServiceInterruptionBannerEnabled
  • earnStablecoinLendingServiceInterruptionBannerEnabled
  • forceRampsStagingEnvironment
  • fullPageAccountList
  • googleLoginIosUnsupportedBlockingEnabled
  • hapticsKillSwitch
  • homeTMCU470AbtestTrendingSections
  • homeTMCU725AbtestHomepagePerpsPillsEmptyState
  • ledgerDmk
  • legacyIosGoogleConfigEnabled
  • metalCardCheckoutEnabled
  • moneyActivityMockDataEnabled
  • moneyEnableActivityDetails
  • moneyEnableActivityDetailsBlockexplorerLink
  • moneyEnableMoneyAccount
  • moneyEnableOnboardingStepperAnimation
  • moneyHomeScreenEnabled
  • moneyShowMoneyAccountAddress
  • pepsSamplePhasedRolloutFlag
  • perpsAdvancedChartEnabled
  • perpsAdvancedChartEnabledV2
  • perpsDefaultPayTokenWhenNoBalanceEnabled
  • perpsMyxProviderEnabled
  • perpsPerpGtmOnboardingModalEnabled
  • perpsPerpTradingServiceInterruptionBannerEnabled
  • perpsSlippageConfig
  • perpsProductsEnabled
  • platformNewLinkHandlerSystem
  • predictClobV2UseLegacyClobHost
  • predictExtendedSportsMarkets
  • predictGtmOnboardingModalEnabled
  • predictHomeRedesign
  • predictHotTab
  • predictTabFeaturedCarousel
  • predictWithAnyToken
  • predictHomepageDiscoveryNbaChampionEnabled
  • priceAlertsEnabled
  • rewardsAnnouncementModalEnabled
  • rewardsBitcoinEnabled
  • rewardsDropsEnabled
  • rewardsEnableMusdDeposit
  • rewardsEnableMusdHolding
  • rewardsMissingEnrolledAccounts
  • rewardsReferralCodeEnabled
  • rewardsReferralEnabled
  • rewardsTronEnabled
  • socialAiAssetDetailsQuickBuy
  • socialAiTSA495AbtestCardRotationInterval
  • solanaOnboardingModal
  • solanaTestnetsEnabled
  • stellarAccounts
  • telegram_login_enabled
  • tempoConfig
  • tmcuActivityRedesignEnabled
  • tokenDetailsTechnicalIndicators
  • tokenDetailsV2ButtonLayout
  • tokenDiscoveryBrowserEnabled
  • tronStaking
  • vipProgramEnabled
  • walletHomeOnboardingSteps

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 test-plan-7.82.0 in the build workflow

tommasini
tommasini previously approved these changes Jun 19, 2026
@sleepytanya

Copy link
Copy Markdown
Contributor

policy-bot: approve

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.57407% with 87 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.27%. Comparing base (5078ae1) to head (8b50ffe).
⚠️ Report is 3316 commits behind head on stable.

Files with missing lines Patch % Lines
...I/Bridge/components/PostTradeBottomSheet/index.tsx 67.24% 5 Missing and 14 partials ⚠️
...nents/PostTradeBottomSheet/usePostTradeTxStatus.ts 86.36% 2 Missing and 4 partials ⚠️
app/components/UI/CollectibleOverview/index.js 0.00% 6 Missing ⚠️
...omponents/UI/Compliance/hooks/useComplianceGate.ts 80.64% 4 Missing and 2 partials ⚠️
...mponents/UI/Bridge/hooks/useBridgeConfirm/index.ts 79.16% 1 Missing and 4 partials ⚠️
...iews/BatchSellReview/BatchSellPercentageSlider.tsx 81.81% 1 Missing and 3 partials ⚠️
...iews/BatchSellTokenSelect/BatchSellTokenSelect.tsx 87.50% 1 Missing and 3 partials ⚠️
...ponents/TransactionDetails/BlockExplorersModal.tsx 60.00% 1 Missing and 3 partials ⚠️
...mponents/UI/Bridge/utils/postTradeNotifications.ts 88.23% 3 Missing and 1 partial ⚠️
...nents/UI/Card/hooks/useMoneyAccountCardLinkage.tsx 92.15% 3 Missing and 1 partial ⚠️
... and 16 more
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

⏭️ Smart E2E selection skipped - PR targets a release or stable branch (release/* or stable)

All E2E tests pre-selected.

View GitHub Actions results

tommasini
tommasini previously approved these changes Jun 20, 2026
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rc-freeze Freeze auto release candidate builds release-7.82.0 Issue or pull request that will be included in release 7.82.0 size-XL team-bots Bot team (for MetaMask Bot, Runway Bot, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.