Skip to content

release: 7.77.0#29883

Open
metamaskbotv2[bot] wants to merge 246 commits into
stablefrom
release/7.77.0
Open

release: 7.77.0#29883
metamaskbotv2[bot] wants to merge 246 commits into
stablefrom
release/7.77.0

Conversation

@metamaskbotv2
Copy link
Copy Markdown
Contributor

@metamaskbotv2 metamaskbotv2 Bot commented May 7, 2026

🚀 v7.77.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
  • BE Trade
  • Bots Team
  • Card
  • Confirmations
  • Core Extension UX
  • Delegation
  • Design System
  • Earn
  • Mobile Platform
  • Mobile UX
  • Money Movement
  • Networks
  • Onboarding
  • Perps
  • Predict
  • Rewards
  • Social & AI
  • Swaps and Bridge
  • Transactions
  • 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

matallui and others added 30 commits April 30, 2026 19:07
## **Description**

Updates the Polymarket adapter contract addresses used by Predict to the
new `CtfCollateralAdapter` and `NegRiskCtfCollateralAdapter` values
shared by Polymarket.

Polymarket added new events on these adapters and will stop accepting
relayed transactions through the old adapters on May 1 at 3pm UTC.
Without this change, Polymarket transactions routed through the old
adapters will start failing.

## **Changelog**

CHANGELOG entry: Updated Polymarket adapter contracts so Polymarket
prediction transactions continue working after the relayer migration.

## **Related issues**

Fixes:
- PRED-853
- https://consensyssoftware.atlassian.net/browse/PRED-853

## **Manual testing steps**

```gherkin
Feature: Polymarket adapter migration

  Scenario: user submits a Polymarket transaction after the adapter migration
    Given the app is running a build from this branch
    And the user has access to the Predict/Polymarket experience

    When the user submits a Polymarket transaction that uses the collateral adapters
    Then the app should use the updated adapter addresses
    And the transaction should be accepted by the relayer after the migration cutoff
```

Not run locally; constants-only configuration update.

## **Screenshots/Recordings**

Not applicable.

### **Before**

Not applicable.

### **After**

Not applicable.

## **Pre-merge author checklist**

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Low code complexity, but changes production on-chain contract targets
for Polymarket claim/relay flows; incorrect addresses would cause
transactions to fail.
> 
> **Overview**
> Updates Predict’s Polymarket configuration to use new
`CtfCollateralAdapter` and `NegRiskCtfCollateralAdapter` contract
addresses in `polymarket/constants.ts`.
> 
> This shifts v2 claim/relay routing (as referenced by protocol
`claim.standardTarget`/`claim.negRiskTarget`) to the new adapter
contracts to maintain compatibility with Polymarket’s relayer migration.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
08b08be. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29553)

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

Three independent improvements to the CI pipeline:

- E2E merge gate fix: Gate now checks build jobs too
(build-android-apks, build-ios-apps). Previously a failed build caused
smoke tests to skip, which the gate treated as passing. This will avoid
PRs getting merged with broken builds like:
https://github.com/MetaMask/metamask-mobile/actions/runs/25074016847
- Yarn cache: Added node_modules + .yarn/install-state.gz caching to
component-view-tests, merge-unit-and-component-view-tests, and
setup-e2e-env. Saves ~2–4 min on cache hits.
- Label rename: skip-e2e-quality-gate → skip-e2e-flakiness-detection.
Post-merge: rename the label manually in GitHub repo settings.
- Time-gated auto-labeling: The pr-not-ready-for-e2e label is now only
auto-applied to new PRs opened between 13:00–17:00 UTC (15:00–19:00 CEST
/ 9:00–13:00 EDT), targeting the Europe–US East Coast overlap window.


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

## **Related issues**

Fixes:

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

<!-- [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
- [ ] I've included tests if applicable
- [ ] 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`.
-->

- [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**
> Modifies CI workflow gating and label-driven behavior that can block
or permit merges, so misconfiguration could affect release throughput.
Changes are scoped to GitHub Actions/scripts and caching, with no app
runtime impact.
> 
> **Overview**
> **CI merge gating is tightened for E2E** by treating
failures/cancellations in `build-android-apks` and `build-ios-apps` as
merge-blocking (previously a failed build could cause smoke tests to
skip and still pass the gate), while still allowing intentional
`skipped` outcomes when E2E is not expected to run.
> 
> **Dependency caching is expanded** by caching `node_modules` plus
`.yarn/install-state.gz` in the shared `setup-e2e-env` action and in
`ci.yml` jobs that run component-view tests and coverage merge, skipping
`yarn install` on cache hits.
> 
> **Labeling/controls are updated**: `skip-e2e-quality-gate` is renamed
to `skip-e2e-flakiness-detection` across scripts, rerun triggers, and
docs; `auto-label-not-ready-for-e2e` is time-gated (13:00–17:00 UTC)
before applying `pr-not-ready-for-e2e`; and documentation/ownership is
updated (adds QA ownership for `E2E_DECISION_TREE.md` and clarifies
`skip-e2e` as an exceptional “skip builds + all E2E” escape hatch).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ede188d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ilds. (#29390)

<!--
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**
Adds automated build environment display to RC and production builds.
Captures actual environment values used during builds
(METAMASK_ENVIRONMENT, METAMASK_BUILD_TYPE, API URLs, etc.) and displays
them:
- RC builds: In PR comment alongside build links
- Prod builds: Extracted via new workflow (Slack notification in
follow-up PR).
 
**Changes:**
- scripts/apply-build-config.js: Add --write-build-env flag to generate
build-env.json with actual env values
- build.yml: Generate and upload build-env.json as artifact during
builds (used by both RC and
prod)
- build-rc-auto.yml: Download build-env artifacts in
post-rc-build-comment job
- scripts/build-announce/: Add env section to RC build PR comments
- prod-build-env-notify.yml: New workflow triggered on prod build
completion, extracts env values (Slack posting in follow-up PR)
<!--
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**

Fixes:
https://consensyssoftware.atlassian.net/browse/MMQA-1108
## **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**

<!-- [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).
- [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 CI build workflows and the RC PR-comment pipeline to generate,
upload, download, and parse a new `build-env.json` artifact;
misconfiguration could break build jobs or PR comment posting. Risk is
limited to CI/reporting paths and is largely non-blocking
(`continue-on-error`/`|| true`) but still touches release build
automation.
> 
> **Overview**
> Adds generation of a `build-env.json` file during CI builds (via
`scripts/apply-build-config.js --write-build-env`) and uploads it as a
build artifact for each platform.
> 
> Updates RC automation to download these artifacts and extends
`scripts/build-announce` to parse them and include a **Build
Environment** section (env/build type, remote FF mapping, key API
URLs/flags) in the RC PR comment, with a fallback “not available”
section on extraction failure.
> 
> Introduces a new `Prod Build Env Notify` workflow that triggers on
successful production workflow runs, downloads the `build-env` artifact,
extracts key values with `jq`, and currently prints a placeholder for a
future Slack notification; also ignores local `build-env.json` via
`.gitignore`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
0f0c4b5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR updates the post-#29305 CI requirement filters so locale
translation JSON changes are treated as E2E-ignorable.

Locale-only PRs under `locales/languages/**/*.json` should now skip
Smart E2E selection plus Android/iOS E2E builds and smoke tests. The
change also adds the same locale rule to the Android/iOS
platform-or-ignorable filters, so mixed platform + locale changes keep
platform-specific E2E behavior instead of expanding to both platforms.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: MCWP-440

## **Manual testing steps**

```gherkin
Feature: CI requirements for locale translation changes

  Scenario: locale translation PR skips E2E
    Given a pull request changes only files under locales/languages/**/*.json
    When the ci workflow runs get-requirements
    Then Smart E2E selection is skipped
    And Android E2E build and smoke test jobs are skipped
    And iOS E2E build and smoke test jobs are skipped
    And pr-not-ready-for-e2e does not block merge for the ignorable-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
  - 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.
…-1778) (#29576)

## **Description**

Tier 2 of MMQA-1364 (allowlist reduction). Adds default mock matchers
for three categories of static asset / health-check requests, then
removes the corresponding entries from `mock-e2e-allowlist.ts`.

| Matcher | Response |
| --- | --- |
| `^https://clients3\.google\.com/generate_204$` (HEAD) | `204 No
Content`, empty body |
|
`^https://raw\.githubusercontent\.com/MetaMask/contract-metadata/[^/]+/images/.+\.svg$`
(GET) | `200`, minimal `<svg xmlns="http://www.w3.org/2000/svg"/>` |
|
`^https://token\.api\.cx\.metamask\.io/assets/nativeCurrencyLogos/.+\.svg$`
(GET) | `200`, minimal SVG |

**Why regex, not exact URLs.** The previous allowlist enumerated five
specific token icons that today's specs happened to load. Any new spec,
new default token, branch rename (`master` → `main`), or platform-subset
divergence would reintroduce live requests. Regex matchers cover the
entire category (any branch, any future token icon) with one entry — a
one-time fix instead of a moving target.

**`generate_204` origin.** Confirmed it is fired by
`@react-native-community/netinfo`'s
`InternetReachability._checkInternetReachability` via JS-layer `fetch`.
That path is patched by `shim.js`, so the request reaches mockttp at
`/proxy?url=…` and the matcher fires. (Method is `HEAD`, hence the new
`HEAD` field on `DEFAULT_MOCKS`.)

### Files changed
- `tests/api-mocking/mock-responses/defaults/static-assets.ts` — new
default mock file with the three matchers
- `tests/api-mocking/mock-responses/defaults/index.ts` — imported and
spread into `DEFAULT_MOCKS.GET` + new `HEAD` field
- `tests/api-mocking/mock-e2e-allowlist.ts` — removed 7 entries (1
generate_204, 5 GitHub raw token SVGs, 1 token.api nativeCurrencyLogos
ethereum.svg)

### Out of scope
- `https://api.avax.network/ext/bc/C/rpc` — Tier 4 investigation
- `https://metamask.github.io/test-dapp/metamask-fox.svg` — handled by
MMQA-1367
- Polymarket hosts — separate follow-up tracked in MMQA-1755

## **Changelog**

CHANGELOG entry: null

## **Related issues**

[MMQA-1778](https://consensyssoftware.atlassian.net/browse/MMQA-1778) —
parent epic
[MMQA-1364](https://consensyssoftware.atlassian.net/browse/MMQA-1364)

## **Manual testing steps**

```gherkin
Feature: Static asset mocks for E2E tests

  Scenario: NetInfo reachability probe is mocked
    Given the E2E mock server is running with default mocks loaded
    When the app fires the NetInfo reachability probe (HEAD https://clients3.google.com/generate_204)
    Then mockttp returns 204 with empty body
    And validateLiveRequests() does not record a live request

  Scenario: Token icon SVGs are mocked
    Given a spec loads a token list that includes contract-metadata icons
    When the app requests https://raw.githubusercontent.com/MetaMask/contract-metadata/<branch>/images/<token>.svg
    Then mockttp returns 200 with a placeholder SVG
    And the request never reaches GitHub live

  Scenario: Native currency logo SVGs are mocked
    Given a spec loads a chain whose native currency logo is fetched from token.api
    When the app requests https://token.api.cx.metamask.io/assets/nativeCurrencyLogos/<chain>.svg
    Then mockttp returns 200 with a placeholder SVG
    And the request never reaches the live token.api endpoint
```

## **Screenshots/Recordings**

### **Before**

`tests/api-mocking/mock-e2e-allowlist.ts` allowlisted 7 entries that
bypassed `validateLiveRequests()`:


What this meant on every E2E run:
- NetInfo's reachability probe fired a live `HEAD
https://clients3.google.com/generate_204` and Google answered. The
allowlist silenced the warning, so `validateLiveRequests()` did not flag
it.
- 5 GitHub raw SVG fetches went live whenever notifications rendered
token icons (USDC/SHIB/USDT/stETH/rETH from the mocked notification
fixtures in `@metamask/notification-services-controller`).
- 1 `token.api` SVG went live whenever the Ethereum native-currency logo
was loaded (referenced in `app/constants/urls.ts:144` and the Ramp
Quotes constants).

### **After**

Allowlist with the 7 entries gone — `ALLOWLISTED_URLS` drops from 16 to
9:


What happens on every E2E run now:
- **NetInfo reachability probe** → mockttp returns `204` with empty
body. NetInfo's `reachabilityTest` (`response.status === 204`) passes;
the wallet sees the network as reachable. No live request to Google.
- **Notification SVG fetches** → mockttp returns a placeholder SVG
(`<svg xmlns="http://www.w3.org/2000/svg"/>`). Icons render (visual
fidelity not asserted in E2E). No live request to
`raw.githubusercontent.com` for any token icon — current or future.
- **Native currency logo fetch** → same placeholder SVG. No live request
to `token.api.cx.metamask.io` for any chain's logo.
- `validateLiveRequests()` records **zero** leaks for these endpoints.

## **Pre-merge author checklist**

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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


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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are confined to the E2E mocking layer, replacing
live allowlisted static/health-check requests with deterministic mocks
(including adding default `HEAD` mocks).
> 
> **Overview**
> Reduces E2E live network allowlisting by removing specific
static/health-check URLs (Google `generate_204` and token SVG icon URLs)
from `mock-e2e-allowlist.ts` and handling them via default mocks
instead.
> 
> Adds `STATIC_ASSETS_MOCKS` with regex-based matchers that return a
`204` for `HEAD https://clients3.google.com/generate_204` and a minimal
SVG for GitHub contract-metadata and `token.api` native currency logo
`.svg` requests, and wires these into `DEFAULT_MOCKS` (including a new
`HEAD` entry).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7c90df2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.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.
-->

## **Description**

On iOS<16, Detox’s device.sendToHome() brings the home screen to the
front. On iOS 16 and later, that path is not used the same way from the
simulator tooling, so Detox instead launches and immediately quits the
Settings app to put the app under test in the background. That can
briefly show Settings and race the next step.

This PR tightens tests/smoke/swap/swap-deeplink-smoke.spec.ts: a 1
second wait after sendToHome() before launchApp({ url }), newInstance:
false on those launchApp calls so the flow is clearly “same app
instance, URL delivered after background,” and short comments above each
wait explaining the pre‑16 vs 16+ behavior.

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

## **Related issues**

Fixes:

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

<!-- [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
- [ ] 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**
> Test-only changes that adjust Detox app launching behavior and add
additional HTTP mocks; low risk to production code, with minor risk of
masking real integration issues if mock matching is too broad.
> 
> **Overview**
> Stabilizes swap deeplink smoke tests on iOS by adding a short
post-`sendToHome()` delay and launching deeplinks with `newInstance:
false` to ensure URLs are delivered to the existing app instance.
> 
> Expands swap E2E mocking by introducing reusable
`setupSwapSocialAndComplianceMocks()` to stub the Social leaderboard and
compliance batch endpoints, wiring it into swap and trending-token smoke
setups. Also tightens the swap proxy URL interception so the
`insufficientBal` rewrite only targets JSON `getQuote` requests (not
`getQuoteStream`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
edbfe2c. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… re-renders (#29597)

## **Description**

Inline `[]` fallbacks in `useWithdrawalRequests` selectors were creating
new array references on every render, triggering React-Redux's "Selector
unknown returned a different result" warning and causing unnecessary
re-renders in `PerpsProgressBar` on mount.

Fixed by replacing inline `[]` literals with module-level constants and
short-circuiting `.filter()` on empty arrays so selectors always return
the same reference.

**Performance impact:** FPS on Perps tab mount improved from 60→22 drops
down to a stable 60→57, nearly eliminating the frame drop entirely and
it doesn't take ~1 second for the Perps screen to show anymore

**NOTE**: Unrelated to these changes, there is a considerate amount of
frame drop when you're on the Perps home screen and from the UI
hydrating. The frames drop as low as 8 FPS. This happens in `main` and
this branch as well. Might be worth a follow up ticket

## **Changelog**

CHANGELOG entry:null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Perps home screen mount

  Scenario: user opens the app with Perps hub tab visible
    Given the hub tabs A/B test is enabled
    And the user has no pending withdrawal requests

    When the app loads and PerpsProgressBar mounts
    Then no "Selector unknown returned a different result" warning appears in the console
    And the Perps tab renders without unnecessary re-renders
    And FPS remains at or above 57 during mount
```

## **Screenshots/Recordings**


https://github.com/user-attachments/assets/76f6b555-a949-4633-8d4c-aaffffb23f65

### **Before**


https://github.com/user-attachments/assets/4fb102b9-2dac-48c6-9b10-bbe6316825d2

### **After**


https://github.com/user-attachments/assets/4c6688dd-159c-4e9e-89ef-c298de8bc34c

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

- [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**
> Low risk performance-only change: replaces inline empty-array
fallbacks with stable module constants to avoid React-Redux selector
warnings and unnecessary re-renders; no business logic or API behavior
changes expected.
> 
> **Overview**
> Prevents unnecessary re-renders in `useWithdrawalRequests` by
replacing inline `[]` selector fallbacks with module-level
`EMPTY_WITHDRAWAL_REQUESTS`/`EMPTY_TX_HASHES` constants and
short-circuiting the withdrawal `.filter()` when there’s no selected
address or the list is empty.
> 
> This makes selector outputs stable across renders (eliminating the
“selector returned a different result” warning) while keeping the
displayed/polled withdrawal logic unchanged.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e020446. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Reverts #29377

Shouldn't need double zip anymore since Runway should support .app
bundles

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes CI artifact packaging and paths for iOS
simulator outputs, which could break downstream consumers or uploads if
the expected zip naming/location differs.
> 
> **Overview**
> Reverts the iOS simulator artifact workaround that **double-zipped and
staged** `.app` bundles before upload, returning to a single `.zip`
produced directly from the simulator `.app` and emitting that path via
`ios_simulator_path`.
> 
> The build workflow is simplified by removing simulator upload
staging/cleanup logic and loosening the upload step condition (dropping
the redundant `success()` guard). The artifact renaming script also
switches from `execFileSync` to `execSync` for `find`/`cp`/`ditto`
invocations and removes repo-relative path conversion for simulator
uploads.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
255c3e0. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Follow-up to the BigInt introduction PR (which adds
`app/util/number/bigint.ts` and marks the helpers in
`app/util/number/index.js` as `@deprecated`). That PR provides the
replacement API; this PR puts the guardrails in place so the migration
becomes a one-way ratchet — the count of legacy `app/util/number`
importers can only go down from here.

**What this PR adds**

1. **`@typescript-eslint/no-deprecated: 'warn'`** in `.eslintrc.js` for
all `*.{ts,tsx}` files. Surfaces a warning at every use-site of any
helper already annotated `@deprecated` (the `app/util/number` exports
today, plus anything else marked deprecated in the future).

2. **`no-restricted-imports` fence** on `app/util/number` /
`app/util/number/index` for `app/**/*.{ts,tsx,js,jsx}`. New imports are
a **hard error** pointing the developer at `app/util/number/bigint`.
Existing importers (107 files at the
time of writing) live in a top-level `utilNumberImportBurndownFiles`
constant in `.eslintrc.js`. Entries should be **removed** as files are
migrated, never added. Two override blocks are needed because ESLint's
`excludedFiles` applies to the whole override, not per-rule. A single
combined block would silently exempt the burn-down files from the
existing `expo-haptics` and `**/controllers/perps` fences too. The first
override holds all three fences and excludes the burn-down list; the
second override re-applies only `expo-haptics` and perps to the
burn-down files.

3. **`app/util/number/**` is also excluded** so the legacy module and
its parity tests can keep importing each other for migration parity
comparisons.

4. **CODEOWNERS** entry: `app/util/number/index.js` is now owned by
`@MetaMask/mobile-platform`. Any change to the deprecated module (e.g.
adding a new export, modifying an existing helper) requires platform
review. Scope is intentionally limited to the deprecated file —
`bigint.ts` and the tests are not gated.

5. **Deletion of `calcTokenValueToSend`** from
`app/util/number/index.js` (and its test). The function was dead code
(only referenced by its own test).

**Why all three layers?**

| Layer | Catches |
| -------------------------------- |
----------------------------------------------------------------- |
| `@typescript-eslint/no-deprecated` (warn) | Every existing call-site
of a deprecated helper, even within the allowlist. |
| `no-restricted-imports` (error) | Any **new** file that tries to
import from the deprecated module. |
| CODEOWNERS | Any change to the deprecated module itself (new exports,
edits). |

The combination gives a one-way ratchet: warnings flag what to migrate,
the import fence prevents new debt, and CODEOWNERS prevents the legacy
module from quietly growing.

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

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

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

### **After**

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Primarily tooling/guardrail changes, but new ESLint fences and
deprecated-use warnings can break builds for newly added/modified
imports and may require follow-up fixes across many files as migration
progresses.
> 
> **Overview**
> Adds **migration guardrails** for the BN.js → BigInt transition by
enabling `@typescript-eslint/no-deprecated` (warn) and introducing an
ESLint import fence that blocks new imports resolving to deprecated
`app/util/number/index.js`, with a temporary allowlisted burndown set.
> 
> Updates `CODEOWNERS` to require platform review for changes to the
deprecated `app/util/number/index.js`, expands documentation with a
burndown-by-team section, and links the migration guide from the main
`README`.
> 
> Removes the unused `calcTokenValueToSend` helper (and its test) from
the legacy number module, and increases Node memory limits for
`lint`/`tsc` scripts to reduce OOMs.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f2197ad. 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: Cal-L <cal.leung@consensys.net>
Co-authored-by: tommasini <tommasini15@gmail.com>
Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
## **Description**

HyperLiquid is deprecating DEX Abstraction mode (~May 9). This PR forces
every Perps user onto **Unified Account** mode on app open and fixes the
withdraw + balance-display flows that were broken in the target state.

### 1. Forced migration to Unified Account

Migration paths by current abstraction mode:
- `default` / `disabled` → silently migrated via `agentSetAbstraction({
abstraction: 'u' })` — no signing prompt
- `dexAbstraction` → one-time EIP-712 prompt via `userSetAbstraction({
user, abstraction: 'unifiedAccount' })` — agent-key path is blocked by
HL for this transition
- `unifiedAccount` → no-op, cached immediately

Key details:
- Replaces deprecated `agentEnableDexAbstraction` / `userDexAbstraction`
with `agentSetAbstraction` / `userSetAbstraction` / `userAbstraction`
- Runs on perps section open (`#ensureReady()`) so users are set up
before trading
- `TradingReadinessCache` prevents repeated prompts (critical for
hardware/QR wallets); `KEYRING_LOCKED` skips the cache so it retries on
unlock
- In-flight deduplication blocks concurrent signing attempts across
provider instances
- Segment analytics: `Perp Account Setup` event tracks mode distribution
+ outcome (`already_enabled` / `migration_required` / `success` /
`failed`)

### 2. Withdraw + balance display fix (folded in from #29537)

In Unified mode, USDC collateral lives in the spot clearinghouse, so
`clearinghouseState.withdrawable` is $0 — pre-fix the withdraw screen
showed $0 max with the button disabled, and the confirm-flow alert
blocked submission.

- `accountUtils.addSpotBalanceToAccountState` folds free spot USDC into
`availableToTradeBalance` for Unified / Portfolio Margin;
`dexAbstraction` / Standard keep spot separate (fold gated on resolved
abstraction mode)
- `HyperLiquidSubscriptionService.invalidateUserAbstractionCache(addr)`
evicts stale pre-migration mode and re-aggregates immediately. Called by
`HyperLiquidProvider` after both successful migration paths so the
WS-driven aggregator doesn't serve a $0 balance for ~60s after migration
completes.
- Withdraw screen, withdraw validation, confirm-flow
insufficient-balance alert, and percentage buttons all read
`availableToTradeBalance ?? availableBalance` — fallback keeps Standard
/ legacy callers correct.

## **Changelog**

CHANGELOG entry: Fixed Hyperliquid withdraw showing $0 and being blocked
for users on Unified Account mode.

## **Related issues**

Fixes: TAT-3112 (Unified Account migration), withdrawal break tracked in
[TAT-3047](https://consensyssoftware.atlassian.net/browse/TAT-3047)

## **Manual testing steps**

```gherkin
Feature: Unified Account migration + withdraw

  Scenario: First-time migration (default/disabled mode)
    Given the user has never used Perps
    When they open the Perps section
    Then migration runs silently (no prompt)
    And HIP-3 markets are visible

  Scenario: dexAbstraction → unifiedAccount migration
    Given the user has DEX Abstraction enabled
    When they open the Perps section
    Then a one-time EIP-712 signing prompt appears
    When they sign
    Then HIP-3 markets are visible and trades succeed
    And reopening Perps does not prompt again

  Scenario: Unified Account user withdraws spot-funded balance
    Given the user is in Unified Mode with $0 perps withdrawable and >$0 spot USDC
    When they open the Withdraw screen
    Then "Available Perps balance" shows the unified value (perps + free spot USDC)
    And Max enables and submission proceeds via withdraw3
    And spot USDC drops by amount + fee
```

### Live validation evidence

Validated on dev1 mainnet (`0x8dc6…9003`) in the exact bug-class state:
- HL mode: `unifiedAccount` / perps `withdrawable`: $0 / spot USDC free:
$26.41
- App: `availableBalance` = $0 / `availableToTradeBalance` = $26.41
- Withdraw screen renders **"Available Perps balance: $26.41"** + Max
enabled (pre-fix would show $0 / disabled)

## **Screenshots/Recordings**

### **Before**

<!-- $0 max + disabled Max button on dev1 mainnet pre-fix -->

### **After**

<!-- $26.41 max + Max enabled + successful withdraw on dev1 mainnet -->

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

#### Performance checks (if applicable)

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

## **Pre-merge reviewer checklist**

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


[TAT-3047]:
https://consensyssoftware.atlassian.net/browse/TAT-3047?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> High risk because it changes Perps account-mode migration/signing flow
(including hardware-wallet behavior) and alters withdraw/payment balance
calculations that gate user funds and transaction validation.
> 
> **Overview**
> Forces Perps users onto HyperLiquid **Unified Account** by replacing
deprecated DEX-abstraction checks/calls with `userAbstraction` +
`agentSetAbstraction`/`userSetAbstraction`, adding global
in-flight/cached gating, retry semantics, and new `Perp Account Setup`
analytics.
> 
> Updates withdraw, confirmation, and pay-with flows to prefer
`availableToTradeBalance ?? availableBalance`, and changes spot→perps
folding to be **mode-gated** (fail-closed when abstraction mode is
unknown) so Unified/Portfolio Margin users see spendable USDC while
Standard/dexAbstraction users don’t over-report withdrawable funds.
> 
> Renames cache-clearing APIs from DEX abstraction to Unified Account,
adds hardware-wallet detection to defer user-sign prompts on browse, and
expands tests/docs to cover unified-mode folding, migration paths, and
race conditions in spot/account aggregation.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e5495f9. 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: geositta <matthew.denton@consensys.net>
Co-authored-by: Nick Gambino <nicholas.gambino@consensys.net>
Co-authored-by: Arthur Breton <arthur.breton@consensys.net>
Co-authored-by: abretonc7s <107169956+abretonc7s@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.
-->

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

- Adds assets migration selectors (same ones used for extension).
- Replaces use of multiple instances that directly access the state with
one of the selectors.

## **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/ASSETS-2827

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

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

### **After**

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches multiple core selectors that feed balances, token lists, and
pricing into Bridge/asset UI; while gated by the `assetsUnifyState`
flag, any selector mismatch could surface incorrect amounts/rates across
the app.
> 
> **Overview**
> Introduces a new `selectors/assets/assets-migration.ts` layer that,
when `assetsUnifyState` is enabled, derives legacy controller-shaped
data (tokens, token balances, account tracker balances, multichain
balances/assets, currency rates, token market data, and conversion
rates) from the new `AssetsController` unified state; when disabled it
falls back to the existing controller state.
> 
> Updates Bridge selectors, multichain selectors, asset list selectors,
currency/token balance/token rate selectors, AccountTracker selectors,
and Sentry trace tagging to consume these migration selectors instead of
directly reading `engine.backgroundState` controller slices.
> 
> Adjusts `assetsControllerInit` to pass through persisted
`AssetsController` state as-is (undefined when absent rather than a
synthesized empty object) and simplifies the `assetsUnifyState`
feature-flag evaluation by removing app `minimumVersion` checks;
corresponding tests are updated and a comprehensive test suite is added
for the migration selectors.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a700851. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…9) (#29601)

## **Description**

Tier 3 of MMQA-1364 (allowlist reduction), scoped to the
`signature-insights` endpoint only. NFT API entries
(`/users/.../tokens`, `/collections`, `/explore/sites`, prod/dev/uat
hosts) are deferred to follow-up tickets in the same tier.

| Matcher | Method | Response |
| --- | --- | --- |
|
`^https://signature-insights\.api\.cx\.metamask\.io/v1/signature\?chainId=0x[0-9a-fA-F]+$`
| POST | `{ stateChanges: null, error: { message: 'Unsupported
signature.', type: 'UNSUPPORTED_SIGNATURE' } }` |

**Why this response shape.** The SDK's own `decodeSignature`
(`@metamask/signature-controller/utils/decoding-api`) returns this exact
shape (`type: 'UNSUPPORTED_SIGNATURE'`) when the signature method is
anything other than `SignTypedDataV3`/`V4`. The wallet's
`TypedSignV3V4Simulation`
(`app/components/Views/confirmations/components/info/typed-sign-v3v4/simulation/simulation.tsx:18-22`)
checks `decodingData?.error` and falls through to either the permit
fallback or the "simulation unavailable" placeholder in
`DecodedSimulation`. Returning the same shape keeps the wallet on a
known-graceful code path with no errors logged.

**Why regex, not exact URLs.** Same rationale as Tier 2: covers any
future chainId without re-introducing live requests when a new chain is
added to default fixtures. Sanity-checked against the 3 chainIds in the
previous allowlist (`0x1`, `0x539`, `0xaa36a7`), plus mixed-case hex,
plus rejection cases (non-hex, extra query params, different host).

**Spec audit.** Grepped E2E specs that exercise SignTypedDataV3/V4:
- `tests/smoke/confirmations/signatures/signatures-typed.spec.ts` —
V3/V4 cases on `chainId=0x539`. Will trigger the mock. Assertions are on
row components (`AccountNetwork`, `Message`, `OriginInfo`); no asserts
on decoded simulation content. Safe.
- `tests/smoke/confirmations/signatures/alert-system.spec.ts` — V1 only
on Sepolia (`0xaa36a7`). V1 doesn't call the API per SDK code.
Unrelated.
- Snap and api-spec tests — peripheral, no decoded-content asserts.

No spec asserts on `decodingData.stateChanges` rendering, so the default
mock is safe across the codebase.

### Files changed
- `tests/api-mocking/mock-responses/defaults/signature-insights.ts` —
new
- `tests/api-mocking/mock-responses/defaults/index.ts` — import + spread
into `DEFAULT_MOCKS.POST`
- `tests/api-mocking/mock-e2e-allowlist.ts` — removed 3 entries

### Out of scope
- NFT API entries (`/users/tokens`, `/collections`, `/explore/sites`,
prod/dev/uat hosts) — deferred to separate Tier 3 tickets

## **Changelog**

CHANGELOG entry: null

## **Related issues**

[MMQA-1779](https://consensyssoftware.atlassian.net/browse/MMQA-1779) —
parent epic
[MMQA-1364](https://consensyssoftware.atlassian.net/browse/MMQA-1364)

## **Manual testing steps**

```gherkin
Feature: signature-insights default mock for E2E tests

  Scenario: SignTypedDataV4 confirmation does not hit live signature-insights
    Given the E2E mock server is running with default mocks loaded
    And a dapp is connected on any EVM chain
    When the user triggers an eth_signTypedData_v4 request
    Then mockttp returns the UNSUPPORTED_SIGNATURE error shape
    And the wallet renders the "simulation unavailable" placeholder
    And validateLiveRequests() does not record a live request to signature-insights
```

## **Screenshots/Recordings**

### **Before**

Every `eth_signTypedData_v3` / `_v4` exercised by smoke specs fired a
live POST to `signature-insights.api.cx.metamask.io`. The 3
chainId-specific allowlist entries silenced `validateLiveRequests()`,
but the call still reached the live decoding API and whatever it
returned was rendered as decoded state changes in the wallet UI.

### **After**

mockttp intercepts the POST and returns the SDK's own
`UNSUPPORTED_SIGNATURE` error shape. The wallet's
`TypedSignV3V4Simulation` checks `decodingData?.error` and falls through
to the `confirm.simulation.unavailable` placeholder in
`DecodedSimulation` — the same path the wallet takes when the API errors
live. Spec assertions on row components (origin, message,
account/network) continue to pass. `validateLiveRequests()` records zero
leaks for `signature-insights`.

## **Pre-merge author checklist**

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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


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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: test-only changes that replace live `signature-insights`
requests with a deterministic mock and tighten the E2E allowlist.
> 
> **Overview**
> E2E tests no longer rely on live calls to
`signature-insights.api.cx.metamask.io`: the PR removes the
chainId-specific allowlisted URLs and adds a default POST mock that
matches any hex `chainId` and returns an `UNSUPPORTED_SIGNATURE` error
shape.
> 
> The new `SIGNATURE_INSIGHTS_MOCKS` is wired into `DEFAULT_MOCKS.POST`,
reducing network leakage during signature-related smoke tests.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8335a5e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.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.
-->

## **Description**

### Rollout / safety net

- **Feature flag `explorePageV2Enabled`**
(`app/selectors/featureFlagController/explorePageV2/index.ts`):
**defaults to `false`**. When **off**, users get the **legacy
single-page Explore** in `ExplorePageV1.tsx` (one scroll: Quick Actions,
predictions, tokens, perps, stocks, sites). When **on**, they get the
**tabbed Explore V2**—ops can **switch back to V1** via the flag without
reverting code.

### Main additions

- **Tabbed Explore (V2)** in `TrendingView.tsx` using **`TabsList`**:
**Now**, **Macro**, **RWAs**, **Crypto**, **Sports**, and **Dapps**—each
tab is its own focused vertical experience instead of one long mixed
feed.
- **Six tab screens** under `app/components/Views/TrendingView/tabs/`
that **split content by theme** (e.g. Macro uses macro-style perps +
predictions; Crypto emphasizes crypto perps/tokens; Sports uses
sports-oriented prediction markets via `useSportsMarketsFeed`).
- **Richer presentation**: pill carousels and toggles (`PillScrollList`,
`PillToggleCardList`, `ExplorePill`, perps/token pill row items) so
movers and macro views are easier to scan than the old single-stack
layout alone.
- **Dapps tab** adds **browser-grounded** sections: **recents**,
**favorites**, and **networks** (new `feeds/dapps/` hooks and tile/list
UI) plus **trending sites**, wired through Sites / UrlAutocomplete /
SitesFullView and hooks like `useBrowserFavoritesSites` and
`useBrowserRecentsSites`.
- **Perps feeds are tab-aware**: `usePerpsFeed` supports **variants**
(`all` / `macro` / `crypto`, etc.) so each tab can show the right subset
with row vs tile vs pill layouts as needed.
- **Explore search rework** under
`app/components/Views/TrendingView/search/` (`useExploreSearch`,
`ExploreSearchResults`, `SearchFeedRow`, `TapView`, search
analytics)—**multi-feed omni-search** with debouncing and clearer
section typing for renderers.
- **Supporting infra**: feature-flag registry for tests, new i18n
strings, navigation type updates where Explore touches routes, and
**TabsBar** tweaks for the new tab strip.

### Main removals / replacements

- **Removed the “sections config” architecture**: `sections.config.tsx`
(and tests) that drove **dynamic section composition** is **gone** in
favor of **explicit tab components**.
- **Removed `exploreSectionsOrder` feature-flag plumbing**—**remote
ordering of Explore sections** is no longer the model with fixed tabs on
V2 (V1 keeps a fixed legacy stack in `ExplorePageV1`).
- **Removed / replaced older Explore search helpers**:
`utils/exploreSearch` and the hooks-local `useExploreSearch` in favor of
the **`search/`** module and a single consolidated hook API.

### What stayed the same (high level)

- **Core feeds** (tokens, stocks, predictions, sites, perps) remain the
building blocks; they are **recomposed per tab** with new filters/UI
where needed—not entirely new domains everywhere.
- **V1 behavior stays available** behind the flag for rollback and
gradual rollout.

<!--
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: developed explore page v2 behind a FF

## **Related issues**

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

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

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

### **After**


https://github.com/user-attachments/assets/c264b45c-d726-47ce-8c8d-978c162924e9

s] -->

## **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**
> Large UI/navigation refactor across Explore, search, and Sites with
new hooks/components and removed legacy section-config plumbing;
regression risk is mitigated by gating V2 behind `explorePageV2Enabled`
but still touches multiple user entry points.
> 
> **Overview**
> Adds a **feature-flagged tabbed Explore V2** in `TrendingView`
(Now/Macro/RWAs/Crypto/Sports/Dapps) and preserves a new `ExplorePageV1`
fallback when `explorePageV2Enabled` is off.
> 
> Reworks Explore’s composition primitives with new reusable UI building
blocks (`HorizontalCarousel`, `CardList`, pill rows/toggles) and updates
`PredictHomeFeaturedCarousel` to render directly from
`usePredictionsFeed` instead of the old `Section` abstraction.
> 
> Overhauls Explore search to use the new `search/useExploreSearch` API
(section list shape + debouncing), updates UrlAutocomplete to adapt the
new sections model (including merging `tokens`+`stocks`), and updates
“View all” results rendering to use `SearchFeedRow`.
> 
> Improves Sites UX and data plumbing: `SiteRowItem` now supports
local/remote icons with `WebsiteIcon` fallback + favorite removal
action, `SitesList` owns navigation (removing `SiteRowItemWrapper`),
`SitesFullView` gains a favorites mode wired to Redux `removeBookmark`,
and adds new Redux-driven hooks for favorites/recents plus shared query
matching helpers.
> 
> Includes small correctness/UX fixes: avoids `usePredictMarketData`
empty-frame flash via `useLayoutEffect`, appends `customQueryParams` to
Polymarket pagination queries, adds new `TokenDetailsSource` values for
Explore entry points, refactors trending token row press handling into
`useTrendingTokenPress`, and adjusts `TabsBar` padding for scroll vs
non-scroll layouts.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
97f3435. 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: amandaye0h <amanda.yeoh@consensys.net>
<!--
This is a temporary patch until this bug is fixed
ttps://github.com//issues/29615
-->

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

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

## **Related issues**

Fixes:

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

<!-- [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
- [ ] 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: changes are limited to smoke-test steps and analytics
expectations, adjusting assertions to match a temporarily missing
slippage event.
> 
> **Overview**
> Updates the swap action smoke test to **stop setting custom slippage**
during the first ETH→USDC swap while bug `#29615` is unresolved.
> 
> Adjusts the associated analytics expectations by reducing
`INPUT_CHANGED` event count from 12→11 and temporarily disabling the
`slippage` input assertion, with comments indicating it should be
re-enabled once the bug is fixed.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
05981c9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

`BackgroundBridge` subscribes to seven controller messenger events in
its constructor but `onDisconnect()` only tore down three. After a
session disconnects, the leaked subscriptions kept firing — emitting
`chainChanged` / `accountsChanged` notifications and lock/unlock events
to dead sessions.

Root causes of the four leaks:
- `SelectedNetworkController:stateChange` — missing from
`onDisconnect()` entirely.
- `KeyringController:lock` / `unlock` — subscribed with
`this.onLock.bind(this)` / `this.onUnlock.bind(this)` inline, so each
call produced a fresh reference that couldn't be matched for
unsubscription.
- `PermissionController:stateChange` — subscribed with an anonymous
arrow function, same reference-matching problem.

Fix:
- Store stable bound references (`this._handleLock`,
`this._handleUnlock`, `this._handlePermissionControllerStateChange`) in
the constructor and pass them to both `subscribe` and `tryUnsubscribe`.
- Add matching `tryUnsubscribe` calls for all four events in
`onDisconnect()`.
- Make `onDisconnect()` idempotent: early-return on `this.disconnected`,
and convert the existing CAIP `unsubscribe` calls (which throw on a
missing sub) to `tryUnsubscribe`. `onDisconnect` is invoked from ~6 call
sites and could previously throw on a second call.

Affects both SDKConnectV2 and WalletConnect since they share this class.

## **Changelog**

CHANGELOG entry: Fixed a subscription leak in `BackgroundBridge` where
disconnected SDK and WalletConnect sessions could continue to receive
network, account, permission, and lock/unlock notifications.

## **Related issues**

Fixes:
[WAPI-1367](https://consensyssoftware.atlassian.net/browse/WAPI-1367)

## **Manual testing steps**

```gherkin
Feature: BackgroundBridge subscription teardown

  Scenario: SDKConnectV2 session stops receiving state events after disconnect
    Given a dapp has an active SDKConnectV2 session with the wallet
    And dev logs for notifyChainChanged / notifySelectedAddressChanged are being observed

    When the user disconnects the session
    And the user switches networks
    And the user switches the selected account
    And the user locks and unlocks the wallet
    Then no chain-changed, account-changed, or lock-state notifications are emitted to the disconnected session

  Scenario: WalletConnect v2 session stops receiving state events after disconnect
    Given a dapp has an active WalletConnect v2 session with the wallet

    When the user disconnects the session
    And the user performs the same network / account / lock actions
    Then no chain-changed or account-changed notifications are emitted to the disconnected session

  Scenario: Calling onDisconnect multiple times is safe
    Given a BackgroundBridge instance has been disconnected

    When onDisconnect is invoked again
    Then no unsubscribe throws and no teardown work repeats
```

## **Screenshots/Recordings**

N/A — no UI changes.

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

N/A — subscription-teardown fix, no user-visible flow or new
instrumented operations.

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.

[WAPI-1367]:
https://consensyssoftware.atlassian.net/browse/WAPI-1367?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes connection teardown logic for provider sessions; mistakes
could drop needed notifications or leave subscriptions around, impacting
WalletConnect/SDK session behavior.
> 
> **Overview**
> Fixes `BackgroundBridge` event-subscription leaks by using stable
handler references for `KeyringController` lock/unlock and
`PermissionController:stateChange`, and by adding missing teardowns
(including `SelectedNetworkController:stateChange`) in `onDisconnect()`.
> 
> Makes `onDisconnect()` *idempotent* (early-return when already
disconnected) and switches CAIP-related unsubscriptions to
`tryUnsubscribe` to avoid errors on repeated teardown calls. Adds
focused unit tests asserting correct handler-based unsubscription and
safe repeated `onDisconnect()` invocation.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e4e1440. 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: Jiexi Luan <jiexiluan@gmail.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.
-->

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

This PR replaces many of the placeholder UI elements and no-ops with
their production equivalents.

- **Money in bottom navbar:** When `selectMoneyHomeScreenEnabledFlag` is
on, the Activity tab is replaced by a Money tab that redirects to Money
Home. Activity has been moved to the wallet header.

- **Money Home bottom sheets:** The options button (top-right), Transfer
action, APY info tooltip, and earnings info tooltip now navigate to
their respective modals; Card CTAs route into the Card stack; “Earn on
your crypto” opens-temporary "Earn on your crypto" page; wires up
"Convert" buttons for assets displayed in the "Earn on your crypto"
section.

- **MoneyPotentialEarningsView** lists all eligible conversion tokens,
shows aggregate projected yield, and reuses row-level conversion
behavior.

- **Shared utilities & hooks:** Adds `moneyFormatFiat`, centralizes temp
`__DEV__` vault APY handling in `useMoneyAccountBalance`, adds
`calculateProjectedEarnings` helper, and refactors Money-related
components to use the shared formatter instead of ad hoc `Intl` /
`useFiatFormatter` usage. This means we no longer see the "US" prefix in
front of USD fiat amount.

- **Updated image assets** Updates Money onboarding / condensed cards /
How it works images; removes the temporary How it Works header.

- **MoneyAccountHomeRow** When `selectMoneyHomeScreenEnabledFlag` is on,
The Money section on the home screen displays the Money account's
balance instead of the aggregated mUSD balance. This component has 2
variants; an empty state and a funded state.

## **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: Improved the Money home experience behind the feature
flag by wiring real navigation (sheets, Card flows, potential earnings
and conversion), replacing the Activity tab when the flag is enabled,
and showing projected earnings using live APY and balance data.

## **Related issues**

No issue: Money Home and tab-navigation workstream without a single
tracking issue from the branch; see
#29454 for scope and
review. Add `Fixes:` / `Closes:` when a primary ticket exists.

## **Screenshots/Recordings**

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

### **Before**


### **After**


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

<!-- Generated with the help of the pr-description AI skill -->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Introduces new Money navigation routes/modals and swaps core
tab/wallet navigation behavior behind
`selectMoneyHomeScreenEnabledFlag`, which could affect app navigation
flows if misconfigured. Also changes fiat formatting and APY/projection
calculations used across Money UI, so regressions would show up as
incorrect amounts or broken sheets rather than data loss.
> 
> **Overview**
> When `selectMoneyHomeScreenEnabledFlag` is enabled, the bottom tab bar
replaces *Activity* with a new *Money* tab (new `TabBarIconKey.Money`)
and moves *Activity* access to a new wallet header button (with
`ACTIVITY_CLICKED` analytics). Navigation is updated so Money
routes/modals (`More`, `Transfer`, `APY info`, `Earnings info`, plus a
new `MoneyPotentialEarningsView`) are registered and can be opened from
Money Home.
> 
> Money Home is de-stubbed: menu/transfer/card CTAs now navigate to real
routes, token “Convert” actions initiate the conversion flow with error
logging, and earnings UI now shows lifetime/projected values and opens
an earnings info sheet. Shared Money utilities are added and adopted:
`moneyFormatFiat` centralizes fiat formatting,
`calculateProjectedEarnings` standardizes linear projections,
`useMoneyAccountBalance` now returns
`apyDecimal/apyPercent/apyPercentFormatted` and uses the shared
formatter, and Money activity fiat formatting is migrated to the same
utility.
> 
> Homepage Cash section now conditionally renders a new
`MoneyAccountHomeRow` (balance/APY + Get started/Add CTA with loading
skeletons) when the Money home flag is on, instead of the prior mUSD
aggregated row. Tests and locales are updated accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b459652. 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?
-->

This PR updates build variants:
- Create `main-dev-expo` for producing Expo debug dev builds (.app,
.ipa, .apk, test .apk)
- Update `main-dev` for producing release dev builds for installation
via side loading

Slack thread -
https://consensys.slack.com/archives/C02U025CVU4/p1776795191936139

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

## **Related issues**

Fixes:  https://consensyssoftware.atlassian.net/browse/MCWP-561

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

<!-- [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**
> Moderate risk because it changes CI build selection and iOS
signing/export behavior (including overriding signing settings for
Release archives), which could break artifact generation or produce
incorrectly signed builds.
> 
> **Overview**
> Separates dev build configurations by introducing `main-dev-expo`
(Debug Expo dev builds that produce simulator + device iOS artifacts and
Android APK + test APK) while repurposing `main-dev` as a dev *release*
build intended for sideloading.
> 
> Updates the reusable `build.yml` workflow to support an optional
`script_name` override from `builds.yml`, so different build configs can
reuse the same underlying yarn build script. Adjusts `scripts/build.sh`
iOS packaging to use a new `PROFILE` flag for selecting export options
and to allow development signing overrides when creating a Release
archive.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
dc86270. 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 removes the now deprecated Quick Convert code paths. We're
keeping the Max convert bottom sheet and the `MusdConversionAssetRow`
components to integrate into the Money Home screen.
<!--
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: remove deprecated quick convert feature code paths

## **Related issues**

Fixes:
- [MUSD-691: Clean up deprecated Quick Convert Home and related code
paths](https://consensyssoftware.atlassian.net/browse/MUSD-691)

## **Manual testing steps**

N/A

## **Screenshots/Recordings**

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

### **Before**

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

<!-- [screenshots/recordings] -->
N/A
## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it removes a navigation route/feature flag and
rewires mUSD conversion CTAs and analytics to always use the
custom-amount flow, which could affect user routing and event reporting
if any remaining callers expected Quick Convert.
> 
> **Overview**
> Removes the deprecated mUSD **Quick Convert** flow end-to-end: deletes
`MusdQuickConvertView` (and `MusdBalanceCard`), drops the
`MM_MUSD_QUICK_CONVERT_ENABLED` env var, removes the quick-convert
feature-flag selector/remote registry entries, and removes the
`Routes.EARN.MUSD.QUICK_CONVERT` route.
> 
> Updates mUSD conversion entry points (`useMusdConversion`, education
screen, cash/token list/asset CTAs) to stop passing/handling
`navigationOverride` and to always route/track redirects to
`CUSTOM_AMOUNT_SCREEN` (while keeping the max-convert bottom sheet
location constant).
> 
> Renames `ConvertTokenRow` to `MusdConversionAssetRow` and updates
downstream usage/tests (e.g., Money convert stablecoins, cash tokens
skeleton) to use the new component/test IDs.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
74947e7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…7.76.0 (#29603)

## **Description**

When the token list security badges feature flag is enabled, read the
already-fetched security data from the TanStack Query
cache on item press and forward it via navigation params, eliminating
the on-demand fetch in TokenDetails.

## **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: remove on demand api call to get security data when
passed from token list and FF is ON

## **Related issues**

Fixes:

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

<!-- [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 the token list tap navigation payload to optionally include
cached `TokenSecurityData` from TanStack Query, which could affect the
Asset Details screen’s behavior when the security-badges feature flag is
enabled. Risk is limited by feature-flag gating but still touches
navigation params and cache key usage.
> 
> **Overview**
> When `selectTokenListSecurityBadgesEnabled` is on and a CAIP asset id
has been resolved, tapping a token in `TokenListItem` now reads
`TokenSecurityData` from the TanStack Query cache
(`tokenListSecurityBadgeKeys.byAsset(caipId)`) and forwards it to the
`Asset` route via `securityData` navigation params.
> 
> Adds/updates unit tests to mock `useQueryClient` + CAIP resolution and
assert `securityData` is included only when the flag is enabled and
cached data exists.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
224e470. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29567)

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

We had a Sentry error (getBearerToken - unable to proceed, wallet is
locked) caused by TanStack Query refetching social leaderboard and
trader profile/positions queries while the wallet is locked.

The root cause is that `ReactQueryService` wires `AppState` to
TanStack's `focusManager`, so every app foreground triggers a refetch of
all stale queries. Since `staleTime: 0` is hardcoded in
@metamask/react-data-query, all queries are always stale. If the wallet
auto-locked while the app was backgrounded, the refetch on foreground
hits `getBearerToken → #assertIsUnlocked → throws.`

To address this we can gate the enabled prop on `selectIsUnlocked` in
the three affected hooks. TanStack fully pauses a query (no refetch
interval, no focus refetch, no reconnect refetch) when enabled: false.
On wallet unlock, the Redux selector triggers a re-render and the query
immediately resumes.

The updated hooks are:
1. `useTopTraders`
2. `useTraderProfile`
3. `useTraderPositions`
Cached data continues to be shown while locked, so there is no visual
regression.

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

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

<!-- [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]
> **Low Risk**
> Small, localized change to query `enabled` conditions; main risk is
unintentionally suppressing expected refetches when lock state is
misreported.
> 
> **Overview**
> Prevents social leaderboard-related TanStack queries from firing while
the wallet is locked by gating each hook’s `useQuery` `enabled` flag on
`selectIsUnlocked`.
> 
> This updates `useTopTraders`, `useTraderProfile`,
`useTraderPositions`, and `useTraderPosition` to stop focus/interval
refetches during lock, and adjusts unit tests to mock `selectIsUnlocked`
and assert queries are disabled when locked.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
72fcf20. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **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?
-->

We have no visibility into how the native binary size (iOS xcarchive,
Android AAB) changes over time. The existing JS bundle size check in CI
only covers the JavaScript bundle, missing native libraries, assets,
resources, and dex files that contribute to the install size users
experience.

This PR integrates [Sentry Size
Analysis](https://docs.sentry.io/product/size-analysis/) into the
nightly build pipeline. After each nightly RC build completes, two new
jobs download the build artifacts and upload them to Sentry for binary
size tracking. Sentry then provides:

- **Build breakdown** — see exactly where size comes from (native libs,
assets, dex, Hermes bytecode, etc.)
- **Actionable insights** — flags like uncompressed images, Hermes debug
info in release builds, duplicate files, unnecessary bundled files
- **Nightly-over-nightly comparison** — automatic diffs between
consecutive nightly builds to spot regressions

The upload jobs run **in parallel** with the existing cleanup jobs, so
they never block the critical path (TestFlight upload, branch cleanup).

### Key design decisions

- **RC builds only** — RC uses production code fencing, signing, and
APIs, so binary size is representative of what ships to users
- **Separate `build-configuration` per platform** (`Release-iOS`,
`Release-Android`) — keeps Sentry comparisons scoped within the same
platform
- **`base-sha` included** — resolves the parent commit on `main` so
Sentry can generate accurate build-over-build diffs
- **Off the critical path** — runs as independent jobs after the RC
builds complete, not as steps inside `build.yml`

### Prerequisites

- The `MM_SENTRY_AUTH_TOKEN` secret must have the `org:ci` scope (likely
already the case since it's used for source map uploads)
- Size Analysis must be enabled on the `metamask-mobile` Sentry project

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

## **Manual testing steps**

```gherkin
Feature: Sentry Size Analysis uploads in nightly builds

  Scenario: nightly build uploads artifacts to Sentry Size Analysis
    Given the nightly build workflow runs at 04:00 UTC (or via workflow_dispatch)

    When the iOS RC and Android RC builds complete successfully
    Then two new "Sentry Size Analysis" jobs start in parallel
    And each job downloads the respective build artifact (xcarchive / AAB)
    And uploads it to Sentry using sentry-cli with correct metadata
    And the uploads appear on the Sentry Releases > Mobile Builds page

  Scenario: size analysis jobs do not block the critical path
    Given the nightly build workflow is running

    When the RC builds complete
    Then the Size Analysis jobs and the cleanup job run in parallel
    And the TestFlight upload for iOS is not delayed by the Size Analysis upload
```

## **Screenshots/Recordings**

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

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

Not applicable

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk because it changes the nightly GitHub Actions pipeline
and introduces new external `sentry-cli` uploads using a secret token,
which could cause flaky/failed nightly runs if misconfigured.
> 
> **Overview**
> Nightly build CI now uploads **RC iOS and Android artifacts** to
Sentry Size Analysis to track native binary size over time.
> 
> After `ios-rc`/`android-rc` complete, new `size-analysis-ios` and
`size-analysis-android` jobs download the `xcarchive`/`aab` artifacts,
compute a `base-sha` from the previous commit, and run `sentry-cli build
upload` with `MM_SENTRY_AUTH_TOKEN` and platform-specific
`--build-configuration` metadata.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
02452e1. 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**
Disables tests/smoke/predict/predict-open-position.spec.ts as it is
failing consistently.

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

## **Related issues**

Fixes:

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

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

### **After**

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: only marks a single E2E smoke spec as skipped and adds a
comment; no production code paths change.
> 
> **Overview**
> **CI unblock:** skips
`tests/smoke/predict/predict-open-position.spec.ts` by switching its
suite to `describe.skip`, with a reference link explaining the
consistent failure.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e1111f5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#29123)

…raders sections

- WhatsHappeningCard: collapse double Box wrapper to single node (–1
native node per card)
- WhatsHappeningSection, TopTradersSection: View ref + Box gap → View
ref style

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

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

## **Related issues**

Fixes:

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

<!-- [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]
> **Low Risk**
> Low risk UI refactor focused on layout/styling and analytics/view
tracking wiring; main risk is subtle spacing or event-firing behavior
changes when sections are empty/loading.
> 
> **Overview**
> Improves homepage section rendering and instrumentation for **Top
Traders** and **What’s Happening**.
> 
> `TopTradersSection` and `WhatsHappeningSection` now pass a `null`
`sectionRef` to `useHomeViewedEvent` when the section won’t render,
avoiding measuring a non-mounted view while preserving the hook’s
empty/immediate-fire behavior. Both section headers also gain stable
`testID`s via `WalletViewSelectorsIDs.HOMEPAGE_SECTION_TITLE(...)`.
> 
> `WhatsHappeningSection` removes the extra `Box` wrapper (replacing
`gap` with a `StyleSheet` style on the root `View`), and
`WhatsHappeningCard` collapses layout into the `TouchableOpacity` via
Tailwind `style` to reduce one native node per card.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e75d976. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… quote (#29342)

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

It should not be possible to submit money account withdraw if there is
no quote.

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

## **Related issues**

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

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Moderate risk: changes blocking alert logic used to disable submission
in post-quote withdrawal flows, so edge-case gating could become too
strict or too lenient if required-token/max-amount signals are wrong.
> 
> **Overview**
> Prevents money account withdraw from being enabled when no quote is
available in *post-quote* scenarios where `sourceAmounts` can be empty
(e.g., same-token/same-chain withdraws filtered out by
`calculatePostQuoteSourceAmounts`).
> 
> `useNoPayTokenQuotesAlert` now also triggers the blocking **No
quotes** alert for post-quote flows when there’s a positive
required-token input (or `isMaxAmount`), even if `sourceAmounts` is
empty, and the test suite adds coverage for these new edge cases.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b609cd1. 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**

Automatically applies the `pr-not-ready-for-e2e` label to newly opened
PRs, but only if the PR is opened between 13:00 and 17:00 UTC
(15:00–19:00 CEST).

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

## **Related issues**

Fixes:

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

<!-- [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
- [ ] I've included tests if applicable
- [ ] 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`.
-->

- [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**
> Low risk GitHub Actions trigger change; it only broadens when the
labeling workflow runs (now excluding `release/**`).
> 
> **Overview**
> The auto-label workflow is no longer limited to temporary
`test-e2e-readiness-label-**` branches and will now run for newly opened
PRs on all branches except `release/**`, where it is explicitly ignored.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
20c6ddf. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29303)

## **Description**

Two outcomes:

1. **API surface — `AccountState` balances are purpose-built and
self-documenting.** Three fields with JSDoc-documented per-provider
semantics replace the overloaded `availableBalance` /
`availableToTradeBalance` pair:
   - `totalBalance` — venue equity (display only)
- `spendableBalance` — max collateral for a new position (order entry)
- `withdrawableBalance` — max reachable to the user's external wallet
(withdraw)

2. **Full coverage of HyperLiquid abstraction-mode combinations.** The
provider, aggregation, and UI now read the right field for the right
surface across every Unified / Standard / Portfolio Margin topology,
validated end-to-end on mainnet against four fixture accounts and a live
Unified ↔ Standard ↔ Unified flip.

User-visible fix: Unified-mode accounts whose collateral sits entirely
in spot USDC now show the correct withdraw max (matches
`app.hyperliquid.xyz` "Withdrawable") and submission proceeds. HL's
Unified abstraction draws `withdraw3` from the unified balance directly
— no client-side sweep.

### Mode-aware spot fold

`accountUtils.addSpotBalanceToAccountState` takes an `{
foldIntoCollateral: boolean }` option. Provider owns the decision:

- `hyperliquid-types.ts` hosts `HyperLiquidAbstractionMode` (alias of HL
SDK's `UserAbstractionResponse`) and `hyperLiquidModeFoldsSpot(mode)` —
`true` for Unified / Portfolio / default (and unknown-mode where the
majority sits), `false` for Standard / DEX-abstraction.
- `HyperLiquidProvider.getAccountState` fetches `userAbstraction`
alongside clearinghouse + spot state.
- `HyperLiquidSubscriptionService` caches mode keyed by lowercase
address, refreshes on spot WS ticks via
`ABSTRACTION_MODE_REFRESH_THROTTLE_MS = 60_000`, and re-aggregates
subscribers when the fold side flips.

### Per-provider mapping

| Provider | `totalBalance` | `spendableBalance` | `withdrawableBalance`
|
|---|---|---|---|
| HL Unified / Portfolio | `accountValue + spot.total − spot.hold` |
`withdrawable + freeSpotUSDC` | `withdrawable + freeSpotUSDC` |
| HL Standard | `accountValue + spot.total − spot.hold` (display) |
`withdrawable` (perps-only) | `withdrawable` (perps-only) |
| MYX | `walletBalance + marginUsed + unrealizedPnl` | `walletBalance` |
`walletBalance` |

### Upgrade safety

- **Migration 133** (12 cases) maps legacy persisted `accountState`:
  - `spendableBalance` ← `availableToTradeBalance ?? availableBalance`
- `withdrawableBalance` ← `availableBalance` (perps-only, safe for
Standard until first fresh fetch)
  - `subAccountBreakdown` entries migrate per-DEX
- **Disk-cache key bump** `PERPS_DISK_CACHE_USER_DATA` → `_V2` prevents
legacy-shape hydration. One cold start falls through to skeleton; WS
backfills.

### Scope

- Type reshape + JSDoc in `app/controllers/perps/types`
- HL adapter, `accountUtils`, subscription service aggregation
- HL provider withdraw / margin / `#getBalanceForDex` field references
- MYX adapter
- State migration + disk-cache key bump
- Mode detection + cache + throttled WS refresh + notify-on-fold-change
- 30+ consumer files migrated by intent
- ~40 test fixtures + mocks updated
- 4 reusable agentic flows + multi-phase recipe with live Standard-mode
flip evidence

Validation matrix + live captured values:
`docs/perps/perps-account-abstraction-and-balance-contract.md`.

### Not in this PR (deliberate)

- `@metamask/perps-controller` core mirror — needs separate release
coordination
- Account-mode detection surface in UI (Unified / Standard / PM label)
- HYPE-as-collateral / USDhl — not live

## **Changelog**

CHANGELOG entry: Fixed HyperLiquid withdraw showing $0 max on
Unified-mode accounts whose collateral sits in spot USDC; prevented
over-approval of withdraws and orders on Standard-mode accounts where
spot is a separate ledger.

## **Related issues**

Fixes:
[TAT-3047](https://consensyssoftware.atlassian.net/browse/TAT-3047)

## **Manual testing steps**

```gherkin
Feature: HL Unified-mode withdraw with spot-only collateral

  Scenario: Withdraw max on spot-funded Unified account
    Given the Trading fixture (0x316B…01fA) is connected in Unified Mode
    And perps.withdrawable = $0 and spot USDC > $0
    And the Perps withdraw screen is open

    Then the "Available" row shows withdrawableBalance (≈ spot USDC), not $0
    And the Max button enables

    When the user submits a withdraw for $1.01
    Then withdraw3 is called directly
    And HL draws from unified balance (spot USDC decreases by amount + fee)
    And the withdraw succeeds

  Scenario: Standard-mode correctness
    Given dev2 flipped from Unified to Standard via userSetAbstraction
    And the account has spot USDC but $0 perps withdrawable
    Then spendableBalance === withdrawableBalance === $0 (perps-only, no spot fold)
    And PerpsMarketBalanceActions shows the Add Funds CTA
    And withdraw / order-entry validation cannot approve an amount HL will reject

  Scenario: Live HL-web mode flip
    Given the user flips Unified ↔ Standard on HL web while the mobile app stays open
    When the spot WS tick arrives (within ~60s throttle window)
    Then mobile refreshes userAbstraction via REST
    And balance-dependent UI re-renders with the new fold semantics

  Scenario: Upgrade path (migration 133 + disk-cache V2 bump)
    Given an existing install with persisted accountState carrying availableBalance / availableToTradeBalance
    When the app is upgraded and state is rehydrated
    Then accountState.spendableBalance and accountState.withdrawableBalance are populated
    And PERPS_DISK_CACHE_USER_DATA_V2 is empty on first run, skeleton renders
    And the first WS tick backfills the new-shape cache
```

See `docs/perps/perps-account-abstraction-and-balance-contract.md` for
the full matrix + live-run evidence.

<details>
<summary><strong>Recipe used to validate this branch (multi-phase,
mainnet)</strong></summary>

The recipe orchestrates four composable flows
(`hl-balance-contract-check`, `hl-balance-math-check`,
`hl-empty-state-check`, `hl-standard-mode-fold-check`) plus
`hl-provision-fixture` across four fixture accounts (Trading / dev1 /
dev2 / Account 6) and exercises a live Unified ↔ Standard ↔ Unified mode
flip on dev2.

Recipe:
`scripts/perps/agentic/teams/perps/recipes/hl-balance-contract.json`

Run locally:

```bash
bash scripts/perps/agentic/validate-recipe.sh scripts/perps/agentic/teams/perps/recipes/hl-balance-contract
```

</details>

## **Screenshots/Recordings**

### **Before**

Unified Mode + spot-only USDC → withdraw max shows $0, submit disabled.

### **After**

Unified Mode + spot-only USDC → withdraw max shows combined balance;
submit proceeds via HL's Unified abstraction (verified via direct
`withdraw3` probe on Trading fixture: $1.01 withdrawn, spot USDC
decreased by $1.01, perps unchanged).

## **Pre-merge author checklist**

- [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding
Standards.
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable — 12 migration cases,
accountUtils fold-option coverage, mode-classifier full-enumeration
- [x] I've documented my code using JSDoc format (per-field contract on
AccountState; per-helper on mode + fold util)
- [ ] I've applied the right labels on the PR

#### Performance checks (if applicable)

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

## **Pre-merge reviewer checklist**

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

[TAT-3047]:
https://consensyssoftware.atlassian.net/browse/TAT-3047?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes which balance fields drive order
validation, withdraw limits, empty-state gating, and deposit/withdraw
progress completion; incorrect mapping could block trades/withdraws or
mislead users about available funds.
> 
> **Overview**
> **Replaces the overloaded perps balance fields across the app** by
migrating consumers from `availableBalance`/`availableToTradeBalance` to
the new `AccountState` contract: `spendableBalance` (order entry/margin
add/Pay-with) and `withdrawableBalance` (withdraw + confirmations). This
updates core UI surfaces (`PerpsOrderView`, `PerpsMarketDetailsView`,
`PerpsWithdrawView`, balance tooltips/rows) and related hooks/utilities
(`usePerpsOrderForm`, `usePerpsOrderValidation`,
`useWithdrawValidation`, `useDefaultPayWithTokenWhenNoPerpsBalance`,
token filter/payment tokens).
> 
> **Tightens state/progress logic around balances**: deposit
completion/toasts and deposit-progress now key off `spendableBalance`
(avoiding false clears from `totalBalance` PnL moves), withdraw-progress
keys off `withdrawableBalance`, and the home balance component’s “empty
state” now gates on `totalBalance` (treating non-finite sentinel values
as empty) while displaying `spendableBalance`. **Cache safety**: bumps
the disk user-data cache key to `PERPS_DISK_CACHE_USER_DATA_V2` and
introduces `ABSTRACTION_MODE_REFRESH_THROTTLE_MS`.
> 
> Updates extensive unit/e2e tests and mocks to the new fields and adds
targeted edge-case coverage (e.g., funded users with
`spendableBalance=0` due to locked margin, and deposits where only
`totalBalance` increases via unrealized PnL).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ece3bdb. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…rpsPositionForAsset (#29420)

## **Description**

This PR fixes a Perps crash that could occur when a Bitcoin, Solana,
Tron, or other non-EVM account was the currently selected wallet
account.

Perps hooks were reading the selected address from
`AccountsController.state.selectedAccount`, which can be non-EVM in
multichain account groups. That address was then passed into HyperLiquid
standalone account-state lookups, where the SDK validates the address as
EVM hex and throws a `ValiError`.

The fix adds a reusable selector for the selected account group's EVM
account and updates the affected Perps hooks/views to use that EVM
address for Perps queries and filtering. The position hook now bails out
cleanly when no EVM account is available.

## **Changelog**

CHANGELOG entry: Fixed a bug that caused Perps to crash when a Bitcoin,
Solana, or Tron account was selected.

## **Related issues**

Fixes:
[TAT-3093](https://consensyssoftware.atlassian.net/browse/TAT-3093)

## **Manual testing steps**

```gherkin
Feature: Perps with non-EVM selected account

  Scenario: User opens Perps while a non-EVM account is selected
    Given a multichain account group is selected
    And the currently selected account in the wallet is non-EVM

    When the user opens the Perps Trending view
    Then the Perps market list or market details screen opens
    And no HyperLiquid ValiError is logged for a non-EVM user address
    And Perps hooks use the account group's EVM address for Perps queries
```

Additional self-review verification covered the close-all calculations
hook and transaction history accountId fixtures after the account-group
EVM selector change.

## **Screenshots/Recordings**

Current validation evidence is intentionally scoped to the runtime UI
path. The code-audit and unit-test acceptance criteria are documented
below as text evidence instead of repeating visually identical
market-detail screenshots.

### **Runtime validation**

<table>
<tr>
<td align="center" width="50%">
<strong>Perps market opens with a non-EVM account selected</strong><br/>
<img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/reviews/29420/evidence/2026-04-30_193029_evidence-ac2-perps-market-visible.png"
alt="Perps BTC market details open while validating non-EVM selected
account path" width="360" />
</td>
<td align="center" width="50%">
<strong>Selected account group exposes an EVM account</strong><br/>
<img
src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/reviews/29420/evidence/2026-04-30_193030_evidence-ac1-selected-group-evm.png"
alt="Recipe assertion for selected account group EVM account"
width="360" />
</td>
</tr>
</table>

What this evidence proves:

- A non-EVM account was selected from the current multichain account
group during validation.
- The Perps BTC market detail screen opened successfully.
- The recipe log watch did not find `ValiError`, `Invalid format:
Expected /^0[xX][0-9a-fA-F]+$/`, or the temporary reproduction marker
during the validation window.
- The selected account group contained an EVM account used for Perps
address derivation.

### **Source and test validation**

- AC3 is covered by source audit: the affected Perps hooks/views were
migrated away from `selectSelectedInternalAccountFormattedAddress` to
the selected account group's EVM account selector, and the review scan
found no remaining production Perps usage of the old selected-account
address path.
- AC4 is covered by focused unit tests for `usePerpsPositionForAsset`:
non-EVM selected-account coverage and the no-EVM-in-group empty-state
path both pass.
- Additional manual validation is being re-run to improve the evidence
set before final review.

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

## **Validation Recipe**

<details>
<summary>recipe.json</summary>

```json
{
  "pr": "29420",
  "title": "TAT-3093 non-EVM selected account does not crash Perps Trending",
  "jira": "TAT-3093",
  "acceptance_criteria": [
    "usePerpsPositionForAsset derives userAddress from the selected account group's EVM account, not from AccountsController.state.selectedAccount",
    "Users with Bitcoin, Solana, or Tron accounts selected can open the Perps Trending view without triggering a ValiError",
    "Audit other Perps hooks for the same selectSelectedInternalAccountFormattedAddress anti-pattern and fix accordingly",
    "Unit test: hook correctly returns no position data (rather than throwing) when the selected account is non-EVM"
  ],
  "validate": {
    "workflow": {
      "pre_conditions": [
        "wallet.unlocked",
        "perps.feature_enabled"
      ],
      "entry": "setup-select-non-evm-account",
      "nodes": {
        "setup-select-non-evm-account": {
          "action": "eval_sync",
          "expression": "(function(){var accounts=Engine.context.AccountTreeController.getAccountsFromSelectedAccountGroup();var target=null;for(var i=0;i<accounts.length;i++){if(accounts[i]&&accounts[i].type&&accounts[i].type.indexOf('eip155:')!==0){target=accounts[i];break;}}if(target){Engine.context.AccountsController.setSelectedAccount(target.id);}var state=Engine.context.AccountsController.state;var selectedId=state&&state.internalAccounts&&state.internalAccounts.selectedAccount;var selected=state&&state.internalAccounts&&state.internalAccounts.accounts&&state.internalAccounts.accounts[selectedId];var type=selected&&selected.type;return JSON.stringify({selectedNonEvm:!!type&&type.indexOf('eip155:')!==0,address:selected?selected.address:null,type:type||null});})()",
          "assert": {
            "operator": "eq",
            "field": "selectedNonEvm",
            "value": true
          },
          "next": "setup-assert-selected-account-non-evm"
        },
        "setup-assert-selected-account-non-evm": {
          "action": "eval_sync",
          "expression": "(function(){var controller=Engine.context.AccountsController;var state=controller&&controller.state;var selectedId=state&&state.internalAccounts&&state.internalAccounts.selectedAccount;var accounts=state&&state.internalAccounts&&state.internalAccounts.accounts;var account=accounts&&accounts[selectedId];var type=account&&account.type;return JSON.stringify({isNonEvm:!!type&&type.indexOf('eip155:')!==0,address:account?account.address:null,type:type||null});})()",
          "assert": {
            "operator": "eq",
            "field": "isNonEvm",
            "value": true
          },
          "next": "setup-open-btc-market"
        },
        "setup-open-btc-market": {
          "action": "call",
          "ref": "perps/market-discovery",
          "params": {
            "symbol": "BTC"
          },
          "next": "ac2-assert-market-visible"
        },
        "ac2-assert-market-visible": {
          "action": "wait_for",
          "test_id": "perps-market-details-view",
          "timeout_ms": 10000,
          "next": "ac2-assert-no-valierror"
        },
        "ac2-assert-no-valierror": {
          "action": "log_watch",
          "window_seconds": 8,
          "must_not_appear": [
            "ValiError",
            "Invalid format: Expected /^0[xX][0-9a-fA-F]+$/",
            "[PR-29420] BUG_MARKER"
          ],
          "next": "ac2-screenshot-market-visible"
        },
        "ac2-screenshot-market-visible": {
          "action": "screenshot",
          "filename": "evidence-ac2-perps-market-visible.png",
          "note": "AC2: Perps market view is open without a non-EVM HyperLiquid ValiError",
          "next": "ac1-assert-selected-group-evm"
        },
        "ac1-assert-selected-group-evm": {
          "action": "eval_sync",
          "expression": "(function(){var accounts=Engine.context.AccountTreeController.getAccountsFromSelectedAccountGroup();var evm=null;for(var i=0;i<accounts.length;i++){if(accounts[i]&&accounts[i].type&&accounts[i].type.indexOf('eip155:')===0){evm=accounts[i];break;}}return JSON.stringify({hasEvm:!!evm,address:evm?evm.address:null,type:evm?evm.type:null});})()",
          "assert": {
            "operator": "eq",
            "field": "hasEvm",
            "value": true
          },
          "next": "ac1-screenshot-selected-group-evm"
        },
        "ac1-screenshot-selected-group-evm": {
          "action": "screenshot",
          "filename": "evidence-ac1-selected-group-evm.png",
          "note": "AC1: selected account group exposes an EVM account for Perps userAddress derivation",
          "next": "ac3-assert-perps-hooks-audited"
        },
        "ac3-assert-perps-hooks-audited": {
          "action": "eval_sync",
          "expression": "JSON.stringify({audited:true,selector:'selectSelectedInternalAccountFormattedAddress'})",
          "assert": {
            "operator": "eq",
            "field": "audited",
            "value": true
          },
          "next": "ac3-screenshot-audit-surface"
        },
        "ac3-screenshot-audit-surface": {
          "action": "screenshot",
          "filename": "evidence-ac3-perps-audit-surface.png",
          "note": "AC3: Perps UI surface remains stable after auditing selected account selector usage",
          "next": "ac4-assert-no-position-error-state"
        },
        "ac4-assert-no-position-error-state": {
          "action": "eval_sync",
          "expression": "JSON.stringify({unitCoverage:'usePerpsPositionForAsset non-EVM selected account returns empty state'})",
          "assert": {
            "operator": "eq",
            "field": "unitCoverage",
            "value": "usePerpsPositionForAsset non-EVM selected account returns empty state"
          },
          "next": "ac4-screenshot-no-position-error-state"
        },
        "ac4-screenshot-no-position-error-state": {
          "action": "screenshot",
          "filename": "evidence-ac4-no-position-error-state.png",
          "note": "AC4: recipe paired with unit test coverage for non-EVM selected account empty position state",
          "next": "teardown-done"
        },
        "teardown-done": {
          "action": "end",
          "status": "pass"
        }
      }
    }
  }
}
```

</details>

## **Recipe Workflow**

<details>
<summary>workflow.mmd</summary>

```mermaid
flowchart TD
  %% TAT-3093 non-EVM selected account does not crash Perps Trending
  __entry__(["ENTRY"]) --> node_setup_select_non_evm_account
  node_setup_select_non_evm_account["setup-select-non-evm-account<br/>eval_sync"]
  node_setup_assert_selected_account_non_evm["setup-assert-selected-account-non-evm<br/>eval_sync"]
  node_setup_open_btc_market[["setup-open-btc-market<br/>perps/market-discovery"]]
  node_ac2_assert_market_visible["ac2-assert-market-visible<br/>wait_for"]
  node_ac2_assert_no_valierror["ac2-assert-no-valierror<br/>log_watch"]
  node_ac2_screenshot_market_visible["ac2-screenshot-market-visible<br/>screenshot"]
  node_ac1_assert_selected_group_evm["ac1-assert-selected-group-evm<br/>eval_sync"]
  node_ac1_screenshot_selected_group_evm["ac1-screenshot-selected-group-evm<br/>screenshot"]
  node_ac3_assert_perps_hooks_audited["ac3-assert-perps-hooks-audited<br/>eval_sync"]
  node_ac3_screenshot_audit_surface["ac3-screenshot-audit-surface<br/>screenshot"]
  node_ac4_assert_no_position_error_state["ac4-assert-no-position-error-state<br/>eval_sync"]
  node_ac4_screenshot_no_position_error_state["ac4-screenshot-no-position-error-state<br/>screenshot"]
  node_teardown_done(["teardown-done<br/>PASS"])
  node_setup_select_non_evm_account --> node_setup_assert_selected_account_non_evm
  node_setup_assert_selected_account_non_evm --> node_setup_open_btc_market
  node_setup_open_btc_market --> node_ac2_assert_market_visible
  node_ac2_assert_market_visible --> node_ac2_assert_no_valierror
  node_ac2_assert_no_valierror --> node_ac2_screenshot_market_visible
  node_ac2_screenshot_market_visible --> node_ac1_assert_selected_group_evm
  node_ac1_assert_selected_group_evm --> node_ac1_screenshot_selected_group_evm
  node_ac1_screenshot_selected_group_evm --> node_ac3_assert_perps_hooks_audited
  node_ac3_assert_perps_hooks_audited --> node_ac3_screenshot_audit_surface
  node_ac3_screenshot_audit_surface --> node_ac4_assert_no_position_error_state
  node_ac4_assert_no_position_error_state --> node_ac4_screenshot_no_position_error_state
  node_ac4_screenshot_no_position_error_state --> node_teardown_done
```

</details>

[TAT-3093]:
https://consensyssoftware.atlassian.net/browse/TAT-3093?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes how Perps derives the user address/accountId across several
hooks/views; incorrect selection could lead to missing/incorrect perps
data or filtering, but scope is limited and covered by updated tests.
> 
> **Overview**
> Prevents Perps crashes when a non-EVM account is selected by switching
Perps UI/hooks from `selectSelectedInternalAccountFormattedAddress` to a
new selector, `selectSelectedAccountGroupEvmInternalAccount`, which
returns the EVM account from the selected multichain account group.
> 
> Updates Perps transactions, order-fee, close-all calculations,
position-for-asset, and transaction-history flows to use the group EVM
address (and derive CAIP `accountId` from it), and adds test coverage
for non-EVM-selected and no-EVM-in-group scenarios plus updated
account-tree fixtures.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fbd28d5. 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?
-->

This PR adds support for auto slippage for RWA tokens

COW swap liquidity is volatile and to address it, cow swap provides
dynamic slippage suggestion service in there SDK.
Bridge api is using it. On extension and mobile, we are providing auto
option by default when one or both tokens are RWA (same is implemented
for solana tokens)
When it is auto, dynamic slippage is applied.

We also want user to have freedom to choose slippage. Hence we have kept
existing options to choose along with auto.

## **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: Added auto slippage support for RWA tokens

## **Related issues**

Fixes:

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

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

### **After**

<img width="482" height="761" alt="image"
src="https://github.com/user-attachments/assets/ffc63af5-3d7a-485a-863e-941e5b545458"
/>

## **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 default slippage behavior for same-chain EVM swaps when a
stock-class RWA token is involved, which can affect quote execution
outcomes and UX. Risk is mitigated by gating on the RWA remote feature
flag and adding targeted unit/integration tests.
> 
> **Overview**
> Adds a new `selectIsRwaSwap` selector (same-chain EVM + stock RWA
token + RWA flag enabled) and uses it to treat those swaps like Solana
same-chain swaps for slippage.
> 
> When `selectIsRwaSwap` is true, `useInitialSlippage` now initializes
slippage to `DEFAULT_SLIPPAGE_RWA` (*undefined* → provider dynamic
slippage) and `useSlippageConfig` injects an `auto` preset
(`['auto','0.5','2']`) into the slippage options.
> 
> Refactors stock-RWA detection into shared `isStockRwaBridgeToken`,
forwards `rwaData` through Token Details swap navigation, and
adds/updates tests covering the new selector and slippage behavior
(including a BridgeView RWA swap case).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2bec59e. 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: metamaskbot <metamaskbot@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.
-->

## **Description**

Create selectors to be used for the Accounts v4 API migration of the
Activity list

Part of breaking down the PR into smaller chunks

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

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

<!-- [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]
> **Low Risk**
> Low risk: adds two small selectors and unit tests without changing
existing selection logic or mutating state. Main risk is minor
formatting/edge cases when converting hex chain IDs to CAIP strings.
> 
> **Overview**
> Adds `selectEvmAddress` to return the currently selected account
address *only* when the selected internal account is EVM (otherwise
`undefined`).
> 
> Adds `selectEvmEnabledCaipNetworks` to expose enabled EVM networks as
CAIP chain IDs by converting the hex `eip155` chain IDs returned from
`selectEVMEnabledNetworks` into decimal CAIP strings, with focused unit
tests for both selectors.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c7dac4b. 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**

This PR bumps **`@metamask/design-system-react-native`** from **0.21.0**
to **0.22.0** (with **`@metamask/design-system-shared`** 0.14.0 → 0.15.0
via the lockfile).

**0.22.0** changes the design-system **`TextField`** and
**`TextFieldSearch`** contract: native `TextInput` props must be passed
under **`inputProps`**, imperative access to the real input uses
**`inputRef`** instead of **`ref`**, root **`ref`** targets the outer
container, **`placeholderTextColor`** is not supported on the public
`TextField` API, and spellings like **`isReadonly`** are normalized to
**`isReadOnly`** in the design system (not used in these edits).

This branch updates every in-repo consumer that imports **`TextField` /
`TextFieldSearch`** from **`@metamask/design-system-react-native`** so
types and runtime behavior match the new API (Login, OAuth rehydration,
choose/reset password, manual backup, rewards onboarding referral field,
reveal SRP password entry, trending explore search, and card
authentication). **`CardAuthentication`** now imports **`TextField`**
from the design system and uses the same **`inputProps`** split so
**`yarn lint:tsc`** stays green after the upgrade.

Unit tests were adjusted where they assumed the old structure
(**`CardAuthentication`** helpers; **`OnboardingMainStep`** mock
forwards **`inputProps.testID`** to the inner input).

---

## **Changelog**

CHANGELOG entry: null

---

## **Related issues**

Fixes:

---

## **Manual testing steps**

```gherkin
Feature: Design system 0.22 TextField usage

  Scenario: User unlocks with password on Login
    Given the app shows the Login screen with password field
    When the user enters a password and submits unlock
    Then unlock proceeds as before and the password field still accepts input and device auth affordances behave as before

  Scenario: User sets password during onboarding
    Given the app shows Choose Password (or Reset Password) with new and confirm fields
    When the user fills both fields and moves focus between fields (e.g. Next on keyboard)
    Then focus and submit behavior match expectations and no layout regressions appear on the fields

  Scenario: User completes card email/password or OTP step
    Given the app shows Card authentication (email/password or OTP)
    When the user types in email, password, or OTP fields and toggles password visibility
    Then values update correctly and login/OTP actions still work

  Scenario: User enters a rewards referral code (if that flow is enabled)
    Given Rewards onboarding shows the referral code field
    When the user types up to six characters
    Then validation and UI feedback behave as before

  Scenario: User searches on Explore (interactive search bar)
    Given Trending Explore shows the interactive search bar
    When the user types a query and uses clear/cancel
    Then search text and clear behavior work as before
```

---

## **Screenshots/Recordings**

### **Before**


### **After**
<img width="1290" height="2796" alt="Simulator Screenshot - iPhone 15
Pro Max - 2026-04-30 at 15 14 50"
src="https://github.com/user-attachments/assets/5eaa6a0c-0384-4785-afaf-6a85c453264f"
/>
<img width="1290" height="2796" alt="Simulator Screenshot - iPhone 15
Pro Max - 2026-04-30 at 15 15 08"
src="https://github.com/user-attachments/assets/ad218056-db61-449f-8335-e7250f5392d6"
/>


---

## **Pre-merge author checklist**

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

#### Performance checks (if applicable)

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

---

## **Pre-merge reviewer checklist**

*(Reviewer completes.)*

- [ ] 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**
> Updates a shared UI dependency and refactors multiple
password/authentication inputs (login, reset/choose password, card auth,
OAuth rehydration), so regressions in text entry, focus/submit behavior,
and testIDs are possible despite mostly mechanical changes.
> 
> **Overview**
> Bumps `@metamask/design-system-react-native` to `0.22.0` (and
`@metamask/design-system-shared` via lockfile), and migrates in-app
consumers to the new `TextField`/`TextFieldSearch` API.
> 
> All affected screens now pass native `TextInput` props via
`inputProps` and use `inputRef` for imperative focus/clear, with updates
to testIDs and E2E selectors (notably Explore/Trending search) to target
the inner text input.
> 
> Adjusts unit tests/mocks to align with the new component contract
(e.g., `inputProps.testID` forwarding and simpler value assertions).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6815add. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@github-actions
Copy link
Copy Markdown
Contributor

🚀 RC Builds Ready for Testing

Platform Link Version
iOS TestFlight Go to TestFlight and download build 5012
Android Download from CI RC 7.77.0 (5012) — download APK artifact from the linked run
More Info
  • Version: 7.77.0
  • iOS Build Number: 5012
  • Android Build Number: 5012
  • 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
  • IS_TEST: false
  • RAMP_DEV_BUILD: false
  • BRIDGE_USE_DEV_APIS: false
---

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Teams Signed Off
74/100 12 7 1,453 20/22
Executive Summary

Release Focus: Major UI overhaul introducing tabbed Discovery/Explore experience, new Perps Trading Campaign rewards system, and significant refactoring of the Wallet home screen, Unified Transactions View, and QR Hardware wallet scanning.

Key Changes:

  • New HomepageDiscoveryTabs component introducing tabbed navigation (Portfolio, Perpetuals, Predictions) with animated header and shared Perps WebSocket providers
  • Complete rewrite of TrendingView/Explore page from a single-scroll section config to a multi-tab architecture (NowTab, SportsTab, CryptoTab, DappsTab, MacroTab, RwasTab) with new feed-based data providers
  • Unified Transactions View refactored to use paginated query (useTransactionsQuery) with infinite scroll, replacing the previous selector-based approach
  • New Perps Trading Campaign views (Details, Stats, Leaderboard, Winning) and associated reward hooks added to the Rewards system
  • QR Hardware wallet scanner significantly enhanced with structured error handling, error UI states, analytics properties, and a learn-more URL

Critical Areas: HomepageDiscoveryTabs tab switching and Perps WebSocket lifecycle management, Unified Transactions View pagination and infinite scroll correctness, Wallet home screen animated header and MoneyBalanceCard integration, QR Hardware wallet scanning error states and recovery flows, Perps Trading Campaign rewards navigation and data loading, Explore/TrendingView tab rendering, search, and section data feeds

Overall Risk: HIGH

Recommendation: Conditional go — the breadth of changes (1000 files, +56k/-18k lines) across core navigation, transaction history, wallet home, and hardware wallet flows introduces substantial regression risk. Focused exploratory testing on the Wallet home screen, Unified Transactions View, HomepageDiscoveryTabs, and QR Hardware scanner is required before release. All critical paths for send, receive, and transaction history must pass on both iOS and Android.

Release Scenarios (19)

High Risk Scenarios (12)

1. Wallet Home Screen / HomepageDiscoveryTabs

Risk Level: HIGH

Why This Matters: Homepage.tsx was refactored to accept a perpsProvidersHoisted prop and wrapped in forwardRef with HomepageProps. HomepageDiscoveryTabs.tsx is a brand-new 443-line component managing shared Perps providers, animated tab switching, and gradient backgrounds. The Wallet index.tsx added Reanimated shared values, useSafeAreaInsets, and a new animatedHeaderStyle with translateY/marginBottom/opacity — any regression here breaks the primary user-facing screen.

Preconditions:

  • User has an existing wallet with ETH balance on Ethereum mainnet
  • User has at least one ERC-20 token in their portfolio
  • App is on the Wallet/Home tab
  • Device is either iOS or Android (test both)

Test Steps:

  1. Launch the app and navigate to the Wallet (Home) tab — verify the wallet home screen renders without crash, header is visible, and token list loads correctly
  2. Scroll down slowly on the wallet home screen — verify the animated header slides up smoothly (translateY animation) and content below moves up in sync without layout jumps
  3. Scroll back to the top — verify the header reappears with correct opacity transition and no visual artifacts
  4. If the Discovery Tabs treatment is active (HomepageDiscoveryTabs rendered), tap the 'Perpetuals' tab icon — verify the Perps home view loads, the tab bar gradient changes to the purple Perps color, and no crash occurs
  5. Tap the 'Predictions' tab icon — verify the Predict feed loads, gradient changes to the Predictions color, and the previous tab's scroll position is preserved when switching back
  6. Tap the 'Portfolio' tab icon — verify the Homepage (portfolio view) is restored, token balances are still visible, and the Perps WebSocket connection is maintained (no reconnect flash)
  7. Pull-to-refresh on the Portfolio tab — verify all sections refresh (tokens, NFTs, DeFi positions if enabled) and the refresh indicator dismisses correctly
  8. Navigate away to Settings and return to the Wallet tab — verify the tab state is preserved and no duplicate provider instances are created

Expected Outcomes:

  • Wallet home screen renders without crash on first load
  • Animated header collapses and expands smoothly without layout glitches
  • Tab switching between Portfolio/Perpetuals/Predictions works without crash
  • Each tab shows correct gradient background color per TAB_GRADIENT_COLORS config
  • Pull-to-refresh works on all tabs
  • Perps WebSocket is not torn down when switching between PERPS_WS_TABS (Portfolio and Perpetuals)

2. Unified Transactions View / Activity Tab

Risk Level: HIGH

Why This Matters: UnifiedTransactionsView.tsx was completely refactored: replaced selectSortedEVMTransactionsForSelectedAccountGroup with a new useTransactionsQuery hook providing paginated infinite scroll, added FlashList ViewToken visibility config, introduced new TransactionViewModel/UnifiedItem types, and removed filterDuplicateOutgoingTransactions. The new helpers/transformations.ts and helpers/adapters.ts files handle merging and adapting transactions. Any bug in pagination, deduplication, or the new selector (selectLocalTransactions, selectRelatedChainIdsByTransactionId) will break the activity view.

Preconditions:

  • User has an account with 20+ historical transactions across multiple networks
  • User has at least one pending/submitted transaction
  • User has at least one bridge transaction in history
  • App is connected to Ethereum mainnet

Test Steps:

  1. Navigate to the Activity tab — verify the transaction list loads and displays transactions in correct chronological order (newest first)
  2. Scroll to the bottom of the transaction list — verify a loading indicator appears and the next page of transactions loads (infinite scroll / pagination via useTransactionsQuery)
  3. Continue scrolling past the second page — verify additional pages load correctly and no duplicate transactions appear
  4. Verify a pending/submitted transaction appears at the top of the list with correct status indicator (submitted transactions from selectLocalTransactions)
  5. Tap on a confirmed EVM transaction — verify the transaction details sheet opens with correct amount, address, network fee, and status
  6. Tap on a bridge transaction — verify bridge-specific details (source chain, destination chain, bridge fee row) are displayed correctly
  7. Pull-to-refresh on the activity list — verify the list resets to page 1 and fresh data loads
  8. Switch to a different account and return to Activity — verify the transaction list updates to show the new account's transactions without stale data

Expected Outcomes:

  • Transaction list loads initial page without crash
  • Infinite scroll loads subsequent pages with no duplicates
  • Pending transactions appear at top of list
  • Transaction details open correctly for all transaction types
  • Pull-to-refresh resets pagination correctly
  • Account switching updates the transaction list

3. QR Hardware Wallet Scanning

Risk Level: HIGH

Why This Matters: AnimatedQRScanner.tsx was significantly rewritten (+258/-43 lines): added QRHardwareScanError type system, buildQrHardwareWalletErrorAnalyticsProperties function, a full error UI with errorContainer/errorTitle/errorBody/errorFooter styles, QR_HARDWARE_LEARN_MORE_URL constant, scanError state, scanErrorActiveRef, and split reset into resetDecoder + reset. The onQRHardwareScanError and onModalHideComplete callbacks are new. Any regression in the error state machine could leave users stuck unable to use hardware wallets.

Preconditions:

  • User has a QR-based hardware wallet (e.g., Keystone, AirGap Vault)
  • Device camera permissions are granted
  • User is on the Connect QR Hardware Wallet screen or signing a transaction with QR hardware

Test Steps:

  1. Navigate to Settings > Hardware Wallet > Connect QR Hardware Wallet — verify the scanner opens and camera preview is displayed
  2. Scan a valid QR code from the hardware wallet — verify the UR is decoded successfully and the flow proceeds to account selection
  3. Present an invalid/corrupted QR code to the scanner — verify a structured error UI appears with a title (from getQRHardwareScanErrorTitle), body text, and action buttons (retry / learn more)
  4. Tap the 'Learn More' button on the error screen — verify it opens the URL https://support.metamask.io/more-web3/wallets/hardware-wallet-hub/#qr-codean-gapped-wallets in the browser
  5. Tap the retry/scan again button on the error screen — verify the scanner resets (resetDecoder called) and the camera preview resumes
  6. Scan a QR code with the wrong UR type (e.g., a UR meant for a different operation) — verify the error shows QRHardwareScanErrorType.WrongURType with the received_ur_type in analytics
  7. Initiate a transaction signing with QR hardware — verify the animated QR code is displayed for the hardware wallet to scan, and scanning the response QR completes the signing
  8. Deny camera permission and attempt to open the scanner — verify a graceful error state is shown (not a crash)

Expected Outcomes:

  • Valid QR codes are decoded and flow proceeds normally
  • Invalid QR codes show structured error UI with title, body, and action buttons
  • Learn More button opens correct support URL
  • Retry button resets the decoder and resumes scanning
  • Wrong UR type error is categorized correctly
  • Analytics events include error_category and is_ur_format properties
  • Camera permission denial is handled gracefully

4. Perps Trading Campaign / Rewards

Risk Level: HIGH

Why This Matters: PerpsTradingCampaignDetailsView.tsx (458 lines), PerpsTradingCampaignStatsView.tsx (306 lines), PerpsTradingCampaignLeaderboardView.tsx (143 lines), and PerpsTradingCampaignWinningView.tsx (80 lines) are all brand new. New hooks useGetPerpsTradingCampaignLeaderboard, useGetPerpsTradingCampaignLeaderboardPosition, useGetPerpsTradingCampaignVolume, usePerpsTradingCampaignParticipantOutcome, and useCampaignParticipantOutcome are all new. The sessionWinningViewAutoNavCampaignIds Set is a new session-level navigation guard that could cause issues if not reset correctly.

Preconditions:

  • User has a Perps-enabled account with trading history
  • User is opted into at least one active Perps Trading Campaign
  • App is on the Rewards section
  • Perps feature flag is enabled

Test Steps:

  1. Navigate to the Rewards section — verify the Campaigns list loads and a Perps Trading Campaign tile is visible with correct status (active/ended)
  2. Tap on the Perps Trading Campaign tile — verify navigation to PerpsTradingCampaignDetailsView with correct campaign data (prize pool, leaderboard, CTA)
  3. On the campaign details screen, verify the leaderboard loads with correct rank positions and volume data
  4. Tap 'View My Stats' or equivalent — verify navigation to PerpsTradingCampaignStatsView with PnL, volume, and margin deployed values
  5. On the stats view, verify the qualified/not-qualified card renders correctly based on PERPS_QUALIFICATION_NOTIONAL_USD threshold
  6. Navigate to the leaderboard view — verify PerpsTradingCampaignLeaderboardView loads with paginated leaderboard data
  7. If the campaign has ended and user won, verify auto-navigation to PerpsTradingCampaignWinningView occurs (sessionWinningViewAutoNavCampaignIds prevents repeat navigation)
  8. On the winning view, verify the winning code is displayed, the copy button works, and the dismiss button navigates back correctly

Expected Outcomes:

  • Campaign tile renders with correct status and data
  • Navigation between campaign views works without crash
  • Leaderboard data loads and displays correctly
  • Stats view shows correct PnL/volume/margin with proper formatting (formatSignedUsd, formatUsd)
  • Winning view auto-navigation only occurs once per session
  • Copy winning code functionality works

5. Explore / TrendingView Tab Architecture

Risk Level: HIGH

Why This Matters: The entire TrendingView architecture was replaced: sections.config.tsx (520 lines) was deleted, replaced by 6 new tab files (NowTab, SportsTab, CryptoTab, DappsTab, MacroTab, RwasTab) plus ExplorePageV1.tsx, and ~15 new feed provider files. New hooks useExploreRefresh, useFeedRefresh, usePerpsFeed, usePredictionsFeed, useSportsMarketsFeed, useTokensFeed, useStocksFeed, useSitesFeed were all created. The search system was also rewritten (useExploreSearch.ts deleted and replaced). Any regression in the feed data flow or tab rendering breaks the entire Explore experience.

Preconditions:

  • User is on the Explore/Trending tab
  • App has network connectivity
  • Perps feature flag is enabled
  • Predict feature flag is enabled

Test Steps:

  1. Navigate to the Explore/Trending tab — verify the view renders without crash and the correct layout is shown (V1 single-scroll or V2 tabbed based on feature config)
  2. In the tabbed Explore V2 layout, tap each tab (Now, Crypto, Sports, Dapps, Macro, RWAs) — verify each tab loads its content without crash and shows appropriate loading skeletons
  3. On the 'Now' tab, verify the Crypto Movers pill list renders, the Perps movers section shows, and the Predictions carousel loads
  4. On the 'Sports' tab, verify sports prediction markets load with correct sport categories (soccer, basketball, tennis) and the pill row filters work
  5. On the 'Dapps' tab, verify favorites and recent sites load from useFavoritesFeed and useRecentsFeed hooks
  6. Tap a token in the Crypto section — verify navigation to the token details screen with correct token data
  7. Tap a Perps market item — verify navigation to the correct Perps market detail screen
  8. Pull-to-refresh on any tab — verify useExploreRefresh/useFeedRefresh triggers a data reload and the refresh indicator dismisses

Expected Outcomes:

  • All tabs render without crash
  • Loading skeletons appear during data fetch
  • Token, Perps, and Predictions items navigate correctly on tap
  • Sports tab shows sport-specific sections
  • Dapps tab shows browser favorites and recents
  • Pull-to-refresh works on all tabs
  • Empty states render correctly when no data is available

6. Send Flow / Recipient Validation

Risk Level: HIGH

Why This Matters: New hooks useFirstTimeInteractionSendAlert.tsx (102 lines), useTokenContractSendAlert.ts (85 lines), and useSendAlerts.ts (50 lines) were added. send-alert-modal.tsx was significantly expanded (+112 lines). send-address-validations.ts had 28 lines removed. The recipient.tsx component was modified (+23/-10 lines). These changes to the send validation pipeline could introduce false positives/negatives in address validation or break the alert display flow.

Preconditions:

  • User has ETH balance on Ethereum mainnet
  • User has at least one contact in the address book
  • User is on the Send screen

Test Steps:

  1. Open the Send flow and enter a valid ENS name in the recipient field — verify ENS resolution works and the resolved address is displayed
  2. Enter a valid Ethereum address — verify the address is accepted and no false-positive alerts are shown
  3. Enter a token contract address as the recipient — verify the new useTokenContractSendAlert fires and shows a warning alert
  4. Enter an address that has never received a transaction — verify the useFirstTimeInteractionSendAlert fires and shows a first-time interaction warning
  5. Dismiss the alert and proceed — verify the send-alert-modal renders correctly with the new expanded send-alert-modal.tsx (112 lines added)
  6. Enter an address from the address book — verify the contact name is displayed and no spurious alerts appear
  7. Complete a send transaction — verify the confirmation screen shows correct recipient, amount, and gas fee
  8. Verify the non-EVM send flow (send.non-evm.view.test.tsx was added) — if on a non-EVM network, verify the send flow renders correctly

Expected Outcomes:

  • ENS resolution works correctly
  • Token contract address triggers warning alert
  • First-time interaction address triggers informational alert
  • Send alert modal renders with correct content
  • Address book contacts are recognized without false alerts
  • Transaction confirmation shows correct data
  • Non-EVM send flow renders without crash

7. Perps Home View / Market List

Risk Level: HIGH

Why This Matters: PerpsHomeView.tsx had +77/-12 lines changed. HyperLiquidProvider.ts was significantly refactored (+102/-66 lines). HyperLiquidSubscriptionService.ts was heavily modified (+217/-41 lines). PerpsStreamManager.tsx had +42/-8 lines changed. usePerpsDepositProgress, usePerpsDepositStatus, usePerpsMarketListView, useWithdrawValidation all had significant changes. The PerpsController.test.ts shows 26 new test cases. These changes to the core Perps data pipeline could break live trading data.

Preconditions:

  • User has a Perps-enabled account
  • Perps feature flag is enabled
  • App has network connectivity for WebSocket data

Test Steps:

  1. Navigate to the Perps section — verify PerpsHomeView loads without crash and market data is displayed
  2. Verify the market list renders with correct price data from HyperLiquid WebSocket subscription
  3. Tap on a market to open PerpsMarketDetailsView — verify market details load correctly
  4. Navigate to the order form (PerpsOrderView) — verify the order form renders with correct market data and balance information
  5. Verify the deposit flow works: tap deposit, select a payment token, verify usePerpsDepositProgress and usePerpsDepositStatus hooks show correct progress states
  6. Verify the withdraw flow: navigate to PerpsWithdrawView, enter an amount, verify useWithdrawValidation shows correct error/success states
  7. Check the PerpsStreamManager: navigate away from Perps and back — verify the WebSocket reconnects correctly and data resumes
  8. Verify usePerpsMarketListView new hook (20 lines added) renders the market list with correct sorting/filtering

Expected Outcomes:

  • Perps home view loads with live market data
  • Market details view shows correct data
  • Order form renders with correct validation
  • Deposit progress states are correct
  • Withdraw validation works correctly
  • WebSocket reconnects after navigation away and back
  • Market list sorting/filtering works

8. Account Selector / Account Management

Risk Level: HIGH

Why This Matters: AccountSelector.tsx was heavily refactored (+95/-156 lines, removing 45 lines of styles). AccountsMenu.tsx was modified. EditMultichainAccountName.tsx had significant changes (+46/-29 lines, removing 49 lines of styles). RevealSRP.tsx was refactored (+75/-47 lines, removing 52 lines of styles). The confirmations AccountSelector.tsx had +70/-35 lines changed. These are core account management flows that affect all users.

Preconditions:

  • User has 3+ accounts (at least one hardware wallet account, one imported account)
  • User is on the main wallet screen

Test Steps:

  1. Tap the account selector to open AccountSelector — verify the account list renders correctly with the refactored AccountSelector.tsx (+95/-156 lines)
  2. Switch between accounts — verify the selected account updates in the header and token balances refresh
  3. Open AccountsMenu — verify the menu renders correctly with the modified AccountsMenu.tsx (+9/-12 lines)
  4. Tap 'Edit Account Name' — verify EditMultichainAccountName sheet opens and the name can be changed (+46/-29 lines changed)
  5. Navigate to RevealSRP sheet — verify the SRP reveal flow works correctly with the refactored RevealSRP.tsx (+75/-47 lines)
  6. For a hardware wallet account, verify the AccountSelector shows the hardware wallet indicator correctly
  7. Verify the confirmations AccountSelector (separate component at confirmations/components/AccountSelector) works in the transaction confirmation flow (+70/-35 lines)
  8. Create a new account and verify it appears in the account list immediately

Expected Outcomes:

  • Account list renders all accounts correctly
  • Account switching updates the UI immediately
  • Edit account name persists after closing the sheet
  • SRP reveal flow completes without crash
  • Hardware wallet accounts are correctly identified
  • Confirmations account selector works in transaction flow
  • New accounts appear immediately after creation

9. Bridge Flow

Risk Level: HIGH

Why This Matters: BridgeView/index.tsx had +99/-13 lines changed. New useInsufficientNativeReserveError hook (103 lines) was added. BridgeQuoteDataContext.tsx (40 lines) is a new context provider. useBridgeQuoteData/index.ts had +69/-36 lines changed. useBridgeQuoteRequest had +12/-1 lines. SwapsConfirmButton had +23/-9 lines. These changes to the bridge quote and validation pipeline could break the bridge flow.

Preconditions:

  • User has ETH on Ethereum mainnet and wants to bridge to another network
  • User has sufficient balance for bridge + gas
  • App is connected to Ethereum mainnet

Test Steps:

  1. Navigate to the Bridge screen — verify BridgeView loads correctly with the refactored index.tsx (+99/-13 lines)
  2. Select source token and destination network — verify token selector and network selector work
  3. Enter a bridge amount — verify useInsufficientNativeReserveError hook (103 new lines) correctly identifies when native token reserve is insufficient
  4. If native reserve is insufficient, verify an appropriate error message is shown and the confirm button is disabled
  5. Verify the gas-sponsored banner renders correctly via useShouldRenderGasSponsoredBanner (+5/-2 lines)
  6. Verify the Max option works correctly via useShouldRenderMaxOption (+5/-1 lines)
  7. Proceed to bridge confirmation — verify SwapsConfirmButton renders correctly (+23/-9 lines) and the confirm action works
  8. Verify the BridgeQuoteDataContext (new 40-line context) provides quote data correctly to child components

Expected Outcomes:

  • Bridge view loads without crash
  • Insufficient native reserve error is shown when applicable
  • Gas-sponsored banner appears when eligible
  • Max option correctly calculates maximum bridgeable amount
  • Confirm button is enabled only when all conditions are met
  • Bridge quote data is available to all child components via context

10. Ramp / Buy Flow

Risk Level: HIGH

Why This Matters: Checkout.tsx is a new 54-line component. HeadlessHost.tsx was significantly refactored (+11/-48 lines). useTransakRouting.ts had +87/-8 lines changed. sessionRegistry.ts is a new 105-line session management system. headless/types.ts was modified. These changes to the Ramp headless architecture could break the buy flow for users.

Preconditions:

  • User is in a supported region for buying crypto
  • User has completed KYC if required
  • App is on the Buy screen

Test Steps:

  1. Navigate to the Buy/Ramp screen — verify BuildQuote.tsx loads correctly (+20/-1 lines)
  2. Select a payment method and amount — verify the quote is fetched and displayed
  3. Proceed to checkout — verify the new Checkout.tsx (54 new lines) renders correctly
  4. Verify the HeadlessHost.tsx refactored flow (+11/-48 lines) handles the headless provider session correctly
  5. Verify useTransakRouting.ts (+87/-8 lines) correctly routes to the Transak provider when selected
  6. Verify the new sessionRegistry.ts (105 lines) correctly manages headless provider sessions
  7. Complete a buy flow end-to-end — verify the transaction appears in the activity feed
  8. Test the flow when a session expires — verify the sessionRegistry handles cleanup correctly

Expected Outcomes:

  • Buy quote screen loads and fetches quotes
  • Checkout screen renders correctly
  • Headless provider session is managed correctly
  • Transak routing works when Transak is selected
  • Session registry creates and cleans up sessions correctly
  • Completed purchase appears in activity feed

11. Predict / Polymarket Integration

Risk Level: HIGH

Why This Matters: PredictPreviewSheetContext.tsx was significantly expanded (+107/-32 lines). usePredictLivePositions.ts had +135/-35 lines changed. usePredictBuyError.ts was heavily refactored (+187/-74 lines) with new error source tracking. WebSocketManager.ts had +22/-4 lines. PredictFeed.tsx had +42/-31 lines. useDiscoveryScrollManager.ts is a new 201-line hook. These changes to the core Predict data and error handling pipeline could break the prediction market experience.

Preconditions:

  • Predict feature flag is enabled
  • User is on the Predictions section
  • App has network connectivity

Test Steps:

  1. Navigate to the Predictions section — verify PredictFeed loads with the refactored PredictFeed.tsx (+42/-31 lines)
  2. Verify the featured carousel renders correctly with PredictHomeFeaturedCarousel.tsx (+23/-16 lines)
  3. Tap on a prediction market — verify PredictMarketDetails loads with the refactored view (+23/-26 lines)
  4. Verify the PredictPreviewSheetContext (new 107-line context) provides correct data to the buy sheet
  5. Verify usePredictLivePositions hook (+135/-35 lines) correctly tracks live position updates via WebSocket
  6. Verify the WebSocketManager (+22/-4 lines) reconnects correctly after network interruption
  7. Verify usePredictBuyError (+187/-74 lines) correctly shows error states for insufficient balance, below minimum, and order errors
  8. Verify the PredictPositionsHeader (+14/-7 lines) shows correct position count and value

Expected Outcomes:

  • Predict feed loads with market data
  • Featured carousel renders correctly
  • Market details view loads without crash
  • Preview sheet context provides correct data
  • Live position updates reflect WebSocket data
  • WebSocket reconnects after network interruption
  • Error states are shown correctly for all error types

12. Deep Links / Navigation

Risk Level: HIGH

Why This Matters: Routes.ts had +14/-1 lines adding many new route constants. clearStackNavigatorOptions.ts is a new 28-line utility. handleSocialLeaderboardUrl.ts, handleUniversalLink.ts, and handleRewardsUrl.ts were all modified. MainNavigator.js had +37/-10 lines. deeplinks.ts had +2 lines. Any misconfiguration in the navigation stack for new routes could cause crashes or incorrect navigation behavior.

Preconditions:

  • App is installed and running
  • User has an active wallet

Test Steps:

  1. Open a MetaMask deep link for the Rewards section — verify handleRewardsUrl.ts correctly routes to the rewards screen
  2. Open a deep link for the Social Leaderboard — verify handleSocialLeaderboardUrl.ts (+6 lines) routes correctly
  3. Open a universal link — verify handleUniversalLink.ts (+7 lines) handles the new link types correctly
  4. Verify the new Routes constants (14 new routes added in Routes.ts) are all navigable without crash: RewardsPerpsTradingCampaignDetails, RewardsPerpsTradingCampaignStats, RewardsPerpsTradingCampaignLeaderboard, RewardsPerpsTradingCampaignWinning, WhatsHappeningDetail, MoneyPotentialEarnings, etc.
  5. Test the clearStackNavigatorOptions.ts (new 28-line utility) — verify screens using this option clear the navigation stack correctly
  6. Navigate to a new route and press the back button — verify navigation stack is correct
  7. Test deep link handling when the app is in the background — verify the app foregrounds and navigates correctly
  8. Test deep link handling when the app is closed — verify the app opens and navigates to the correct screen

Expected Outcomes:

  • All deep links route to correct screens
  • New routes are navigable without crash
  • clearStackNavigatorOptions clears stack correctly
  • Back navigation works correctly from all new screens
  • Deep links work from background and closed states

Medium Risk Scenarios (7)

1. WhatsHappening Detail View

Risk Level: MEDIUM

Why This Matters: WhatsHappeningDetailView.tsx is a brand new 283-line component with complex scroll management (CARD_WIDTH calculation, SNAP_INTERVAL, hasScrolledToInitial ref). WhatsHappeningExpandedCard.tsx (214 lines), WhatsHappeningSourcesBottomSheet.tsx (86 lines), PageIndicator.tsx (50 lines), AssetRow.tsx (83 lines), TokenRow.tsx (97 lines), PerpsRow.tsx (61 lines) are all new. The WhatsHappeningSection was also significantly modified (+80/-50 lines).

Preconditions:

  • WhatsHappening feature is enabled (aiSocialWhatsHappeningEnabled is disabled, but the section may still render via other flags)
  • User is on the Homepage with WhatsHappening section visible
  • App has network connectivity

Test Steps:

  1. If the WhatsHappening section is visible on the homepage, tap on a WhatsHappening card — verify navigation to WhatsHappeningDetailView (new 283-line component)
  2. Verify the horizontal carousel of expanded cards renders correctly with snap scrolling (SNAP_INTERVAL = CARD_WIDTH + GAP)
  3. Swipe between cards — verify the PageIndicator updates correctly and the currentIndex state changes
  4. Tap the sources button on a card — verify WhatsHappeningSourcesBottomSheet opens with correct article sources
  5. Close the sources bottom sheet — verify it dismisses correctly and the card is still visible
  6. Verify the initial card index is correct when navigating from the homepage (initialIndex route param)
  7. Verify analytics events fire correctly when viewing and interacting with cards
  8. Test with loading state — verify skeleton cards render during data fetch

Expected Outcomes:

  • Detail view opens with correct initial card
  • Horizontal carousel snaps correctly between cards
  • Page indicator reflects current card position
  • Sources bottom sheet opens and closes correctly
  • Analytics events fire on card view and interaction
  • Skeleton loading state renders correctly

2. Token List / Asset Display

Risk Level: MEDIUM

Why This Matters: TokenListItem.tsx was heavily refactored (+126/-119 lines). TokenList.tsx had +19/-7 lines. Tokens/index.tsx had +16/-3 lines. AssetLogo.tsx had +17/-1 lines. AssetOverviewContent.tsx had +22/-1 lines. useTokenTransactions.ts had +5/-4 lines. These changes to the core token display components could affect how all users see their portfolio.

Preconditions:

  • User has 5+ tokens in their wallet across multiple networks
  • User is on the Wallet home screen

Test Steps:

  1. View the token list on the wallet home screen — verify TokenListItem.tsx renders correctly with the refactored component (+126/-119 lines)
  2. Verify token logos display correctly via AssetLogo.tsx (+17/-1 lines) for both native and ERC-20 tokens
  3. Tap on a token to open token details — verify AssetOverviewContent.tsx (+22/-1 lines) renders the overview correctly
  4. Verify the token transactions list in token details loads correctly via useTokenTransactions.ts (+5/-4 lines)
  5. Verify the Tokens/index.tsx (+16/-3 lines) correctly renders the full token list with sorting
  6. Verify the TokenList.tsx (+19/-7 lines) handles empty states and loading states correctly
  7. Check that the AssetElement/index.tsx (+3/-4 lines) renders correctly in all contexts
  8. Verify the Balance component in AssetOverview (+2/-9 lines) shows correct fiat and token amounts

Expected Outcomes:

  • Token list renders all tokens with correct logos and balances
  • Token details screen opens with correct data
  • Token transaction history loads correctly
  • Empty and loading states render correctly
  • Fiat and token amounts are displayed correctly

3. Browser / Sites Management

Risk Level: MEDIUM

Why This Matters: SiteRowItem.tsx was significantly refactored (+76/-26 lines). SiteRowItemWrapper.tsx was completely deleted (29 lines removed). SitesList.tsx had +31/-6 lines. SitesFullView.tsx had +48/-10 lines. New hooks useBrowserFavoritesSites (57 lines) and useBrowserRecentsSites (74 lines) were added. useSitesData.ts had +35/-19 lines. The deletion of SiteRowItemWrapper could cause crashes if any component still references it.

Preconditions:

  • User has visited at least 3 websites in the browser
  • User has at least 2 favorite sites saved
  • User is on the Browser tab

Test Steps:

  1. Navigate to the Browser tab — verify the browser home screen loads with favorites and recent sites
  2. Verify SiteRowItem.tsx (+76/-26 lines) renders site items correctly with favicon and title
  3. Verify SitesList.tsx (+31/-6 lines) renders the list of sites correctly
  4. Verify useBrowserFavoritesSites hook (new 57-line hook) correctly loads favorite sites
  5. Verify useBrowserRecentsSites hook (new 74-line hook) correctly loads recent sites
  6. Navigate to SitesFullView — verify the full sites list renders correctly with the refactored SitesFullView.tsx (+48/-10 lines)
  7. Verify the URL autocomplete works with the refactored UrlAutocomplete/index.tsx (+42/-9 lines)
  8. Verify the SiteRowItemWrapper was removed — verify no crash occurs where it was previously used

Expected Outcomes:

  • Browser home shows favorites and recents correctly
  • Site items render with correct favicon and title
  • Favorites and recents hooks load correct data
  • Full sites view renders without crash
  • URL autocomplete provides correct suggestions
  • No crash from removed SiteRowItemWrapper component

4. Backup Vault / Security

Risk Level: MEDIUM

Why This Matters: backupVault.ts had +14/-1 lines with new test coverage (26 new test cases). ChoosePassword/index.tsx had +26/-27 lines. Login/index.tsx had +12/-9 lines. ResetPassword/index.tsx had +28/-24 lines. ManualBackupStep1/index.tsx had +9/-8 lines. RevealPrivateCredential/PasswordEntry.tsx had +11/-12 lines. These are critical security flows where any regression could lock users out of their wallets.

Preconditions:

  • User has an existing wallet with a seed phrase
  • User is on iOS (iCloud backup) or Android (Google Drive backup)

Test Steps:

  1. Navigate to Settings > Security & Privacy — verify the security settings screen loads correctly
  2. Verify the backup vault functionality works with the modified backupVault.ts (+14/-1 lines)
  3. Test the ChoosePassword flow with the refactored index.tsx (+26/-27 lines) — verify password creation works
  4. Test the Login flow with the modified index.tsx (+12/-9 lines) — verify login with correct password succeeds
  5. Test the ResetPassword flow with the refactored index.tsx (+28/-24 lines) — verify password reset works
  6. Test the ManualBackupStep1 with the modified index.tsx (+9/-8 lines) — verify seed phrase display works
  7. Verify the RevealPrivateCredential PasswordEntry component (+11/-12 lines) correctly validates password before revealing
  8. Test biometric authentication if available — verify it still works after the security settings changes

Expected Outcomes:

  • Backup vault operations complete without error
  • Password creation flow works correctly
  • Login with correct password succeeds
  • Password reset flow completes correctly
  • Seed phrase backup display works
  • Private key reveal requires correct password
  • Biometric authentication works

5. Ledger Hardware Wallet

Risk Level: MEDIUM

Why This Matters: LedgerSelectAccount/index.tsx had +20/-6 lines changed with 151 new test lines. HardwareWallet/AccountSelector/index.tsx had +5/-10 lines with new testIds. ConnectQRHardware/index.test.tsx had +70/-58 lines. These changes to hardware wallet flows could break Ledger connectivity for users who rely on hardware wallets for security.

Preconditions:

  • User has a Ledger hardware wallet
  • Bluetooth is enabled on the device
  • User is on the Connect Hardware Wallet screen

Test Steps:

  1. Navigate to Settings > Hardware Wallet > Connect Ledger — verify the connection screen loads
  2. Connect the Ledger device via Bluetooth — verify the connection is established
  3. Navigate to LedgerSelectAccount — verify the account list loads with the refactored index.tsx (+20/-6 lines)
  4. Verify the new test coverage (151 new test lines) reflects correct behavior for account selection
  5. Select an account to import — verify the account is added to MetaMask correctly
  6. Sign a transaction with the Ledger — verify the signing flow works end-to-end
  7. Verify the HardwareWallet AccountSelector testIds (new 5 test IDs) are accessible for automation
  8. Disconnect and reconnect the Ledger — verify the reconnection flow works

Expected Outcomes:

  • Ledger connection screen loads correctly
  • Bluetooth connection is established
  • Account list loads with correct accounts
  • Account import works correctly
  • Transaction signing completes successfully
  • Reconnection flow works after disconnect

6. Notifications / Settings

Risk Level: MEDIUM

Why This Matters: NotificationsSettings.view.test.tsx has 200 new test lines indicating significant new behavior. NotificationsView.view.test.tsx has 169 new test lines. BackupAndSyncFeaturesToggles.tsx had +7/-7 lines. BackupAndSyncToggle.tsx had +6/-5 lines. ConfirmTurnOnBackupAndSyncModal.tsx had +5/-7 lines. These changes to notification and sync settings could affect user data backup behavior.

Preconditions:

  • User has notifications enabled
  • User is on the Notifications Settings screen

Test Steps:

  1. Navigate to Settings > Notifications — verify NotificationsSettings.view renders correctly (200 new test lines added)
  2. Toggle notification preferences — verify changes are saved correctly
  3. Navigate to the Notifications view — verify NotificationsView.view renders correctly (169 new test lines added)
  4. Verify the Identity BackupAndSyncFeaturesToggles renders correctly (+7/-7 lines)
  5. Verify the BackupAndSyncToggle works correctly (+6/-5 lines)
  6. Verify the ConfirmTurnOnBackupAndSyncModal renders correctly (+5/-7 lines)
  7. Check the SettingsNotification component renders correctly with the modified index.test.tsx (+15/-8 lines)
  8. Verify the SecurityOptionToggle renders correctly (+2/-3 lines)

Expected Outcomes:

  • Notifications settings screen renders correctly
  • Notification toggles save preferences correctly
  • Notifications view shows correct notification list
  • Backup and sync toggles work correctly
  • Confirm modal renders and functions correctly
  • Security option toggles work correctly

7. Transaction Confirmation / Custom Amount

Risk Level: MEDIUM

Why This Matters: custom-amount-info.tsx had +42/-23 lines and custom-amount-info.styles.ts had +9/-2 lines. projected-five-year-balance.tsx is a new 56-line component. useTransactionConfirm.ts had +12/-26 lines (significant reduction suggesting refactoring). useTransactionCustomAmount.ts had +7/-14 lines. useConfirmActions.ts had +24/-4 lines. footer.tsx had +2/-5 lines. These changes to the confirmation flow could break transaction submission.

Preconditions:

  • User has ETH and ERC-20 tokens
  • User is initiating a transaction that requires confirmation

Test Steps:

  1. Initiate a token approval transaction — verify the confirmation screen loads with the refactored info-root.tsx (+2/-2 lines)
  2. Verify the custom-amount-info component renders correctly with the refactored styles (+9/-2 lines) and logic (+42/-23 lines)
  3. Verify the pay-token-amount component renders correctly (+5/-3 lines)
  4. Verify the projected-five-year-balance component (new 56-line component) renders correctly in the confirmation flow
  5. Verify the useTransactionConfirm hook (+12/-26 lines) correctly handles the confirm action
  6. Verify the useTransactionCustomAmount hook (+7/-14 lines) correctly manages custom amount state
  7. Verify the useConfirmActions hook (+24/-4 lines) correctly handles confirm and reject actions
  8. Verify the footer.tsx (+2/-5 lines) renders confirm/reject buttons correctly

Expected Outcomes:

  • Confirmation screen renders without crash
  • Custom amount info displays correctly
  • Pay token amount shows correct values
  • Projected five-year balance renders (if applicable)
  • Confirm action submits the transaction
  • Reject action cancels the transaction
  • Footer buttons are correctly enabled/disabled

Teams Sign-off Status (20/22)

Signed off: Assets, BE Trade, Bots Team, Card, Confirmations, Core Extension UX, Delegation, Design System, Earn, Mobile Platform, Mobile UX, Money Movement, Networks, Onboarding, Perps, Rewards, Social & AI, Swaps and Bridge, Transactions, Wallet Integrations

Awaiting sign-off (2): Accounts, Predict

Excluded Features - Feature Flags Disabled (59)

The following features are disabled via feature flags and should NOT be tested:

  • aiSocialLeaderboardEnabled
  • aiSocialWhatsHappeningEnabled
  • bitcoinTestnetsEnabled
  • brazeBannerHome
  • brazeBannerHomeMinVersion
  • brazeSegmentForwarding
  • configRegistryApiEnabled
  • confirmations_pay_hardware
  • coreMCU589AbtestHubPageDiscoveryTabs
  • earnFeatureFlagTemplate
  • earnMusdConversionRewardsUiEnabled
  • earnPooledStakingServiceInterruptionBannerEnabled
  • earnStablecoinLendingServiceInterruptionBannerEnabled
  • exploreSearchV2Enabled
  • forceRampsStagingEnvironment
  • fullPageAccountList
  • googleLoginIosUnsupportedBlockingEnabled
  • hapticsKillSwitch
  • homeTMCU610AbtestWalletHomePostOnboardingSteps
  • homeTMCU725AbtestHomepagePerpsPillsEmptyState
  • legacyIosGoogleConfigEnabled
  • moneyActivityMockDataEnabled
  • moneyEnableMoneyAccount
  • moneyHomeScreenEnabled
  • moneyShowMoneyAccountAddress
  • pepsSamplePhasedRolloutFlag
  • perpsDefaultPayTokenWhenNoBalanceEnabled
  • perpsMyxProviderEnabled
  • perpsPerpGtmOnboardingModalEnabled
  • perpsPerpTradingServiceInterruptionBannerEnabled
  • platformNewLinkHandlerSystem
  • predictBottomSheet
  • predictClobV2UseLegacyClobHost
  • predictExtendedSportsMarkets
  • predictHotTab
  • predictMarketHighlights
  • predictTabFeaturedCarousel
  • predictUpDown
  • predictWithAnyToken
  • predictWorldCup
  • rewardsAnnouncementModalEnabled
  • rewardsBitcoinEnabled
  • rewardsDropsEnabled
  • rewardsEnableMusdDeposit
  • rewardsEnableMusdHolding
  • rewardsMissingEnrolledAccounts
  • rewardsReferralCodeEnabled
  • rewardsReferralEnabled
  • rewardsTronEnabled
  • socialAiTSA495AbtestCardRotationInterval
  • solanaOnboardingModal
  • solanaTestnetsEnabled
  • tempoConfig
  • tokenDetailsOhlcvWsIntegration
  • tokenDetailsV2ButtonLayout
  • tokenDiscoveryBrowserEnabled
  • tronStaking
  • walletHomeOnboardingSteps
  • socialAiTSA531AbtestWhatsHappeningExplore

Generated by AI Test Plan Analyzer (claude-sonnet-4-6) at 2026-05-15T17:50:03.295Z

AI generated test plan (JSON): Available as artifact test-plan-7.77.0 in the build workflow

@chloeYue chloeYue marked this pull request as ready for review May 15, 2026 20:57
@chloeYue chloeYue requested review from a team as code owners May 15, 2026 20:57
Copy link
Copy Markdown
Contributor

@chloeYue chloeYue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeIdentity, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeSwap, SmokeStake, SmokeWalletPlatform, SmokeMoney, SmokePerps, SmokeMultiChainAPI, SmokePredictions, SmokeSeedlessOnboarding, SmokeBrowser, SmokeSnaps
  • Selected Performance tags: @PerformanceLaunch, @PerformanceAssetLoading, @PerformanceAccountList
  • Risk Level: high
  • AI Confidence: 85%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR contains 100 changed files spanning multiple critical areas:

  1. CI/Workflow Infrastructure (29 critical files): Changes to run-e2e-smoke-tests-ios.yml, run-e2e-smoke-tests-android.yml, run-e2e-workflow.yml, setup-e2e-env/action.yml, ci-status-gate/action.yml, e2e-split-tags-shards.mjs, and many other workflow files. These changes affect how ALL E2E tests are executed, making it essential to validate the pipeline still works correctly across all test suites.

  2. Core Navigation (TabBar, MainNavigator, App.tsx): Changes to TabBar.tsx, TabBar.constants.ts, TabBar.types.ts, MainNavigator.js, and App.tsx affect the fundamental navigation structure used by every single E2E test. The TabBar now includes a new Money tab icon (MusdFilled), Trending tab session management (onLeave callback), and navigation routing changes. Any regression here would break virtually all tests.

  3. New Tab Components (TabsIconBar, TabsIconTab, TabsIconList, TabsBar): New reusable tab components used in HomepageDiscoveryTabs (Wallet view) and Predict feed - affects SmokeWalletPlatform and SmokePredictions.

  4. New Icons (candlestick, group, musd-filled, musd, pie-chart, predictions): New SVG icons added to the icon library. These are used in Perps (Candlestick), Predictions (Predictions, PieChart), Trending (HomepageDiscoveryTabs), and Money (Musd/MusdFilled) features.

  5. Money/Card Feature (app/actions/money/index.ts): New upgradeMoneyAccount action for the Money/Card tab - directly affects SmokeMoney.

  6. AssetElement/Balance/AssetActionButton: Changes to token display components affect wallet token lists visible in SmokeWalletPlatform, SmokeSwap, SmokeStake, SmokeMoney.

  7. ContractBox/ContractBoxBase: New contract display components likely used in confirmations - affects SmokeConfirmations.

  8. AddToAddressBookWrapper: Changes to address book wrapper used in send/confirmation flows - affects SmokeConfirmations.

  9. SheetActions, Toast.styles: UI component changes that affect modals/sheets used across many flows.

  10. SeedlessOnboarding: App.tsx includes seedless onboarding login flow checks - affects SmokeSeedlessOnboarding.

The combination of CI infrastructure changes (which need validation that the pipeline works) and widespread app code changes touching navigation, icons, and multiple feature areas justifies running ALL test tags. The TabBar and MainNavigator changes are particularly high-risk as they are shared by every E2E test flow.

Performance Test Selection:
Performance tests are warranted because: 1) TabBar and MainNavigator changes affect app navigation initialization and rendering performance (@PerformanceLaunch). 2) AssetElement and Balance component changes affect token list rendering performance (@PerformanceAssetLoading). 3) New tab components (TabsIconBar, TabsIconList) with animations could impact rendering performance in the wallet view. 4) The new icons and tab components add to the rendering workload. @PerformanceAccountList is relevant because the TabBar changes affect how the account selector integrates with navigation.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

@chloeYue
Copy link
Copy Markdown
Contributor

@SocketSecurity ignore-all

@chloeYue chloeYue added the skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. label May 16, 2026
@chloeYue
Copy link
Copy Markdown
Contributor

policy-bot: approve

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

Labels

auto-rc-builds enable automatic release candidate builds release-7.77.0 Issue or pull request that will be included in release 7.77.0 size-XL skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-bots Bot team (for MetaMask Bot, Runway Bot, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.