Skip to content

release: 13.54.0 - #47119

Merged
DDDDDanica merged 116 commits into
stablefrom
release/13.54.0
Oct 27, 2026
Merged

DDDDDanica merged 116 commits into
stablefrom
release/13.54.0

Conversation

@metamaskbot

@metamaskbot metamaskbot commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

🚀 v13.54.0 Testing & Release Quality Process

Hi Team,
As part of our new MetaMask Release Quality Process, here’s a quick overview of the key processes, testing strategies, and milestones to ensure a smooth and high-quality deployment.


📋 Key Processes

Testing Strategy

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

GitHub Signoff

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

Issue Resolution

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

Cherry-Picking Criteria

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

🗓️ Timeline and Milestones

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

✅ Signoff Checklist

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

Team sign-off checklist

  • Accounts
  • Assets
  • Bots Team
  • Confirmations
  • Core Extension UX
  • Core Platform
  • Earn
  • Emerging Opportunities
  • Engagement
  • Extension Platform
  • Networks
  • Onboarding
  • Perps
  • Swaps and Bridge
  • team-extension-ux

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

HowardBraham and others added 30 commits October 8, 2026 19:17
## **Description**

This PR solves two related problems:
1. For a very long time, `yarn start`/`yarn build:dev` would start the
wallet with Sepolia selected, There was an ask for it to start with `All
networks`, just like the prod build does.
2. When we recently added Arc to the list of networks in the Config
Registry, it would change the user's currently selected network to Arc.
This could happen either on a brand new wallet, or on a wallet that got
upgraded. I made new rules:
  **A.** If exactly one network is enabled, do not change it
  **B.** If all networks are enabled, add the new network to the list

Also moved the function `isInE2eTest()` from
`ui/contexts/hardware-wallets/is-in-e2e-test.ts` to
`shared/lib/environment.ts`. This is the cause of many of the "Files
changed" and the cause of most of the CODEOWNERS requirements.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MWPE-748
MWPE-748 #done

<!--## **Manual testing steps**
## **Screenshots/Recordings**
## **Pre-merge author checklist**
## **Pre-merge reviewer checklist**-->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes default network enablement for fresh installs and dev builds
plus async restore logic when Config Registry auto-adds
chains—user-visible network selection with regression tests but broad
behavioral impact.
> 
> **Overview**
> **Fresh wallets and dev builds now start in “All popular networks”
mode** instead of pre-enabling Sepolia (debug/testing) or a fixed
featured set. `NetworkEnablementController` initializes with every known
network disabled, then calls `enableAllPopularNetworks()` for non-test
installs that have no persisted enablement map; `IN_TEST` still defaults
to **Localhost only**.
> 
> **Config Registry auto-enabled networks (e.g. Arc) no longer hijack
the network filter.** On `NetworkController:networkAdded`, when the
chain is registry-marked `isAutoEnabled`, init waits for enablement then
**`restoreEnabledNetworkMap`** to the prior map so a single-network
selection stays put and “all on” mode only adds the new chain as
disabled until the user opts in.
> 
> **Test/E2E support:** `isInE2eTest()` moves to
`shared/lib/environment`; fixture-less E2E builds get Localhost via
`initializeWallet`; LLM fixtures use the fixture store when
`fixtureServerPort` is set and default fixtures disable sync/external
services. New unit and E2E coverage for the above behaviors.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e66b176. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

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

## **Related issues**

Fixes:

## **Manual testing steps**

No manual testing steps


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

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **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**
> Updates profile-sync and cryptography dependency boundaries (Web
Crypto via LavaMoat) without local code changes; behavior changes come
only from the upstream controller release.
> 
> **Overview**
> Bumps **`@metamask/profile-sync-controller`** from `^33.0.0` to
**`^34.0.3`** in `package.json` and refreshes **`yarn.lock`**.
> 
> The new controller release routes crypto through
**`@metamask/cryptography`** instead of **`@noble/ciphers`**, pulls in
**`@metamask/seedless-onboarding-controller@^12.0.0`** (and related
transitive packages such as analytics/config-registry controllers), and
updates other deps (e.g. **`immer`**, **`@noble/curves`**). There are
**no application source changes**—only dependency and LavaMoat policy
updates.
> 
> All **eight** webpack LavaMoat **`policy.json`** files (MV2/MV3 ×
main/beta/flask/experimental) add allowances for
**`@metamask/profile-sync-controller>@metamask/cryptography`**
(`crypto.getRandomValues` and **`crypto.subtle`**
encrypt/decrypt/importKey), wire that package into the
profile-sync-controller entry, drop **`@noble/ciphers`**, and allow
**`@metamask/utils>pony-cause`** where utils is used in that graph.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5d0fdbc. 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: MetaMask Bot <metamaskbot@users.noreply.github.com>
)

## **Description**

### Context

All [Vault Corruption
Detected](https://mixpanel.com/project/2212883/view/2760759/app/boards#id=10932487&edited-bookmark=zGCMqkScpJLk)
events have the Browser property as `not set` in Mixpanel.

### Problem

Events tracked through `trackEarlySegmentEvent` (Vault Corruption
Detected, critical errors, state migration events) fire before
`AnalyticsController` is initialized. They are sent to Segment with a
minimal context containing only `app`, so they never carry
`context.userAgent`. Segment's server-side enrichment parses
`context.userAgent` to derive the browser name and version (delivered to
Mixpanel as the `Browser` / `Browser Version` properties), so without it
the browser shows as `not set` for these events.

### Solution

- Extract the existing inline userAgent read from
`createEnrichmentContext` into a shared `getUserAgent()` helper in the
platform adapter.
- Populate `context.userAgent` in `trackEarlySegmentEvent` using that
helper, matching how standard enriched events carry it.
- Update the colocated unit tests that assert exact Segment payload
context.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: none

## **Manual testing steps**

1. Run the extension (`yarn start`) and load it in Chrome.
2. Opt in to MetaMetrics (so early events can be tracked).
3. Trigger a vault corruption event locally.
4. Observe the outgoing Segment `track` payload (e.g. via the Segment
debugger).
5. Verify `context.userAgent` is populated with `navigator.userAgent`
instead of being absent.

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Analytics context enrichment only; no changes to auth, vault handling,
or event consent gating.
> 
> **Overview**
> Early Segment events (vault corruption, critical errors, state
migrations) now include **`context.userAgent`** so Mixpanel can show
Browser instead of `not set`.
> 
> A shared **`getUserAgent()`** helper was extracted from the platform
adapter enrichment context (empty string when there is no `window`, e.g.
MV3 service worker). **`trackEarlySegmentEvent`** uses it in its default
context, aligned with normal AnalyticsController-enriched payloads.
**`createEnrichmentContext`** now calls the same helper instead of
inlining the read.
> 
> Unit tests that assert full Segment `track` payloads were updated to
expect **`userAgent`** in `context`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bd1b150. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

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

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This PR does
bump stellar-wallet-snap from 1.1.0 to 1.1.1

Fix the issue that memo show when sending contract base token , it
shouldnt show, becoz memo is not allowed when sending contract base
token
https://www.loom.com/share/f0f6a5ad706b49bab10beedbacade985
<!--
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: Bump stellar-wallet-snap from 1.1.0 to 1.1.1

## **Related issues**

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Patch-level dependency-only update with no extension code changes;
Stellar snap behavior may differ only per the snap package’s 1.1.1
release notes.
> 
> **Overview**
> Bumps the **`@metamask/stellar-wallet-snap`** dependency from
**1.1.0** to **1.1.1** in `package.json` and refreshes **`yarn.lock`**
so installs resolve to the new package version and checksum.
> 
> There are **no application or source changes** in this PR—only the
dependency pin and lockfile. The extension still bundles the Stellar
snap via the existing preinstalled snap wiring.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
cc88b76. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Version Bump After Release

This PR bumps the main branch version from 13.53.0 to 13.54.0 after
cutting the release branch.

### Why this is needed:
- **Nightly builds**: Each nightly build needs to be one minor version
ahead of the current release candidate
- **Version conflicts**: Prevents conflicts between nightlies and
release candidates
- **Platform alignment**: Maintains version alignment between MetaMask
mobile and extension
- **Update systems**: Ensures nightlies are accepted by app stores and
browser update systems

### What changed:
- Version bumped from `13.53.0` to `13.54.0`
- Platform: `extension`
- Files updated by `set-semvar-version.sh` script

### Next steps:
This PR should be **manually reviewed and merged by the release
manager** to maintain proper version flow.

### Related:
- Release version: 13.53.0
- Release branch: release/13.53.0
- Platform: extension
- Test mode: false

---
*This PR was automatically created by the
`create-platform-release-pr.sh` script.*

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
release: sync stable to main for version 13.51.0
…6936)

## **Description**

When a hardware wallet device is locked (e.g. a Ledger that hasn't been
unlocked), the error modal previously showed multi-step recovery
instructions telling the user to unlock the device and then reconnect.
This was unnecessarily verbose for a simple state — the user only needs
to unlock the device and retry.

The change simplifies the `AuthenticationDeviceLocked` error case in
`buildErrorContent`:
- **Before:** `variant: 'recovery'` with two bullet-point instructions
(`hardwareWalletErrorRecoveryUnlock1`,
`hardwareWalletErrorRecoveryUnlock2`)
- **After:** `variant: 'description'` with a single, concise
description: *"Unlock it and try again to continue"*
(`hardwareWalletErrorDeviceLockedDescription`)

The lock icon is preserved. The repair link remains hidden for this
error code. The modal layout switches from the multi-step recovery
format to the simpler description format used by other acknowledge-only
errors.

## **Changelog**

CHANGELOG entry: Simplified the locked device error modal into a single
unlock description instead of multi-step recovery instructions

## **Related issues**

Fixes:
https://consensyssoftware.atlassian.net/browse/MUL-2232?atlOrigin=eyJpIjoiNTgxYjVmZDkzODk4NGEyNGI4Mzc5ODBlNjdlNzkxZGIiLCJwIjoiaiJ9

## **Manual testing steps**

1. Connect a hardware wallet (e.g. Ledger)
2. Lock the device while it's connected
3. Initiate an action that requires the device (e.g. signing a
transaction)
4. Verify the error modal shows a lock icon, title with the wallet type,
and the description "Unlock it and try again to continue" — without
multi-step recovery instructions

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

<img width="546" height="981" alt="Screenshot 2026-10-08 at 19 27 51"
src="https://github.com/user-attachments/assets/2c755b05-643a-4e17-9c33-212091603747"
/>


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

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Copy and modal layout only for one hardware-wallet error code;
retry/reconnect behavior is unchanged.
> 
> **Overview**
> When a hardware wallet is locked (`AuthenticationDeviceLocked`), the
error modal no longer uses the **recovery** layout with two unlock
bullet steps. It now uses the simpler **description** layout with one
line: *"Unlock it and try again to continue"*
(`hardwareWalletErrorDeviceLockedDescription`), added in `en` and
`en_GB` locales.
> 
> The lock icon and device-locked title are unchanged; repair link
behavior for this error is unchanged. Unit tests in
`error-content-builder` and `hardware-wallet-error-modal` assert the new
copy and that the old recovery unlock strings are not shown.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
396a9fe. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Upgrade `@metamask/perps-controller` from 17.1.0 to 20.0.0 (MV2/MV3
LavaMoat policies regenerated; no further policy changes from 19 to 20).

Fee previews now match what the controller charges:
- **Shared notional helper.** Order entry, close, close-all, reverse,
auto-close and TP/SL use one helper to derive the USD notional passed to
the controller fee quote and refetch when it changes. Close-all quotes
each symbol using the combined batch notional. Since controller 18,
bounded subscription waivers depend on size.
- **Fees from the controller quote.** Resolved rates, the VIP badge and
the struck-through original rate come from controller 20's quote
metadata. The badge shows only when the quote is reduced. The hook and
close-all share one pure function to apply rewards discounts only to
local fallbacks.
- **Controller 20 changes.** Missing realized PnL displays as Unknown
(zero stays zero); the error map includes `ORDER_SCALE_PREVIEW_STALE`.

Validation: unit tests for every preview (discounted, undiscounted, full
and blended waivers, rewards-lookup disagreement), TypeScript, lint,
LavaMoat. Read-only live proof (dev1 testnet BTC long, 3x, USD 100 and
1000, HUD on) passes 43/43 on controller 19 and on this branch. No
fixture account currently has a positive discount (10 fixtures checked
on testnet, then mainnet read-only), so the discounted path is proven by
the unit tests; no order, close or signature was submitted.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

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

## **Manual testing steps**

1. Load the updated extension and unlock a wallet with Perps enabled.
2. Open Perps in the fullscreen wallet.
3. Confirm the account balance and market watchlist load with prices.
4. Open positions, orders, and transaction history; confirm each view
loads without errors.
5. For a history entry whose liquidation metadata omits the user
address, confirm its other trade information remains visible and it does
not show an account-specific “Liquidated” badge.

6. Open an order preview and enter an amount. Confirm the fee estimate
updates and any rewards/subscription discount is applied once; leave the
order unsubmitted.
7. With existing positions, open the close-all confirmation. Confirm its
fee estimate loads and reflects each position size; leave the close
action unsubmitted.

## **Screenshots/Recordings**

Current rebased-source controller20 home and shared-helper fee preview
proof; no trade mutations.

<table>
<tr><td align="center" valign="top" width="50%"><strong>Current Perps
home</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-extension-farm-artifacts/main/fixes/46934/recipe-run/screenshots/ac2-home.png?sha=42214ad6391774bc"
alt="Current Perps home" width="320" /></td><td align="center"
valign="top" width="50%"><strong>BTC USD100 fee with
HUD</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-extension-farm-artifacts/main/fixes/46934/fee-preview-run/screenshots/btc-100-fee.png?sha=9db6d320f5a01fcb"
alt="BTC USD100 fee with HUD" width="320" /><br/><sub>caption
confidence: LOW — generic filename — no state-specific
suffix</sub></td></tr>
<tr><td align="center" valign="top" width="50%"><strong>BTC USD1000 fee
with HUD</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-extension-farm-artifacts/main/fixes/46934/fee-preview-run/screenshots/btc-1000-fee.png?sha=8d707699d820cd95"
alt="BTC USD1000 fee with HUD" width="320" /><br/><sub>caption
confidence: LOW — generic filename — no state-specific
suffix</sub></td><td align="center" valign="top"
width="50%"><strong>Existing SOL close-all fee with
HUD</strong><br/><img
src="https://raw.githubusercontent.com/abretonc7s/mm-extension-farm-artifacts/main/fixes/46934/fee-preview-run/screenshots/close-all-fee.png?sha=f4185b15d4122f96"
alt="Existing SOL close-all fee with HUD" width="320"
/><br/><sub>caption confidence: LOW — generic filename — no
state-specific suffix</sub></td></tr>
</table>

## **Validation Recipe**

<details><summary>recipe.json (14 nodes — TAT-4063 Perps controller
19.0.0 proof)</summary>

```json
{
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
  "title": "TAT-4063 Perps controller 19.0.0 proof",
  "description": "Read-only live regression guard followed by the new dependency-version assertion. Derived AC3 is corroborated outside this runtime recipe.",
  "workflow": {
    "entry": "setup-status",
    "nodes": {
      "setup-status": {
        "action": "app.status",
        "next": "setup-cdp",
        "intent": "Resolve the Extension checkout and adapter status before Perps proof"
      },
      "setup-cdp": {
        "action": "cdp.target",
        "required": true,
        "timeout_ms": 15000,
        "next": "setup-ensure-unlocked",
        "intent": "Confirm the Extension CDP runtime is reachable"
      },
      "setup-ensure-unlocked": {
        "action": "metamask.wallet.ensure_unlocked",
        "timeout_ms": 45000,
        "next": "setup-open-perps",
        "intent": "Ensure the wallet is unlocked before opening Perps"
      },
      "setup-open-perps": {
        "action": "ui.navigate",
        "next": "setup-perps-ready",
        "intent": "Show the Perps home surface",
        "hash": "#/perps-home"
      },
      "ac2-read-positions": {
        "action": "metamask.perps.read_positions",
        "next": "ac2-read-orders",
        "intent": "Read live Perps positions without mutating account state"
      },
      "ac2-read-orders": {
        "action": "metamask.perps.read_orders",
        "next": "ac2-settle",
        "intent": "Read live Perps open orders without mutating account state"
      },
      "gate-done": {
        "action": "end",
        "status": "pass"
      },
      "ac2-read-home": {
        "action": "metamask.perps.read_visible_state",
        "surface": "home",
        "minimum_market_count": 1,
        "require_features": [
          "balance",
          "market-list"
        ],
        "intent": "Observe a populated Perps home after setup",
        "next": "ac2-assert-home",
        "forbid_test_ids": [
          "perps-tutorial-skip-button"
        ],
        "max_items": 200
      },
      "ac2-assert-home": {
        "action": "assert_output",
        "source": "ac2-read-home",
        "assert": {
          "path": "$.surface",
          "operator": "eq",
          "value": "home"
        },
        "proves": [
          "AC2"
        ],
        "intent": "The observed surface is Perps home",
        "next": "ac2-assert-markets"
      },
      "ac2-assert-markets": {
        "action": "assert_output",
        "source": "ac2-read-home",
        "assert": {
          "path": "$.marketCount",
          "operator": "gte",
          "value": 1
        },
        "proves": [
          "AC2"
        ],
        "intent": "Perps home contains market data rather than only a loading shell",
        "next": "ac2-read-positions"
      },
      "ac2-settle": {
        "action": "ui.wait_for",
        "test_id": "perps-watchlist-BTC",
        "timeout_ms": 20000,
        "intent": "Show the populated account market watchlist",
        "next": "ac2-capture",
        "proves": [
          "AC2"
        ]
      },
      "ac2-capture": {
        "action": "ui.screenshot",
        "intent": "Preserve the read-only trading overview",
        "next": "ac1-version",
        "proves": [
          "AC2"
        ]
      },
      "ac1-version": {
        "action": "command",
        "cmd": "node -e 'const fs=require('\"'\"'node:fs'\"'\"');const assert=require('\"'\"'node:assert/strict'\"'\"');const manifest=require('\"'\"'./package.json'\"'\"').dependencies['\"'\"'@metamask/perps-controller'\"'\"'];const installed=require('\"'\"'./node_modules/@metamask/perps-controller/package.json'\"'\"').version;const lock=fs.readFileSync('\"'\"'yarn.lock'\"'\"','\"'\"'utf8'\"'\"');console.log(JSON.stringify({manifest,installed,lock19:lock.includes('\"'\"'resolution: \\\"@metamask/perps-controller@npm:19.0.0\\\"'\"'\"')}));assert.equal(manifest,'\"'\"'^19.0.0'\"'\"');assert.equal(installed,'\"'\"'19.0.0'\"'\"');assert.ok(lock.includes('\"'\"'resolution: \\\"@metamask/perps-controller@npm:19.0.0\\\"'\"'\"'));'",
        "timeout_ms": 10000,
        "intent": "The installed trading controller matches the requested release",
        "next": "gate-done",
        "proves": [
          "AC1"
        ]
      },
      "setup-perps-ready": {
        "action": "ui.wait_for",
        "test_id": "perps-watchlist-BTC",
        "timeout_ms": 60000,
        "intent": "The account watchlist is ready before checking the trading overview",
        "next": "ac2-read-home"
      }
    }
  },
  "proofTargets": [
    {
      "id": "AC1",
      "claim": "The Extension manifest, lockfile and installed controller resolve 19.0.0."
    },
    {
      "id": "AC2",
      "claim": "The live Perps home remains populated and positions/orders reads succeed."
    }
  ]
}
```
</details>

## **Validation Logs**

<details><summary>Full output (14/14 passed, pass)</summary>

```
# MetaMask Recipe Run

Status: pass
Duration: 5.2s
Nodes: 14/14 passed

## Side findings
- REVIEW 2 distinct application warning/error event(s) (non-blocking; expanded below and stored in diagnostics.json)

## Steps
- PASS setup-status (app.status, 14ms): platform=extension
- PASS setup-cdp (cdp.target, 8ms): platform=extension
- PASS setup-ensure-unlocked (metamask.wallet.ensure_unlocked, 341ms): proof=extension-password-unlock
- PASS setup-open-perps (ui.navigate, 151ms): proof=ui-navigation
- PASS setup-perps-ready (ui.wait_for, 3.3s): matched=true, cdpPort=7666, targetUrl=chrome-extension://hebhblbkkdabgoldnojllkipeoacjioc/home.html#/perps-home, cdpTargetId=9EB98A70161C9ACB2FD39A995ADBD422, runtimeSessionId=2a5d1c03-88df-4870-b00a-b6144cb1bff4
- PASS ac2-read-home (metamask.perps.read_visible_state, 149ms): platform=extension, route=#/perps-home, proof=visible-dom-accessibility
- PASS ac2-assert-home (assert_output, 7ms): source=ac2-read-home, stream=stdout
- PASS ac2-assert-markets (assert_output, 8ms): source=ac2-read-home, stream=stdout
- PASS ac2-read-positions (metamask.perps.read_positions, 137ms): count=0, matching=0
- PASS ac2-read-orders (metamask.perps.read_orders, 130ms): count=0, matching=0
- PASS ac2-settle (ui.wait_for, 548ms): matched=true, cdpPort=7666, targetUrl=chrome-extension://hebhblbkkdabgoldnojllkipeoacjioc/home.html#/perps-home, cdpTargetId=9EB98A70161C9ACB2FD39A995ADBD422, runtimeSessionId=2a5d1c03-88df-4870-b00a-b6144cb1bff4
- PASS ac1-version (command, 36ms): exitCode=0, stdout={"manifest":"^19.0.0","installed":"19.0.0","lock19":true}

- PASS gate-done (end, 0ms)
```
</details>

## **Pre-merge author checklist**

- [x] Followed the repository coding guidelines.
- [x] Completed the available template prose and retained validation
evidence.
- [x] Included focused regression tests.
<!-- Labels are assigned by the publication host; no PR exists yet. -->
<!-- Documentation checklist: no new public component or utility. -->

<!--
## **Pre-merge reviewer checklist**

Reserved for the human reviewer after publication.
-->

## **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-4063]:
https://consensyssoftware.atlassian.net/browse/TAT-4063?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches trading fee display and discount logic across order/close
flows; incorrect notional or double-discount would misstate fees but
does not change signing paths directly.
> 
> **Overview**
> Upgrades **`@metamask/perps-controller`** to **20.0.0** (with LavaMoat
policy updates for nested `@metamask/utils`) so Perps fee previews align
with what submit/close paths charge.
> 
> **Notional-aware quoting:** New `getPerpsNotionalUsd` centralizes USD
notional (order amount, partial closes, close-all batch totals, reverse
2× position value, TP/SL max trigger). Order entry, close, close-all,
reverse, auto-close, and update-TP/SL pass that notional into
`perpsCalculateFees` / `usePerpsOrderFees` and refetch when size or
prices change.
> 
> **Discount handling:** Resolved controller quotes use `feeSource`,
`metamaskFeeDiscountBips`, and `undiscountedMetamaskFeeRate` for badges
and strikethrough rates—rewards are not applied twice. UI rewards
discounts apply only to local RPC/timeout fallbacks via
`applyPerpsFallbackDiscount` (including close-all’s per-symbol fallback
split).
> 
> **Other behavior:** Transaction history treats missing realized PnL as
**Unknown** (zero PnL preserved); liquidation UI/metadata tolerates
missing `liquidatedUser`; maps `ORDER_SCALE_PREVIEW_STALE` to a generic
order-failed message.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
85d5ffc. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Adds the `confirmations_pay_rpc` remote feature flag and
`isPayRpcTypeAllowed`, a pure helper that decides whether a dApp origin
may request a MetaMask Pay type (`perpsDeposit` / `perpsWithdraw`)
through the upcoming `wallet_mmPay` RPC method. No caller yet.

Stack 1/7: followed by #46982.
Gated by `confirmations_pay_rpc`; off by default.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[CONF-2130](https://consensyssoftware.atlassian.net/browse/CONF-2130)

## **Manual testing steps**

Nothing to try in the extension yet; the helper has no caller. Verify:

1. The extension builds and behaves as before (no flag value set means
nothing changes).
2. `confirmations_pay_rpc` is listed in the feature flag registry with
everything off by default.

<!--
## **Screenshots/Recordings**

### **Before**

### **After**
-->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

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


[CONF-2130]:
https://consensyssoftware.atlassian.net/browse/CONF-2130?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> No runtime integration yet; missing or default flag values deny all
requests, so extension behavior stays the same until later PRs connect
the helper.
> 
> **Overview**
> Introduces the **`confirmations_pay_rpc`** remote feature flag
(registered for CI/E2E with **empty `allowedTypes` and `dapps`**, so
nothing is enabled in production by default) and
**`PAY_RPC_FEATURE_FLAG`** in the known-flag constants map.
> 
> Adds **`isPayRpcTypeAllowed`** in `shared/lib/transaction/pay-rpc.ts`:
a pure gate for upcoming **`wallet_mmPay`** that requires the type in
the flag’s top-level allowlist and in the requesting dApp’s config,
matches origins strictly (with **`http://localhost`** matching any
port), and for **`perpsWithdraw`** also requires
**`confirmations_pay_post_quote`** to be enabled. **No callers in this
PR**—behavior is unchanged until follow-up stacks wire the RPC.
> 
> Unit tests cover allowlists, origin edge cases, malformed flag
payloads, and withdraw gating.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
dc299d9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… misleading fee alerts (#46049)

## **Description**

Monad enforces a protocol-level **10 MON reserve balance**. When a
transaction would leave an account below that floor (especially Smart
Accounts), the network rejects it.

Users on extension ~13.44 were seeing **generic “insufficient network
fees” / interaction failures** for dApp transactions (e.g. MON swaps)
even when the real cause was the reserve rule—and even when they
expected the post-tx balance to stay above 10 MON. The reserve alert was
previously gated on gasless/sponsorship support, so hardware wallets and
other non-relay paths never got the correct message; fee /
estimate-failed alerts won instead.

**Solution**
- Shared Monad reserve helpers (`shared/lib/monad-reserve-balance.ts`)
for mainnet + testnet
- Always show the blocking reserve-balance alert when the tx is not
gas-sponsored (simulation `callTraceErrors` / `simulationFails`, plus
proactive `balance - value < 10 MON`)
- Suppress generic insufficient-balance and gas-estimate-failed alerts
when a reserve violation is the root cause
- Clearer EN copy explaining ending balance + Smart Account strictness
- Unrelated unblock: Shield config no longer imports removed `Env` from
`@metamask/shield-controller` (was breaking confirmation unit tests)

## **Changelog**

CHANGELOG entry: Fixed misleading insufficient network fee alerts on
Monad when the 10 MON reserve balance requirement was the actual cause

## **Related issues**

Related: #42068

<!--
Fixes:
-->

## **Manual testing steps**

1. Load the extension build from this branch and switch to **Monad**
(`0x8f`).
2. With an EOA holding ~12–15 MON, submit a native value spend / dApp
interaction that would leave **less than 10 MON** after the transfer.
3. Confirm the confirmation shows the **Reserve balance is required**
alert (10 MON), and that Confirm is blocked.
4. Confirm you do **not** see the generic “You do not have enough MON …
to pay for network fees” message for that case.
5. Repeat with a spend that leaves **≥ 10 MON** remaining and verify the
reserve alert does not appear.
6. If available, repeat with a **Smart Account** on Monad and confirm
the reserve messaging still appears when ending balance would go below
10 MON.

<!--
## **Screenshots/Recordings**

### **Before**

### **After**
-->

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: gabrieledm <gabriele.delmonte-ext@consensys.net>
Co-authored-by: Gabriele Del Monte <37625739+gabrieledm@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Bump LavaMoat tooling to the latest version which includes bug fixes
that we are interested in. More specifically includes policy generation
improvements and prevents runtime errors being thrown when Chrome
accesses `chrome`.

Pins SES to `2.2.0` since `>=2.3.0` has a bug that prevents it from
running in some versions of Chrome.

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

https://metamask.sentry.io/issues/7442639463/
https://consensyssoftware.atlassian.net/browse/WPC-1401

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Changes the SES/LavaMoat sandbox and webpack policy surface for every
production bundle; mis-generated or overly permissive policy updates
could affect runtime security or break builds across all extension
flavors.
> 
> **Overview**
> Upgrades **LavaMoat** (`lavamoat` **10.0.5 → ^11.1.7**) and
**`@lavamoat/webpack`** (**2.2.3 patched → ^3.0.1**), dropping the Yarn
patch that added webpack **≥5.107** runtime helpers (`dn`, `ns`)—those
are expected to ship in the new plugin.
> 
> Adds a root **`resolutions`** pin for **`ses` at 2.2.0** (replacing
the older SES 1.x line pulled in by prior LavaMoat packages).
Regenerates **LavaMoat webpack policies** for the build profile and all
**MV2/MV3** variants (`beta`, `experimental`, `flask`, `main`): package
keys are reshaped (e.g. `@lavamoat/webpack>lavamoat-*` →
`lavamoat>lavamoat-*`), new entries appear for nested Babel/tofu deps,
and many packages gain **`Float32Array` / `Float64Array`** (and related)
global allowances; some stale globals (e.g. broad TypeScript
language-service names) are removed.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8957b3d. 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: MetaMask Bot <metamaskbot@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
The internal error dialog (state corruption / trouble starting) was
always dark. Its styles used fixed dark greys, and the screen is shown
before the app sets `html[data-theme]`.
The dialog now uses theme tokens, and the background sends
`PreferencesController.theme` (`light`, `dark`, or `os`) so the UI can
apply it before the dialog renders. If the controller is not ready yet,
the same preference is read from extension storage.
<!--
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: Fixed the internal error dialog so it follows the
selected theme

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MWPE-716

## **Manual testing steps**

1. Open MetaMask and set the theme to light in Settings.
2. Lock the wallet.
3. In the browser Application storage for the extension, delete the
Keyring data.
4. On the Chrome extensions page, click Reload.
5. Open MetaMask and confirm the internal error dialog uses the light
theme.
6. Repeat with dark, and with the OS theme, and confirm the dialog
matches that preference.

## **Screenshots/Recordings**

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

### **Before**

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

### **After**
<img width="375" height="849" alt="Screenshot 2026-10-06 at 10 56 22"
src="https://github.com/user-attachments/assets/84b5766e-f7d8-4c9c-aa7b-c347d112e6b9"
/>
<img width="368" height="848" alt="Screenshot 2026-10-06 at 11 49 21"
src="https://github.com/user-attachments/assets/657d4c97-df86-41bc-9c62-11cfb8cccd66"
/>

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

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI-only changes to the critical error screen and theme application; no
changes to vault recovery, auth, or persistence logic beyond passing
theme in error params.
> 
> **Overview**
> The internal **trouble starting / state corruption** screen no longer
stays locked to dark styling. The background now forwards
**`PreferencesController.theme`** with startup error messages, and the
UI applies **`html[data-theme]`** (via `setTheme`) before the dialog
HTML is injected—using the passed value when available, otherwise
reading **`PreferencesController`** from extension storage with a short
timeout.
> 
> Styling moves from **`errors.scss`** to **Tailwind utilities** in
`getErrorHtml`, with a new **`light:`** variant
(`html[data-theme="light"]`) so light mode uses semantic design tokens
while dark keeps the existing brand greys. Only CSS anchor positioning
for the legal popover remains in SCSS. Tests cover theme propagation and
OS theme / storage fallbacks.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
42cbcf3. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…eta (#46949)

## **Description**

One of the four root causes of the non-deterministic Firefox build (the
`c`/`l` variable-name swaps in `runtime.js` that fail the AMO reviewers'
byte-for-byte rebuild check). The mechanism shared by all four is
explained in plain language
[here](#46845 (comment)):
anything build-specific that leaks into webpack's module hashes ends up
changing the provisional chunk hashes written into `runtime.js`, which
SWC's letter-frequency-based variable naming then reacts to. This PR
closes one such leak. It is extracted from #46845.

### What was happening

Our React Compiler wrapper collects statistics for the
`--reactCompilerVerbose` report. For each function it compiles, it
records an event (compiled, skipped or error, the line and column, and
**the file's absolute path**) and stores the list on the module as
`buildMeta.__reactCompilerStatus__`.

`buildMeta` is the wrong drawer. webpack treats it as "facts about what
this module is" and **includes `JSON.stringify(buildMeta)` in the
module's hash**. So:

```json
"__reactCompilerStatus__": { "events": [
  { "filename": "/home/runner/work/metamask-extension/metamask-extension/work/i1-xxxxxx/metamask-extension/ui/contexts/assetPolling.tsx", … }
]}
```

made 1,800 module hashes depend on the build directory. Worse, they also
depended on **timing**. The wrapper can only record events when it runs
in the main process (it needs `this._module`, which `thread-loader`
workers do not have). `thread-loader` normally runs these loaders in
worker processes, but when its worker pool is unavailable it silently
falls back to running them in-process. On a fast machine the pool stays
alive and nothing is ever recorded. On a slow 2-core CI runner the pool
goes idle and gets disposed mid-build, and a **timing-dependent subset**
of modules gets the statistics recorded:

```
  build 1:  assetPolling.tsx → buildMeta has __reactCompilerStatus__  (path i1-xxxxxx)
  build 2:  assetPolling.tsx → buildMeta has __reactCompilerStatus__  (path i2-xxxxxxxxxxxx)
  build 5:  assetPolling.tsx → no __reactCompilerStatus__ at all
```

This is why this one can only be seen on CI: on a laptop it is literally
not there.

### The fix

Store the events on `buildInfo` instead, webpack's drawer for "things
that happened while building this module", which is **not** hashed, and
record the filename relative to the project root. `ReactCompilerPlugin`
reads from `buildInfo` now. The verbose report is unchanged.

```diff
-  const buildMeta = this._module?.buildMeta
+  const buildInfo = this._module?.buildInfo
   …
-          filename,
+          filename: rootContext ? relative(rootContext, filename) : filename,
   …
-        buildMeta[REACT_COMPILER_STATUS_KEY] = { events };
+        buildInfo[REACT_COMPILER_STATUS_KEY] = { events };
```

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Related:
[INFRA-3920](https://consensyssoftware.atlassian.net/browse/INFRA-3920)

## **Manual testing steps**

1. Run a build with the verbose report: `yarn webpack
--reactCompilerVerbose` and check the React Compiler summary still
prints at the end (statistics are collected only when thread-loader runs
loaders in-process, same as before this PR).
2. Build the Firefox production bundle: `ENABLE_MV3=false yarn
webpack:lavamoat:build:mv2 --env production`
3. Load `dist/firefox` as a temporary add-on in Firefox
(`about:debugging`), unlock or onboard, and verify the UI renders
normally. The emitted code is unchanged by this PR.

<!--
## **Screenshots/Recordings**

### **Before**

### **After**
-->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

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


[INFRA-3920]:
https://consensyssoftware.atlassian.net/browse/INFRA-3920?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches the React Compiler loader path for ~1,800 UI modules but only
changes where stats are stored, not compiled output; wrong placement
could still affect hashes or verbose stats collection.
> 
> **Overview**
> Fixes **non-deterministic webpack module hashes** caused by React
Compiler verbose statistics being written to `module.buildMeta`, which
webpack folds into each module’s hash.
> 
> The wrapper loader now records `__reactCompilerStatus__` events on
**`module.buildInfo`** (not hashed) instead, and stores **paths relative
to `rootContext`** rather than absolute filesystem paths.
**`ReactCompilerPlugin`** reads and clears that key from `buildInfo`
after emit; verbose reporting behavior is unchanged.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b26ce25. 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 Fable 5.1 <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

- sticky table column headers
- prevent status icon from shrinking

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

1. Go to this page...
2.
3.

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Cosmetic layout and styling only; no logic, data, or security changes.
> 
> **Overview**
> Small UI polish for the cashtag token results table and overflow
popover.
> 
> The token results table header is now **sticky** (`sticky top-0` with
background) so column labels stay visible while scrolling long result
lists. The **24h volume** header uses `whitespace-nowrap` to avoid
awkward wrapping, and the inline **security badge icon** gets
`flex-shrink-0` so it doesn’t compress next to truncated tickers.
> 
> **Overflow menu** popover panel adds `p-0` to strip default padding on
the popover container.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9b40a0b. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Interim while waiting for the new chart component, align color and line
type with mobile

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

1. Go to this page...
2.
3.

## **Screenshots/Recordings**

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

|before|after|
|---|---|
|<img width="375" height="720" alt="image"
src="https://github.com/user-attachments/assets/12d409a6-d97f-421f-8e5a-e0b56208be0e"
/>|<img width="372" height="725" alt="image"
src="https://github.com/user-attachments/assets/1bb8b68a-f65f-42f4-ba4e-31a94b236b2e"
/>|

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

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

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

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

`submitRequestToBackground` allows UI files to call code defined within
the "background" process. An engineer first defines a method within the
object that `MetamaskController.getApi` returns. When
`submitRequestToBackground` is called, the method and its arguments are
passed to a persistent instance of `MetaRpcClient`. This object then
sends a message through the background<->UI connection stream, and the
message is processed on the background side. The background process
ultimately calls a method on the `getApi` object.

As time has gone on, we have encouraged engineers to place more logic
inside of controllers and services instead of arbitrary locations within
the background process. We have also integrated messengers across the
stack. All controllers and services have messengers — little
communication "devices" that can be used to enforce modularity — which
are fed into a message bus, creating an application-wide "platform API".
Provided that the proper wiring is in place, any UI file can access a
controller or service through this message bus.

We now consider the API defined by `getApi` to be legacy, and
eventually, we want to migrate all instances of
`submitRequestToBackground` to make use of the aforementioned message
bus instead. Since this would take a long time, we are taking an
intermediate route.

In this commit, we change `submitRequestToBackground` so that if a UI
messenger action type string is provided, the special `messengerCall`
method in `getApi` is called, which routes the referenced action and its
arguments through the message bus. (For instance, an engineer could pass
`NetworkController:addNetwork` with its required arguments and it would
end up calling `NetworkController.addNetwork`.)

Gradually, we can convert all `submitRequestToBackground` callsites to
use this new syntax and thus remove legacy methods from and finally
deprecate `getApi`.

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

https://consensyssoftware.atlassian.net/browse/WPC-1290

## **Manual testing steps**

(N/A)

## **Screenshots/Recordings**

(N/A)

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the UI→background request entry point and uses a `:` heuristic
to choose messenger vs legacy RPC; backward compatible but affects how
all background calls are dispatched.
> 
> **Overview**
> **`submitRequestToBackground`** now accepts **root messenger action
names** (e.g. `SnapController:installSnaps`) in addition to legacy
background API method names. If the first argument contains `:`, the
call is forwarded through the existing **`messengerCall`** RPC with the
action name and argument list; otherwise behavior stays on the legacy
**`background[method]`** path.
> 
> Call sites get **stronger TypeScript typing** via `UIMessengerActions`
and messenger `ExtractActionParameters` / `ExtractActionResponse`,
including support for actions with all-optional parameters and no args.
**Sentry trace context** is still appended when present, including for
messenger-routed calls.
> 
> **Tests** were added for messenger routing, default/optional args,
trace propagation, and legacy method names (e.g. `messengerSubscribe`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
490c9d2. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

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

Up to now, wiring UI code to the background so that it can call
controllers and services was achieved by adding a method to the
`MetamaskController.getApi` object.

However, in recent months, the Core Platform team has developed an
approach that can be shared between the Extension and Mobile codebases
by taking advantage of the fact that controllers and services have
messengers which feed into a "root messenger" (an application-wide API).
For more information on this strategy, read here:


https://github.com/MetaMask/core/blob/main/docs/legacy/ui-messengers-announcement.md

We have been cleaning up bespoke infrastructure within
MetamaskController into a LegacyBackgroundApiService, but both this
class and `getApi` are now legacy code, and we do not want engineers to
expand their surface area any longer.

To enforce this, this commit:

- Adds a JSON file, `legacy-background-api-snapshot.json`, which holds a
snapshot of all members of `MetamaskController.getApi` and
LegacyBackgroundApiService
- Adds a new script, `development/legacy-background-api.ts`, which can
be used to compare the current members to the snapshotted members to
ensure that nothing new has been added (or to update the snapshot if it
is out of date).
- Adds a couple of new package scripts, `legacy-background:check` and
`legacy-background:update`, and wires `legacy-background:check` into
`lint` so that it is run on CI.

## **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/WPC-1294.

## **Manual testing steps**

1. Check out this branch.
2. Add a new method to `getApi` in `MetamaskController`.
3. Run `yarn legacy-background-api:check`.
4. You should see an error, recommending that this method be removed.
5. Add a new method to LegacyBackgroundApiService.
6. You should see an error (slightly different error message).
7. Remove the new methods and instead, modify
`legacy-background-api-snapshot.json` by adding a new method under
`MetamaskController.getApi`.
8. Run `yarn legacy-background-api:check`.
9. You should see a different error, recommending that the snapshot be
updated.

## **Screenshots/Recordings**

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

(N/A)

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Changes are limited to dev tooling, a snapshot file, and lint; runtime
extension behavior is unchanged at merge time.
> 
> **Overview**
> Adds **snapshot-based enforcement** so `MetamaskController.getApi` and
`LegacyBackgroundApiService` cannot grow without an intentional, Core
Platform–reviewed update.
> 
> A new `legacy-background-api-snapshot.json` records the allowed member
names. The `development/legacy-background-api` CLI (`check` / `update`)
parses those APIs from source (TypeScript AST), compares them to the
snapshot, and fails with guidance toward UI messengers when new methods
appear. `yarn legacy-background-api:check` is wired into `lint` (CI).
**CODEOWNERS** assigns the snapshot and tooling to
`@MetaMask/core-platform`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a13d71a. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
Clear release-blocking yarn audit advisories.
- **`http-cache-semantics`
([GHSA-ch52-4w7c-c8xp](https://github.com/advisories/GHSA-ch52-4w7c-c8xp)):**
Resolve to **4.3.0**. The `.yarnrc.yml` age-gate preapproval was removed
after 7 Oct 2026.
- **`braces`
([GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm)):**
Resolve **`chokidar`** to **4.x** (the dashboard watch uses directory
roots plus an extension filter, because Chokidar 4 does not expand
globs); patch **`micromatch@4.0.8`** with the vendored depth-limit fix;
resolve **`braces`** to **`npm-empty-package`**; add **`fill-range`**
and a LavaMoat build-policy grant so patched micromatch can load it.
- **`pbkdf2` → `^3.1.7`** for
[GHSA-477h-4r7f-fvrx](GHSA-477h-4r7f-fvrx).
- **`shell-quote` → `^1.11.0`** (lockfile **1.12.0**) for
[GHSA-pqg4-j6r4-53mv](GHSA-pqg4-j6r4-53mv).
- **`sharp` → `^0.35.5`** for
[GHSA-wq5f-xc86-pv6w](GHSA-wq5f-xc86-pv6w).
Additional production resolutions in the same lockfile:
- **`postcss-selector-parser` 6.x → `^7.1.6`** for
[GHSA-rj75-hqrm-r3gf](GHSA-rj75-hqrm-r3gf).
This is a major bump; 7.1.6 keeps parse output byte-identical and only
changes the flat-selector complexity.
- **`compression` → `^1.8.2`** for
[GHSA-vc2v-76pw-4v95](GHSA-vc2v-76pw-4v95).
- **`proxy-addr` → `^2.0.8`** for
[GHSA-jqcg-44mw-7w3h](GHSA-jqcg-44mw-7w3h).
- **`source-map-js` → `^1.2.2`** for
[GHSA-68fv-2mgg-jv7q](GHSA-68fv-2mgg-jv7q).
- **`@grpc/grpc-js` → `^1.14.5`** for
[GHSA-99f4-grh7-6pcq](GHSA-99f4-grh7-6pcq)
(fixed in 1.14.4).


<!--
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: #46899
Fixes: #46883
Fixes: #46855

## **Manual testing steps**

1. Go to this page...
2.
3.

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **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**
> Touches crypto (`pbkdf2` / hashing) LavaMoat allowances and a major
`postcss-selector-parser` resolution; risk is mitigated as audit-driven
graph alignment rather than application logic changes.
> 
> **Overview**
> Clears release-blocking **yarn audit** findings by adding or
tightening **Yarn resolutions** in `package.json` (notably
**`postcss-selector-parser` 6.x → `^7.1.6`**, **`@grpc/grpc-js` →
`^1.14.5`**, **`sharp` → `^0.35.5`**, plus bumps for GraphQL utils,
tinypool, and OpenTelemetry instrumentation packages). The
**`chokidar`** resolution line is removed from `resolutions` in this
diff slice.
> 
> **LavaMoat webpack policies** are updated to match the new lockfile
graph. In **`lavamoat/webpack/build/policy.json`**, cssnano/tailwind
consumers now allow a single **`stylelint>postcss-selector-parser`**
dependency instead of many nested duplicate entries;
**`webpack-dev-server>compression`** gains **`koa>destroy`**.
> 
> Across **MV2/MV3** policy variants, **`crypto-browserify>pbkdf2`** no
longer references separate **`pbkdf2>create-hash` / `pbkdf2>ripemd160`**
subtrees—it routes through **`ethereumjs-util>create-hash`** instead.
Related **`hash-base` / `readable-stream`** grants are expanded (e.g.
**`@ngraveio/bc-ur>sha.js>to-buffer`**, dedicated
safe-buffer/string_decoder nodes), and
**`remote-redux-devtools>socketcluster-client>sc-channel`** now points
at the nested **`sc-channel>component-emitter`** path.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
aa0004d. 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: MetaMask Bot <metamaskbot@users.noreply.github.com>
…x submission (#46872)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Alternative solution to [this
PR](#46556) which
introduced a new bug when importing multichain accounts.

The new bug showed failed transactions on non-evm account import (if
failed transactions on that account existed). On wallet start-up,
non-evm historical account data is backfilled, so any existing failed
transaction was added and then read as a transaction to be handled by
the toast listener. As the code always showed a failed toast for a
failed transaction, this led to the bug.

This new solution adds a pre-submitted state for approved or signed
transactions. It then allows failed transactions to be shown which were
approved or signed but not submitted (e.g. the original nonce issue).
But it doesn't create the non-evm bug as it still requires failed
transactions to go through a pre-submitted state first.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fixed a bug that hid the failed-transaction toast when
a transaction failed before it was submitted

## **Related issues**

Fixes: #46458

## **Manual testing steps**

Confirm that a send tx with a used/low nonce shows a failed toast
Confirm that happy-path send still shows pending → success toasts
Verify that rejecting on the confirmation screen still shows no toast

## **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/aa3af090-9983-48f3-b46a-087413181805




## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> UI-only toast gating with broad test coverage; behavior change is
limited to when transaction notifications appear, not transaction
handling.
> 
> **Overview**
> Introduces an **`approvedOrSigned` toast lifecycle phase** so
transaction toasts only fire for txs the user actually started, fixing
missing **failed** toasts when a send dies after approval/signing but
before broadcast (e.g. nonce errors) without reintroducing spurious
failed toasts for backfilled historical non-EVM failures.
> 
> `setApprovedOrSignedToastPhase` is recorded on EVM `approved`/`signed`
status updates; `shouldShowTerminalToast` now allows success/failure
only after **approved/signed** or a shown **pending** toast, and
`shouldShowPendingToast` no longer advances from unrelated phases. Hook
tests cover approve→fail, approve→submit, reject, and
historical/non-started failure paths for both controllers.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
47ede73. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Bump Snaps packages to latest, resolving a LavaMoat issue, uses the
`cryptography` package and fixes some log statements. Due to type issues
this PR also resolves `utils` to v12 across the board, the only breaking
changes shipped are build-output and `engines` related so should have no
impact on functionality.

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

https://consensyssoftware.atlassian.net/browse/WPC-1401

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches Snaps iframe execution URL and LavaMoat crypto/globals for all
extension builds; utils v12 is a major bump but described as
non-functional for consumers.
> 
> **Overview**
> Bumps **Snaps** stack and aligns shared **`@metamask/utils`** at
**v12** across dependencies and Yarn resolutions.
> 
> **Package / build config:** `@metamask/snaps-controllers` (21.1.2),
`@metamask/snaps-utils` (12.6.1),
`@metamask/snaps-execution-environments` (11.3.2), and `@metamask/utils`
(12.0.0). All build flavors in `builds.yml` now point
`IFRAME_EXECUTION_ENVIRONMENT_URL` at iframe **11.3.2**.
> 
> **LavaMoat (MV2 policies for main/beta/experimental/flask):**
Regenerated policies after dependency deduping—nested per-package
`@metamask/utils` entries collapse to a single `@metamask/utils`;
cryptography is wired through
`@metamask/snaps-utils>@metamask/cryptography` (with
`crypto.subtle.digest` allowed) instead of profile-sync’s copy;
`@metamask/utils` no longer lists `@metamask/scure-bip39` in the policy.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
37174cd. 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: MetaMask Bot <metamaskbot@users.noreply.github.com>
## **Description**

Adds a `TimestampEnforcer` deadline caveat to every EIP-7702 delegation,
and moves delegation caveat generation into a dedicated `caveats.ts`
module.

- New `app/scripts/lib/transaction/caveats.ts` owns caveat building via
`getDelegationCaveats`:
  - Provided caveats are used unchanged.
- Otherwise shared base caveats (`limitedCalls`, deadline, and
`redeemer` when redeemers are set) are combined with either
`exactExecution` / `exactExecutionBatch` or the subsidized caveats.
- New `app/scripts/lib/transaction/subsidized-caveats.ts` contains the
subsidized `allowedTargets` / `allowedCalldata` logic, built from the
parent execution.
- Subsidized transactions reuse the default parent execution builder,
and calldata normalization is private to `delegation.ts`.
- The deadline defaults to 30 minutes and can be overridden with
`deadlineSeconds` in the `confirmations_delegations` remote feature
flag.
- Adds dedicated unit tests for both modules.
- `delegation.ts` now only orchestrates and imports the caveat helpers.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

1. Submit a gas fee token transaction on an EIP-7702 supported network.
2. Verify the transaction is relayed and confirmed.
3. Submit a MetaMask Pay transaction and verify it completes.

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

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

## **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]
> **High Risk**
> Changes which caveats are signed into EIP-7702 delegations across
gasless, sponsored, and relay paths; incorrect deadline or caveat
ordering could break redemption or widen delegation scope.
> 
> **Overview**
> Adds a **TimestampEnforcer** deadline to every auto-generated EIP-7702
delegation and centralizes caveat construction in new modules.
> 
> **`getDelegationCaveats`** (`caveats.ts`) now builds default caveats
as `limitedCalls` → **timestamp** → optional `redeemer` → either
`exactExecution` / `exactExecutionBatch` or subsidized `allowedTargets`
/ `allowedCalldata`. Caller-supplied `caveats` are returned as-is (no
extra redeemer caveat). The expiry defaults to **30 minutes** and can be
tuned via remote flag `confirmations_delegations.deadlineSeconds`
(invalid values fall back to the default).
> 
> **`delegation.ts`** delegates caveat generation to that helper, wires
**`RemoteFeatureFlagController:getState`** on the delegation messenger,
and moves subsidized calldata enforcement into
**`subsidized-caveats.ts`** (without its own `LimitedCalls`
caveat—limited calls live in the shared base). Publish/delegation tests
expect **one additional caveat** (the timestamp) on relay flows.
> 
> Registers `confirmations_delegations` in the e2e feature-flag registry
and adds CI resolution for
`CONFIRMATIONS_DELEGATIONS_FEATURE_FLAG_NAME`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8252538. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Non-Money MetaMask Pay deposits now prefill 50% of the selected token
balance. Their transaction events also include the same amount-input
metrics used by Money Account deposits.

Prefill is enabled per transaction type by the
`confirmations_pay_extended.prefilledAmount` flag, with no hard-coded
type list, matching mobile.

## **Changelog**

CHANGELOG entry: Updated Perps and Predict deposits to prefill half of
the selected token balance.

## **Related issues**

Fixes: CONF-2076

## **Manual testing steps**

1. Start a Perps or Predict deposit with a funded token.
2. Open the MetaMask Pay confirmation.
3. Verify the amount is prefilled with 50% of the selected token
balance.
4. Switch the selected token and verify the prefill updates to 50% of
its balance.

<!--
## **Screenshots/Recordings**

### **Before**

### **After**
-->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes confirmation amount defaults, Max/prefill application, and Pay
transaction metrics for multiple deposit types; incorrect prefill or Max
arming could affect quoted/submitted amounts.
> 
> **Overview**
> Extends **MetaMask Pay deposit prefill** beyond money-account
deposits: when `confirmations_pay_extended.prefilledAmount` is enabled
per transaction type, Perps/Predict (and similar) confirmations
prefilled **50%** of the selected token balance, while money-account
deposits still use **100%** only for stablecoin route tokens (otherwise
50%).
> 
> **`useDepositPrefillAmount`** is renamed to **`useDepositPrefill`**
and now exposes **`percentage`** and **`isLimitCapped`** so consumers
can apply percentage prefills vs fixed (limit-capped) amounts.
**`useTransactionCustomAmount`** applies prefill whenever the hook is
enabled (not only `moneyAccountDeposit`), routes 50%/uncapped-100%
through **`updatePendingAmountPercentage`**, and avoids arming
**`isMaxAmount`** for 100% prefills based on a stale snapshot balance.
> 
> Amount-input analytics are centralized in
**`useTransactionCustomAmountPercentageMetrics`** (`prefilled_50`,
`prefilled_max`, `mm_pay_prefilled_amount`), replacing inline
`upsertTransactionUIMetricsFragment` calls; executed transaction metrics
continue to copy those UI fragment fields (e.g. perps deposits).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
649ae0e. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

PR #46742 changed the default Robinhood Chain block explorer to
`https://robin.etherscan.io/`. That default is used when Robinhood Chain
is added, but existing installations keep their previously persisted
`NetworkController` configuration after an upgrade. As a result, users
who already had Robinhood Chain configured continued to open
`https://robinhoodchain.blockscout.com` unless they deleted and re-added
the network.

This PR adds state migration 231. For Robinhood Chain (`0x1237`), it
replaces explorer entries whose hostname is exactly
`robinhoodchain.blockscout.com` with `https://robin.etherscan.io/`. The
migration preserves the explorer array order and
`defaultBlockExplorerUrlIndex`, leaves custom and lookalike explorer
URLs unchanged, and records `NetworkController` as changed so the
migrated state is persisted.

Unit tests cover the version bump, both trailing-slash forms of the old
URL, index preservation, custom and lookalike URLs, missing network
state, and migration registration.

## **Changelog**

CHANGELOG entry: Fixed Robinhood Chain explorer links for existing users

## **Related issues**

Refs:
[WPN-2104](https://consensyssoftware.atlassian.net/browse/WPN-2104)

Follow-up to #46742.

## **Manual testing steps**

1. Install Extension 13.51.0 in Chrome and complete onboarding.
2. Add Robinhood Chain and confirm its saved block explorer is
`https://robinhoodchain.blockscout.com`.
3. Build this branch and update the same installed extension/profile
without clearing its data.
4. Open an address or transaction explorer link while Robinhood Chain is
selected.
5. Confirm the link opens on `https://robin.etherscan.io/` without
deleting and re-adding the network.

<!--
## **Screenshots/Recordings**

N/A — this is a persisted-state migration with no UI changes.
-->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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


[WPN-2104]:
https://consensyssoftware.atlassian.net/browse/WPN-2104?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Scoped persisted-state rewrite for one chain’s block explorer URLs
with hostname-exact matching and broad test coverage; no auth or
transaction logic changes.
> 
> **Overview**
> Adds **state migration 231** so existing installs pick up the
Robinhood Chain block explorer change that new adds already get from
defaults.
> 
> On upgrade, if `NetworkController` has Robinhood Chain (`0x1237`), any
`blockExplorerUrls` entry whose hostname is exactly
`robinhoodchain.blockscout.com` is rewritten to
`https://robin.etherscan.io/`. **Explorer list order** and
**`defaultBlockExplorerUrlIndex`** stay the same; custom URLs and
lookalike hostnames are untouched. When nothing matches or the chain
isn’t configured, the migration is a no-op. Successful rewrites mark
**`NetworkController`** as changed so persisted state updates.
> 
> Migration **231** is wired into the migrations list, covered by unit
tests (version bump, URL replacement, no-op cases), and e2e
fixtures/snapshots bump **`meta.version`** /
**`currentMigrationVersion`** from 230 to 231.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
07f1e8d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

### Context

Native EVM sends calculated Max using a fixed 21,000 gas assumption.
That assumption is not safe for networks or recipients where the
selected RPC returns a higher gas requirement.

### Problem

Selecting Max could fill the entire balance before a usable gas estimate
was available, or reserve too little for the final transaction. On
legacy and `eth_gasPrice` networks, Max reserved no gas at all because
only the fee-market `medium.suggestedMaxFeePerGas` rate was read, so the
confirmation was blocked with an insufficient-balance alert. Slow
estimates could also race and overwrite newer results.

### Solution

- Estimate the Max transaction with the node's `eth_estimateGas` on the
send's network client, using the full raw balance as the value. Without
fee fields, `eth_estimateGas` only requires the value to be covered by
the balance. This was verified on mainnet, Arbitrum, Optimism, Base,
Polygon, Linea, BSC and Scroll, where the estimate did not vary with
value.
- Reserve exactly `gasLimit × fee rate + L1 fee`, with no extra gas
buffer. The fee rate is the same `medium` / `gasPrice` level
TransactionController applies, and it supports fee-market, legacy and
`eth_gasPrice` networks, reusing the GasFeeController estimate types.
- Keep the background `estimateGas` as a plain `eth_estimateGas`
request, only adding an optional `networkClientId`, so existing callers
(subscription approval, edit spending cap) are unchanged.
- Keep sponsored, token, and non-EVM sends on their existing
full-balance behavior.
- Keep Max stable as fee polling refreshes, while using the latest fee
rate to calculate the amount.
- Show loading only while estimation is running and show explanatory
error copy only after estimation fails.
- Prevent stale asynchronous estimates from replacing the latest result.

## **Changelog**

CHANGELOG entry: Fixed native Max sends to reserve the gas estimated by
the selected network.

## **Related issues**

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

## **Manual testing steps**

1. Build and load the extension, then fund an account with a native
asset on an EVM network.
2. Start a native send and enter a valid recipient.
3. Verify the Max control shows a loading state while the gas estimate
is being calculated.
4. Click Max after it becomes available and verify the amount is below
the full balance by enough to reserve the estimated network fee.
5. Leave the send screen open through a gas-fee refresh and verify Max
does not return to a loading or disabled state.
6. Continue to confirmation and verify the transaction can be submitted
without an insufficient-funds error caused by gas.
7. Repeat with a balance close to the network fee and verify Max remains
available when a smaller send amount is viable.
8. Repeat on a supported L2 and verify Max also reserves the displayed
L1 fee.
9. Repeat on a legacy (non-EIP-1559) network, e.g. a local Anvil started
with a pre-London hardfork, and verify Max reserves the network fee and
the transaction can be submitted.
10. Configure an unreachable custom RPC, start another native send, and
verify Max becomes disabled with an explanation after estimation fails.
11. On a gas-sponsored network, verify Max still selects the full native
balance.

## **Automated testing**

- `npx jest --no-watchman
app/scripts/services/legacy-background-api-service.test.ts
ui/hooks/useAsync.test.tsx
ui/pages/confirmations/components/send/amount-recipient/amount-recipient.test.tsx
ui/pages/confirmations/components/send/amount/amount.test.tsx
ui/pages/confirmations/hooks/send/useMaxAmount.test.ts`
- `npx jest --no-watchman ui/hooks/subscription
ui/pages/confirmations/components/confirm/info/approve/edit-spending-cap-modal`
- `yarn lint:tsc`
- `yarn circular-deps:check`

## **Screenshots/Recordings**

### **Before**

To be added before the PR is marked ready for review.

### **After**

To be added before the PR is marked ready for review.

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes how max native send amounts are computed across send and
confirmation, which directly affects spendable value and fee
reservation; regression risk is mitigated by updated hook tests but
touches core transaction UX.
> 
> **Overview**
> **Moves native “Max” gas reservation off the send screen and into
confirmation**, so the send flow no longer subtracts fees from a fixed
21k-gas / fee-estimate heuristic.
> 
> `useMaxAmount` now returns the **full asset balance** (native, ERC20,
Solana) and documents that native EVM gas is adjusted later by
`useMaxValueRefresher` using `TransactionController` gas and fee fields.
Related Redux/gas-estimate/L1-fee plumbing and `getLayer1GasFees` in
send utils are removed, with tests narrowed to match.
> 
> On confirmation, `useMaxValueRefresher` passes **`updateType: false`**
when it writes the gas-adjusted value so a max send to a contract
address stays classified as a simple send instead of flipping to a
contract interaction.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
839b712. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

- Open the Chainlist network list with the add-network form, anchored
under the network name field and filling the space above Save. Focusing
or clicking Chain ID moves that list under the Chain ID field.
- Keep the Add RPC suggestion list open for the chain being added.
- Preserve in-progress form details when leaving and returning from Add
RPC or Add block explorer. Return to Edit network when the block
explorer page was opened from an existing network.
- Allow any custom RPC URL to be deleted. Infura endpoints stay locked.
- Rebuild the add block explorer page with the same design-system field,
label, and footer as Add RPC.

## **Changelog**

CHANGELOG entry: Fixed the add-network Chainlist lists so they stay
open, stay attached to the field that opened them, and keep entered
details when adding an RPC or block explorer URL.

## **Related issues**

Fixes:

## **Manual testing steps**

Enable the `extension-ux-chainlist-v-2` remote feature flag, then reload
the extension.

1. Open Settings, then Networks, then Add custom network.
2. Confirm the Chainlist list is already open under Network name,
matches that field's width, has no info icon in the source banner, and
extends down the page.
3. Close the list, click Chain ID, and confirm the list opens under
Chain ID rather than under Network name.
4. Pick a network that is not already added. Confirm the name, chain ID,
ticker, and RPC stay filled in.
5. Open the RPC list and delete the custom RPC URL. Confirm it is
removed. Repeat on an Infura network such as Ethereum and confirm that
Infura endpoint cannot be deleted.
6. Fill the form again, open Add RPC URL, then press back. Confirm the
name, chain ID, ticker, and RPC are still there and the Chainlist list
does not cover them.
7. Open Add a block explorer URL, then press back. Confirm the same
fields are still there.
8. On Add a block explorer URL, confirm the field and Add URL button
match the Add RPC page. Enter an invalid URL and confirm the error
appears. Enter a valid `https` URL and add it.
9. From Add custom network, pick a network that is already added so Edit
network opens. Open Add a block explorer URL, then press back. Confirm
you return to Edit network with that network's details, not to Add
network.

## **Screenshots/Recordings**


### **Before**

### **After**



https://github.com/user-attachments/assets/f3ddcd6d-c46e-45f9-a0ee-6b5335498ebb



## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
This PR adds a CTA to token row. It will appear next to some stablecoins
and vault tokens. The exact tokens it will appear next to is controlled
by a feature flag.

This PR adds two new flags. One to control which tokens the CTA appears
next to, and another to control whether the CTA is shown at all. Both
are essentially duplicates of the flags that we used in the mobile
client. I have already set both flags up in launchdarkly
<!--
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: add money account CTAs to token row, gated behind
feature flag

## **Related issues**

Fixes: MUSD-1449

## **Manual testing steps**

1. With the flags enabled (RC & Dev envs) visit the home page
2. Look at the token list, find a stablecoin for which you have balance
3. Observe the `get x% APY` CTA
4. Click it, you should see the deposit modal, prefilled with the
appropriate token

## **Screenshots/Recordings**

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

### **Before**
<img width="861" height="1287" alt="image"
src="https://github.com/user-attachments/assets/ab1ec42c-c580-47db-8cb9-f5c00ddb5e8c"
/>

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

### **After**


https://github.com/user-attachments/assets/233452a0-4426-4984-b799-e8706d82fa61


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

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **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**
> Introduces a new deposit entry point on the home token list with
remote flag and geo gating; mistakes could show CTAs or start deposits
for wrong tokens, though parsing and eligibility fail closed.
> 
> **Overview**
> Adds a **feature-flagged “Get X% APY” CTA** on wallet token list rows
for allowlisted ERC-20s, wired through new remote flags
`earnMoneyTokenListItemCtaEnabled` and
`earnMoneyDepositCtaTokenAddresses` (plus registry/i18n `moneyGetApy`).
> 
> **`useMoneyTokenListCta`** resolves the CTA once per list (flags,
geo/Money account, vault APY, min balance, blocked tokens); eligible
rows render **`MoneyTokenListCta`**, which **replaces** the
percent-change footer and **takes priority over** the mUSD convert link,
then **tracks analytics** and **`initiateDeposit`** with the clicked
token pre-selected. Vault APY fetching moves to **`useMoneyVaultApy`**;
deposit eligibility is shared via **`getMoneyDepositFiatAmountUsd`**.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bc2730c. 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 5.5 <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Part 1/6 of the MFA phase 1 client kit (stacked PRs: #46909 → #46910 →
#46911 → #46912 → #46913 → #46914; mobile stack starting at
MetaMask/metamask-mobile#37234). The kit is not
used by any feature yet, and its entry points are hidden in production
builds.

First piece of the MFA client kit on the extension: the
platform-agnostic engine, a copy of metamask-mobile's (reviewed in
MetaMask/metamask-mobile#37237). It talks to the
controller through the ports in `engine/types.ts`.

- `types.ts`: shared types (methods, plan steps, flow state, ports, kit
error codes).
- `planner.ts`: `getMethodStatuses` (a per-method view of the server's
credential list) and the pure planners for `verifyOrEnroll` and
`enroll`: what to set up, whether to confirm first, and whether a final
verification is needed.
- `errors.ts`: the error table that maps every MFA error code to how the
flow handles it.

**About the `eslint-disable` comments:** the engine is kept identical to
metamask-mobile's (`app/util/identity/mfa/engine`) so both clients
behave the same, and the two repos' lint rules disagree on a few points:
mobile requires `interface` where the extension requires `type`, the
error table's keys are the server's snake_case codes, and the SDK's
WebAuthn types share their names with browser globals. Each disable is
scoped to the lines concerned and says why.

Nothing imports it yet.

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

## **Manual testing steps**

N/A: unit tests only; the code is not reachable from the UI yet.

## **Screenshots/Recordings**

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

N/A

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> New, unused engine code with unit tests only; no runtime wiring yet,
though the logic will eventually govern MFA enrollment and verification.
> 
> **Overview**
> Introduces the first slice of the extension MFA client kit under
`ui/hooks/identity/mfa/engine`, aligned with metamask-mobile’s engine so
both clients plan flows the same way. Nothing in the app imports it yet
(stacked PR 1/6).
> 
> **`types.ts`** defines shared contracts: credential method status,
plan/flow steps and state, controller and passkey adapter ports, and
kit-specific error codes.
> 
> **`planner.ts`** adds pure planning for `verifyOrEnroll` and
`enroll`—intro, confirm-before-enroll, setup order (with `verifyWith`
methods last), session reuse/`maxSessionAgeMs`, platform limits
(extension: email only; passkeys rejected until supported), and
`getMethodStatuses` / `getEnrollmentMaxSessionAgeMs`.
> 
> **`errors.ts`** maps every MFA flow error code to UI handling
(`refresh`, `inline`, `restart`, etc.), normalizes unknown errors to
`server_error`, and adds `MfaFlowError` for kit rejections.
> 
> Unit tests cover the error table, planners, and edge cases (pending
email, extension passkey rejection, session age rules).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9d16de1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR is to update button text to Save in Add/edit contact and add
tokens

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

## **Related issues**

Fixes: Updating button save text. Going to update rest in follow up
tickets https://consensyssoftware.atlassian.net/browse/CEUX-1401

## **Manual testing steps**

1. Go to this page...
2.
3.

## **Screenshots/Recordings**

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

### **Before**

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

### **After**
<img width="1292" height="1590" alt="Screenshot 2026-10-12 at 5 07
52 PM"
src="https://github.com/user-attachments/assets/19beaad7-3ddf-4ef2-80cb-878b5dc4bc88"
/>

<img width="1304" height="1606" alt="Screenshot 2026-10-12 at 5 09
37 PM"
src="https://github.com/user-attachments/assets/b3085789-91f2-47e0-ba80-a8548feea623"
/>

<img width="1298" height="1562" alt="Screenshot 2026-10-12 at 5 09
59 PM"
src="https://github.com/user-attachments/assets/85bc8637-5f19-4c00-aa04-2c233be51178"
/>

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Copy and layout-only UI changes; exit paths move to header navigation
with no backend or persistence logic changes.
> 
> **Overview**
> **Aligns primary action copy and contact form footers** with a single
**Save** label on add/edit contact and custom token import (replacing
**Add token** on import).
> 
> On **add** and **edit contact**, the footer **Cancel** button and
`onCancel` wiring are removed; dismissal is via the page header **back**
/ **close** controls. The **Save** action is **full width** in the
footer instead of sharing a row with Cancel.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
49e2c43. 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 the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Part 2/6 of the MFA phase 1 client kit (stacked PRs: #46909 → #46910 →
#46911 → #46912 → #46913 → #46914; mobile stack starting at
MetaMask/metamask-mobile#37234). The kit is not
used by any feature yet, and its entry points are hidden in production
builds.

The engine's runtime, a copy of metamask-mobile's (reviewed in
MetaMask/metamask-mobile#37238):

- `flow.ts`: `createMfaFlow`, a state machine (`getState` / `subscribe`
/ `dispatch`) that runs the plan step by step, re-plans from fresh state
after each step and applies the error table.
- `activeFlow.ts`: one MFA flow at a time; an identical request joins
the running flow, anything else gets `flow_in_progress`.
- `useActiveMfaFlow.ts`: a `useSyncExternalStore` hook for the page that
hosts a flow.

The `eslint-disable` comments are explained in the previous PR of the
stack. Nothing imports it yet.

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

## **Manual testing steps**

N/A: unit tests only; the code is not reachable from the UI yet.

## **Screenshots/Recordings**

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

N/A

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> New, test-only MFA kit code with no production imports yet; behavior
mirrors the reviewed mobile engine and does not change existing auth
paths.
> 
> **Overview**
> Adds the **MFA engine runtime** (part 2 of the phase 1 client kit):
orchestration and UI-facing state, still **not wired into any feature**.
> 
> **`createMfaFlow`** (`flow.ts`) is a dispatch-driven state machine
that advances through planner steps (intro, email entry, OTP, passkey,
method picker, success/failure), talks to the MFA controller adapter for
enroll/verify, and maps SDK errors to inline retry, cooldown, credential
refresh, or terminal failure. It can finish silently when credentials
and a valid session already satisfy the request.
> 
> **`startMfaFlow`** (`activeFlow.ts`) enforces a **single global
flow**: identical operation + request joins the in-flight promise;
anything else rejects with `flow_in_progress`, and the slot clears when
the flow settles.
> 
> **`useActiveMfaFlow`** exposes the active flow and live `MfaFlowState`
to React via `useSyncExternalStore`.
> 
> Broad unit coverage is included for flow behavior, singleton
semantics, and the hook.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5afeeca. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@metamask-ci

metamask-ci Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor
Builds ready [acf000d]
⚡ Performance Benchmarks (Total: 🟢 8 pass · 🟡 3 warn · 🔴 2 fail)

Baseline (latest main): 171ed20 | Date: 7/28/2026 | Pipeline: 39891988127 | Baseline logs

Metricschrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 load_new_account(p95) [CI log]🔴 load_new_account(p95) [CI log]

Regressions (🔴 2 failures)

Interaction Benchmarks · Samples: 5 🔴 2
Benchmarkchrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 [CI log]
🔴 load_new_account
🔴 [CI log]
🔴 load_new_account
confirmTx
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
bridgeUserActions
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ loadNewAccount/load_new_account: +416%
  • ↑ loadNewAccount/total: +416%
  • ↓ loadNewAccount/inp: -24%
  • ↓ loadNewAccount/fcp: -16%
  • ↓ loadNewAccount/lcp: -21%
  • ↑ loadNewAccount/cls: +15%
  • ↑ confirmTx/longTaskTotalDuration: +19%
  • ↑ confirmTx/longTaskMaxDuration: +51%
  • ↑ confirmTx/tbt: +34%
  • ↓ confirmTx/inp: -32%
  • ↓ confirmTx/fcp: -15%
  • ↓ confirmTx/lcp: -13%
  • ↑ bridgeUserActions/bridge_load_page: +22%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +65%
  • ↑ bridgeUserActions/longTaskCount: +67%
  • ↑ bridgeUserActions/longTaskTotalDuration: +39%
  • ↓ bridgeUserActions/longTaskMaxDuration: -19%
  • ↓ bridgeUserActions/tbt: -14%
  • ↓ bridgeUserActions/fcp: -17%
  • ↓ bridgeUserActions/lcp: -20%
  • ↑ loadNewAccount/load_new_account: +423%
  • ↑ loadNewAccount/total: +423%
  • ↓ loadNewAccount/inp: -24%
  • ↑ loadNewAccount/fcp: +23%
  • ↑ loadNewAccount/lcp: +1277%
  • ↓ confirmTx/longTaskCount: -100%
  • ↓ confirmTx/longTaskTotalDuration: -100%
  • ↓ confirmTx/longTaskMaxDuration: -100%
  • ↓ confirmTx/tbt: -100%
  • ↓ confirmTx/inp: -17%
  • ↑ confirmTx/fcp: +19%
  • ↑ confirmTx/lcp: +1281%
  • ↑ bridgeUserActions/bridge_load_page: +406%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +121%
  • ↓ bridgeUserActions/longTaskCount: -100%
  • ↓ bridgeUserActions/longTaskTotalDuration: -100%
  • ↓ bridgeUserActions/longTaskMaxDuration: -100%
  • ↓ bridgeUserActions/tbt: -100%
  • ↑ bridgeUserActions/total: +43%
  • ↑ bridgeUserActions/inp: +92%
  • ↑ bridgeUserActions/fcp: +15%
  • ↑ bridgeUserActions/lcp: +1238%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🟡 loadNewAccount/FCP: p75 2.1s
  • 🟡 confirmTx/FCP: p75 2.0s
  • 🟡 bridgeUserActions/FCP: p75 2.0s
Startup Benchmarks · Samples: 100
Benchmarkchrome-webpackfirefox-webpack
startupStandardHome
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ startupStandardHome/load: -11%
  • ↓ startupStandardHome/domContentLoaded: -11%
  • ↓ startupStandardHome/backgroundConnect: -19%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -33%
  • ↓ startupStandardHome/loadScripts: -11%
  • ↑ startupStandardHome/setupStore: +150%
  • ↓ startupStandardHome/longTaskCount: -33%
  • ↓ startupStandardHome/longTaskTotalDuration: -19%
  • ↓ startupStandardHome/longTaskMaxDuration: -16%
  • ↓ startupStandardHome/tbt: -16%
  • ↓ startupStandardHome/inp: -11%
  • ↓ startupStandardHome/fcp: -12%
  • ↓ startupStandardHome/domInteractive: -26%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -50%
  • ↑ startupStandardHome/setupStore: +153%
  • ↓ startupStandardHome/fcp: -22%
User Journey Benchmarks · Samples: 5 · real API
Benchmarkchrome-webpackfirefox-webpack
onboardingImportWallet
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
🟡 total
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ onboardingImportWallet/srpButtonToSrpForm: +51%
  • ↑ onboardingImportWallet/confirmSrpToPwForm: +40%
  • ↑ onboardingImportWallet/pwFormToMetricsScreen: +36%
  • ↑ onboardingImportWallet/metricsToWalletReadyScreen: +21%
  • ↓ onboardingImportWallet/doneButtonToHomeScreen: -94%
  • ↓ onboardingImportWallet/openAccountMenuToAccountListLoaded: -75%
  • ↓ onboardingImportWallet/longTaskCount: -100%
  • ↓ onboardingImportWallet/longTaskTotalDuration: -100%
  • ↓ onboardingImportWallet/longTaskMaxDuration: -100%
  • ↓ onboardingImportWallet/tbt: -100%
  • ↓ onboardingImportWallet/total: -89%
  • ↑ onboardingNewWallet/srpButtonToPwForm: +43%
  • ↑ onboardingNewWallet/createPwToRecoveryScreen: +17%
  • ↑ onboardingNewWallet/skipBackupToMetricsScreen: +17%
  • ↑ onboardingNewWallet/agreeButtonToOnboardingSuccess: +26%
  • ↓ onboardingNewWallet/doneButtonToAssetList: -83%
  • ↓ onboardingNewWallet/longTaskCount: -69%
  • ↓ onboardingNewWallet/longTaskTotalDuration: -79%
  • ↓ onboardingNewWallet/longTaskMaxDuration: -51%
  • ↓ onboardingNewWallet/tbt: -99%
  • ↓ onboardingNewWallet/total: -80%
Dapp Page Load Benchmarks · Samples: 100
Benchmarkchrome-webpack
dappPageLoad
[Sentry log · main/release]
🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ dappPageLoad/pageLoadTime: -67%
  • ↓ dappPageLoad/domContentLoaded: -23%
  • ↓ dappPageLoad/firstPaint: -55%
  • ↓ dappPageLoad/firstContentfulPaint: -55%
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Status Bundle Total Diff Change
🚨 background 15.44 MiB +40.58 KiB +0.26%
🚨 ui 19.26 MiB +2.42 KiB +0.01%
✅ common 0 Bytes 0 Bytes 0.00%
🚨 other 4.35 MiB +1.15 KiB +0.03%
🚨 content scripts 3.15 MiB +2.3 KiB +0.07%
🚨 zip 23.94 MiB +22.93 KiB +0.09%
🍒 What's in this RC

Cherry-picks (9 commits)
Commit Description
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
6b5b96561d Merge pull request #47235 from MetaMask/runway-cherry-pick-13.54.0-1792581661
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
841196fa40 Merge pull request #47179 from MetaMask/stable-sync-release-13.54.0

Changelog (107 commits since v13.53.0)
Commit Description
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
a13345c31d chore: update CHANGELOG.md
bb2c5bce6e release(runway): cherry-pick chore: include Perps in the Flask build (#47173)
ca07950b68 release-changelog/13.54.0
bdbbdc6499 release(runway): cherry-pick feat: bump Tron, Solana snaps (#47122)
2d78bac0cd Merge release/13.53.0 into release/13.54.0
71d78824fc fix: reset AuthenticationController's needsSocialPairing via migration (#46979)
2f47b7b282 chore: upsert stx_get_fees_error to Transaction events (#46825)
7fe46a6a83 fix: keep the active network state same (#47098)
d720afa45c fix(nfts): point the import NFT media banner to Basic Functionality (#47044)
857ed7243e feat(assets): show a skeleton during the first asset load (#47105)
d0938138b7 fix(content): add article to Arc usage notice (#47112)
14d6dd2ebe chore: bump @metamask/client-mcp-core to 0.11.0 (#47106)
a85440bcd3 chore: make accounts-engineers the sole owners of MFA (#47110)
f1a2598b69 feat: [musd-1450] show earn banner in asset details (#47056)
0ef185a52d feat(tron): read resources from TRX balance metadata and show unavailable banner (#47046)
b88d694e06 fix: mixed clock domains onboarding traces (#47107)
ecf092a9dd feat(mfa): replace experimental UI with final designs and experience (#47103)
681327ef37 feat: ensure that money menu is aligned with nav burger menu (#47071)
1ac1748e39 feat(confirmations): improve Ledger-funded Money Account deposits (#47003)
731673e6e8 test: e2e cover Tokens native row on non-zero native networks (#45885)
7541962d96 feat: track seedless PrimarySrp error events (#46886)
b3ab41f3e7 chore(assets-controller): bump to 19.0.0 (#47031)
b96424fd61 feat: [musd-1453] money account design feedback tweaks (#47026)
f006fc49cb feat: report lifetime earnings API call failures (#47078)
989b387948 chore: remove Bitcoin account label tags everywhere but multichain account address list (#47077)
af2aef8d69 feat: upgrade wallet package to 17.1.0 (#47075)
d72b33d728 chore: fix announcement markdown (#47095)
2a47afd4ef fix: Infinite loading when sending with QR hardware wallet cp-13.53.0 (#47067)
e4316eb78a feat: add notification settings deeplinks [GE-525] (#46753)
fad47100c2 feat: fetch fresh Tron assets on the token details page (#46795)
f68af4cb8b Merge origin/main into stable-main-13.52.0
d1d130c778 fix: set tempo nativeCurrency to USD (#47074)
dcaa87cdb2 fix(money): hide unavailable lifetime earnings (#47076)
9a95d8db25 refactor: use SentinelApiService in Sentinel utils (#46867)
67a682ef21 test: create a new page object for Import NFT page (#47057)
7341169ec2 fix(confirmations): restore max-value correction for OP-stack L2 native sends (#46880)
94f6ef8e3f chore: update @metamask/stellar-wallet-snap to ^1.2.0 cp-13.53.0 (#47080)
9cd49a940b fix(mfa): apply the stack review follow-ups (#47072)
20c5a33e77 ci: add feature flags coverage metrics to QA stats workflow (#47079)
1c60e11c13 fix: swaps retry on failure (#47060)
e8ba981bca fix: removed majority of arc specific logic since has been moved to bridge-api (#46805)
9805977ea0 feat(perps): show the outage banner across Perps screens (#46864)
0662e26225 fix: hide fiat in send flow when currency conversion/basic functionality is off (#47022)
b66dd071f8 test: use page objects on llm scripts (#47055)
753c41cd55 fix(hardware-wallets): stop auto-showing error modal during swap (#46766)
efd2940403 feat(mfa): add verification methods settings (#46914)
44439d0701 chore: expand cashtag widget selector (#47061)
f9426fbe85 fix: manage tokens dedupe native entries (#47038)
cb90dd22ac test(e2e): add Money Account withdraw E2E coverage (#46784)
ab046448ef feat: add token symbol to search asset rows (#47045)
a9b874af29 feat(mfa): add flow host page and launcher (#46913)
d107264220 bump: upgrade Bitcoin wallet Snap to 3.2.0 (#47052)
da9d8472cb feat: move import NFT from a modal to a full page (#47027)
0c708dd21b feat(mfa): add placeholder flow screens (#46912)
87f5adde92 fix(perps): stop logging account fetch failures after channel teardown (#46846)
545fa39daf feat(perps): reverse position modal briefly shows the previous size's fee while the new quote loads (#47016)
44b714f019 fix: money transaction ids default to 0x0 cp-13-52-0 (#47035)
ab0216466d feat(perps): add market about section (#46610)
01401ca8c7 refactor(7408): migrate development build tooling batch 2 to TypeScript (#46808)
85edf42416 test(e2e): add Money Account deposit E2E coverage (#46783)
019e30011b fix(contacts): match add contact network border to other fields (#47037)
a8ca616aae feat(notifications): order agentic cli section above marketing (#47023)
f2d2a67af6 chore(deps): bump analytics-controller, config-registry-controller, and wallet (#46794)
4df5dd7865 test: remove anti-pattern for enable-notifications.spec (#47036)
fdd0011dce test: fix flaky test swap quote wait during skeleton (#46938)
06e8d58038 feat(money): open Money Home from the home card summary (#46901)
fa8145e4db test: Sync Feature Flag Registry - 2026-10-13 01:30 UTC (#47033)
50ccb5ece6 chore: ignore disputed braces advisory cp-13.52.0 (#47029)
52a96b79d8 feat(mfa): add controller bindings, useMfa hook and kit gate (#46911)
9bbbc4fd7b feat(analytics): track referral as standard Deep Link Used property (#47021)
a6b6f4648f fix(confirmations): block Money deposits while the Max quote is stale cp-13.52.0 (#47018)
4a0b918e04 feat(mfa): add engine flow state machine and active flow (#46910)
e7333ff4d3 feat: update button text to save (#47024)
22d671fa8c feat(mfa): add engine types, planner and error handling (#46909)
bc3f58442f feat: musd-1449 add money account CTA to token row (#46923)
0d40d25d31 fix(networks): keep Chainlist add-network details in place (#47001)
18921add8e fix(confirmations): estimate gas for native max sends (#46461)
3b07243075 fix(networks): migrate Robinhood explorer URL (#47019)
861bb9c47e feat(confirmations): align non-money deposit prefills (#46892)
762ae63d72 feat: add deadline caveat to EIP-7702 delegations (#46937)
65d920ed75 chore: Bump Snaps packages (#47004)
8cd528d20e fix: add approvedOrSigned toast phase to allow failed toasts before tx submission (#46872)
95553d8431 chore: audit braces and http-cache-semantics cp-13.52.0 (#46865)
b02ad71a23 chore: Gate additions to legacy background APIs (#46695)
a860a0ee54 chore: submitRequestToBackground supports UI messenger action types (#46903)
9318567d64 chore: align chart color (#47006)
65b8e55a12 chore: ui nits (#47005)
bbf3b7e72c fix(build): keep React Compiler stats out of the hashed module buildMeta (#46949)
e5d7d3cc92 fix(716): apply theme preference to the internal error dialog (#46890)
e9acc626fc chore: Bump LavaMoat (#46989)
3cec5e9453 fix(confirmations): surface Monad reserve-balance failures instead of misleading fee alerts (#46049)
c98475c3dd feat(confirmations): add confirmations_pay_rpc remote flag (#46981)
9d57c2b0af feat(perps): update controller to 20.0.0 cp-13.52.0 (#46934)
71e1f3d929 fix(hardware-wallets): simplify locked device error modal message (#46936)
3aab8a48d3 Merge origin/main into stable-main-13.51.0
3a8a1eeb91 release: Bump main version to 13.54.0 (#46960)
c1d9fba651 bump(stellar): bump stellar-wallet-snap from 1.1.0 to 1.1.1 cp-13.52.0 (#46973)
a284fe9f47 fix(analytics): add userAgent enrichment to early Segment events (#46921)
d61f0ab0f9 chore: bump @metamask/profile-sync-controller to 34.0.3 (#46947)
cc552ce832 fix: start with "All networks" not Sepolia or Arc (#46928)

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Commits
56/100 6 7 587 111
Cherry-Pick Scenarios (3)

Medium Risk Scenarios (3)

1. Snaps: Tron Snap update (connect, sign transaction, permissions)

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47122 bumps Tron Snap; Snap permission/signing flows can break on version changes, risking failed sends or incorrect confirmations.

Test Steps:

  1. Install/connect the Tron Snap from a known demo dapp and approve requested permissions.
  2. View Tron account details in the Snap UI and send a small TRX transfer from the demo dapp.
  3. Verify the confirmation screen data (to, amount, fee) and that the transaction status updates to confirmed.
  4. Revoke the Snap’s permissions and ensure subsequent dapp requests are blocked or prompt re-approval.

2. Snaps: Solana Snap update (connect, sign, message signing)

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47122 updates Solana Snap; changes may affect signing formats and account routing, causing user-facing errors.

Test Steps:

  1. Connect a Solana Snap via a demo dapp and approve all requested capabilities.
  2. Initiate a SOL transfer and confirm the MetaMask Snap confirmation displays correct details.
  3. Request a message/signData operation and ensure it signs and returns as expected.
  4. Switch accounts and retry; confirm the Snap respects the selected account and permissions.

3. Snaps: Stellar Wallet Snap update (connect, sign transaction)

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47224 updates the Stellar Snap; permission and signing behavior can change with Snap versions and must be validated.

Test Steps:

  1. Connect the Stellar Wallet Snap from a demo dapp and grant permissions.
  2. Send a small XLM transfer via the dapp and confirm the transaction through the Snap UI.
  3. Verify post-send details (hash, status) appear correctly in the dapp and MetaMask activity if surfaced.
  4. Disconnect the Snap and confirm the dapp cannot initiate further requests without re-connection.

Release Scenarios (10)

High Risk Scenarios (6)

1. State Migrations (231–233): NFT detection and asset preferences

Risk Level: HIGH

Why This Matters: Migrations can inadvertently drop or duplicate user assets; manual NFT imports and detection settings are persistent user data that must not regress.

Test Steps:

  1. Start with a 13.53.x profile having NFT detection OFF and 2 manually imported NFTs on Ethereum.
  2. Upgrade to 13.54.0 and open the NFTs tab for the same account and network.
  3. Verify previously imported NFTs still appear once, with correct metadata and no duplicates.
  4. Toggle NFT detection ON, refresh the NFTs tab, and confirm no duplicate entries are created for already imported NFTs.

2. State Migrations (231–233): Network enablement and asset fetch behavior

Risk Level: HIGH

Why This Matters: Network enablement logic impacts background asset fetching; incorrect defaults or migrations can cause unexpected RPC traffic or missing tokens.

Test Steps:

  1. Use a pre-upgrade profile with multiple networks configured (e.g., Ethereum Mainnet, Polygon, BSC) and token auto-detection OFF for Polygon.
  2. Upgrade to 13.54.0 and open the Assets tab on Polygon.
  3. Verify token lists are not auto-fetched for networks that previously had detection disabled and existing tokens remain intact.
  4. Enable token detection for Polygon, reopen the Assets tab, and confirm the list updates without overwriting/removing user-added tokens.

3. Transaction Sending: EIP-1559 fee estimation and speed-up/cancel (Transaction Pay Controller patch)

Risk Level: HIGH

Why This Matters: A patched transaction-pay dependency can break fee estimation or replacement logic, causing user loss or stuck transactions.

Test Steps:

  1. On Ethereum Mainnet, send a standard ETH transfer using the default suggested gas (EIP-1559) and submit.
  2. From the activity view, speed up the pending transaction using a higher priority and confirm it is replaced and mined.
  3. Send another transaction and cancel it before it is mined; verify final statuses reflect 'Cancelled' cleanly in activity and state.
  4. Confirm the network fee is calculated and displayed consistently across the confirm screen and activity details.

4. Transaction Sending: Legacy gas on non-1559 networks

Risk Level: HIGH

Why This Matters: Incorrect handling of legacy gas can block transactions on popular non-1559 networks, directly impacting user funds.

Test Steps:

  1. Switch to a legacy gas network (e.g., BSC) and initiate a token transfer.
  2. Manually edit gas price and gas limit, submit the transaction, and ensure it confirms.
  3. Verify the confirm screen and activity detail display legacy gas correctly and no 1559 fields are shown.
  4. Ensure retry/speed-up behaves correctly using legacy gas (no base/priority fields).

5. Assets: Network enablement initialization (Assets/network-enablement-controller-init)

Risk Level: HIGH

Why This Matters: Initialization changes can cause missing or excessive asset fetches per network, impacting performance and user trust in balances.

Test Steps:

  1. Fresh install 13.54.0 and complete basic onboarding to a new seed.
  2. Visit Assets on Ethereum, then switch to Polygon and Arbitrum; observe asset population timing and behavior.
  3. Toggle any available per-network detection setting (if present) and confirm the asset list updates only for the toggled network.
  4. Reload the extension and confirm settings persist and do not trigger unexpected re-fetches on disabled networks.

6. NFTs: Detection notice and Import NFTs flow

Risk Level: HIGH

Why This Matters: New notice/UI around NFT detection can alter the import flow; errors here create duplicates or hide assets.

Test Steps:

  1. With NFT detection OFF, open the NFTs tab and choose 'Import NFTs'.
  2. Verify a detection-related notice appears, read-through it, and proceed to manual import with a known contract and token ID.
  3. After successful import, enable NFT detection and ensure the imported NFT is not duplicated after refresh.
  4. Disable NFT detection again and confirm the imported NFT remains visible and stable.

Medium Risk Scenarios (4)

1. Account Group Balance: Totals and currency conversion accuracy

Risk Level: MEDIUM

Why This Matters: A miscalculated group balance undermines user trust and can drive incorrect financial decisions.

Test Steps:

  1. Create at least 3 accounts with different ETH/token balances and ensure fiat conversion is enabled.
  2. Open the home/account overview and note the account-group total balance display.
  3. Switch the primary currency (e.g., from USD to EUR) and verify the group total updates accurately.
  4. Switch networks (Mainnet to a testnet) and confirm the group total reflects only relevant assets for the selected network.

2. Privacy and Analytics: MetaMetrics consent and event gating

Risk Level: MEDIUM

Why This Matters: Analytics adapter changes can inadvertently enable tracking when disabled or destabilize flows guarded by analytics checks.

Test Steps:

  1. From Settings > Security & Privacy, opt OUT of MetaMetrics and perform common actions (switch networks, open activity).
  2. Confirm no analytics-related prompts or errors occur and that flows work normally.
  3. Opt IN to MetaMetrics and repeat actions; ensure no intrusive prompts and navigation remains smooth.
  4. Lock and unlock the wallet to ensure consent persists across sessions.

3. App State Controller: Lock/Unlock and pending approvals UX

Risk Level: MEDIUM

Why This Matters: App-state changes can cause lost approvals or broken navigation, directly affecting signing and dapp trust.

Test Steps:

  1. With an active dapp connection requesting a signature, lock the wallet while the request is pending.
  2. Unlock and confirm the pending approval is restored to the foreground with correct data.
  3. Complete the approval and verify the app returns to the correct route without orphaned state.
  4. Repeat with multiple queued approvals to confirm order and UI focus are correct.

4. Assets List Interaction: Search/filter stability

Risk Level: MEDIUM

Why This Matters: UI changes in the assets list/control bar can introduce subtle state bugs affecting token discoverability.

Test Steps:

  1. On a network with many tokens, use the Assets list search to filter by symbol and name.
  2. Add a new custom token that matches the current search; confirm it appears immediately in filtered results.
  3. Clear the search, switch networks, and ensure filters reset properly without stale results.
  4. Reopen the popup and verify the previous network and assets render correctly without lag or empty states.

Teams Sign-off Status

Signed off: None yet

Awaiting sign-off (9):
Accounts, Assets, Confirmations, Networks, Permissions, Security, Snaps, Transactions, Wallet


Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-23T03:15:51.297Z

AI generated test plan (JSON): test-plan-13.54.0.json

- fix(ui): bottom navbar cp-13.54.0 cp-13.55.0 (#47321)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Money routes can be a dead-end if reached without the bottom navbar

The bottom navbar is dependent on LaunchDarkly and if unavailable can
cause the dead-end scenario above

Since bottom navbar has been resolved to treatment in the latest main
branch, retroactively applying it to older versions to avoid the issue
above

## **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: enable bottom navbar

## **Related issues**

https://consensys.slack.com/archives/C06FXU326RL/p1792765914662259

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding

Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes default UX for one AB test when flags are missing or invalid,
which affects navigation on money routes but is limited to non-test
runtime and preserves explicit flag assignments.
> 
> **Overview**
> When LaunchDarkly does not yield a valid bottom-nav AB assignment,
**`resolveABTestAssignment`** now falls back to **`treatment`** (bottom
navbar on) instead of **`control`**, matching the resolved behavior on
latest main and avoiding money flows that become a dead end without the
navbar.
> 
> The special-case applies only for **`BOTTOM_NAV_AB_TEST_KEY`** and is
skipped when **`IN_TEST`** or **`NODE_ENV === 'test'`**, so other AB
tests still default to **`control`** and unit tests keep the prior
behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d58b39a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[b094138](b094138)

Co-authored-by: Francis Nepomuceno <n3ps@users.noreply.github.com>
@metamask-ci

metamask-ci Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor
Builds ready [3755e33]
⚡ Performance Benchmarks (Total: 🟢 7 pass · 🟡 3 warn · 🔴 3 fail)

Baseline (latest main): 171ed20 | Date: 7/28/2026 | Pipeline: 40007974008 | Baseline logs

Metricschrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 load_new_account(p95) [CI log]🔴 load_new_account(p95) [CI log]
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🔴 [CI log]

Regressions (🔴 3 failures)

Interaction Benchmarks · Samples: 5 🔴 2
Benchmarkchrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 [CI log]
🔴 load_new_account
🔴 [CI log]
🔴 load_new_account
confirmTx
[Sentry log · main/release]
🟡 [CI log]🟢 [CI log]
bridgeUserActions
[Sentry log · main/release]
🟡 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ loadNewAccount/load_new_account: +418%
  • ↑ loadNewAccount/total: +418%
  • ↑ loadNewAccount/fcp: +12%
  • ↑ loadNewAccount/lcp: +994%
  • ↑ confirmTx/longTaskCount: +33%
  • ↑ confirmTx/longTaskTotalDuration: +75%
  • ↑ confirmTx/longTaskMaxDuration: +93%
  • ↑ confirmTx/tbt: +108%
  • ↑ confirmTx/fcp: +13%
  • ↑ confirmTx/lcp: +29%
  • ↑ bridgeUserActions/bridge_load_page: +109%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +41%
  • ↑ bridgeUserActions/longTaskCount: +67%
  • ↑ bridgeUserActions/longTaskTotalDuration: +161%
  • ↑ bridgeUserActions/longTaskMaxDuration: +67%
  • ↑ bridgeUserActions/tbt: +327%
  • ↑ bridgeUserActions/total: +11%
  • ↑ loadNewAccount/load_new_account: +424%
  • ↑ loadNewAccount/total: +424%
  • ↑ loadNewAccount/inp: +165%
  • ↑ loadNewAccount/lcp: +1356%
  • ↓ confirmTx/longTaskCount: -100%
  • ↓ confirmTx/longTaskTotalDuration: -100%
  • ↓ confirmTx/longTaskMaxDuration: -100%
  • ↓ confirmTx/tbt: -100%
  • ↓ confirmTx/fcp: -40%
  • ↑ confirmTx/lcp: +1275%
  • ↑ bridgeUserActions/bridge_load_page: +271%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +116%
  • ↓ bridgeUserActions/longTaskCount: -100%
  • ↓ bridgeUserActions/longTaskTotalDuration: -100%
  • ↓ bridgeUserActions/longTaskMaxDuration: -100%
  • ↓ bridgeUserActions/tbt: -100%
  • ↑ bridgeUserActions/total: +77%
  • ↑ bridgeUserActions/inp: +54%
  • ↓ bridgeUserActions/fcp: -41%
  • ↑ bridgeUserActions/lcp: +1232%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🟡 loadNewAccount/FCP: p75 1.9s
  • 🟡 confirmTx/FCP: p75 1.9s
  • 🟡 bridgeUserActions/FCP: p75 1.9s
  • 🟡 loadNewAccount/INP: p75 280ms
  • 🟡 loadNewAccount/LCP: p75 2.5s
Startup Benchmarks · Samples: 100
Benchmarkchrome-webpackfirefox-webpack
startupStandardHome
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ startupStandardHome/uiStartup: -11%
  • ↓ startupStandardHome/load: -13%
  • ↓ startupStandardHome/domContentLoaded: -13%
  • ↓ startupStandardHome/backgroundConnect: -17%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -33%
  • ↓ startupStandardHome/loadScripts: -13%
  • ↑ startupStandardHome/setupStore: +142%
  • ↓ startupStandardHome/longTaskCount: -33%
  • ↓ startupStandardHome/longTaskTotalDuration: -21%
  • ↓ startupStandardHome/longTaskMaxDuration: -17%
  • ↓ startupStandardHome/tbt: -18%
  • ↓ startupStandardHome/inp: -11%
  • ↓ startupStandardHome/fcp: -13%
  • ↓ startupStandardHome/uiStartup: -29%
  • ↓ startupStandardHome/load: -23%
  • ↓ startupStandardHome/domContentLoaded: -23%
  • ↓ startupStandardHome/domInteractive: -50%
  • ↓ startupStandardHome/backgroundConnect: -15%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -50%
  • ↓ startupStandardHome/loadScripts: -23%
  • ↑ startupStandardHome/setupStore: +110%
  • ↓ startupStandardHome/fcp: -37%
  • ↓ startupStandardHome/lcp: -21%
User Journey Benchmarks · Samples: 5 · real API 🔴 1
Benchmarkchrome-webpackfirefox-webpack
onboardingImportWallet
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
🟡 total
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🔴 [CI log]
🔴 total

📈 Results compared to the previous 5 runs on main

  • ↑ onboardingImportWallet/srpButtonToSrpForm: +39%
  • ↑ onboardingImportWallet/confirmSrpToPwForm: +40%
  • ↑ onboardingImportWallet/pwFormToMetricsScreen: +37%
  • ↑ onboardingImportWallet/metricsToWalletReadyScreen: +16%
  • ↓ onboardingImportWallet/doneButtonToHomeScreen: -94%
  • ↓ onboardingImportWallet/openAccountMenuToAccountListLoaded: -75%
  • ↓ onboardingImportWallet/longTaskCount: -100%
  • ↓ onboardingImportWallet/longTaskTotalDuration: -100%
  • ↓ onboardingImportWallet/longTaskMaxDuration: -100%
  • ↓ onboardingImportWallet/tbt: -100%
  • ↓ onboardingImportWallet/total: -89%
  • ↑ onboardingNewWallet/srpButtonToPwForm: +41%
  • ↑ onboardingNewWallet/createPwToRecoveryScreen: +25%
  • ↑ onboardingNewWallet/skipBackupToMetricsScreen: +22%
  • ↑ onboardingNewWallet/agreeButtonToOnboardingSuccess: +21%
  • ↓ onboardingNewWallet/doneButtonToAssetList: -82%
  • ↓ onboardingNewWallet/longTaskCount: -69%
  • ↓ onboardingNewWallet/longTaskTotalDuration: -79%
  • ↓ onboardingNewWallet/longTaskMaxDuration: -47%
  • ↓ onboardingNewWallet/tbt: -94%
  • ↓ onboardingNewWallet/total: -78%
Dapp Page Load Benchmarks · Samples: 100
Benchmarkchrome-webpack
dappPageLoad
[Sentry log · main/release]
🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ dappPageLoad/pageLoadTime: -57%
  • ↓ dappPageLoad/firstPaint: -41%
  • ↓ dappPageLoad/firstContentfulPaint: -41%
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Status Bundle Total Diff Change
🚨 background 15.44 MiB +40.72 KiB +0.26%
🚨 ui 19.26 MiB +2.57 KiB +0.01%
✅ common 0 Bytes 0 Bytes 0.00%
🚨 other 4.35 MiB +1.15 KiB +0.03%
🚨 content scripts 3.15 MiB +2.3 KiB +0.07%
🚨 zip 23.94 MiB +23.03 KiB +0.09%
🍒 What's in this RC

Cherry-picks (10 commits)
Commit Description
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
6b5b96561d Merge pull request #47235 from MetaMask/runway-cherry-pick-13.54.0-1792581661
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
841196fa40 Merge pull request #47179 from MetaMask/stable-sync-release-13.54.0

Changelog (108 commits since v13.53.0)
Commit Description
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
a13345c31d chore: update CHANGELOG.md
bb2c5bce6e release(runway): cherry-pick chore: include Perps in the Flask build (#47173)
ca07950b68 release-changelog/13.54.0
bdbbdc6499 release(runway): cherry-pick feat: bump Tron, Solana snaps (#47122)
2d78bac0cd Merge release/13.53.0 into release/13.54.0
71d78824fc fix: reset AuthenticationController's needsSocialPairing via migration (#46979)
2f47b7b282 chore: upsert stx_get_fees_error to Transaction events (#46825)
7fe46a6a83 fix: keep the active network state same (#47098)
d720afa45c fix(nfts): point the import NFT media banner to Basic Functionality (#47044)
857ed7243e feat(assets): show a skeleton during the first asset load (#47105)
d0938138b7 fix(content): add article to Arc usage notice (#47112)
14d6dd2ebe chore: bump @metamask/client-mcp-core to 0.11.0 (#47106)
a85440bcd3 chore: make accounts-engineers the sole owners of MFA (#47110)
f1a2598b69 feat: [musd-1450] show earn banner in asset details (#47056)
0ef185a52d feat(tron): read resources from TRX balance metadata and show unavailable banner (#47046)
b88d694e06 fix: mixed clock domains onboarding traces (#47107)
ecf092a9dd feat(mfa): replace experimental UI with final designs and experience (#47103)
681327ef37 feat: ensure that money menu is aligned with nav burger menu (#47071)
1ac1748e39 feat(confirmations): improve Ledger-funded Money Account deposits (#47003)
731673e6e8 test: e2e cover Tokens native row on non-zero native networks (#45885)
7541962d96 feat: track seedless PrimarySrp error events (#46886)
b3ab41f3e7 chore(assets-controller): bump to 19.0.0 (#47031)
b96424fd61 feat: [musd-1453] money account design feedback tweaks (#47026)
f006fc49cb feat: report lifetime earnings API call failures (#47078)
989b387948 chore: remove Bitcoin account label tags everywhere but multichain account address list (#47077)
af2aef8d69 feat: upgrade wallet package to 17.1.0 (#47075)
d72b33d728 chore: fix announcement markdown (#47095)
2a47afd4ef fix: Infinite loading when sending with QR hardware wallet cp-13.53.0 (#47067)
e4316eb78a feat: add notification settings deeplinks [GE-525] (#46753)
fad47100c2 feat: fetch fresh Tron assets on the token details page (#46795)
f68af4cb8b Merge origin/main into stable-main-13.52.0
d1d130c778 fix: set tempo nativeCurrency to USD (#47074)
dcaa87cdb2 fix(money): hide unavailable lifetime earnings (#47076)
9a95d8db25 refactor: use SentinelApiService in Sentinel utils (#46867)
67a682ef21 test: create a new page object for Import NFT page (#47057)
7341169ec2 fix(confirmations): restore max-value correction for OP-stack L2 native sends (#46880)
94f6ef8e3f chore: update @metamask/stellar-wallet-snap to ^1.2.0 cp-13.53.0 (#47080)
9cd49a940b fix(mfa): apply the stack review follow-ups (#47072)
20c5a33e77 ci: add feature flags coverage metrics to QA stats workflow (#47079)
1c60e11c13 fix: swaps retry on failure (#47060)
e8ba981bca fix: removed majority of arc specific logic since has been moved to bridge-api (#46805)
9805977ea0 feat(perps): show the outage banner across Perps screens (#46864)
0662e26225 fix: hide fiat in send flow when currency conversion/basic functionality is off (#47022)
b66dd071f8 test: use page objects on llm scripts (#47055)
753c41cd55 fix(hardware-wallets): stop auto-showing error modal during swap (#46766)
efd2940403 feat(mfa): add verification methods settings (#46914)
44439d0701 chore: expand cashtag widget selector (#47061)
f9426fbe85 fix: manage tokens dedupe native entries (#47038)
cb90dd22ac test(e2e): add Money Account withdraw E2E coverage (#46784)
ab046448ef feat: add token symbol to search asset rows (#47045)
a9b874af29 feat(mfa): add flow host page and launcher (#46913)
d107264220 bump: upgrade Bitcoin wallet Snap to 3.2.0 (#47052)
da9d8472cb feat: move import NFT from a modal to a full page (#47027)
0c708dd21b feat(mfa): add placeholder flow screens (#46912)
87f5adde92 fix(perps): stop logging account fetch failures after channel teardown (#46846)
545fa39daf feat(perps): reverse position modal briefly shows the previous size's fee while the new quote loads (#47016)
44b714f019 fix: money transaction ids default to 0x0 cp-13-52-0 (#47035)
ab0216466d feat(perps): add market about section (#46610)
01401ca8c7 refactor(7408): migrate development build tooling batch 2 to TypeScript (#46808)
85edf42416 test(e2e): add Money Account deposit E2E coverage (#46783)
019e30011b fix(contacts): match add contact network border to other fields (#47037)
a8ca616aae feat(notifications): order agentic cli section above marketing (#47023)
f2d2a67af6 chore(deps): bump analytics-controller, config-registry-controller, and wallet (#46794)
4df5dd7865 test: remove anti-pattern for enable-notifications.spec (#47036)
fdd0011dce test: fix flaky test swap quote wait during skeleton (#46938)
06e8d58038 feat(money): open Money Home from the home card summary (#46901)
fa8145e4db test: Sync Feature Flag Registry - 2026-10-13 01:30 UTC (#47033)
50ccb5ece6 chore: ignore disputed braces advisory cp-13.52.0 (#47029)
52a96b79d8 feat(mfa): add controller bindings, useMfa hook and kit gate (#46911)
9bbbc4fd7b feat(analytics): track referral as standard Deep Link Used property (#47021)
a6b6f4648f fix(confirmations): block Money deposits while the Max quote is stale cp-13.52.0 (#47018)
4a0b918e04 feat(mfa): add engine flow state machine and active flow (#46910)
e7333ff4d3 feat: update button text to save (#47024)
22d671fa8c feat(mfa): add engine types, planner and error handling (#46909)
bc3f58442f feat: musd-1449 add money account CTA to token row (#46923)
0d40d25d31 fix(networks): keep Chainlist add-network details in place (#47001)
18921add8e fix(confirmations): estimate gas for native max sends (#46461)
3b07243075 fix(networks): migrate Robinhood explorer URL (#47019)
861bb9c47e feat(confirmations): align non-money deposit prefills (#46892)
762ae63d72 feat: add deadline caveat to EIP-7702 delegations (#46937)
65d920ed75 chore: Bump Snaps packages (#47004)
8cd528d20e fix: add approvedOrSigned toast phase to allow failed toasts before tx submission (#46872)
95553d8431 chore: audit braces and http-cache-semantics cp-13.52.0 (#46865)
b02ad71a23 chore: Gate additions to legacy background APIs (#46695)
a860a0ee54 chore: submitRequestToBackground supports UI messenger action types (#46903)
9318567d64 chore: align chart color (#47006)
65b8e55a12 chore: ui nits (#47005)
bbf3b7e72c fix(build): keep React Compiler stats out of the hashed module buildMeta (#46949)
e5d7d3cc92 fix(716): apply theme preference to the internal error dialog (#46890)
e9acc626fc chore: Bump LavaMoat (#46989)
3cec5e9453 fix(confirmations): surface Monad reserve-balance failures instead of misleading fee alerts (#46049)
c98475c3dd feat(confirmations): add confirmations_pay_rpc remote flag (#46981)
9d57c2b0af feat(perps): update controller to 20.0.0 cp-13.52.0 (#46934)
71e1f3d929 fix(hardware-wallets): simplify locked device error modal message (#46936)
3aab8a48d3 Merge origin/main into stable-main-13.51.0
3a8a1eeb91 release: Bump main version to 13.54.0 (#46960)
c1d9fba651 bump(stellar): bump stellar-wallet-snap from 1.1.0 to 1.1.1 cp-13.52.0 (#46973)
a284fe9f47 fix(analytics): add userAgent enrichment to early Segment events (#46921)
d61f0ab0f9 chore: bump @metamask/profile-sync-controller to 34.0.3 (#46947)
cc552ce832 fix: start with "All networks" not Sepolia or Arc (#46928)

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Commits
54/100 5 9 588 112
Cherry-Pick Scenarios (3)

Medium Risk Scenarios (3)

1. Snaps: Tron and Solana snap bumps

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47122 bumps chain snaps that can alter permissions and signing flows; regressions here can break cross-chain interactions and user security prompts.

Test Steps:

  1. From a snaps demo dapp, request installation of the updated Tron or Solana snap and review new/changed permission prompts before approving.
  2. Connect the snap-enabled dapp and sign a basic transaction and a message; verify prompts render correctly and the signature/tx finalizes.
  3. Reopen the extension; ensure permissions persist and the snap remains connected without re-approval.
  4. Revoke the snap permission and confirm the dapp reconnect flow re-prompts appropriately.

2. Snaps: Stellar Wallet Snap bump

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47224 updates the Stellar Wallet Snap; version bumps can change permission scopes and signing behavior, risking broken or unsafe user prompts.

Test Steps:

  1. Install/connect the updated Stellar Wallet Snap via a compatible dapp and approve requested permissions.
  2. Perform a Stellar account view and sign a simple payment transaction; confirm success and correct rendering of details.
  3. Lock/unlock the wallet and confirm snap connection and permissions persist.
  4. Attempt a message/signing denial to verify proper error handling and safe fallback.

3. UI Navigation: Bottom Navbar fix

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47322 fixes bottom navbar behavior; navigation regressions can strand users or hide critical actions across core app areas.

Test Steps:

  1. Navigate across bottom tabs (Tokens, NFTs, Activity, Browser/Explore, Settings) and verify tabs switch reliably with correct highlighting.
  2. Resize the window to narrow width and ensure the navbar remains visible and tappable with no overlapping UI.
  3. From a transaction confirmation screen, open/close the navbar overlays (if any) to ensure primary action buttons aren’t obscured.
  4. Rapidly switch tabs and return to confirm state is preserved without rendering glitches.

Release Scenarios (11)

High Risk Scenarios (5)

1. State Migrations (231–233) — existing users

Risk Level: HIGH

Why This Matters: Migrations can corrupt or reset persisted user state; three new migrations in one release increase the chance of data loss or inconsistent settings across networks and assets.

Test Steps:

  1. Start on the previous stable release with a profile containing: 2+ accounts, 1 custom network, several imported ERC-20s, at least 1 hidden token, and 1 imported NFT; disable NFT autodetection and enable test networks.
  2. Upgrade to 13.54.0 and unlock.
  3. Verify all accounts, custom networks, hidden token state, and NFT entries persist; ensure test-net toggle state is preserved.
  4. Send a small native token transaction on an existing custom network and confirm it completes.
  5. Inspect Settings > Advanced and Security & Privacy to ensure prior preferences remain unchanged and no migration error banners/toasts appear.

2. State Migrations (231–233) — locked vault/first-unlock path

Risk Level: HIGH

Why This Matters: Some migrations run pre- or post-unlock; running them against encrypted state can lead to partial migrations or blank UI until a refresh.

Test Steps:

  1. On an older version, lock the wallet and then upgrade to 13.54.0.
  2. Before unlocking, verify no crash or unexpected prompts; then unlock.
  3. Confirm accounts, networks, tokens, and NFTs appear immediately after unlock without needing a reload.
  4. Open the Activity, Tokens, and NFTs tabs to ensure no placeholders/errors block rendering.
  5. Perform a hard refresh of the extension UI and confirm state remains intact.

3. Transaction Creation and Gas Controls (Transaction Pay Controller patch)

Risk Level: HIGH

Why This Matters: Controller patching around transaction payment introduces risk to gas estimation, EIP-1559 handling, and replacement transactions—core functions that must not regress.

Test Steps:

  1. On Ethereum mainnet, send a native token transaction; open Advanced gas controls and modify Max fee and Priority fee; submit and ensure broadcast success.
  2. Send an ERC-20 transfer; verify gas estimation populates correctly and confirmation proceeds without rejections due to fee errors.
  3. Speed up the pending transaction; verify replacement transaction adopts new gas settings and confirms.
  4. Cancel a pending transaction; ensure cancellation replaces the tx and clears the queue without stuck states.
  5. Repeat a native send on a congested network (e.g., set low base fee) to ensure robust error messaging without UI soft-locks.

4. Network Enablement Initialization (network-enablement-controller-init)

Risk Level: HIGH

Why This Matters: Initialization changes can misconfigure which networks appear or are enabled, breaking core flows like switching networks or adding tokens.

Test Steps:

  1. Fresh install 13.54.0; complete onboarding.
  2. Verify default networks shown/hidden match expected policy (e.g., mainnet visible, test networks behind toggle).
  3. Enable test networks in Settings; confirm they appear in the network switcher and persist across a restart.
  4. Add a custom network; verify it appears enabled, selectable, and persists after reload.
  5. Attempt to add a token on a network that is disabled/hidden and confirm the UI prompts to enable/select the correct network.

5. Assets Initialization and Detection (assets-controller-init)

Risk Level: HIGH

Why This Matters: Controller/init changes can lead to duplicate tokens, cross-network leakage of assets, or incorrect persistence of visibility settings.

Test Steps:

  1. On mainnet, verify existing token balances populate on load without delay or zeroed placeholders persisting.
  2. Toggle token autodetection off/on in Settings; confirm tokens appear/disappear as expected without duplications.
  3. Switch to a custom network; import a token by contract address and ensure it displays correctly and does not leak into other networks’ lists.
  4. Hide a token, reload the extension, and verify it remains hidden on the same network while visible state is unaffected on others.
  5. Remove the custom network and verify its assets do not appear in any other network views.

Medium Risk Scenarios (6)

1. NFT Empty State and Detection Notice

Risk Level: MEDIUM

Why This Matters: New notices and empty-state logic can confuse users or lead to duplicates/missing NFTs if detection vs manual import states are mishandled.

Test Steps:

  1. With no NFTs, open the NFTs tab and verify the updated empty state text and any CTA to import or enable detection render correctly.
  2. Toggle NFT autodetection on; verify detection notice behavior and that detected NFTs appear when applicable.
  3. Import an NFT manually; ensure the empty state disappears, details render, and no duplicate appears if detection is enabled.
  4. Disable detection and reload; confirm previously detected NFTs remain, and detection notice reflects the disabled state.
  5. Switch networks to confirm the empty state and detection messaging adjust per-network.

2. Account Group Balance display

Risk Level: MEDIUM

Why This Matters: Incorrect aggregation or formatting can mislead users about portfolio value and undermine trust.

Test Steps:

  1. With 2+ accounts on mainnet, view the home screen and note the total/account group balance in fiat.
  2. Receive a small ERC-20 into one account; verify the group balance updates promptly without a reload.
  3. Switch networks to a custom network; ensure group balance recalculates correctly without mixing balances across networks.
  4. Hide a token with non-zero balance and confirm the group balance reflects the hidden status (if design specifies).
  5. Toggle currency display (e.g., USD to another fiat) and verify recalculation and formatting are correct.

3. Asset List Control Bar (filters/search/sorting)

Risk Level: MEDIUM

Why This Matters: Small control-bar regressions can block discoverability of assets or lead to incorrect list states across networks.

Test Steps:

  1. On the Tokens list, use search to filter; verify responsive filtering and no UI jumps or stale results.
  2. Apply any available sorting/filter toggles (e.g., by balance) and ensure results persist after navigating away and back.
  3. Hide/unhide a token from within the list and confirm the control bar state updates accordingly.
  4. Switch networks and verify the control bar resets appropriately without persisting filters across unrelated networks.
  5. Resize the window to a narrow width and ensure the control bar remains accessible without overlapping buttons.

4. Onboarding, App State, and Analytics Consent (app-state-controller, analytics platform-adapter)

Risk Level: MEDIUM

Why This Matters: Changes to app-state and analytics wiring can cause repeat prompts, lost preferences, or degraded first-run UX.

Test Steps:

  1. Fresh install; walk through onboarding and observe analytics opt-in dialog behavior and copy.
  2. Choose to opt-in; complete onboarding and then lock/unlock to verify choice persists in Settings.
  3. Restore from SRP; confirm onboarding state completes cleanly without repeated prompts.
  4. Toggle analytics off and verify no further analytics prompts/events are emitted in the UI (spot-check via devtools logs if available).
  5. Navigate across main tabs to ensure no unexpected banners or state resets occur.

5. Network switching across Tokens/NFTs/Activity tabs

Risk Level: MEDIUM

Why This Matters: Controller/init refactors often surface as cross-tab stale data or incorrect network scoping.

Test Steps:

  1. From the Tokens tab, switch networks and confirm the tab content updates without stale data or loading spinners persisting.
  2. Move to NFTs and switch networks; confirm correct per-network NFTs load.
  3. In Activity, switch networks; ensure historical transactions correspond to the selected network only.
  4. Rapidly switch between 3+ networks to look for UI freezes or errors.
  5. After switching, initiate a send flow and verify the selected network is respected end-to-end.

6. Speed Up/Cancel flows across networks

Risk Level: MEDIUM

Why This Matters: Any transaction controller changes can cascade into replacement-transaction handling and surface as stuck or duplicated entries.

Test Steps:

  1. On mainnet, submit a low-fee tx to keep it pending; use Speed Up and confirm replacement tx is mined.
  2. Repeat on a custom network; use Cancel and verify the queue clears properly.
  3. Verify activity list shows a single final outcome per original tx (no duplicates).
  4. Confirm gas controls remain editable and accurate during the replacement flows.
  5. Ensure no residual notifications or toasts stay after completion.

Teams Sign-off Status

Signed off: None yet

Awaiting sign-off (7):
Accounts, Assets, Networks, Onboarding, Snaps, Transactions, Wallet


Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-23T19:22:21.007Z

AI generated test plan (JSON): test-plan-13.54.0.json

@metamask-ci

metamask-ci Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor
Builds ready [0801fdb]
⚡ Performance Benchmarks (Total: 🟢 6 pass · 🟡 5 warn · 🔴 2 fail)

Baseline (latest main): 171ed20 | Date: 7/28/2026 | Pipeline: 40045516330 | Baseline logs

Metricschrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 load_new_account(p95) [CI log]🔴 load_new_account(p95) [CI log]

Regressions (🔴 2 failures)

Interaction Benchmarks · Samples: 5 🔴 2
Benchmarkchrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 [CI log]
🔴 load_new_account
🔴 [CI log]
🔴 load_new_account
confirmTx
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]
bridgeUserActions
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ loadNewAccount/load_new_account: +416%
  • ↑ loadNewAccount/total: +416%
  • ↓ loadNewAccount/inp: -17%
  • ↑ confirmTx/longTaskTotalDuration: +58%
  • ↑ confirmTx/longTaskMaxDuration: +81%
  • ↑ confirmTx/tbt: +89%
  • ↓ confirmTx/inp: -17%
  • ↑ bridgeUserActions/bridge_load_page: +93%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +102%
  • ↑ bridgeUserActions/longTaskCount: +67%
  • ↑ bridgeUserActions/longTaskTotalDuration: +122%
  • ↑ bridgeUserActions/longTaskMaxDuration: +43%
  • ↑ bridgeUserActions/tbt: +241%
  • ↑ bridgeUserActions/total: +15%
  • ↑ loadNewAccount/load_new_account: +420%
  • ↑ loadNewAccount/total: +420%
  • ↑ loadNewAccount/fcp: +22%
  • ↑ loadNewAccount/lcp: +1325%
  • ↓ confirmTx/longTaskCount: -100%
  • ↓ confirmTx/longTaskTotalDuration: -100%
  • ↓ confirmTx/longTaskMaxDuration: -100%
  • ↓ confirmTx/tbt: -100%
  • ↑ confirmTx/inp: +173%
  • ↓ confirmTx/fcp: -38%
  • ↑ confirmTx/lcp: +1300%
  • ↑ bridgeUserActions/bridge_load_page: +287%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +195%
  • ↑ bridgeUserActions/bridge_search_token: +19%
  • ↓ bridgeUserActions/longTaskCount: -100%
  • ↓ bridgeUserActions/longTaskTotalDuration: -100%
  • ↓ bridgeUserActions/longTaskMaxDuration: -100%
  • ↓ bridgeUserActions/tbt: -100%
  • ↑ bridgeUserActions/total: +42%
  • ↑ bridgeUserActions/inp: +200%
  • ↑ bridgeUserActions/fcp: +18%
  • ↑ bridgeUserActions/lcp: +1295%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🟡 loadNewAccount/FCP: p75 1.8s
  • 🟡 confirmTx/FCP: p75 1.8s
  • 🟡 bridgeUserActions/FCP: p75 1.8s
  • 🟡 loadNewAccount/FCP: p75 2.1s
  • 🟡 confirmTx/INP: p75 288ms
  • 🟡 bridgeUserActions/INP: p75 312ms
  • 🟡 bridgeUserActions/FCP: p75 2.0s
Startup Benchmarks · Samples: 100
Benchmarkchrome-webpackfirefox-webpack
startupStandardHome
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ startupStandardHome/uiStartup: -28%
  • ↓ startupStandardHome/load: -29%
  • ↓ startupStandardHome/domContentLoaded: -29%
  • ↓ startupStandardHome/domInteractive: -18%
  • ↓ startupStandardHome/firstPaint: -21%
  • ↓ startupStandardHome/backgroundConnect: -33%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -67%
  • ↓ startupStandardHome/loadScripts: -30%
  • ↑ startupStandardHome/setupStore: +112%
  • ↓ startupStandardHome/longTaskCount: -33%
  • ↓ startupStandardHome/longTaskTotalDuration: -37%
  • ↓ startupStandardHome/longTaskMaxDuration: -35%
  • ↓ startupStandardHome/tbt: -38%
  • ↓ startupStandardHome/inp: -18%
  • ↓ startupStandardHome/fcp: -30%
  • ↓ startupStandardHome/lcp: -20%
  • ↓ startupStandardHome/domInteractive: -41%
  • ↓ startupStandardHome/firstReactRender: -98%
  • ↓ startupStandardHome/initialActions: -50%
  • ↑ startupStandardHome/setupStore: +147%
  • ↓ startupStandardHome/fcp: -35%
User Journey Benchmarks · Samples: 5 · real API
Benchmarkchrome-webpackfirefox-webpack
onboardingImportWallet
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
🟡 total

📈 Results compared to the previous 5 runs on main

  • ↑ onboardingImportWallet/confirmSrpToPwForm: +11%
  • ↑ onboardingImportWallet/pwFormToMetricsScreen: +10%
  • ↑ onboardingImportWallet/metricsToWalletReadyScreen: +20%
  • ↓ onboardingImportWallet/doneButtonToHomeScreen: -94%
  • ↓ onboardingImportWallet/openAccountMenuToAccountListLoaded: -75%
  • ↓ onboardingImportWallet/longTaskCount: -100%
  • ↓ onboardingImportWallet/longTaskTotalDuration: -100%
  • ↓ onboardingImportWallet/longTaskMaxDuration: -100%
  • ↓ onboardingImportWallet/tbt: -100%
  • ↓ onboardingImportWallet/total: -89%
  • ↑ onboardingNewWallet/srpButtonToPwForm: +40%
  • ↑ onboardingNewWallet/createPwToRecoveryScreen: +19%
  • ↑ onboardingNewWallet/skipBackupToMetricsScreen: +17%
  • ↑ onboardingNewWallet/agreeButtonToOnboardingSuccess: +32%
  • ↓ onboardingNewWallet/doneButtonToAssetList: -83%
  • ↓ onboardingNewWallet/longTaskCount: -100%
  • ↓ onboardingNewWallet/longTaskTotalDuration: -100%
  • ↓ onboardingNewWallet/longTaskMaxDuration: -100%
  • ↓ onboardingNewWallet/tbt: -100%
  • ↓ onboardingNewWallet/total: -80%
Dapp Page Load Benchmarks · Samples: 100
Benchmarkchrome-webpack
dappPageLoad
[Sentry log · main/release]
🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ dappPageLoad/pageLoadTime: -73%
  • ↓ dappPageLoad/domContentLoaded: -38%
  • ↓ dappPageLoad/firstPaint: -59%
  • ↓ dappPageLoad/firstContentfulPaint: -59%
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Status Bundle Total Diff Change
🚨 background 15.44 MiB +40.72 KiB +0.26%
🚨 ui 19.26 MiB +2.57 KiB +0.01%
✅ common 0 Bytes 0 Bytes 0.00%
🚨 other 4.35 MiB +1.15 KiB +0.03%
🚨 content scripts 3.15 MiB +2.3 KiB +0.07%
🚨 zip 23.94 MiB +23.03 KiB +0.09%
🍒 What's in this RC

Cherry-picks (11 commits)
Commit Description
0801fdbb42 chore: update changelog for 13.54.0
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
6b5b96561d Merge pull request #47235 from MetaMask/runway-cherry-pick-13.54.0-1792581661
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
841196fa40 Merge pull request #47179 from MetaMask/stable-sync-release-13.54.0

Changelog (109 commits since v13.53.0)
Commit Description
0801fdbb42 chore: update changelog for 13.54.0
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
a13345c31d chore: update CHANGELOG.md
bb2c5bce6e release(runway): cherry-pick chore: include Perps in the Flask build (#47173)
ca07950b68 release-changelog/13.54.0
bdbbdc6499 release(runway): cherry-pick feat: bump Tron, Solana snaps (#47122)
2d78bac0cd Merge release/13.53.0 into release/13.54.0
71d78824fc fix: reset AuthenticationController's needsSocialPairing via migration (#46979)
2f47b7b282 chore: upsert stx_get_fees_error to Transaction events (#46825)
7fe46a6a83 fix: keep the active network state same (#47098)
d720afa45c fix(nfts): point the import NFT media banner to Basic Functionality (#47044)
857ed7243e feat(assets): show a skeleton during the first asset load (#47105)
d0938138b7 fix(content): add article to Arc usage notice (#47112)
14d6dd2ebe chore: bump @metamask/client-mcp-core to 0.11.0 (#47106)
a85440bcd3 chore: make accounts-engineers the sole owners of MFA (#47110)
f1a2598b69 feat: [musd-1450] show earn banner in asset details (#47056)
0ef185a52d feat(tron): read resources from TRX balance metadata and show unavailable banner (#47046)
b88d694e06 fix: mixed clock domains onboarding traces (#47107)
ecf092a9dd feat(mfa): replace experimental UI with final designs and experience (#47103)
681327ef37 feat: ensure that money menu is aligned with nav burger menu (#47071)
1ac1748e39 feat(confirmations): improve Ledger-funded Money Account deposits (#47003)
731673e6e8 test: e2e cover Tokens native row on non-zero native networks (#45885)
7541962d96 feat: track seedless PrimarySrp error events (#46886)
b3ab41f3e7 chore(assets-controller): bump to 19.0.0 (#47031)
b96424fd61 feat: [musd-1453] money account design feedback tweaks (#47026)
f006fc49cb feat: report lifetime earnings API call failures (#47078)
989b387948 chore: remove Bitcoin account label tags everywhere but multichain account address list (#47077)
af2aef8d69 feat: upgrade wallet package to 17.1.0 (#47075)
d72b33d728 chore: fix announcement markdown (#47095)
2a47afd4ef fix: Infinite loading when sending with QR hardware wallet cp-13.53.0 (#47067)
e4316eb78a feat: add notification settings deeplinks [GE-525] (#46753)
fad47100c2 feat: fetch fresh Tron assets on the token details page (#46795)
f68af4cb8b Merge origin/main into stable-main-13.52.0
d1d130c778 fix: set tempo nativeCurrency to USD (#47074)
dcaa87cdb2 fix(money): hide unavailable lifetime earnings (#47076)
9a95d8db25 refactor: use SentinelApiService in Sentinel utils (#46867)
67a682ef21 test: create a new page object for Import NFT page (#47057)
7341169ec2 fix(confirmations): restore max-value correction for OP-stack L2 native sends (#46880)
94f6ef8e3f chore: update @metamask/stellar-wallet-snap to ^1.2.0 cp-13.53.0 (#47080)
9cd49a940b fix(mfa): apply the stack review follow-ups (#47072)
20c5a33e77 ci: add feature flags coverage metrics to QA stats workflow (#47079)
1c60e11c13 fix: swaps retry on failure (#47060)
e8ba981bca fix: removed majority of arc specific logic since has been moved to bridge-api (#46805)
9805977ea0 feat(perps): show the outage banner across Perps screens (#46864)
0662e26225 fix: hide fiat in send flow when currency conversion/basic functionality is off (#47022)
b66dd071f8 test: use page objects on llm scripts (#47055)
753c41cd55 fix(hardware-wallets): stop auto-showing error modal during swap (#46766)
efd2940403 feat(mfa): add verification methods settings (#46914)
44439d0701 chore: expand cashtag widget selector (#47061)
f9426fbe85 fix: manage tokens dedupe native entries (#47038)
cb90dd22ac test(e2e): add Money Account withdraw E2E coverage (#46784)
ab046448ef feat: add token symbol to search asset rows (#47045)
a9b874af29 feat(mfa): add flow host page and launcher (#46913)
d107264220 bump: upgrade Bitcoin wallet Snap to 3.2.0 (#47052)
da9d8472cb feat: move import NFT from a modal to a full page (#47027)
0c708dd21b feat(mfa): add placeholder flow screens (#46912)
87f5adde92 fix(perps): stop logging account fetch failures after channel teardown (#46846)
545fa39daf feat(perps): reverse position modal briefly shows the previous size's fee while the new quote loads (#47016)
44b714f019 fix: money transaction ids default to 0x0 cp-13-52-0 (#47035)
ab0216466d feat(perps): add market about section (#46610)
01401ca8c7 refactor(7408): migrate development build tooling batch 2 to TypeScript (#46808)
85edf42416 test(e2e): add Money Account deposit E2E coverage (#46783)
019e30011b fix(contacts): match add contact network border to other fields (#47037)
a8ca616aae feat(notifications): order agentic cli section above marketing (#47023)
f2d2a67af6 chore(deps): bump analytics-controller, config-registry-controller, and wallet (#46794)
4df5dd7865 test: remove anti-pattern for enable-notifications.spec (#47036)
fdd0011dce test: fix flaky test swap quote wait during skeleton (#46938)
06e8d58038 feat(money): open Money Home from the home card summary (#46901)
fa8145e4db test: Sync Feature Flag Registry - 2026-10-13 01:30 UTC (#47033)
50ccb5ece6 chore: ignore disputed braces advisory cp-13.52.0 (#47029)
52a96b79d8 feat(mfa): add controller bindings, useMfa hook and kit gate (#46911)
9bbbc4fd7b feat(analytics): track referral as standard Deep Link Used property (#47021)
a6b6f4648f fix(confirmations): block Money deposits while the Max quote is stale cp-13.52.0 (#47018)
4a0b918e04 feat(mfa): add engine flow state machine and active flow (#46910)
e7333ff4d3 feat: update button text to save (#47024)
22d671fa8c feat(mfa): add engine types, planner and error handling (#46909)
bc3f58442f feat: musd-1449 add money account CTA to token row (#46923)
0d40d25d31 fix(networks): keep Chainlist add-network details in place (#47001)
18921add8e fix(confirmations): estimate gas for native max sends (#46461)
3b07243075 fix(networks): migrate Robinhood explorer URL (#47019)
861bb9c47e feat(confirmations): align non-money deposit prefills (#46892)
762ae63d72 feat: add deadline caveat to EIP-7702 delegations (#46937)
65d920ed75 chore: Bump Snaps packages (#47004)
8cd528d20e fix: add approvedOrSigned toast phase to allow failed toasts before tx submission (#46872)
95553d8431 chore: audit braces and http-cache-semantics cp-13.52.0 (#46865)
b02ad71a23 chore: Gate additions to legacy background APIs (#46695)
a860a0ee54 chore: submitRequestToBackground supports UI messenger action types (#46903)
9318567d64 chore: align chart color (#47006)
65b8e55a12 chore: ui nits (#47005)
bbf3b7e72c fix(build): keep React Compiler stats out of the hashed module buildMeta (#46949)
e5d7d3cc92 fix(716): apply theme preference to the internal error dialog (#46890)
e9acc626fc chore: Bump LavaMoat (#46989)
3cec5e9453 fix(confirmations): surface Monad reserve-balance failures instead of misleading fee alerts (#46049)
c98475c3dd feat(confirmations): add confirmations_pay_rpc remote flag (#46981)
9d57c2b0af feat(perps): update controller to 20.0.0 cp-13.52.0 (#46934)
71e1f3d929 fix(hardware-wallets): simplify locked device error modal message (#46936)
3aab8a48d3 Merge origin/main into stable-main-13.51.0
3a8a1eeb91 release: Bump main version to 13.54.0 (#46960)
c1d9fba651 bump(stellar): bump stellar-wallet-snap from 1.1.0 to 1.1.1 cp-13.52.0 (#46973)
a284fe9f47 fix(analytics): add userAgent enrichment to early Segment events (#46921)
d61f0ab0f9 chore: bump @metamask/profile-sync-controller to 34.0.3 (#46947)
cc552ce832 fix: start with "All networks" not Sepolia or Arc (#46928)

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Commits
63/100 8 8 588 113
Cherry-Pick Scenarios (3)

High Risk Scenarios (2)

1. Snaps — Solana transaction signing and permissions

Risk Level: HIGH

Why This Matters: Cherry-pick 47122 bumps the Solana Snap; Snap permission/transaction changes can break account derivation and signing, directly impacting user funds and dApp compatibility.

Test Steps:

  1. Connect to a Solana dApp that requests the Solana Snap; approve the Snap install/update and required permissions.
  2. Create/derive a Solana account via the Snap; request a devnet airdrop.
  3. Send a SOL transfer on devnet; confirm fee/lamports display correctly and the transaction succeeds.
  4. Sign a message and verify the signature is accepted by the dApp.

2. Snaps — Tron transaction signing and account management

Risk Level: HIGH

Why This Matters: Cherry-pick 47122 bumps the Tron Snap; any signing or address-derivation regression will block Tron dApp usage and risk failed transactions.

Test Steps:

  1. Connect to a Tron dApp that requests the Tron Snap; approve the Snap install/update.
  2. Create a Tron account via the Snap and ensure the address appears in the accounts list under Snaps.
  3. Send a TRX transfer; confirm the UI displays correct fees and the transaction is confirmed on a Tron explorer.
  4. Sign a personal message; verify success on the dApp.

Medium Risk Scenarios (1)

1. UI Navigation — bottom navbar responsiveness and visibility

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47322 fixes bottom navbar issues; navigation is core to usability in the popup, and regressions can block users from reaching key screens.

Test Steps:

  1. Resize the extension popup to a small viewport; verify the bottom navbar is anchored correctly and all tabs are tappable/clickable.
  2. Switch between tabs using the navbar, then start a Send flow; verify the navbar behaves correctly on confirm screens (hidden if intended, restored after).
  3. Switch networks and open a notification (e.g., connect request), then close it; ensure the navbar’s active state and layout remain correct with no overlaps.

Release Scenarios (13)

High Risk Scenarios (6)

1. State Migrations (231–233) — data preservation

Risk Level: HIGH

Why This Matters: Migrations can silently corrupt or drop user state; validating end-to-end preservation avoids asset loss, wrong balances, and broken preferences after upgrade.

Test Steps:

  1. Start from a 13.53.x profile containing: 3+ HD accounts, 1 Ledger/Hardware account, custom networks (e.g., Linea, BSC), custom tokens (ERC-20) and NFTs, address book entries, and token/NFT detection set differently per network.
  2. Upgrade to 13.54.0 and unlock the wallet.
  3. Verify all accounts (names, order, hardware label) are present and selectable.
  4. For each network, check Assets and NFTs tabs for exact parity with pre-upgrade (no loss, no duplicates, correct balances).
  5. Confirm settings (token/NFT detection, privacy/analytics opt-in, primary currency) persist across upgrade and remain consistent after a browser restart.

2. State Migrations (231–233) — resilience to partial/corrupt state

Risk Level: HIGH

Why This Matters: Defensive migrations must handle missing or malformed data to prevent bricked UIs and user lockouts.

Test Steps:

  1. Using a test profile, intentionally remove or null specific persisted slices (e.g., assetsController, networkEnablement, appState) before launching 13.54.0.
  2. Unlock and navigate across Home, Assets, NFTs, and Settings.
  3. Confirm the extension loads without a white screen or fatal error; defaults are applied where data is missing.
  4. Switch between at least two networks and re-enter Assets/NFTs to ensure controllers recover and render without console errors.
  5. Lock and unlock once more to confirm stable state post-recovery.

3. Transaction Flow — EIP-1559 gas editing, speed up/cancel (Transaction Pay Controller patch)

Risk Level: HIGH

Why This Matters: Core transaction payment logic changes can break fee calculations and nonce management, risking stuck transactions or user overpayment.

Test Steps:

  1. On Ethereum Mainnet or Sepolia, send an ETH transfer; on the confirm screen open Advanced gas controls.
  2. Edit max priority fee and max fee; verify ETA/fee labels update in real time and total changes accordingly.
  3. Submit and, while pending, use Speed up with higher fees; confirm only the replacement txn remains (original is dropped).
  4. Repeat with Cancel on a new pending txn; verify it executes and the original is marked canceled.
  5. Inspect Activity for correct statuses and nonces with no duplicate or stuck pending entries.

4. Transaction Flow — token approvals and swaps fee estimation

Risk Level: HIGH

Why This Matters: Approvals and swaps are high-frequency flows; mis-estimated or misapplied fees can cause failed txns, stuck approvals, or financial loss.

Test Steps:

  1. From a dApp, initiate an ERC-20 approval with a large allowance; review the confirm screen’s gas/fee estimates and risk messaging.
  2. Switch between preset gas options (Low/Market/Aggressive) and Advanced to confirm estimates and times adjust correctly.
  3. Confirm the approval and verify it succeeds on-chain and appears correctly in Activity.
  4. Initiate a Swap on a supported network; verify quote refreshes, fee breakdown appears accurately, and the swap completes.
  5. Ensure the fiat total reflects both gas and protocol fees without rounding errors.

5. Network Enablement Gating — Buy/Swap/Bridge feature visibility per network

Risk Level: HIGH

Why This Matters: Incorrect feature gating confuses users and can route them to broken flows or unsupported services.

Test Steps:

  1. On Ethereum Mainnet, confirm Buy, Swap, and Bridge CTAs are visible and enabled on Home/Asset screens.
  2. Switch to a custom or less-supported network and check that unsupported features are hidden or disabled with clear tooltips.
  3. Switch back to Mainnet and ensure controls immediately re-enable (no stale gating).
  4. Lock, unlock, and re-check gating remains accurate.
  5. Resize the popup (small/large) and verify no layout overlap or missing buttons.

6. Assets Controller Initialization — first-run defaults and token detection

Risk Level: HIGH

Why This Matters: Initialization regressions can cause missing or duplicate assets, leading to user distrust and support incidents.

Test Steps:

  1. Fresh install; create a new wallet; land on Home.
  2. Verify default token visibility on Mainnet: native asset appears, and auto-detected tokens match detection setting.
  3. Turn Token Detection off in Settings; return to Assets to confirm no new auto-added tokens appear after a refresh.
  4. Switch networks and verify each network has an independent, correct token list without duplicates carrying over.
  5. Manually import a token and ensure it persists only on the network where added.

Medium Risk Scenarios (7)

1. NFTs — detection notice and manual import flow

Risk Level: MEDIUM

Why This Matters: Users rely on clear guidance when NFTs aren’t auto-detected; incorrect notices or duplication undermine confidence.

Test Steps:

  1. With NFT detection off, open the NFTs tab and confirm a clear notice explaining detection is disabled plus a Settings link.
  2. Click the Settings link, enable NFT detection, and return; confirm the notice disappears without reload.
  3. Manually import a known NFT; verify it renders correctly and is not duplicated after enabling detection.
  4. Switch networks and confirm the notice and imported items behave per-network.

2. NFTs — empty state behavior across networks

Risk Level: MEDIUM

Why This Matters: Accurate empty states prevent user confusion and encourage correct next actions (import, detection).

Test Steps:

  1. On two networks with no NFTs (e.g., Sepolia and another testnet), open NFTs and verify the empty state text and CTAs display correctly.
  2. Add an NFT on one network and confirm the empty state disappears only on that network.
  3. Rapidly switch networks and re-enter NFTs to ensure the empty state updates without stale content or flicker.

3. Account Group Balance — aggregate fiat/native display

Risk Level: MEDIUM

Why This Matters: Incorrect totals or formatting can mislead users about their portfolio value and cause financial mistakes.

Test Steps:

  1. Hold assets across 3+ accounts; verify the group/aggregate balance equals the sum of visible accounts’ fiat values.
  2. Toggle primary currency between Fiat and Native; confirm consistent recalculation and formatting.
  3. Hide one account (if supported) or switch active accounts and ensure the aggregate updates immediately.
  4. Trigger a refresh or network switch to confirm no transient wrong totals or flicker.

4. App State — lock/unlock, routing, and recovery from interrupts

Risk Level: MEDIUM

Why This Matters: App-state regressions trap users on wrong routes or overlays, breaking core wallet usability.

Test Steps:

  1. Navigate to the Activity tab, then lock the wallet.
  2. Unlock and verify return to Activity (not a wrong or onboarding screen).
  3. While on Home, trigger an external connect request and reject it; ensure overlays close and state is consistent.
  4. Close and reopen the popup; verify last-viewed screen persists correctly.

5. Analytics opt-in/out — preference, persistence, and behavior

Risk Level: MEDIUM

Why This Matters: Privacy controls must be trustworthy; unexpected telemetry erodes user trust and may have compliance implications.

Test Steps:

  1. During onboarding, opt out of analytics; finish and verify the toggle state in Settings.
  2. Toggle analytics on in Settings, close the popup, reopen, and confirm persistence.
  3. With DevTools Network open, perform common actions (open Home, switch network); verify telemetry calls align with the toggle state (no calls when opted out).
  4. Lock/unlock and re-check the toggle remains correct.

6. Asset List Control Bar — sorting/filter persistence

Risk Level: MEDIUM

Why This Matters: Small UI regressions in high-traffic lists quickly degrade usability and accessibility.

Test Steps:

  1. On a list with many tokens, change sort (e.g., by name/balance if available).
  2. Switch tabs (Assets/NFTs) and networks, then return to confirm the chosen sort persists.
  3. Verify keyboard navigation and focus states work and controls do not overlap or truncate on small popup sizes.

7. Online/Offline initialization — controller rehydration

Risk Level: MEDIUM

Why This Matters: Robust initialization must handle connectivity changes; failures here cause blank screens or stale balances.

Test Steps:

  1. With DevTools set to Offline, open the extension; verify Home/Assets render an offline-safe state (no crashes).
  2. Switch networks while offline and return to Home.
  3. Go back online and confirm assets, balances, and feature gating refresh automatically without a manual reload.
  4. Open NFTs to confirm data and notices update post-reconnect.

Teams Sign-off Status

Signed off: None yet

Awaiting sign-off (9):
Accounts, Assets, Confirmations, Networks, Permissions, Snaps, Swaps, Swaps and Bridge, Transactions


Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-24T00:53:06.063Z

AI generated test plan (JSON): test-plan-13.54.0.json

DDDDDanica and others added 3 commits October 26, 2026 18:25
…ci, serialize-javascript, and GridPlus zod cp-13.54.0 (#47358)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
New production advisories were blocking release. Same-major patches:
- `fast-uri` 3.1.8 → 3.1.9
- `body-parser` 1.20.6 → 1.20.9 and 2.3.0 → 2.4.0
- `undici` 7.30.0 → 7.30.1
- `serialize-javascript` 7.0.5 → 7.1.3
- Zod 4 ranges, including `gridplus-sdk`'s `^4.1.11`, re-resolved to
4.6.7 with no resolution
The snap copies are an exact pin at 3.25.76, so those two use a
resolution to `^4.6.6`. The snap bundles do not import Zod.
`@reown/appkit-wallet` stays on Zod 3.22.4, which is dev-only.

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

## **Manual testing steps**

1. Go to this page...
2.
3.

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Same-major dependency and resolution-only changes driven by
advisories; no extension logic or API surface changes in the diff.
> 
> **Overview**
> Bumps **Yarn resolutions** and the lockfile so production security
advisories can clear for release 13.54.0. No application source changes.
> 
> **Pinned / resolution updates in `package.json`:**
`serialize-javascript` **7.0.5 → 7.1.3**, `undici` **^7.30.0 →
^7.30.1**, `fast-uri` **^3.1.8 → ^3.1.9**, and explicit **zod 4.6.7**
for `@metamask/gator-permissions-snap` and
`@metamask/permissions-kernel-snap` nested dependencies (those snaps
ship an older zod copy that does not affect runtime validation in the
extension).
> 
> **Lockfile fallout:** `body-parser` **1.20.9** and **2.4.0** (with
`qs` ~6.16), plus minor transitive bumps (`content-type` 2.1.0,
`iconv-lite` 0.7.3). Shared **zod** v4 ranges resolve to **4.6.7** (from
4.6.5); the standalone **3.25.76** lock entry is folded into the v4
resolution set per the PR notes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b93aca1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ci, serialize-javascript, and GridPlus zod (#47363)

- chore: patch fast-uri, body-parser, undici, serialize-javascript, and
GridPlus zod cp-13.54.0 (#47358)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
New production advisories were blocking release. Same-major patches:
- `fast-uri` 3.1.8 → 3.1.9
- `body-parser` 1.20.6 → 1.20.9 and 2.3.0 → 2.4.0
- `undici` 7.30.0 → 7.30.1
- `serialize-javascript` 7.0.5 → 7.1.3
- Zod 4 ranges, including `gridplus-sdk`'s `^4.1.11`, re-resolved to
4.6.7 with no resolution
The snap copies are an exact pin at 3.25.76, so those two use a
resolution to `^4.6.6`. The snap bundles do not import Zod.
`@reown/appkit-wallet` stays on Zod 3.22.4, which is dev-only.

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

## **Manual testing steps**

1. Go to this page...
2.
3.

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

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding

Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Same-major dependency and resolution-only changes driven by
advisories; no extension logic or API surface changes in the diff.
> 
> **Overview**
> Bumps **Yarn resolutions** and the lockfile so production security
advisories can clear for release 13.54.0. No application source changes.
> 
> **Pinned / resolution updates in `package.json`:**
`serialize-javascript` **7.0.5 → 7.1.3**, `undici` **^7.30.0 →
^7.30.1**, `fast-uri` **^3.1.8 → ^3.1.9**, and explicit **zod 4.6.7**
for `@metamask/gator-permissions-snap` and
`@metamask/permissions-kernel-snap` nested dependencies (those snaps
ship an older zod copy that does not affect runtime validation in the
extension).
> 
> **Lockfile fallout:** `body-parser` **1.20.9** and **2.4.0** (with
`qs` ~6.16), plus minor transitive bumps (`content-type` 2.1.0,
`iconv-lite` 0.7.3). Shared **zod** v4 ranges resolve to **4.6.7** (from
4.6.5); the standalone **3.25.76** lock entry is folded into the v4
resolution set per the PR notes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b93aca1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[396c3f1](396c3f1)

---------

Co-authored-by: Danica Shen <zhaodanica@gmail.com>
Co-authored-by: metamask-ci[bot] <271559518+metamask-ci[bot]@users.noreply.github.com>
@metamask-ci

metamask-ci Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor
Builds ready [799dbd7]
⚡ Performance Benchmarks (Total: 🟢 10 pass · 🟡 1 warn · 🔴 2 fail)

Baseline (latest main): 171ed20 | Date: 7/28/2026 | Pipeline: 40385638228 | Baseline logs

Metricschrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 load_new_account(p95) [CI log]🔴 load_new_account(p95) [CI log]

Regressions (🔴 2 failures)

Interaction Benchmarks · Samples: 5 🔴 2
Benchmarkchrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 [CI log]
🔴 load_new_account
🔴 [CI log]
🔴 load_new_account
confirmTx
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]
bridgeUserActions
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ loadNewAccount/load_new_account: +415%
  • ↑ loadNewAccount/total: +415%
  • ↓ loadNewAccount/fcp: -10%
  • ↑ confirmTx/longTaskTotalDuration: +26%
  • ↑ confirmTx/longTaskMaxDuration: +51%
  • ↑ confirmTx/tbt: +46%
  • ↓ confirmTx/inp: -32%
  • ↓ confirmTx/fcp: -15%
  • ↓ confirmTx/lcp: -13%
  • ↑ bridgeUserActions/bridge_load_page: +45%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +15%
  • ↑ bridgeUserActions/longTaskCount: +67%
  • ↑ bridgeUserActions/longTaskTotalDuration: +48%
  • ↓ bridgeUserActions/longTaskMaxDuration: -16%
  • ↑ bridgeUserActions/tbt: +11%
  • ↓ bridgeUserActions/inp: -15%
  • ↓ bridgeUserActions/fcp: -17%
  • ↓ bridgeUserActions/lcp: -10%
  • ↑ loadNewAccount/load_new_account: +418%
  • ↑ loadNewAccount/total: +418%
  • ↑ loadNewAccount/inp: +14%
  • ↓ loadNewAccount/fcp: -49%
  • ↑ loadNewAccount/lcp: +1072%
  • ↓ confirmTx/longTaskCount: -100%
  • ↓ confirmTx/longTaskTotalDuration: -100%
  • ↓ confirmTx/longTaskMaxDuration: -100%
  • ↓ confirmTx/tbt: -100%
  • ↓ confirmTx/inp: -32%
  • ↓ confirmTx/fcp: -47%
  • ↑ confirmTx/lcp: +1064%
  • ↑ bridgeUserActions/bridge_load_page: +245%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +78%
  • ↓ bridgeUserActions/longTaskCount: -100%
  • ↓ bridgeUserActions/longTaskTotalDuration: -100%
  • ↓ bridgeUserActions/longTaskMaxDuration: -100%
  • ↓ bridgeUserActions/tbt: -100%
  • ↑ bridgeUserActions/total: +30%
  • ↑ bridgeUserActions/inp: +31%
  • ↓ bridgeUserActions/fcp: -48%
  • ↑ bridgeUserActions/lcp: +1039%
Startup Benchmarks · Samples: 100
Benchmarkchrome-webpackfirefox-webpack
startupStandardHome
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ startupStandardHome/domInteractive: +19%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -33%
  • ↑ startupStandardHome/setupStore: +173%
  • ↓ startupStandardHome/uiStartup: -37%
  • ↓ startupStandardHome/load: -34%
  • ↓ startupStandardHome/domContentLoaded: -34%
  • ↓ startupStandardHome/domInteractive: -54%
  • ↓ startupStandardHome/backgroundConnect: -25%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -50%
  • ↓ startupStandardHome/loadScripts: -35%
  • ↑ startupStandardHome/setupStore: +67%
  • ↓ startupStandardHome/fcp: -47%
  • ↓ startupStandardHome/lcp: -32%
User Journey Benchmarks · Samples: 5 · real API
Benchmarkchrome-webpackfirefox-webpack
onboardingImportWallet
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
🟡 total
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ onboardingImportWallet/srpButtonToSrpForm: -11%
  • ↓ onboardingImportWallet/confirmSrpToPwForm: -14%
  • ↓ onboardingImportWallet/pwFormToMetricsScreen: -12%
  • ↓ onboardingImportWallet/metricsToWalletReadyScreen: -31%
  • ↓ onboardingImportWallet/doneButtonToHomeScreen: -95%
  • ↓ onboardingImportWallet/openAccountMenuToAccountListLoaded: -75%
  • ↓ onboardingImportWallet/longTaskCount: -100%
  • ↓ onboardingImportWallet/longTaskTotalDuration: -100%
  • ↓ onboardingImportWallet/longTaskMaxDuration: -100%
  • ↓ onboardingImportWallet/tbt: -100%
  • ↓ onboardingImportWallet/total: -89%
  • ↓ onboardingNewWallet/doneButtonToAssetList: -81%
  • ↓ onboardingNewWallet/longTaskCount: -100%
  • ↓ onboardingNewWallet/longTaskTotalDuration: -100%
  • ↓ onboardingNewWallet/longTaskMaxDuration: -100%
  • ↓ onboardingNewWallet/tbt: -100%
  • ↓ onboardingNewWallet/total: -78%
Dapp Page Load Benchmarks · Samples: 100
Benchmarkchrome-webpack
dappPageLoad
[Sentry log · main/release]
🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ dappPageLoad/pageLoadTime: -62%
  • ↓ dappPageLoad/domContentLoaded: -11%
  • ↓ dappPageLoad/firstPaint: -41%
  • ↓ dappPageLoad/firstContentfulPaint: -41%
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Status Bundle Total Diff Change
🚨 background 15.44 MiB +41.41 KiB +0.26%
🚨 ui 19.26 MiB +2.57 KiB +0.01%
✅ common 0 Bytes 0 Bytes 0.00%
🚨 other 4.35 MiB +1.15 KiB +0.03%
🚨 content scripts 3.15 MiB +2.3 KiB +0.07%
🚨 zip 23.94 MiB +23.28 KiB +0.10%
🍒 What's in this RC

Cherry-picks (14 commits)
Commit Description
799dbd7181 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod (#47363)
fe0274cd41 release: dedupe, update LavaMoat policies, update attributions
037d4b2d60 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod cp-13.54.0 (#47358)
0801fdbb42 chore: update changelog for 13.54.0
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
6b5b96561d Merge pull request #47235 from MetaMask/runway-cherry-pick-13.54.0-1792581661
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
841196fa40 Merge pull request #47179 from MetaMask/stable-sync-release-13.54.0

Changelog (112 commits since v13.53.0)
Commit Description
799dbd7181 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod (#47363)
fe0274cd41 release: dedupe, update LavaMoat policies, update attributions
037d4b2d60 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod cp-13.54.0 (#47358)
0801fdbb42 chore: update changelog for 13.54.0
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
a13345c31d chore: update CHANGELOG.md
bb2c5bce6e release(runway): cherry-pick chore: include Perps in the Flask build (#47173)
ca07950b68 release-changelog/13.54.0
bdbbdc6499 release(runway): cherry-pick feat: bump Tron, Solana snaps (#47122)
2d78bac0cd Merge release/13.53.0 into release/13.54.0
71d78824fc fix: reset AuthenticationController's needsSocialPairing via migration (#46979)
2f47b7b282 chore: upsert stx_get_fees_error to Transaction events (#46825)
7fe46a6a83 fix: keep the active network state same (#47098)
d720afa45c fix(nfts): point the import NFT media banner to Basic Functionality (#47044)
857ed7243e feat(assets): show a skeleton during the first asset load (#47105)
d0938138b7 fix(content): add article to Arc usage notice (#47112)
14d6dd2ebe chore: bump @metamask/client-mcp-core to 0.11.0 (#47106)
a85440bcd3 chore: make accounts-engineers the sole owners of MFA (#47110)
f1a2598b69 feat: [musd-1450] show earn banner in asset details (#47056)
0ef185a52d feat(tron): read resources from TRX balance metadata and show unavailable banner (#47046)
b88d694e06 fix: mixed clock domains onboarding traces (#47107)
ecf092a9dd feat(mfa): replace experimental UI with final designs and experience (#47103)
681327ef37 feat: ensure that money menu is aligned with nav burger menu (#47071)
1ac1748e39 feat(confirmations): improve Ledger-funded Money Account deposits (#47003)
731673e6e8 test: e2e cover Tokens native row on non-zero native networks (#45885)
7541962d96 feat: track seedless PrimarySrp error events (#46886)
b3ab41f3e7 chore(assets-controller): bump to 19.0.0 (#47031)
b96424fd61 feat: [musd-1453] money account design feedback tweaks (#47026)
f006fc49cb feat: report lifetime earnings API call failures (#47078)
989b387948 chore: remove Bitcoin account label tags everywhere but multichain account address list (#47077)
af2aef8d69 feat: upgrade wallet package to 17.1.0 (#47075)
d72b33d728 chore: fix announcement markdown (#47095)
2a47afd4ef fix: Infinite loading when sending with QR hardware wallet cp-13.53.0 (#47067)
e4316eb78a feat: add notification settings deeplinks [GE-525] (#46753)
fad47100c2 feat: fetch fresh Tron assets on the token details page (#46795)
f68af4cb8b Merge origin/main into stable-main-13.52.0
d1d130c778 fix: set tempo nativeCurrency to USD (#47074)
dcaa87cdb2 fix(money): hide unavailable lifetime earnings (#47076)
9a95d8db25 refactor: use SentinelApiService in Sentinel utils (#46867)
67a682ef21 test: create a new page object for Import NFT page (#47057)
7341169ec2 fix(confirmations): restore max-value correction for OP-stack L2 native sends (#46880)
94f6ef8e3f chore: update @metamask/stellar-wallet-snap to ^1.2.0 cp-13.53.0 (#47080)
9cd49a940b fix(mfa): apply the stack review follow-ups (#47072)
20c5a33e77 ci: add feature flags coverage metrics to QA stats workflow (#47079)
1c60e11c13 fix: swaps retry on failure (#47060)
e8ba981bca fix: removed majority of arc specific logic since has been moved to bridge-api (#46805)
9805977ea0 feat(perps): show the outage banner across Perps screens (#46864)
0662e26225 fix: hide fiat in send flow when currency conversion/basic functionality is off (#47022)
b66dd071f8 test: use page objects on llm scripts (#47055)
753c41cd55 fix(hardware-wallets): stop auto-showing error modal during swap (#46766)
efd2940403 feat(mfa): add verification methods settings (#46914)
44439d0701 chore: expand cashtag widget selector (#47061)
f9426fbe85 fix: manage tokens dedupe native entries (#47038)
cb90dd22ac test(e2e): add Money Account withdraw E2E coverage (#46784)
ab046448ef feat: add token symbol to search asset rows (#47045)
a9b874af29 feat(mfa): add flow host page and launcher (#46913)
d107264220 bump: upgrade Bitcoin wallet Snap to 3.2.0 (#47052)
da9d8472cb feat: move import NFT from a modal to a full page (#47027)
0c708dd21b feat(mfa): add placeholder flow screens (#46912)
87f5adde92 fix(perps): stop logging account fetch failures after channel teardown (#46846)
545fa39daf feat(perps): reverse position modal briefly shows the previous size's fee while the new quote loads (#47016)
44b714f019 fix: money transaction ids default to 0x0 cp-13-52-0 (#47035)
ab0216466d feat(perps): add market about section (#46610)
01401ca8c7 refactor(7408): migrate development build tooling batch 2 to TypeScript (#46808)
85edf42416 test(e2e): add Money Account deposit E2E coverage (#46783)
019e30011b fix(contacts): match add contact network border to other fields (#47037)
a8ca616aae feat(notifications): order agentic cli section above marketing (#47023)
f2d2a67af6 chore(deps): bump analytics-controller, config-registry-controller, and wallet (#46794)
4df5dd7865 test: remove anti-pattern for enable-notifications.spec (#47036)
fdd0011dce test: fix flaky test swap quote wait during skeleton (#46938)
06e8d58038 feat(money): open Money Home from the home card summary (#46901)
fa8145e4db test: Sync Feature Flag Registry - 2026-10-13 01:30 UTC (#47033)
50ccb5ece6 chore: ignore disputed braces advisory cp-13.52.0 (#47029)
52a96b79d8 feat(mfa): add controller bindings, useMfa hook and kit gate (#46911)
9bbbc4fd7b feat(analytics): track referral as standard Deep Link Used property (#47021)
a6b6f4648f fix(confirmations): block Money deposits while the Max quote is stale cp-13.52.0 (#47018)
4a0b918e04 feat(mfa): add engine flow state machine and active flow (#46910)
e7333ff4d3 feat: update button text to save (#47024)
22d671fa8c feat(mfa): add engine types, planner and error handling (#46909)
bc3f58442f feat: musd-1449 add money account CTA to token row (#46923)
0d40d25d31 fix(networks): keep Chainlist add-network details in place (#47001)
18921add8e fix(confirmations): estimate gas for native max sends (#46461)
3b07243075 fix(networks): migrate Robinhood explorer URL (#47019)
861bb9c47e feat(confirmations): align non-money deposit prefills (#46892)
762ae63d72 feat: add deadline caveat to EIP-7702 delegations (#46937)
65d920ed75 chore: Bump Snaps packages (#47004)
8cd528d20e fix: add approvedOrSigned toast phase to allow failed toasts before tx submission (#46872)
95553d8431 chore: audit braces and http-cache-semantics cp-13.52.0 (#46865)
b02ad71a23 chore: Gate additions to legacy background APIs (#46695)
a860a0ee54 chore: submitRequestToBackground supports UI messenger action types (#46903)
9318567d64 chore: align chart color (#47006)
65b8e55a12 chore: ui nits (#47005)
bbf3b7e72c fix(build): keep React Compiler stats out of the hashed module buildMeta (#46949)
e5d7d3cc92 fix(716): apply theme preference to the internal error dialog (#46890)
e9acc626fc chore: Bump LavaMoat (#46989)
3cec5e9453 fix(confirmations): surface Monad reserve-balance failures instead of misleading fee alerts (#46049)
c98475c3dd feat(confirmations): add confirmations_pay_rpc remote flag (#46981)
9d57c2b0af feat(perps): update controller to 20.0.0 cp-13.52.0 (#46934)
71e1f3d929 fix(hardware-wallets): simplify locked device error modal message (#46936)
3aab8a48d3 Merge origin/main into stable-main-13.51.0
3a8a1eeb91 release: Bump main version to 13.54.0 (#46960)
c1d9fba651 bump(stellar): bump stellar-wallet-snap from 1.1.0 to 1.1.1 cp-13.52.0 (#46973)
a284fe9f47 fix(analytics): add userAgent enrichment to early Segment events (#46921)
d61f0ab0f9 chore: bump @metamask/profile-sync-controller to 34.0.3 (#46947)
cc552ce832 fix: start with "All networks" not Sepolia or Arc (#46928)

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Commits
57/100 7 5 588 116
Cherry-Pick Scenarios (2)

High Risk Scenarios (1)

1. Snaps: Tron and Solana Snap version bump

Risk Level: HIGH

Why This Matters: Cherry-pick 47122 updates Tron and Solana Snaps, which can alter permissions, account derivation, and signing/transaction behavior; regressions here would break non-EVM user flows.

Test Steps:

  1. Install and connect to a Solana Snap-compatible dapp; approve permissions and create/derive the first account.
  2. Receive SOL to the Snap account and send a SOL transfer; confirm successful confirmation and accurate balance update.
  3. Sign a message via the Snap and verify the signature is valid on-chain or via a verifier.
  4. Repeat the connect and send flow with a Tron Snap-compatible dapp and confirm transactions and signatures complete without errors.

Medium Risk Scenarios (1)

1. Navigation: Bottom navbar behavior

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47322 fixes bottom navbar issues that can block navigation or approvals, directly impacting core user flows.

Test Steps:

  1. In popup mode, navigate across tabs using the bottom navbar and verify the selected state and content update correctly.
  2. Initiate a transaction approval and ensure the bottom navbar doesn’t overlap or block approval actions.
  3. Resize between small popup and expanded window; verify the navbar remains visible/hidden appropriately and touch/click targets work.
  4. Lock and unlock the wallet and confirm the previously selected tab is restored (or defaulted) per spec without misalignment.

Release Scenarios (10)

High Risk Scenarios (6)

1. State Migrations (231): Asset/Network enablement and settings reshaping

Risk Level: HIGH

Why This Matters: Migrations can corrupt or drop persisted data; this ensures asset visibility, detection settings, and network enablement map correctly to the new schema without user data loss.

Test Steps:

  1. Start on 13.53.x, create a vault, add Ethereum Mainnet and one test network (e.g., Sepolia), turn NFT auto-detection OFF and token auto-detection ON; hide at least one token and one NFT.
  2. Add a custom token and import an NFT manually; connect to a dapp and approve account permissions.
  3. Upgrade the same profile to 13.54.0 and unlock the wallet.
  4. Verify tokens, NFTs (including hidden and manually imported) still exist and display correctly; confirm the old enablement/ARC-style settings are either removed or mapped to equivalent toggles without regressions.
  5. Open Settings -> Security & Privacy and Networks; verify previous choices are preserved or sensibly migrated and that existing dapp connections remain functional.

2. State Migrations (232): NFT detection and import flow

Risk Level: HIGH

Why This Matters: Migration changes around NFT detection/notice can confuse users or misrepresent detection state, risking missed assets or duplicate imports.

Test Steps:

  1. On 13.53.x, ensure NFT auto-detection is OFF and the prior NFT detection notice (if any) is dismissed; have at least one manually imported NFT.
  2. Upgrade to 13.54.0 and open the NFTs tab, then open the Import NFTs screen.
  3. Verify the new detection notice appears as intended (not duplicated or missing) and reflects the OFF state.
  4. Use the notice CTA to turn ON NFT auto-detection and confirm the toggle changes in Settings and detected NFTs populate after refresh.
  5. Reopen the Import NFTs screen and verify the notice behaves consistently with the new state.

3. State Migrations (233): App-state persistence (dismissed banners, onboarding, preferences)

Risk Level: HIGH

Why This Matters: App-state migrations can regress preferences and UI flags, causing spammy banners, lost settings, or broken approval flows.

Test Steps:

  1. On 13.53.x, dismiss any visible banners/tooltips, set a non-USD fiat currency, and enable advanced gas controls.
  2. Upgrade to 13.54.0 and unlock; open the home view and settings.
  3. Verify previously dismissed banners do not reappear unexpectedly and the selected fiat currency is still applied throughout the UI.
  4. Initiate a dapp approval (connect request), reload the extension, and confirm the approval state is preserved with correct UI context.
  5. Lock and unlock the wallet and verify app-state (selected tab, preferences) persists.

4. Transaction Flow: Transaction Pay Controller patch

Risk Level: HIGH

Why This Matters: A patched transaction-pay controller directly affects fee calculation, submission, and replacement flows; regressions here can cause stuck or mispriced transactions.

Test Steps:

  1. On Ethereum Mainnet, send a standard ETH transfer; review the gas/total and open Edit to switch between low/market/high and custom gas.
  2. Submit the transaction, then use Speed Up; verify the replacement transaction updates status correctly and final cost is reflected in Activity and fiat totals.
  3. Repeat with an ERC-20 transfer and verify gas estimates and total are reasonable and consistent.
  4. Attempt Cancel on a pending transaction and confirm proper replacement and final statuses without UI hangs.
  5. Check activity details for accurate fee breakdown and no duplicated or missing entries.

5. Network Management: Network Enablement Controller initialization

Risk Level: HIGH

Why This Matters: Reworked controller init can flip defaults or break persistence, impacting which networks and assets users can see or use.

Test Steps:

  1. Fresh install 13.54.0, open Settings -> Networks and note default enabled networks.
  2. Disable a non-primary network (e.g., a testnet), close and reopen the extension, and verify the network remains disabled and its assets are hidden from the Assets list.
  3. Re-enable the network and confirm previously visible assets reappear with correct balances.
  4. From a dapp on the disabled network, attempt to connect; verify you are guided to enable the network and that connection subsequently succeeds.
  5. Confirm no phantom or duplicate networks appear and switching networks remains stable.

6. Security: Message/HTML sanitization in signing and insights surfaces

Risk Level: HIGH

Why This Matters: Sanitizer/library patches can create XSS risks in approval UIs, leading to phishing or UI hijacking at critical signing moments.

Test Steps:

  1. From a test dapp, trigger a personal_sign and an EIP-712 signature request containing HTML tags, scripts, and external links in string fields.
  2. In the signature preview, confirm that no HTML is rendered (only safe text) and no scripts or inline images execute.
  3. Attempt to click any displayed URL; verify it is either not clickable or opens safely without inline execution or UI breakage.
  4. Approve and reject each request and confirm the confirmation screen remains functional and secure.
  5. Review transaction insights/warnings panels for any HTML content and verify it is sanitized and cannot break layout.

Medium Risk Scenarios (4)

1. Approvals and Session Restore: App State Controller changes

Risk Level: MEDIUM

Why This Matters: Changes to app-state controller can disrupt approval continuity, causing lost context or stuck approvals.

Test Steps:

  1. From a dapp, initiate a connect request and a pending transaction so the approval screen is open.
  2. Lock the wallet, then unlock; verify the pending approval UI restores to the same step with correct details.
  3. Close the popup and reopen; ensure the selected tab and approval context persist.
  4. Reject the request and confirm app state returns to the previous screen without stale banners or misnavigation.

2. Portfolio Display: Account Group Balance calculation

Risk Level: MEDIUM

Why This Matters: Incorrect balance aggregation erodes trust and can influence send/receive decisions.

Test Steps:

  1. With multiple accounts and tokens, view the total balance header; note fiat totals.
  2. Hide a token with non-zero value and verify the total updates immediately and matches the sum of visible assets.
  3. Switch fiat currency (e.g., USD to EUR) and verify totals and per-asset fiat values recalculate consistently.
  4. Add a watch-only account; confirm whether it is included/excluded per design and totals reflect that behavior.

3. NFTs: Detection notice and manual import pathway

Risk Level: MEDIUM

Why This Matters: Reworked notice and flow must correctly guide users between manual import and detection, avoiding duplicates or missing items.

Test Steps:

  1. Turn OFF NFT auto-detection in Settings.
  2. Open NFTs -> Import NFTs and verify the new detection notice appears with correct messaging.
  3. Use the notice CTA to enable detection; verify the toggle updates and detected NFTs populate after refresh.
  4. Manually import an NFT and confirm it appears without duplication after detection runs.

4. Assets List: Control bar search/filter behavior

Risk Level: MEDIUM

Why This Matters: Small logic changes in list controls can degrade asset discovery and lead to user confusion.

Test Steps:

  1. On the Assets tab with many tokens, use the search field to filter by symbol and name; verify results and clear state.
  2. Toggle any available filter (e.g., hide small balances) and confirm the list updates correctly and persists after navigation.
  3. Switch to another tab and back; verify the search/filter state behaves as intended (persisted or reset per spec) without UI jumpiness.
  4. Open a token details screen from filtered results and navigate back; confirm the filter state is intact.

Teams Sign-off Status

Signed off: None yet

Awaiting sign-off (9):
Accounts, Assets, Confirmations, Networks, Onboarding, Security, Settings, Snaps, Transactions


Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-26T19:38:53.622Z

AI generated test plan (JSON): test-plan-13.54.0.json

sleepytanya
sleepytanya previously approved these changes Oct 26, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Client UI review (modern-web-guidance)

Two new Money surfaces use clickable containers that wrap real buttons/links. That creates nested interactive elements and leaves keyboard/screen-reader users with ambiguous targets (modern-web-guidance accessibility: prefer native <button>/<a> and avoid nesting interactives).

No Chrome extension / MV3 issues stood out in this release diff (app/ changes are controller wiring, cashtag selector tweaks, and E2E wallet-init).

Open in Web View Automation 

Sent by Cursor Automation: Modern web guidance

marginHorizontal={4}
marginTop={4}
className="cursor-pointer rounded-xl"
onClick={onBannerClick}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nested interactives / non-native banner control: The outer Box is clickable (onClick={onBannerClick}) but it is not keyboard-focusable and has no role/tabIndex/onKeyDown. It also wraps a dismiss ButtonIcon and a TextButton CTA, so assistive tech sees buttons inside another activation target.

Suggestion: Pick one primary action pattern—for example, make only the CTA a <button> (and keep dismiss separate), or use a single native <button type="button"> for the banner body and drop the outer onClick. If the whole row must navigate, avoid nesting: put dismiss/CTA outside the banner button or use stopPropagation on siblings without making the parent a pseudo-control. Match the keyboard pattern used in money-account-balance (role="link", tabIndex={0}, Enter/Space handler) if you keep a non-button wrapper.

alignItems={BoxAlignItems.Center}
padding={4}
className="cursor-pointer rounded-r-2xl"
onClick={startDeposit}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nested interactives on the Add section: This Box calls onClick={startDeposit} while the child Add component renders a design-system Button with its own onClick. That duplicates activation and nests interactive elements (section click + button), which is awkward for keyboard and screen-reader users.

Suggestion: Keep a single control—either remove the wrapper onClick and enlarge the Button hit area with padding/className, or replace the inner Button with non-interactive styling and put role="button", tabIndex={0}, and Enter/Space handling on the section (same pattern as the summary block above).

@metamask-ci

metamask-ci Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor
Builds ready [4bb70a9]
⚡ Performance Benchmarks (Total: 🟢 6 pass · 🟡 5 warn · 🔴 2 fail)

Baseline (latest main): 171ed20 | Date: 7/28/2026 | Pipeline: 40439100360 | Baseline logs

Metricschrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 load_new_account(p95) [CI log]🔴 load_new_account(p95) [CI log]

Regressions (🔴 2 failures)

Interaction Benchmarks · Samples: 5 🔴 2
Benchmarkchrome-webpackfirefox-webpack
loadNewAccount
[Sentry log · main/release]
🔴 [CI log]
🔴 load_new_account
🔴 [CI log]
🔴 load_new_account
confirmTx
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]
bridgeUserActions
[Sentry log · main/release]
🟡 [CI log]🟡 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ loadNewAccount/load_new_account: +422%
  • ↑ loadNewAccount/total: +422%
  • ↑ loadNewAccount/fcp: +20%
  • ↑ loadNewAccount/lcp: +21%
  • ↑ confirmTx/longTaskCount: +33%
  • ↑ confirmTx/longTaskTotalDuration: +90%
  • ↑ confirmTx/longTaskMaxDuration: +114%
  • ↑ confirmTx/tbt: +132%
  • ↑ confirmTx/fcp: +18%
  • ↑ confirmTx/lcp: +15%
  • ↑ bridgeUserActions/bridge_load_page: +131%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +78%
  • ↑ bridgeUserActions/longTaskCount: +122%
  • ↑ bridgeUserActions/longTaskTotalDuration: +163%
  • ↑ bridgeUserActions/longTaskMaxDuration: +75%
  • ↑ bridgeUserActions/tbt: +364%
  • ↑ bridgeUserActions/total: +24%
  • ↑ bridgeUserActions/inp: +31%
  • ↑ bridgeUserActions/fcp: +15%
  • ↑ bridgeUserActions/lcp: +25%
  • ↑ loadNewAccount/load_new_account: +418%
  • ↑ loadNewAccount/total: +418%
  • ↓ loadNewAccount/fcp: -41%
  • ↑ loadNewAccount/lcp: +1281%
  • ↓ confirmTx/longTaskCount: -100%
  • ↓ confirmTx/longTaskTotalDuration: -100%
  • ↓ confirmTx/longTaskMaxDuration: -100%
  • ↓ confirmTx/tbt: -100%
  • ↓ confirmTx/inp: -24%
  • ↑ confirmTx/fcp: +18%
  • ↑ confirmTx/lcp: +1286%
  • ↑ bridgeUserActions/bridge_load_page: +255%
  • ↑ bridgeUserActions/bridge_load_asset_picker: +140%
  • ↑ bridgeUserActions/bridge_search_token: +23%
  • ↓ bridgeUserActions/longTaskCount: -100%
  • ↓ bridgeUserActions/longTaskTotalDuration: -100%
  • ↓ bridgeUserActions/longTaskMaxDuration: -100%
  • ↓ bridgeUserActions/tbt: -100%
  • ↑ bridgeUserActions/total: +58%
  • ↑ bridgeUserActions/inp: +108%
  • ↓ bridgeUserActions/fcp: -39%
  • ↑ bridgeUserActions/lcp: +1271%

🌐 Core Web Vitals — 🟢 good · 🟡 needs improvement · 🔴 poor (web.dev thresholds)

  • 🟡 loadNewAccount/FCP: p75 2.1s
  • 🟡 confirmTx/FCP: p75 2.0s
  • 🟡 bridgeUserActions/FCP: p75 2.0s
  • 🟡 confirmTx/FCP: p75 2.0s
  • 🟡 bridgeUserActions/INP: p75 216ms
Startup Benchmarks · Samples: 100
Benchmarkchrome-webpackfirefox-webpack
startupStandardHome
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ startupStandardHome/uiStartup: +11%
  • ↑ startupStandardHome/domInteractive: +16%
  • ↑ startupStandardHome/firstPaint: +11%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -33%
  • ↑ startupStandardHome/setupStore: +211%
  • ↓ startupStandardHome/longTaskCount: -33%
  • ↓ startupStandardHome/uiStartup: -31%
  • ↓ startupStandardHome/load: -26%
  • ↓ startupStandardHome/domContentLoaded: -26%
  • ↓ startupStandardHome/domInteractive: -54%
  • ↓ startupStandardHome/backgroundConnect: -20%
  • ↓ startupStandardHome/firstReactRender: -99%
  • ↓ startupStandardHome/initialActions: -50%
  • ↓ startupStandardHome/loadScripts: -26%
  • ↑ startupStandardHome/setupStore: +99%
  • ↓ startupStandardHome/fcp: -43%
  • ↓ startupStandardHome/lcp: -23%
User Journey Benchmarks · Samples: 5 · real API
Benchmarkchrome-webpackfirefox-webpack
onboardingImportWallet
[Sentry log · main/release]
🟢 [CI log]🟡 [CI log]
🟡 total
onboardingNewWallet
[Sentry log · main/release]
🟢 [CI log]🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↑ onboardingImportWallet/srpButtonToSrpForm: +48%
  • ↑ onboardingImportWallet/confirmSrpToPwForm: +40%
  • ↑ onboardingImportWallet/pwFormToMetricsScreen: +34%
  • ↑ onboardingImportWallet/metricsToWalletReadyScreen: +36%
  • ↓ onboardingImportWallet/doneButtonToHomeScreen: -94%
  • ↓ onboardingImportWallet/openAccountMenuToAccountListLoaded: -75%
  • ↓ onboardingImportWallet/longTaskCount: -100%
  • ↓ onboardingImportWallet/longTaskTotalDuration: -100%
  • ↓ onboardingImportWallet/longTaskMaxDuration: -100%
  • ↓ onboardingImportWallet/tbt: -100%
  • ↓ onboardingImportWallet/total: -89%
  • ↑ onboardingNewWallet/srpButtonToPwForm: +43%
  • ↑ onboardingNewWallet/createPwToRecoveryScreen: +33%
  • ↑ onboardingNewWallet/skipBackupToMetricsScreen: +27%
  • ↑ onboardingNewWallet/agreeButtonToOnboardingSuccess: +17%
  • ↓ onboardingNewWallet/doneButtonToAssetList: -82%
  • ↓ onboardingNewWallet/longTaskCount: -38%
  • ↓ onboardingNewWallet/longTaskTotalDuration: -56%
  • ↓ onboardingNewWallet/longTaskMaxDuration: -45%
  • ↓ onboardingNewWallet/tbt: -91%
  • ↓ onboardingNewWallet/total: -78%
Dapp Page Load Benchmarks · Samples: 100
Benchmarkchrome-webpack
dappPageLoad
[Sentry log · main/release]
🟢 [CI log]

📈 Results compared to the previous 5 runs on main

  • ↓ dappPageLoad/pageLoadTime: -57%
  • ↓ dappPageLoad/firstPaint: -41%
  • ↓ dappPageLoad/firstContentfulPaint: -41%
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Status Bundle Total Diff Change
🚨 background 15.44 MiB +41.41 KiB +0.26%
🚨 ui 19.26 MiB +2.57 KiB +0.01%
✅ common 0 Bytes 0 Bytes 0.00%
🚨 other 4.35 MiB +1.15 KiB +0.03%
🚨 content scripts 3.15 MiB +2.3 KiB +0.07%
🚨 zip 23.94 MiB +23.28 KiB +0.10%
🍒 What's in this RC

Cherry-picks (15 commits)
Commit Description
4bb70a99dc chore: update CHANGELOG.md
799dbd7181 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod (#47363)
fe0274cd41 release: dedupe, update LavaMoat policies, update attributions
037d4b2d60 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod cp-13.54.0 (#47358)
0801fdbb42 chore: update changelog for 13.54.0
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
6b5b96561d Merge pull request #47235 from MetaMask/runway-cherry-pick-13.54.0-1792581661
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
841196fa40 Merge pull request #47179 from MetaMask/stable-sync-release-13.54.0

Changelog (113 commits since v13.53.0)
Commit Description
4bb70a99dc chore: update CHANGELOG.md
799dbd7181 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod (#47363)
fe0274cd41 release: dedupe, update LavaMoat policies, update attributions
037d4b2d60 release(runway): cherry-pick chore: patch fast-uri, body-parser, undici, serialize-javascript, and GridPlus zod cp-13.54.0 (#47358)
0801fdbb42 chore: update changelog for 13.54.0
3755e330f2 release(runway): cherry-pick fix(ui): bottom navbar (#47322)
acf000dabd release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt (#47306)
9da0c8d9c0 release(runway): cherry-pick ci: mint a token for the release changelog workflow (#47296)
0af7566055 release(runway): cherry-pick chore: New Crowdin Translations by GitHub Action (#47262)
49adeb2562 fix: patch transaction-pay-controller to prefer checksummed asset ID (13.54.0) (#47233)
e49e988437 release: dedupe, update LavaMoat policies, update attributions
921bfdebb8 release(runway): cherry-pick bump: multiple to fix audit, trying the new prompt cp-13.54.0 (#47229)
16199fd409 release(runway): cherry-pick chore: update @metamask/stellar-wallet-snap to ^1.3.0 (#47224)
a13345c31d chore: update CHANGELOG.md
bb2c5bce6e release(runway): cherry-pick chore: include Perps in the Flask build (#47173)
ca07950b68 release-changelog/13.54.0
bdbbdc6499 release(runway): cherry-pick feat: bump Tron, Solana snaps (#47122)
2d78bac0cd Merge release/13.53.0 into release/13.54.0
71d78824fc fix: reset AuthenticationController's needsSocialPairing via migration (#46979)
2f47b7b282 chore: upsert stx_get_fees_error to Transaction events (#46825)
7fe46a6a83 fix: keep the active network state same (#47098)
d720afa45c fix(nfts): point the import NFT media banner to Basic Functionality (#47044)
857ed7243e feat(assets): show a skeleton during the first asset load (#47105)
d0938138b7 fix(content): add article to Arc usage notice (#47112)
14d6dd2ebe chore: bump @metamask/client-mcp-core to 0.11.0 (#47106)
a85440bcd3 chore: make accounts-engineers the sole owners of MFA (#47110)
f1a2598b69 feat: [musd-1450] show earn banner in asset details (#47056)
0ef185a52d feat(tron): read resources from TRX balance metadata and show unavailable banner (#47046)
b88d694e06 fix: mixed clock domains onboarding traces (#47107)
ecf092a9dd feat(mfa): replace experimental UI with final designs and experience (#47103)
681327ef37 feat: ensure that money menu is aligned with nav burger menu (#47071)
1ac1748e39 feat(confirmations): improve Ledger-funded Money Account deposits (#47003)
731673e6e8 test: e2e cover Tokens native row on non-zero native networks (#45885)
7541962d96 feat: track seedless PrimarySrp error events (#46886)
b3ab41f3e7 chore(assets-controller): bump to 19.0.0 (#47031)
b96424fd61 feat: [musd-1453] money account design feedback tweaks (#47026)
f006fc49cb feat: report lifetime earnings API call failures (#47078)
989b387948 chore: remove Bitcoin account label tags everywhere but multichain account address list (#47077)
af2aef8d69 feat: upgrade wallet package to 17.1.0 (#47075)
d72b33d728 chore: fix announcement markdown (#47095)
2a47afd4ef fix: Infinite loading when sending with QR hardware wallet cp-13.53.0 (#47067)
e4316eb78a feat: add notification settings deeplinks [GE-525] (#46753)
fad47100c2 feat: fetch fresh Tron assets on the token details page (#46795)
f68af4cb8b Merge origin/main into stable-main-13.52.0
d1d130c778 fix: set tempo nativeCurrency to USD (#47074)
dcaa87cdb2 fix(money): hide unavailable lifetime earnings (#47076)
9a95d8db25 refactor: use SentinelApiService in Sentinel utils (#46867)
67a682ef21 test: create a new page object for Import NFT page (#47057)
7341169ec2 fix(confirmations): restore max-value correction for OP-stack L2 native sends (#46880)
94f6ef8e3f chore: update @metamask/stellar-wallet-snap to ^1.2.0 cp-13.53.0 (#47080)
9cd49a940b fix(mfa): apply the stack review follow-ups (#47072)
20c5a33e77 ci: add feature flags coverage metrics to QA stats workflow (#47079)
1c60e11c13 fix: swaps retry on failure (#47060)
e8ba981bca fix: removed majority of arc specific logic since has been moved to bridge-api (#46805)
9805977ea0 feat(perps): show the outage banner across Perps screens (#46864)
0662e26225 fix: hide fiat in send flow when currency conversion/basic functionality is off (#47022)
b66dd071f8 test: use page objects on llm scripts (#47055)
753c41cd55 fix(hardware-wallets): stop auto-showing error modal during swap (#46766)
efd2940403 feat(mfa): add verification methods settings (#46914)
44439d0701 chore: expand cashtag widget selector (#47061)
f9426fbe85 fix: manage tokens dedupe native entries (#47038)
cb90dd22ac test(e2e): add Money Account withdraw E2E coverage (#46784)
ab046448ef feat: add token symbol to search asset rows (#47045)
a9b874af29 feat(mfa): add flow host page and launcher (#46913)
d107264220 bump: upgrade Bitcoin wallet Snap to 3.2.0 (#47052)
da9d8472cb feat: move import NFT from a modal to a full page (#47027)
0c708dd21b feat(mfa): add placeholder flow screens (#46912)
87f5adde92 fix(perps): stop logging account fetch failures after channel teardown (#46846)
545fa39daf feat(perps): reverse position modal briefly shows the previous size's fee while the new quote loads (#47016)
44b714f019 fix: money transaction ids default to 0x0 cp-13-52-0 (#47035)
ab0216466d feat(perps): add market about section (#46610)
01401ca8c7 refactor(7408): migrate development build tooling batch 2 to TypeScript (#46808)
85edf42416 test(e2e): add Money Account deposit E2E coverage (#46783)
019e30011b fix(contacts): match add contact network border to other fields (#47037)
a8ca616aae feat(notifications): order agentic cli section above marketing (#47023)
f2d2a67af6 chore(deps): bump analytics-controller, config-registry-controller, and wallet (#46794)
4df5dd7865 test: remove anti-pattern for enable-notifications.spec (#47036)
fdd0011dce test: fix flaky test swap quote wait during skeleton (#46938)
06e8d58038 feat(money): open Money Home from the home card summary (#46901)
fa8145e4db test: Sync Feature Flag Registry - 2026-10-13 01:30 UTC (#47033)
50ccb5ece6 chore: ignore disputed braces advisory cp-13.52.0 (#47029)
52a96b79d8 feat(mfa): add controller bindings, useMfa hook and kit gate (#46911)
9bbbc4fd7b feat(analytics): track referral as standard Deep Link Used property (#47021)
a6b6f4648f fix(confirmations): block Money deposits while the Max quote is stale cp-13.52.0 (#47018)
4a0b918e04 feat(mfa): add engine flow state machine and active flow (#46910)
e7333ff4d3 feat: update button text to save (#47024)
22d671fa8c feat(mfa): add engine types, planner and error handling (#46909)
bc3f58442f feat: musd-1449 add money account CTA to token row (#46923)
0d40d25d31 fix(networks): keep Chainlist add-network details in place (#47001)
18921add8e fix(confirmations): estimate gas for native max sends (#46461)
3b07243075 fix(networks): migrate Robinhood explorer URL (#47019)
861bb9c47e feat(confirmations): align non-money deposit prefills (#46892)
762ae63d72 feat: add deadline caveat to EIP-7702 delegations (#46937)
65d920ed75 chore: Bump Snaps packages (#47004)
8cd528d20e fix: add approvedOrSigned toast phase to allow failed toasts before tx submission (#46872)
95553d8431 chore: audit braces and http-cache-semantics cp-13.52.0 (#46865)
b02ad71a23 chore: Gate additions to legacy background APIs (#46695)
a860a0ee54 chore: submitRequestToBackground supports UI messenger action types (#46903)
9318567d64 chore: align chart color (#47006)
65b8e55a12 chore: ui nits (#47005)
bbf3b7e72c fix(build): keep React Compiler stats out of the hashed module buildMeta (#46949)
e5d7d3cc92 fix(716): apply theme preference to the internal error dialog (#46890)
e9acc626fc chore: Bump LavaMoat (#46989)
3cec5e9453 fix(confirmations): surface Monad reserve-balance failures instead of misleading fee alerts (#46049)
c98475c3dd feat(confirmations): add confirmations_pay_rpc remote flag (#46981)
9d57c2b0af feat(perps): update controller to 20.0.0 cp-13.52.0 (#46934)
71e1f3d929 fix(hardware-wallets): simplify locked device error modal message (#46936)
3aab8a48d3 Merge origin/main into stable-main-13.51.0
3a8a1eeb91 release: Bump main version to 13.54.0 (#46960)
c1d9fba651 bump(stellar): bump stellar-wallet-snap from 1.1.0 to 1.1.1 cp-13.52.0 (#46973)
a284fe9f47 fix(analytics): add userAgent enrichment to early Segment events (#46921)
d61f0ab0f9 chore: bump @metamask/profile-sync-controller to 34.0.3 (#46947)
cc552ce832 fix: start with "All networks" not Sepolia or Arc (#46928)

AI Test Plan

Risk Score High Risk Medium Risk Files Changed Commits
51/100 4 10 588 117
Cherry-Pick Scenarios (4)

Medium Risk Scenarios (4)

1. Snaps — Tron Snap bump (install/connect and sign flow)

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47122 updates critical Snap behavior; Snap bumps can change permissions, key derivation, or signing flows causing broken connections or failed approvals.

Test Steps:

  1. From Settings → Snaps (or via a compatible dapp), install the Tron Snap and approve requested permissions.
  2. Connect to a Tron dapp and request an address; verify account exposure and network prompts behave correctly.
  3. Initiate a simple transfer or message signing from the dapp; approve in MetaMask and confirm success.

2. Snaps — Solana Snap bump (install/connect and sign flow)

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47122 updates Solana Snap; changes can impact signing UX, address formats, or permission prompts, breaking dapp interoperability.

Test Steps:

  1. Install the Solana Snap and approve its permissions.
  2. Connect to a Solana dapp, request an address, and verify correct account exposure and network labeling.
  3. Sign a test transaction or message and ensure the confirmation UI renders correctly and the action succeeds.

3. Snaps — Stellar Wallet Snap bump (basic install and send)

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47224 updates Stellar Snap; Snap upgrades can subtly break address derivation and signing or introduce new permission scopes.

Test Steps:

  1. Install the Stellar Wallet Snap and approve permissions.
  2. From a Stellar-compatible dapp, connect and request an address; verify it displays correctly.
  3. Trigger a small send or message sign; approve and confirm the result in both the dapp and MetaMask Activity.

4. UI Navigation — bottom navbar fix

Risk Level: MEDIUM

Why This Matters: Cherry-pick 47322 fixes navigation; navbar regressions can block critical actions or obscure confirmations on small viewports.

Test Steps:

  1. Resize the extension popup to a small height/width where the bottom navbar appears; navigate between tabs (e.g., Home, Activity, NFTs).
  2. Open a confirmation screen (send or connect) and verify the navbar does not overlap buttons or block scrolling.
  3. Return to Home and confirm the navbar highlights the correct active tab and remains clickable.

Release Scenarios (10)

High Risk Scenarios (4)

1. State Migrations (231–233) — assets/network enablement flags and UI gating

Risk Level: HIGH

Why This Matters: Migrations can corrupt or reset user preferences and asset lists; verifying preserved settings and clean UI state prevents asset loss confusion and broken onboarding prompts.

Test Steps:

  1. On 13.53.x, create a profile with: Token detection ON, NFT detection OFF, and at least one custom network added; hold at least one token and one NFT on different networks.
  2. Upgrade to 13.54.0 and unlock; do not reset state.
  3. Open Assets and NFTs tabs across two networks (e.g., Ethereum Mainnet and a custom RPC); verify prior detection toggles persist and no legacy ‘enablement’ banners unexpectedly appear.
  4. Toggle NFT detection ON, reload the extension, and confirm the toggle persists and NFTs list populates without duplicates.
  5. Check console for migration errors and ensure balances/asset lists remain intact (no missing or duplicated tokens/NFTs).

2. Network Enablement Controller Init — first-visit prompts and per-network defaults

Risk Level: HIGH

Why This Matters: Initialization order and persistence of per-network enablement can cause repeated prompts or incorrect defaults, disrupting users and creating inconsistent detection behavior.

Test Steps:

  1. Add a new custom network (RPC) and switch to it for the first time.
  2. Visit the Assets tab and observe any enablement or detection prompts; dismiss them and reload the extension.
  3. Verify dismissed prompts do not reappear (persistence) and that detection toggles reflect the user’s action.
  4. Switch between networks (Mainnet ↔ custom) and confirm prompts/flags are scoped per-network and do not leak across networks.

3. Assets Controller Init — token detection and deduplication

Risk Level: HIGH

Why This Matters: Controller init refactors can introduce race conditions or duplication in asset discovery, affecting balances and user trust.

Test Steps:

  1. On Mainnet with token detection ON, import an account holding common ERC-20s; verify automatic token discovery populates once.
  2. Turn token detection OFF and manually import one of the same tokens; confirm it shows once and is not duplicated.
  3. Re-enable token detection and reload; verify no duplicates are created and balances remain accurate.
  4. Switch to another EVM network where the token also exists; verify lists are network-scoped and consistent.

4. NFT Import Flow — Detection Notice on 'Import NFTs'

Risk Level: HIGH

Why This Matters: A new notice in a critical flow can block or confuse NFT imports, causing users to miss assets or repeat actions.

Test Steps:

  1. Ensure NFT detection is OFF; open NFTs tab with zero NFTs.
  2. Click 'Import NFTs' and verify the new detection notice component appears with correct messaging and actions.
  3. Dismiss or act on the notice (enable detection), then reload; confirm the choice persists and the notice does not reappear unnecessarily.
  4. Complete a manual NFT import and confirm it displays correctly alongside any auto-detected NFTs without duplication.

Medium Risk Scenarios (6)

1. NFTs Empty State — copy/CTA behavior with detection on/off

Risk Level: MEDIUM

Why This Matters: Incorrect empty-state guidance can mislead users about how to add or discover NFTs, increasing support burden.

Test Steps:

  1. With NFT detection OFF and zero NFTs, open the NFTs tab and validate the empty-state text and CTA are appropriate (e.g., option to import).
  2. Toggle NFT detection ON; reload and re-check the empty state messaging and CTAs.
  3. Add one NFT (manual or detected) and ensure the empty state is replaced correctly without lingering CTAs.

2. Account Group Balance — total computation and hidden assets

Risk Level: MEDIUM

Why This Matters: Balance integrity drives user trust; UI refactors can miscompute totals, especially with hidden assets and pending transactions.

Test Steps:

  1. Create two accounts with different token balances; view any grouped balance display on Home/Portfolio.
  2. Hide one low-value token and verify the group total updates accordingly in fiat and native units.
  3. Initiate a pending transaction (send a small token amount) and verify the total reflects pending changes without double counting.

3. Assets List Control Bar — search/filter/sort stability

Risk Level: MEDIUM

Why This Matters: Small control-bar changes can regress filtering or persistence, making it hard to locate assets.

Test Steps:

  1. In the Tokens tab with a mixed list, use the search bar to filter by token symbol and name; verify accurate results.
  2. Toggle 'Hide small balances' (or equivalent control) and ensure filtering is applied correctly and persists on navigation.
  3. Switch networks and confirm the control bar state does not leak incorrectly across networks.

4. App State Controller — lock/unlock and modal/popup persistence

Risk Level: MEDIUM

Why This Matters: App-state bugs around lock/unlock can strand users mid-flow or re-show dismissed UI elements, breaking critical journeys.

Test Steps:

  1. Begin a send or connect flow that opens a confirmation screen, then lock the wallet.
  2. Unlock and verify the app resumes in a valid state (e.g., returns to the pending confirmation or a clear, recoverable screen).
  3. Trigger and dismiss a global banner or tooltip, reload, and confirm dismissal persists and doesn't resurface unexpectedly.

5. Analytics Platform Adapter — consent-gated events

Risk Level: MEDIUM

Why This Matters: Privacy and regulatory expectations require strict consent gating; adapter changes can accidentally emit events without consent.

Test Steps:

  1. On fresh install, decline analytics consent; perform common actions (switch account, open Settings, add network).
  2. In DevTools Network, verify no analytics requests are sent (Segment/Amplitude endpoints) when consent is OFF.
  3. Enable analytics in Settings and repeat actions; verify events are now emitted once, without duplicates.

6. Send Transaction — gas estimate and confirmation (regression around transaction-pay controller patch)

Risk Level: MEDIUM

Why This Matters: Low-level controller patches can impact gas estimation or fee flows; regressions here directly cause failed or overpriced transactions.

Test Steps:

  1. On Ethereum Mainnet, send an ERC-20 transfer; review gas estimates in basic and advanced settings.
  2. Edit gas (max fee/priority fee), confirm the transaction, and verify it broadcasts with chosen fees.
  3. Use Speed Up/Cancel flows and confirm status updates and final fees are accurate in Activity.

Teams Sign-off Status

Signed off: None yet

Awaiting sign-off (7):
Accounts, Assets, Confirmations, Networks, Snaps, Transactions, Wallet


Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-27T02:54:04.449Z

AI generated test plan (JSON): test-plan-13.54.0.json

This branch had an error being deployed

1 failed (outdated), 2 active (outdated), and 3 inactive (1 outdated) deployments
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.54.0 Issue or pull request that will be included in release 13.54.0 team-bots Bot team (for MetaMask Bot, Runway Bot, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.