Repository navigation
release: 13.52.0 - #46848
release: 13.52.0#46848
Conversation
## **Description** Updates the OP Mainnet network icon (`app/images/optimism.svg`) to the current official Optimism brand asset. 1. **Reason for the change:** the asset currently shipped in the extension is an outdated version of the OP mark, authored at 360x360 with the logo nested inside a translated/scaled `<g>` wrapper. 2. **Improvement/solution:** replaces it with the current OP mark drawn as a single path on a 1024x1024 viewBox, so it renders crisply at every size the wallet uses for network icons and matches the mark used across Optimism surfaces. Asset-only change, no code paths touched. A matching PR against `metamask-mobile` will follow so both clients ship the same asset. ## **Changelog** CHANGELOG entry: Updated the OP Mainnet network icon to the current Optimism brand asset ## **Related issues** N/A ## **Manual testing steps** 1. Build and run the extension. 2. Open the network picker and confirm the OP Mainnet icon renders correctly. 3. Switch to OP Mainnet and confirm the icon renders correctly in the network pill, the account overview and the asset list rows. 4. Confirm the mark is sharp and correctly framed at small sizes, with no clipping or stretching. ## **Screenshots/Recordings** ### **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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Static asset swap with no runtime or security impact; existing references keep the same path. > > **Overview** > Replaces **`app/images/optimism.svg`** with the current Optimism brand mark. The old 360×360 asset used a scaled group wrapper; the new file is a **1024×1024** canvas with a single path on a red background (`#FF0421`) and off-white mark (`#FAFAF9`), so OP Mainnet icons stay sharp in the network picker, network pill, and related UI that already point at this file (e.g. `OPTIMISM_TOKEN_IMAGE_URL`). > > **No application logic changes**—only the bundled SVG. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit cafdbf2. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
#46600) ## **Description** Moves ownership of the marketing campaign cookie id (`marketingCampaignCookieId`) from `MetaMetricsController` to `AnalyticsController`, which now supports the field as of `@metamask/analytics-controller@3.2.0` (core PR #10373). **Context:** `AnalyticsController` already owns the marketing consent state (`optedInToMarketing`, `marketingConsentDecisionMade`), and core #10373 added the cookie id plus a `AnalyticsController:setMarketingCampaignCookieId` messenger action to it, with controller-side auto-clear on `optOutOfMarketing` and `resetMarketingConsentDecision`. This completes the migration on the extension side and resolves [mcmire's comment on #46473](#46473 (comment)): the clearing is now a controller action invoked through the messenger, and the manual clearing blocks are gone from `analytics.ts`. **Solution:** - Dependency bumped to stable `@metamask/analytics-controller@^3.2.0` (no preview builds). - Migration `229` moves the persisted cookie id value from `MetaMetricsController` state to `AnalyticsController` state, preserving both the string and the historically-supported numeric forms. - `MetaMetricsController` no longer holds any state or exposed methods (the controller shell remains). - The platform adapter reads the cookie via `AnalyticsController:getState`; `metamask-controller.js` writes via the new controller action. - `setParticipateInMetaMetrics` no longer clears the cookie at all, and `setDataCollectionForMarketing` no longer clears it manually — the controller handles clearing. **Accepted behavior change:** the cookie id is retained after a full metrics opt-out / onboarding reset while marketing consent remains on (core's `optOut`/`resetConsentDecision` intentionally do not clear it). - Flat-state type, Sentry-state flag, E2E fixtures/snapshots and unit tests follow the new owner. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: Depends on: MetaMask/core#10373 (shipped in `@metamask/analytics-controller@3.2.0`) Follow-up context: #46473 (comment) ## **Manual testing steps** 1. Enable the marketing consent toggle during onboarding (or via Settings → Privacy → Data collection for marketing toggle). 2. Visit a website (e.g. metamask.io), open the inspector console, and execute the following: ``` window.postMessage( { target: 'metamask-contentscript', data: { name: 'metamask-cookie-handler', data: { jsonrpc: '2.0', method: 'getCookieFromMarketingPage', params: [{ ga_client_id: 99999, origin: window.location.origin }], id: Date.now(), origin: window.location.origin, }, }, }, window.location.origin, ); ``` 3. Confirm AnalyticsController state has marketingCampaignCookieId set to 99999 (check in the inspector). 4. Toggle "Data collection for marketing" off in Privacy Settings and confirm marketingCampaignCookieId is cleared. 5. Do the same steps again with marketing consent toggle disabled during onboarding and confirm marketingCampaignCookieId is not set. <!-- ## **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** > Touches persisted analytics/marketing identity state and consent clearing behavior across upgrades; migration 229 must run correctly for existing users. > > **Overview** > **`marketingCampaignCookieId`** is moved from **`MetaMetricsController`** to **`AnalyticsController`** (via **`@metamask/analytics-controller@^3.2.0`**), with migration **229** copying persisted string/numeric values and stripping the field from **`MetaMetricsController`**, which is now an empty controller shell. > > Reads and writes go through **`AnalyticsController:getState`** and **`AnalyticsController:setMarketingCampaignCookieId`** (platform adapter, marketing-page cookie handler, messenger delegation). Extension helpers **`setParticipateInMetaMetrics`** / **`setDataCollectionForMarketing`** no longer manually null the cookie; clearing is delegated to core on marketing opt-out. **Opting out of MetaMetrics alone no longer clears the cookie** (intentional behavior change). Types, Sentry flags, fixtures, and tests follow the new owner. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4ac3158. 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** Opening the wallet crashed with `new BigNumber() not a number: 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` (Solana mainnet CAIP reference). The crash was in the unified-assets migration selectors in `shared/lib/selectors/assets-migration.ts`, which remap `assetsBalance` onto the legacy EVM controllers. Those selectors filtered EVM accounts, then treated every asset under them as EVM and passed the CAIP chain reference to `decimalToPrefixedHex`. A Solana native asset stored under an EVM account made that call throw and the UI error boundary took over. This PR skips any asset whose CAIP namespace is not `eip155` before the hex conversion, matching the other selectors in the same file. ## **Changelog** CHANGELOG entry: Fixed a crash that occurred when unified asset state included a non-EVM asset on an EVM account ## **Related issues** Fixes: #46636 ## **Manual testing steps** 1. Build and load the extension with unified assets enabled (`ASSETS_UNIFIED_STATE_ENABLED` and the remote flag). 2. Unlock a wallet that has both an EVM account and Solana assets (or state where a Solana native asset is present under an EVM account in `assetsBalance`). 3. Open the home screen. 4. Confirm the wallet home renders and does not show "Your information can't be shown". 5. Confirm ETH / EVM balances still display. <!-- ## **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 - [ ] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches home-screen balance/token selectors on the unified-assets path; the change is narrow defensive filtering with new regression tests, but incorrect filtering could hide or mis-map balances. > > **Overview** > Fixes a wallet crash when unified asset state includes **non-EVM assets (e.g. Solana) on an EVM account** in `assetsBalance`. The unified-assets migration selectors in `assets-migration.ts` already limited work to EVM accounts but still ran every asset through EVM-only steps like `decimalToPrefixedHex`, which throws on Solana CAIP chain references. > > **Account tracker, tokens, and token-balances** migration selectors now **skip assets whose CAIP namespace is not `eip155`** before hex conversion and legacy controller shaping, consistent with other filters in the same module. > > Unit tests cover Solana native/token balances attached to an `eip155:eoa` account and assert only EVM data is emitted without throwing. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 70f5477. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Updated the Basic Functionality migration messaging to match the latest copy from the product/design discussion. - Reworded the SRP migration toast to explain the consolidated Basic Functionality setting and preserve the on/off state. - Reworded the social-login modal to explain profile and wallet-address storage, keep Basic Functionality enabled for social login, and link to the blog post and Privacy Notice. - Changed the modal CTA to “Continue”. - Updated the English and English (UK) locale catalogs and related unit-test expectations. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** 1. Build and launch the extension with the Basic Functionality consolidation feature enabled. 2. Use an SRP wallet that has a pending Basic Functionality migration toast. 3. Verify the toast says the privacy toggles are now one Basic Functionality setting, reflects whether it was turned on or off based on previous settings, and includes the Settings > Privacy link. 4. Open the toast’s Settings > Privacy link and verify it navigates to Privacy settings. 5. Use a social-login wallet with a pending migration modal. 6. Verify the modal explains that the sign-in email or Telegram handle is saved with wallet addresses, says Basic Functionality stays on, includes the blog post and Privacy Notice links, and has a Continue button. 7. Click Continue and verify the modal closes. ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> Not applicable: this PR updates copy in existing UI surfaces. ### **After** <!-- [screenshots/recordings] --> Not applicable: this PR updates copy in existing UI surfaces. ## **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] > **Low Risk** > Copy, localization, and a non-functional external link in migration UI only; no changes to privacy logic or data handling. > > **Overview** > Updates **Basic Functionality migration** user-facing copy to match consolidated privacy settings and social-login behavior. > > The **migration toast** now explains that former privacy toggles are a single **Basic Functionality** setting, still reflects on/off from prior preferences, and adds a **Learn more** link (blog post) as a third placeholder in `basicFunctionalityMigrationToastDescription`. The **social-login modal** copy is rewritten around Google/Apple/Telegram profile linkage, that Basic Functionality stays on for those accounts, and shorter links to the blog and Privacy Notice; its title and general modal title strings change, and the primary action label switches from **Accept and close** to **Continue**. > > **English** and **en_GB** catalogs carry the full message updates plus the new `basicFunctionalityMigrationToastLearnMore` key; other locale files mainly extend the toast string **description** to document the new `$3` placeholder. Tests assert the blog link and updated button wording. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b34425a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…of 3) (#46149) ## **Description** Per MetaMask content guidelines: UI strings shouldn't ask for favors. Use direct imperative language instead. Updated strings in `app/_locales/en/messages.json`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: N/A ## **Manual testing steps** 1. Load the extension in a browser. 2. Navigate to any screen that displays the updated strings. 3. Confirm the updated wording appears correctly with no layout regressions. ## **Screenshots/Recordings** ### **Before** N/A — locale string changes only. ### **After** N/A — locale string changes only. ## **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** > Copy-only locale updates with no behavioral or security impact; minor UX wording changes in error and confirmation surfaces. > > **Overview** > Updates **English UI copy** in `app/_locales/en/messages.json` and `app/_locales/en_GB/messages.json` to follow MetaMask content guidelines: drop favor-asking phrasing in favor of direct imperatives. > > Across notifications, onboarding, perps, ramps, rewards, security, and Shield flows, **"Please try again"** (and similar) becomes **"Try again"** or shorter variants (e.g. **"Wait and try again"**). Validation hints drop **"Please"** (**"Enter a valid URL"**, chain ID, email). Other tweaks include **`pleaseConfirm`** → **"Confirm"**, tighter error/retry lines, and a straight apostrophe in **`rampsServiceDisruptionDescription`**. > > No application logic or message keys change—only displayed strings for those locales. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a59cdc9. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…of 3) (#46150) ## **Description** Per MetaMask content guidelines: UI strings shouldn't ask for favors. Use direct imperative language instead. Updated strings in `app/_locales/en/messages.json`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: N/A ## **Manual testing steps** 1. Load the extension in a browser. 2. Navigate to any screen that displays the updated strings. 3. Confirm the updated wording appears correctly with no layout regressions. ## **Screenshots/Recordings** ### **Before** N/A — locale string changes only. ### **After** N/A — locale string changes only. ## **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** > Copy-only localization updates with no behavioral or security impact; minor UX wording change in error and guidance strings. > > **Overview** > Aligns **English (`en`) and British English (`en_GB`)** copy with MetaMask content guidelines by replacing polite “please …” phrasing with **direct imperatives** across Transaction Shield claims/coverage, swap/smart-tx errors, Snaps privacy text, notifications, unlock, Trezor, terms-of-use, and related UI strings. > > Examples of the pattern: validation hints like “Please enter …” become “Enter …”; retry/support lines drop “Please” (e.g. “Try again later”, “reach out to $1”); payment-pause and reimbursement warnings use “Update …” / “Contact support …” instead of “Please update/contact …”. **`unlockPageIncorrectPassword`** is reworded to “Password is incorrect. Try again.” > > No code or logic changes—only **`message` text** in the two locale JSON files. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5622820. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…6151) ## **Description** Per MetaMask content guidelines: "successfully" is redundant — the success state is implied. Updated strings in `app/_locales/en/messages.json`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: N/A ## **Manual testing steps** 1. Load the extension in a browser. 2. Navigate to any screen that displays the updated strings. 3. Confirm the updated wording appears correctly with no layout regressions. ## **Screenshots/Recordings** ### **Before** N/A — locale string changes only. ### **After** N/A — locale string changes only. ## **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** > Copy-only locale edits with no logic or security impact; minor UX wording change in English locales only. > > **Overview** > Updates **English (`en`) and British English (`en_GB`)** locale copy so success toasts and confirmations no longer say **"successfully"**, per MetaMask content guidelines (success is already implied by the UI state). > > Wording changes cover dapp disconnect flows, hardware wallet reconnect, token/network/NFT add-edit-remove, token import, generic result pages, and Perps TP/SL update toasts—e.g. `"All dapps successfully disconnected."` → `"All dapps disconnected."` and similar shortenings. **No message keys or code paths change**, only the `message` strings in `app/_locales/en/messages.json` and `app/_locales/en_GB/messages.json`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 90df98e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…e str… (#46645) …ings (#46151)" This reverts commit ee33105. That PR broke our e2e tests, leading to a blocked ci. Reverting the PR, so the PR owners can fix the tests within their changes <!-- 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: ## **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** > English locale copy only with no logic, API, or behavior changes. > > **Overview** > Reverts the prior copy change that stripped **"successfully"** from several extension success messages in **`app/_locales/en/messages.json`** and **`app/_locales/en_GB/messages.json`**. > > Affected user-facing strings include dapp disconnect confirmations, hardware wallet reconnect success, token/network/NFT add-edit-import toasts, NFT removal, generic result-page success, and Perps TP/SL update success. Wording is updated only; message keys and placeholders (e.g. `$1`) are unchanged. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 42e3304. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ngs (… (#46660) …batch 3 of 3) (#46150)" This reverts commit 54bf455. <!-- 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: ## **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** > User-visible string changes only in locale JSON; no application logic, auth, or data handling is modified. > > **Overview** > Reverts the prior copy edit that stripped **"Please"** from many user-facing strings, updating **`app/_locales/en/messages.json`** and **`app/_locales/en_GB/messages.json`** in parallel so both English variants stay aligned. > > The touched copy spans **Transaction Shield** (claims validation, coverage paused alerts, membership payment tooltips), **Snaps** install privacy text, **state log** errors, **swap** failure/expired-quote messaging, **Terms of Use** footer, **token search** errors, **Trezor** desktop setup, **MetaMask notifications** enable/disable errors, **watch Ethereum accounts** beta copy, and the **window.web3** shim notice—mostly by prefixing imperatives with "Please" or softening follow-up instructions (e.g. "Contact support" → "Please contact support if you need…"). > > Separately, **`unlockPageIncorrectPassword`** is reworded from "Password is incorrect. Try again." to **"Incorrect password. Try again."** > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 52fcb04. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ngs (… (#46663) …batch 2 of 3) (#46149)" This reverts commit dab5f03. <!-- 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: ## **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** > Copy-only locale updates with no functional or security impact; risk is limited to UI string length or tone consistency in en/en_GB. > > **Overview** > Reverts the prior content change that stripped **"please"** from many extension strings, restoring more polite copy in **`app/_locales/en/messages.json`** and **`app/_locales/en_GB/messages.json`** only. > > Updates are wording-only across error/retry toasts, validation hints, and empty-state guidance—e.g. **"Try again" → "Please try again"**, **"Enter a valid URL" → "Please enter a valid URL"**, **"Confirm" → "Please confirm"**—touching areas such as notifications, onboarding IPFS validation, Perps, ramps, rewards, security password errors, and Shield claim flows. No logic or key renames; only `message` text changes. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 725d70e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…46592) <!-- 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** Converts the remaining legacy JavaScript migrations to TypeScript as part of the incremental TS migration effort. Runtime behavior is unchanged. Existing quirks are preserved deliberately, including migration 017's legacy boolean-to-status comparison and migration 026's rejection on error. <!-- 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: MetaMask/MetaMask-planning#7370 ## **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 run on every persisted-state upgrade via the migration loader and touch vault, preferences, network, and transaction data, but the diff is primarily typing and test hardening with stated runtime parity. > > **Overview** > This PR **TypeScript-converts** the early legacy migration stack (002 through 026), the shared **`fail-tx`** helper, and the migration **loader** (`index.ts`), without intending to change upgrade behavior. > > Each migration now imports **`LegacyMigration`** / **`MigrationState`** from the migrator, uses local **`LegacyState`** (and related) types for the old on-disk shapes, and exports with **`satisfies LegacyMigration`**. Catch blocks use **`(err as Error).stack`** instead of untyped `err.stack`. Known legacy quirks stay explicit (e.g. migration **017** keeps its boolean/status comparison via **`@ts-expect-error`**; migration **026** still **rejects** on transform errors). > > The loader is renamed from **`index.js`** to **`index.ts`**, typed as **`Migration[]`**, and still loads migrations via static **`require()`** for interop. **AI PR analyzer** critical-file config and the TS migration dashboard list are updated to match the new paths. > > Migration **tests** (021–026, **`migrations.test.ts`**, **`023.test`**) gain typed fixtures, **`MigrationInput`** aliases, and stricter assertions (e.g. **`toBeUndefined()`** / **`toBeDefined()`**). Deleted **`.js`** counterparts include **002**, **026**, **`fail-tx`**, and **`023.test.js`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a6c0003. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Recreates the non-session-sharing improvements of the upstream PR #45713 without the shared-Chrome-session infrastructure (see WPN-1881). Part of a series of parallel, self-contained Tron E2E PRs (#46113–#46118). - Adds `tests/account-activity/tron/{tron-activity-status,tron-activity-types}.spec.ts` — first E2E coverage for Tron activity history (pending/failed states; approve/send/receive/swap/bridge presentations). - Adds `tron-activity.flow` (`landOnTronActivityHome`, `openTronTransactionDetails` with a route-close wait for the details back button), `ActivityTab.clickActivityByText` / `checkTransactionActivityNotPresentByText`, and transaction-details helpers. - Adds `FixtureBuilderV2.withBridgeStatusController` and a `tronBridgeHistoryItem` fixture so bridge txs are reclassified via `BridgeStatusController.txHistory` keyed by TronGrid `txID`. - Includes an EVM-activity filter case (EVM send hidden under Tron-only filter, visible under all-networks) via a dynamic `v4/multiaccount/transactions` mock; fixture transactions live in `transactions.raw` with `valueTransfers[].amount` in base units so amounts render correctly. - Includes shared Tron helpers this suite needs (readiness-based `selectTronNetwork` in `tron-network.flow`, select-network-modal `closeIfOpen`); these are intentionally duplicated across the sibling PRs (byte-identical copies). Local verification: `yarn build:test` + `test:e2e:single` on chrome — 1/1 and 2/2 passing. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: Part of WPN-1881. Parallel sibling PRs: #46113 (network), #46114 (account), #46115 (assets), #46116 (send), #46117 (swap). Recreates #45713 without session sharing. ## **Manual testing steps** 1. Check out the branch, `yarn install && yarn webpack:tsc && yarn build:test`. 2. `node test/e2e/run-e2e-test.js --browser chrome test/e2e/tests/account-activity/tron/tron-activity-status.spec.ts` (expect 1 passing) and `... test/e2e/tests/account-activity/tron/tron-activity-types.spec.ts` (expect 2 passing). ## **Screenshots/Recordings** <!-- Not applicable: new E2E coverage with no user-facing UI change. --> ## **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.
…ion and improve error handling (#46340) ## **Description** When the extension holds no WebHID grant for a Ledger device, the DMK transport's `listenToAvailableDevices()` never emits, so discovery only failed after `LEDGER_DEVICE_DISCOVERY_TIMEOUT_MS` (15s). An empty `navigator.hid.getDevices()` result is definitive, so there is nothing to wait for. - **Fast-fail discovery** — `#assertPermittedDevicePresent()` probes `getDevices()` first and rejects immediately when no Ledger device is present. - **Shared error** — `createNoPermittedDeviceError()` is now used by both the fast-fail probe and the timeout path in `normalizeDiscoveryError`, so both emit identical copy and classification. - **`requestWebHidDevices()`** — new grant helper returning devices filtered by wallet type, with `requestWebHidPermission()` as a boolean wrapper. Fixes a latent bug where `ledger-info.tsx` compared `device.vendorId` (number) to `LEDGER_USB_VENDOR_ID` (the string `'0x2c97'`). - **De-duplication** — `ledger-info.tsx` and `connectHardware()` now share the helper and `isInE2eTest()` instead of inlining their own `requestDevice` call and E2E check. - **App-closed errors surface as errors** — `getConnectionStateFromError` maps `DeviceStateEthAppClosed` to the error state, consistent with the rest of the switch. The awaiting-app UX is unchanged, driven by `DeviceEvent.AppNotOpen`. ## **Changelog** CHANGELOG entry: Improved Ledger connection feedback by failing fast with a clear error when no permitted Ledger device is found, instead of waiting for the discovery timeout. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUL-2206 Related: https://consensyssoftware.atlassian.net/browse/MUL-2221 Related: https://consensyssoftware.atlassian.net/browse/MUL-2230 ## **Manual testing steps** 1. Run the extension and load `dist/chrome` as an unpacked extension. 2. Connect a Ledger with a WebHID grant in place — verify connecting still succeeds. 3. Revoke the grant (`chrome://settings/content/hidDevices`, or a fresh profile). 4. Start the Ledger connection flow from a confirmation's Ledger info step. 5. Verify "No permitted Ledger device found" appears promptly (not after ~15s) in the error state. 6. Verify the device picker still opens and lists Ledger devices when no grant exists. 7. With the Ledger on the dashboard, trigger an Ethereum-app transaction and verify the app-closed state is shown as an error. ## **Screenshots/Recordings** N/A ## **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 Ledger connection timing, WebHID grant entry points, and error-to-UI mapping during hardware signing flows (including automatic send-bundle retries), where regressions would block or confuse device signing. > > **Overview** > Ledger DMK discovery now **fails immediately** when `navigator.hid.getDevices()` shows no permitted Ledger device, instead of waiting for the discovery timeout. The offscreen handler shares **`createNoPermittedDeviceError()`** with the timeout path so both surface the same **"No permitted Ledger device found"** error. > > WebHID permission is centralized in **`requestWebHidDevices()`** (with **`requestWebHidPermission()`** as a boolean wrapper), replacing duplicated `requestDevice` logic in **`ledger-info`**, **`connectHardware`**, and related tests— including a fix for comparing **`vendorId`** to the string **`LEDGER_USB_VENDOR_ID`**. E2E detection uses shared **`isInE2eTest()`**. > > Hardware-wallet **connection errors** no longer go through **`getConnectionStateFromError`**; structured errors always become **`ConnectionState.error(error)`**. For **swap/send signing**, **`DeviceStateEthAppClosed`** no longer drives failed/disconnected signature states: **`getHardwareWalletSignatureErrorEvent`** returns **`null`**, connection monitoring ignores it, and **send-bundle** flows **auto-restart** after **`ensureDeviceReady()`** via **`handleRetry({ skipConnectionCheck: true })`** when the Ethereum app was closed mid-submit. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit eb65be7. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adds a Chrome-first exact storage-byte measurement path for sampled split-state write telemetry. **Reason:** The existing follow-up PR reduces measurement cost by estimating controller size with `JSON.stringify(value).length`. This PR explores another approach using `getBytesInUse` so sampled writes can report actual extension-storage quota bytes when the browser supports it. **Solution:** - Add an optional `BaseStore.getBytesInUseByKey(keys)` capability. - Implement that capability in `ExtensionStore` using one `browser.storage.local.getBytesInUse(key)` call per controller key. - After a successful sampled persist, await per-key storage-byte measurement inside the existing exclusive persist lock. - Fall back to the string-length estimate when `getBytesInUse` is unavailable or fails. - Emit `sizeMeasurementSource` so Sentry can distinguish exact storage bytes from fallback estimates. This is intentionally stacked on top of #46423. ## **Changelog** CHANGELOG entry: null ## **Related issues** Related: #46423 Related: #44812 ## **Manual testing steps** 1. Ensure `.metamaskrc` has `SENTRY_DSN_DEV` set and `MANIFEST_OVERRIDES=.manifest-overrides.json`. 2. Set `_flags.remoteFeatureFlags.sentry.persistenceWriteSampleRate` to `1` in `.manifest-overrides.json`. 3. Run `yarn start --sentry`, load the extension, and opt in to MetaMetrics. 4. Trigger a split-state write, for example by unlocking and changing a wallet setting. 5. In Sentry test-metamask, open `State Persist` traces. 6. Confirm spans include `state.write.size_measurement_source`. 7. On Chrome, confirm the value is `storage_get_bytes_in_use` and byte attributes are present. 8. On unsupported browsers, confirm telemetry still works with `json_string_length_estimate`. ## **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** > Changes affect sampled telemetry only after successful persists, with explicit fallbacks and tests; persistence success path is guarded so measurement errors cannot fail writes. > > **Overview** > Sampled **split-state write telemetry** can now report **actual extension-storage byte counts** (Chrome `storage.local.getBytesInUse`) instead of relying only on `JSON.stringify` length estimates. > > **PersistenceManager** awaits optional `getBytesInUseByKey` after a successful sampled persist (still inside the write lock), sums per-controller bytes, and emits **`sizeMeasurementSource`** (`storage_get_bytes_in_use` vs `json_string_length_estimate`). Measurement failures or missing APIs fall back to the JSON estimate without failing the write. **`SplitStateWriteEvent`** drops redundant **`controllerKeys`**; controller identity comes from **`bytesByController`**. > > **ExtensionStore** implements **`getBytesInUseByKey`** on **`BaseStore`**. **Sentry** spans gain **`state.write.size_measurement_source`**; controller count/list attributes are derived from the byte map. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e644a2f. 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> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## **Description** `Swap Quote Fetch` (added in #45667) was missing from `DEFAULT_TRANSACTION_SAMPLE_RATES`, so the `tracesSampler` resolved it through its generic fallbacks instead of a pinned per-name rate. The consequence was not just "inherits the global rate". `getTransactionSampleRate` resolves an unlisted name through the `parentSampled` branch, which returns `1` on a positive parent decision: ```typescript if (typeof parentSampled === 'boolean') { return parentSampled ? Math.min(1, ceiling) : 0; } ``` `trace()` marks a span started under an active parent as `forceTransaction` (`shared/lib/trace.ts`), and `forceTransaction` causes Sentry to re-consult the sampler — which the repo's integration test already asserts ("re-consult the sampler for forced transactions... so a throttled name is dropped even nested under a sampled parent"). So a quote fetch nested under a sampled parent (e.g. a `pageload` span) could be recorded at full rate rather than the global ~0.5%. **Solution:** register the name in `DEFAULT_TRANSACTION_SAMPLE_RATES` with a pinned `0.001` starting rate, matching the Perps precedent. A listed name stops at tier 2 of the sampler and never reaches the `parentSampled` branch, so its rate is deterministic and nesting-independent. It also becomes tunable via the existing remote `sentry.transactionSampleRates` flag. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: null ## **Manual testing steps** 1. Load the extension and note the Sentry sample rate (default `0.005`; `tracesSampleRate: 1` in `.manifest-overrides.json` makes the outcome deterministic). 2. Navigate to the unified Swaps/Bridge view and request a quote. 3. Confirm `Swap Quote Fetch` spans still emit and carry the correct `op:bridge.data_fetch` and `result` attribute. 4. Confirm the interval between recorded `Swap Quote Fetch` spans widens to roughly 1-in-1000 (or tune `sentry.transactionSampleRates` to `1` for the name and confirm they all emit). Unit coverage that pins the behavior: ```bash yarn jest app/scripts/lib/sentry-traces-sampler.test.ts app/scripts/lib/sentry-traces-sampler.integration.test.ts --no-coverage ``` <!-- ## **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** > Changes only Sentry trace sampling configuration and tests; no product logic, auth, or data handling. > > **Overview** > **Swap Quote Fetch** Sentry transactions are now pinned to a **0.1%** (`0.001`) per-name sample rate via `SWAP_QUOTE_FETCH_SAMPLE_RATE` and an entry in `DEFAULT_TRANSACTION_SAMPLE_RATES`, matching the existing Perps high-volume pattern. > > Previously this name was unlisted, so nested quote fetches under a sampled parent could hit the `parentSampled` path and be recorded at **full rate** (debounced typing + `forceTransaction` re-sampling). The pinned rate applies even when `parentSampled: true`, and the name can still be tuned through remote `sentry.transactionSampleRates`. Unit coverage asserts both behaviors. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b9cdb68. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** This investigation started with the impact of [EIP-2780](https://eips.ethereum.org/EIPS/eip-2780) on Smart Transaction cancellation variants. EIP-2780 replaces the flat intrinsic transaction cost, so the cancellation path's hardcoded 21,000 gas limit needs to go: a self-transfer may have a different intrinsic cost, and delegated senders can incur additional runtime work. While tracing that path, we found that Extension cannot execute it at all. Rather than redesigning gas estimation for unreachable behavior, this PR removes the dead cancellation variant altogether. Smart Transaction publication retained a cancellation-aware branch that could rewrite a transaction into a self-transfer with empty data and force its gas limit to 21,000. The branch was unreachable: the publish hook had one fee-signing call, that call always passed `false`, and the resulting submission always supplied an empty `signedCanceledTransactions` array. This PR therefore: - removes `isCancel` from `#createSignedTransactions` and `#applyFeeToTransaction`; - removes the hardcoded 21,000 gas selection and the `to = from` / `data = '0x'` mutation; - removes the now-unused `CANCEL_GAS_LIMIT_DEC` constant; - omits `signedCanceledTransactions` so the Smart Transactions controller uses its optional parameter default; - preserves pre-signed, fee-signed, and batch publication behavior; - updates `@metamask/transaction-controller` from `^69.8.0` to `^70.1.0`; and - uses LavaMoat policies generated by `@metamaskbot update-policies` on the CI operating system, avoiding platform-dependent macOS policy output. The controller upgrade resolves to 70.1.0, whose package is ESM, declares Node `^22.14.0 || ^24`, and exposes its compiled entry point and declarations through package exports. Existing Jest partial mocks were updated to preserve the package's live export property descriptors instead of spreading and eagerly evaluating them during circular module initialization. Extension TypeScript and focused Jest validation pass with it; MetaMask Bot generated the final Linux LavaMoat policies in [`fb7a815`](fb7a815). ### **Why the removed code is verifiably dead without manual testing** The dead-code conclusion follows from the local call graph and data flow, rather than from an inability to reproduce the behavior manually: 1. `#createSignedTransactions` was private and had exactly one call site in `SmartTransactionHook`. 2. That call site always passed the literal `false` as `isCancel`. 3. `#createSignedTransactions` only forwarded that value to the private `#applyFeeToTransaction` helper. 4. Every cancellation-specific operation—forcing gas to 21,000, setting `to` to `from`, and emptying `data`—was guarded by `isCancel`. 5. No path read `tradeTxFees.cancelFees`; every submission constructed `signedCanceledTransactions` as the literal empty array. Because private methods have no external call surface and the only incoming value was a constant `false`, the cancellation branch could not execute for pre-signed, fee-signed, or batch publication. This is statically inspectable and does not depend on relay behavior, feature flags, timing, or network state. The focused regression test strengthens that proof: its fee response now contains non-empty `cancelFees`, yet it asserts that `approveTransactionsWithSameNonce` is invoked exactly once with only the trade transaction. Submission tests for pre-signed, fee-signed, and batch paths also assert that `signedCanceledTransactions` is absent. ### **Git history analysis** The history distinguishes when the cancellation behavior was introduced from when it became dead: - The cancellation signing implementation first appears in draft publish-hook commit [`143053e`](143053e) on January 22, 2024. It actively signed both `tradeTxFees.fees` with `isCancel = false` and `tradeTxFees.cancelFees` with `isCancel = true`. - The behavior reached the main product path in [#23155](#23155), merged as [`f5ef4c7`](f5ef4c7) on April 10, 2024. That change introduced `CANCEL_GAS_LIMIT_DEC` and retained the active cancellation-fee signing call. - The branch became dead in [#26251](#26251), merged as [`590f0a9`](590f0a9) on August 21, 2024. To support hardware-wallet/pre-signed publication and "sign a transaction only once," that change removed the `cancelFees` signing call and replaced its output with `signedCanceledTransactions: []`, but left the `isCancel` helper branch and 21,000 constant behind. This PR removes the residue left by #26251; it does not remove behavior that has remained reachable since #26251 merged. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [CONF-1991](https://consensyssoftware.atlassian.net/browse/CONF-1991) Related client implementation: [MetaMask Mobile #36487](MetaMask/metamask-mobile#36487) Related: [CONF-1998](https://consensyssoftware.atlassian.net/browse/CONF-1998), [CONF-2002](https://consensyssoftware.atlassian.net/browse/CONF-2002) Blocks: [CONF-2003](https://consensyssoftware.atlassian.net/browse/CONF-2003) ## **Automated verification** - `yarn install` — passed with existing peer-dependency warnings. - `yarn lint:lockfile:dedupe:fix` — passed; existing 70.x ranges deduplicated to transaction-controller 70.1.0. - `yarn allow-scripts auto` — passed; no configuration changes required. - Local `yarn lavamoat:auto` and `yarn build:test` validation passed before rebase, but the platform-dependent macOS policy output was intentionally discarded; MetaMask Bot generated and committed the final policies on Linux CI. - Final Linux CI LavaMoat validation — webpack build, MV2, and MV3 policy checks passed after the bot commit. - Final post-rebase Smart Transaction and transaction-controller partial-mock validation — 5 suites and 127 tests passed. - `yarn lint:tsc` — passed after the ESM mock compatibility update. - `yarn lint:changed:fix` — passed. - `yarn lint:tsc` — passed. - `yarn lint:json` — passed. - `yarn lint:lockfile` and `yarn lint:lockfile:dedupe` — passed. - `yarn circular-deps:check` — passed. - Attributions were regenerated for both the original and updated dependency graphs; the generated outputs were identical, so this package update requires no `attribution.txt` change. ## **Manual testing steps** 1. Run the Extension with Smart Transactions enabled and unlock a software wallet on a supported network. 2. Submit a Smart Transaction that requires MetaMask to apply relay-provided fees, then verify it is published and receives a transaction hash. 3. Submit a pre-signed Smart Transaction, such as through the applicable hardware-wallet flow, and verify it is published without a behavior change. 4. Submit a supported transaction batch from a batch-capable test dapp and verify each transaction receives its expected result. 5. While inspecting the relay submission, verify only trade transactions are signed and submitted: the original gas, recipient, and data are preserved, and no cancellation transaction array is sent. <!-- ## **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 (no new public API) - [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. [CONF-1991]: https://consensyssoftware.atlassian.net/browse/CONF-1991?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Removes statically unreachable cancellation code; observable publish behavior for trade, pre-signed, and batch Smart Transactions stays the same. > > **Overview** > Removes unreachable Smart Transaction **cancellation** signing from the Extension publish hook. Fee application no longer branches on `isCancel`, does not force a 21,000 gas self-transfer with empty `data`, and drops the unused `CANCEL_GAS_LIMIT_DEC` constant. > > Submissions now omit `signedCanceledTransactions` so the controller relies on its optional default; **trade-only** signing via `tradeTxFees.fees` is unchanged for pre-signed, fee-signed, and batch paths. > > Tests were tightened to use non-empty `cancelFees` in mocks and assert `approveTransactionsWithSameNonce` runs once and submit payloads never include `signedCanceledTransactions`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d804ca6. 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** > Messenger changes expand account-tree and snap-account access to account listing/removal and keyring removal paths; incorrect delegation could affect wallet/account lifecycle, though changes are permission wiring aligned with upstream controllers. > > **Overview** > This PR updates **accounts-related controller packages** and wires the extension to their new messenger and dependency requirements. > > **Account tree and snap account messengers** grant additional delegated actions/events required by the bumped `@metamask/account-tree-controller` and `@metamask/snap-account-service` versions— including listing accounts (`AccountsController:getAccounts` / `getState`), removing wallets and keyring accounts (`MultichainAccountService:removeMultichainAccountWallet`, `KeyringController:removeAccount`), and reacting to `AccountsController:accountsAdded` / `accountsRemoved`. > > **Rewards authentication** adds an explicit TypeScript cast on the `siwe` argument passed to `KeyringController:signPersonalMessage`, working around a temporary type mismatch between older `detectSIWE` from `@metamask/controller-utils` and the keyring controller’s SIWE types until `controller-utils` is upgraded. > > **LavaMoat webpack policies** (all MV2/MV3 variants) are regenerated to match the new nested package graph— notably scoped `@metamask/keyring-controller` and `@metamask/utils` entries, `console.error` for account-tree-controller, and related allowance tweaks across controllers that depend on the bumped stack. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4c6824c. 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>
…irectly by URL (#46547) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## **Description** Opening a MetaMask page as the first history entry (new window, pasted URL, bookmark) made the in-app Back arrow call navigate(-1) and leave the extension. This is the same issue as #44590, but it also showed up on Money, Send, Asset, Activity details. Perps is also affected but I will make changes separately as they are more complex. `useInAppBack` now treats React Router’s `location.key === 'default'` or `state.fromFreshTab` as “no in-app history.” In that case the in-app Back button replaces the current entry with an explicit in-app fallback. If there is in-app history, it still goes back one step. Browser Back is unchanged. Fallbacks: - Money (activity, earn, how-it-works, transaction details) → Money home - Send / Asset → wallet home - Activity details → activity home ## **Changelog** CHANGELOG entry: Fixed the back arrow navigating outside of MetaMask when pages are opened directly from a URL ## **Related issues** Fixes: #46496 ## **Manual testing steps** ### Money 1. Open the browser and go to any page 2. Paste a Money activity, earn, how-it-works, and a Money transaction details URL, e.g. "#/money-home/earn" 3. Tap in-app Back on each. Confirm you land on Money home, still inside MetaMask. 4. From Money home, open the same screens in-app, then Back. Confirm you return to the previous Money/home screen. ### Assets 1. Open the browser and go to any page 2. Paste a deep link, e.g. https://link.metamask.io/asset?assetId=eip155:1/erc20:0x6B175474E89094C44Da98b954EedeAC495271d0F (continue through the interstitial if shown) 3. On the asset page, click the back arrow 4. Verify you land on the MetaMask home page instead of the previous website 5. Regression check: open MetaMask normally, click a token in the list, press the back arrow — verify you return to the token list as before ### Send 1. Open the browser and go to any page 2. Paste the Send flow URL. 3. Tap in-app Back. Confirm you land on wallet home. 4. Start Send from home, then Back. Confirm you return to the previous in-app screen. ### Activity details 1. Open the browser and go to any page 2. Paste a generic transaction details URL (/tx-details/... or equivalent). 3. Tap in-app Back. 4. Bottom nav on: confirm you land on /activity. 5. Bottom nav off: confirm you land on home with the Activity tab (/?tab=activity). 6. Open the same details from Activity, then Back. Confirm you return to the activity list/tab you came from. ## **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_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-13eec30d-e9d2-42c9-ac02-cea6bf80d43a?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-13eec30d-e9d2-42c9-ac02-cea6bf80d43a&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Amélie <ameliejyc@users.noreply.github.com>
…led to fetch account'` (#46670) <!-- 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 console error also appears in the Edit Accounts test, WE have a bug ticket opened here: #46623 Temporarily ignore the error like in this other PR #46624 <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** 1. Ci should pass ## **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** > Test-only change that suppresses a known console error during e2e; no production behavior is modified. > > **Overview** > The **Edit Accounts Permissions** e2e test now passes `ignoredConsoleErrors` into `withFixtures` so a known **`[PerpsStreamManager] Failed to fetch account`** console message does not fail the run. > > This mirrors the temporary workaround from PR #46624 while **#46623** tracks the underlying issue; a short comment in the spec points reviewers to that ticket. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c2885ac. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…3.50.0 (#46641) <!-- 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 social-login Basic Functionality migration modal showed two body blocks with a large gap: the explanation, then “Read more in our blog post and Privacy Notice.” This renders those two existing strings as one paragraph so the layout matches the intended notice design. Copy and links are unchanged. ## **Changelog** CHANGELOG entry: Combined the social login Basic Functionality update notice into a single paragraph. <!-- ## **Related issues** Fixes: --> ## **Manual testing steps** 1. Run the extension and unlock a **social login** wallet (Google, Apple, or Telegram). 2. Trigger the Basic Functionality social migration modal (consolidation notice scheduled as modal). 3. Confirm the explanation and “Read more in our blog post and Privacy Notice.” appear as **one** paragraph, not two stacked blocks. 4. Confirm **blog post** and **Privacy Notice** still open the correct URLs. 5. Confirm **Continue** still dismisses the modal. 6. Confirm an SRP wallet still gets the toast, not this modal. ## **Screenshots/Recordings** ### **Before** Two body paragraphs with a gap between the explanation and the “Read more…” line. ### **After** <img width="712" height="792" alt="Screenshot 2026-09-25 at 8 38 02 AM" src="https://github.com/user-attachments/assets/e851cb5b-ef59-4f4b-bd5f-40d587d281c9" /> ## **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 - [ ] 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**
The Buy amount screen header showed **Buy MUSD** instead of **Buy
mUSD**. The title is built by interpolating the token symbol from the
ramps catalog into the `rampsBuyToken` locale string ("Buy $1"), and the
catalog reports the uppercase registry symbol `MUSD` — while the
on-chain token (verified via `symbol()`) and every locale string in the
product use the branded casing `mUSD`.
This PR canonicalizes the symbol through `getTokenDisplaySymbol` from
`@metamask/money-account-utils` — the shared single source of truth that
already exists for exactly this registry-vs-branded casing problem — at
every Buy flow display site (build-quote header, complete-buy handoff,
payment-method labels, provider-selection quotes, token-selection rows).
It also replaces the stale duplicate `MUSD_TOKEN` constant in
`ui/components/app/musd/constants.ts` with a re-export from the
canonical package, correcting activity rows, the confirmation hero, and
money transaction details displays as well.
Note: `trackTokenSelected` analytics now report `mUSD` for mUSD buys
(previously `MUSD`), matching what users see. Events still carry
`token_caip19`, so dashboards can key by address. A backend fix to
return the branded casing from the token catalog is tracked separately
([TRAM-4050](https://consensyssoftware.atlassian.net/browse/TRAM-4050));
once it lands, the client-side canonicalization becomes a no-op.
## **Changelog**
CHANGELOG entry: Fixed a bug that was causing mUSD to appear as "MUSD"
in the Buy flow headers and labels
## **Related issues**
Fixes:
[TRAM-3972](https://consensyssoftware.atlassian.net/browse/TRAM-3972)
## **Manual testing steps**
1. Run the extension and unlock a wallet on Ethereum Mainnet or Linea.
2. Start the Buy flow for mUSD (token selection → amount screen).
3. Verify the top header on the Buy amount / Build Quote screen reads
"Buy mUSD" (previously "Buy MUSD").
4. Proceed to the payment method and provider selection screens and
verify quote labels show "mUSD".
5. Continue to the provider checkout and return to the completion
screen; verify the token symbol shows "mUSD".
6. Check the token selection list rows and verify mUSD appears as
"mUSD".
## **Screenshots/Recordings**
### **After**
<img width="429" height="854" alt="mUSD-casing"
src="https://github.com/user-attachments/assets/6cdd3d89-6817-4bfe-b234-ad8d27a48e5b"
/>
## **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.
[TRAM-4050]:
https://consensyssoftware.atlassian.net/browse/TRAM-4050?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Display and constant sourcing changes only; behavior is covered by
unit tests and does not touch auth, transactions, or payment logic.
>
> **Overview**
> Fixes **Buy MUSD** headers and labels when the ramps catalog returns
the uppercase registry symbol **MUSD** instead of the branded **mUSD**.
>
> **mUSD metadata** now comes from `@metamask/money-account-utils`:
local `MUSD_TOKEN` in `ui/components/app/musd/constants.ts` is a
re-export (symbol **mUSD**, name **MetaMask USD**), so wallet import and
other mUSD UI stay aligned with on-chain branding.
>
> **Ramps buy flow** routes catalog symbols through new
`getRampsTokenDisplaySymbol` in `ui/pages/ramps/utils/token-display.ts`,
which uses shared `getTokenDisplaySymbol` with the ERC-20 address parsed
from the CAIP-19 asset id. Build quote titles, complete-buy handoff,
payment-method quote labels, provider-selection quotes, and
token-selection list rows all use this helper; token mapping reuses the
same helper and replaces the local asset-id address parser with
`getErc20AddressFromAssetId`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
284c1ce. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#46685) ## **Description** On the Buy token selection page, replaces the "Show all tokens" button with scroll-to-bottom pagination. - The list starts with the catalog's top tokens. Scrolling near the bottom reveals 50 more tokens at a time (`ScrollNearBottom`, a small helper rendered inside the existing `ScrollContainer`), until the full catalog is visible. - Lists too short to scroll keep revealing pages automatically so extra tokens are never unreachable. - Search and network-filter views are unchanged (full filtered list at once). - The info icon explaining disabled tokens was already delivered in #46347 (TRAM-3710/TRAM-3961), so this PR only covers the scrolling half of the ticket. ## **Changelog** CHANGELOG entry: Replaced the "Show all tokens" button on the Buy token selection page with scroll-to-bottom pagination ## **Related issues** [TRAM-3962](https://consensyssoftware.atlassian.net/browse/TRAM-3962) ## **Manual testing steps** 1. Run the extension and open the Buy flow. 2. On the token selection page, confirm the list initially shows the top tokens and the "Show all tokens" button is gone. 3. Scroll to the bottom of the list — verify roughly 50 more tokens appear, and repeat until the full catalog is shown (scrolling further adds nothing). 4. With a region/catalog whose top tokens don't fill the screen, verify the list fills itself with more tokens automatically (no scrollbar needed). 5. Enter a search term and apply a network filter — verify the full filtered list shows at once and scrolling adds nothing. 6. Verify disabled (region-unsupported) tokens still show the info icon and explanation modal. ## **Screenshots/Recordings** ### **After** https://github.com/user-attachments/assets/2d6275c2-ac70-4da1-8c22-35dd4fb27c29 ## **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. [TRAM-3962]: https://consensyssoftware.atlassian.net/browse/TRAM-3962?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [TRAM-3962]: https://consensyssoftware.atlassian.net/browse/TRAM-3962?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only change to ramps token list loading with dedicated unit tests; no auth, payments, or data-layer changes. > > **Overview** > On the Buy **token selection** screen, the footer **"Show all tokens"** control is removed in favor of **scroll-to-load** behavior inside the existing scroll area. > > The list still opens with catalog **top tokens** only; scrolling within ~200px of the bottom appends **50 deduplicated catalog tokens** at a time via a new **`ScrollNearBottom`** helper on **`ScrollContainer`**, until the full catalog is shown. If the first page is too short to scroll, the helper keeps loading pages automatically so tokens are not stuck behind a missing button. > > **Search** and **network filter** modes are unchanged: they still render the full filtered list immediately, with scroll pagination disabled. The **`rampsShowAllTokens`** string is dropped from all locale files, and tests/snapshots cover pagination, no-op scroll, search, filters, and short-list auto-fill. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5091031. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** `applyPatches` in `ui/store/actions.ts` folds background state patches into the Redux store. immer's patch support is a plugin you have to turn on, and the registry is per copy of immer, so someone has to enable it for the copy this file imports. Nobody here ever did. It works by accident: we and the core packages both want immer 9, so yarn dedupes them to one module and `@metamask/base-controller` enables the plugin for us as a side effect. Core is moving to immer 11 (MetaMask/core#10382). Once `base-controller` ships with it, we get a second copy of immer that nobody enables, and every background state update throws. Measured in #46595: **58 e2e jobs red without this change, 64 green with it.** ## **Changelog** CHANGELOG entry: null ## **Related issues** MetaMask/core#10382 Tested by: #46595 ## **Manual testing steps** Normal CI covers current behaviour. For the failure this prevents, see #46595. ## **Screenshots/Recordings** N/A, no UI change. ## **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 - [ ] 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] > **Low Risk** > Single module-load initialization with no intended behavior change today; it hardens the critical background-to-Redux patch path ahead of an immer version split. > > **Overview** > Calls **`enablePatches()`** in `ui/store/actions.ts` on the extension UI’s own **`immer`** import, right before **`applyPatches`** runs during **`updateMetamaskState`**. > > Patch support in immer is opt-in and **per module instance**. **`applyPatches`** already merges background **`Patch[]`** into Redux **`metamask`** state; today that often works only because **`@metamask/base-controller`** enables patches on a deduped shared **`immer@9`**. When core moves to **`immer@11`** (MetaMask/core#10382), the UI can get a second copy with patches never enabled, and **every background state update throws**. > > This makes patch application reliable for the UI regardless of how dependencies dedupe immer. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5903dcc. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
release: sync stable to main for version 13.50.0
## **Description** Users could complete social login and wallet creation, but fail to restore the wallet on another device with: ```text SeedlessOnboardingController - Primary secret data must be of type mnemonic. ``` The issue occurred when the primary SRP metadata was saved remotely but OPRF share persistence failed. The SRP hash was already committed locally, so a retry skipped the remote backup and left the server with incomplete primary SRP data. This PR: - Upgrades `@metamask/seedless-onboarding-controller` from `^10.1.1` to `^11.0.1`, while keeping `@metamask/wallet` at `14.0.1`. - Fixes retry behavior for incomplete TOPRF backups. - Keeps users on the create-password page when wallet setup fails. - Displays a localized error message: “Something went wrong. Please try again.” - Clears the error when the user retries. - Adds unit test coverage for the failure state. ## **Changelog** CHANGELOG entry: Fixed an issue that could prevent social-login users from restoring their wallet on a new device. ## **Related issues** Fixes: [#46631](#46631) ## **Manual testing steps** 1. Open MetaMask in a clean profile and start creating a new wallet using social login. 2. Complete social login and navigate to the create-password page. 3. Use a test failure injection or block the seedless/Toprf backup request, then submit a valid password. - in network tab, block all the url matching `https://node-[1-5].dev-node.web3auth.io/sss/jrpc` as shown in below recording 4. Verify that the user remains on the create-password page and sees: “Something went wrong. Please try again.” 5. Restore the backup request and submit again. - unblock all the network requests 6. Verify that the error clears and successful onboarding continues. 7. In another device (or browser), login with the same social login email 8. Assert the successful rehydration with the same wallet restored. ## **Screenshots/Recordings** ### **Before** <!-- Add a before screenshot/recording if available. --> Silent error causes user's retry failed to backup the new encrypted SRP metadata in the server. Login to new device failed with **missing Primary SRP**, as it was failed during the account creation. https://github.com/user-attachments/assets/75387239-a3be-40f8-b58f-eb923825a5c3 ### **After** <!-- Add an after screenshot/recording showing the inline error state. --> Handle network errors and allow user retry to backup the new encrypted SRP metadata to the server. https://github.com/user-attachments/assets/7ae871cb-7574-4466-b56c-3f3fc0ad6b90 ## **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 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. pulled and built the branch, ran the app, and tested the changed flow). - [ ] 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 seedless onboarding and backup retry paths plus dependency/LavaMoat policy changes around crypto-related controllers, though runtime behavior is mostly improved error handling and a controller bugfix. > > **Overview** > Upgrades **`@metamask/seedless-onboarding-controller`** to **`^11.0.1`** so incomplete TOPRF/OPRF backup failures can be retried correctly instead of leaving remote primary SRP data in a bad state. **LavaMoat** policies across MV2/MV3 build flavors are updated to match the new dependency graph (direct `@metamask/seedless-onboarding-controller` entry and scoped `@metamask/utils` allowances). > > On the **create-password** onboarding step, failed wallet setup no longer silently bounces the flow: the page stays put, **`CreatePasswordForm`** accepts an **`error`** prop and shows the localized “Something went wrong. Please try again.” message, and the error clears when the user submits again. Unit tests cover the new error UI in the form and onboarding page. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 123f0c6. 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>
…cp-13.51.0 (#46668) ## **Description** Money Account could become the pay method for a Perps deposit, and the receive method for a Perps withdraw, without the Money ↔ Perps feature flags being on. Because that route has no quote, fee, or settlement path yet, the confirmation showed no fee or quote details before Confirm, Perps withdraws to Money Account found no quotes, and a confirmed deposit never debited the money account or credited the Perps account. Two paths let it through: 1. `defaultPaySelectedSection` resolved a section for perps / predict types from a shared `default` key, and from the sibling deposit ↔ withdraw key. A value served for the Money Account deposit rollout therefore also made Money Account the default for Perps deposit and withdraw. These directions roll out one at a time, so the confirmation type now has to be named explicitly in the flag. 2. The `payWithOption=money_account` branch in `useDefaultPaySelectedSection` applied the Money Account payment override after checking only the transaction type — no flag check at all. A restored URL or the developer-options button could lock a Perps deposit to Money Account while `enableMoneyAccountTransactions.perpsDeposit` was off, and `PayWithRow` hides the token picker in that state, leaving no way to pick anything else. That condition now lives in `useIsMoneyAccountPerpsNavigation`, which also requires the flag, and every surface that presents the Money Account → Perps flow reads it: the payment override, the pay-with row, the Perps account picker row, the header title, and the footer label. Both gates stay flag-driven, so setting `confirmations_pay_extended.enableMoneyAccountTransactions` still enables the flow for testing and for the eventual rollout. ## **Related issues** Fixes: [CONF-2085](https://consensyssoftware.atlassian.net/browse/CONF-2085) Fixes: [CONF-2086](https://consensyssoftware.atlassian.net/browse/CONF-2086) ## **Manual testing steps** With the Money ↔ Perps flags off (no `confirmations_pay_extended.enableMoneyAccountTransactions` entries for perps): 1. Run the extension with an upgraded money account that holds a balance. 2. Open a Perps deposit confirmation from the Perps UI. 3. Verify the pay-with row defaults to a crypto token, not Money account. 4. Open the "Pay with" modal and verify there is no Money account row. 5. Open a Perps withdraw confirmation and verify the receive token defaults to a crypto token, not Money account. 6. On Money Home, open the transfer sheet and verify the Perps account row is disabled. With `enableMoneyAccountTransactions: { "perpsDeposit": true, "perpsWithdraw": true }` set in `.manifest-overrides.json`: 7. Repeat steps 2 and 4 and verify the Money account row appears in the "Pay with" modal. 8. From Money Home → transfer sheet → Perps account, verify the deposit opens with Money account locked as the source, the title reads "Send to perps", and the footer button reads "Send". 9. Verify Money account only becomes the *default* when `defaultPaySelectedSection` names the type explicitly (for example `{ "perpsDeposit": "money-account" }`); a `{ "default": "money-account" }` entry alone must not default Perps to Money account. <!-- ## **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. [CONF-2085]: https://consensyssoftware.atlassian.net/browse/CONF-2085?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes payment defaults and confirmation UI for Perps/Money flows; mis-flagging could hide pay options or skip Money Account overrides, but behavior stays behind explicit remote feature flags. > > **Overview** > Money Account ↔ Perps was activating without the right remote flags, leaving confirmations without quotes or a way to change funding source. This PR **tightens two gates** and **centralizes** the Money Account → Perps deposit UX behind one hook. > > **`useIsMoneyAccountPerpsNavigation`** now requires `payWithOption=money_account`, a **perps deposit** confirmation, and **`enableMoneyAccountTransactions.perpsDeposit`**. Header title, footer **Send** vs **Add funds**, hidden **Pay with** row, **Perps account picker**, and the payment override in **`useDefaultPaySelectedSection`** all read this hook instead of URL params alone. > > **`useIsMoneyAccountFlagDefault`** no longer infers Money Account from a **`default`** key or a **sibling** deposit/withdraw flag entry; the confirmation **type must be named explicitly**, and availability uses **`selectIsMoneyAccountTransactionEnabled`** per type. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 13f7cdb. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** ### Context Advanced gas modals read their gas limit from the active transaction. The transaction controller now provides a selected-network node estimate for transactions without caller-provided gas following prerequisite PR #46548. ### Problem When the transaction did not yet contain a gas estimate, both the EIP-1559 and legacy advanced gas modals substituted `0x5208` (21,000). That value could be displayed and saved while estimation was loading, had failed, or belonged to an earlier transaction or network state. ### Solution - Initialize both advanced gas modals from the current transaction gas value without fabricating a fallback. - Track the transaction shape and network client that produced the estimate. - Clear stale values and disable gas-limit editing and Save while an estimate is pending or stale. - Preserve manual gas-limit recovery when estimation fails: the input becomes editable, explains the failure, and enables Save after the user supplies a valid value. - Preserve in-progress custom fee edits when the transaction controller refreshes suggested fees. - Link unavailable-status text to the gas input and disabled Save action, and use numeric input mode without number-input behavior. - Keep each advanced modal's markup local; broader modal deduplication is deferred to a separate change. ### Implementation notes `useAdvancedGasLimit` excludes fee fields from its transaction-shape key. This allows users to edit EIP-1559 or legacy fee values without invalidating the gas-limit estimate. Changes to the transaction payload, account, chain, or network client still invalidate an unchanged gas value until a fresh estimate arrives. The modal content is keyed only by that transaction shape, so 10-second gas-fee polling updates do not remount the editor and discard unsaved custom values. Related work: - #46548: wallet and transaction-controller dependency alignment - CONF-1988: native-send max gas estimation - CONF-1989: transaction-aware gas-limit validation - CONF-2003: cross-client integration coverage ## **Changelog** CHANGELOG entry: Fixed advanced gas dialogs showing an incorrect default gas limit when estimation was unavailable. ## **Related issues** Fixes: CONF-2001 ## **Manual testing steps** 1. Start a native-token send on an EIP-1559 network where the selected RPC returns a gas estimate above 21,000. 2. Open the advanced gas modal and verify its gas-limit field displays the transaction estimate rather than 21,000. 3. Edit the EIP-1559 fee values and gas limit, save them, reopen the modal, and verify the custom values are preserved. 4. Repeat the flow on a legacy-fee network and verify the estimated gas limit and custom gas price can be saved. 5. Delay `eth_estimateGas`, start another transaction, and open the advanced gas modal while estimation is pending. 6. Verify the gas-limit field is empty and disabled, the unavailable-status copy is visible, and Save is disabled. 7. Make `eth_estimateGas` fail and verify the gas-limit field becomes editable with the estimation-failure explanation while Save remains disabled. 8. Enter a valid manual gas limit, save, and verify the custom transaction settings are applied. 9. While editing a fee value, leave the modal open for longer than the gas-fee polling interval and verify the unsaved value is not reset. 10. Inspect the gas-limit input and verify it remains `type="text"` with `inputmode="numeric"`. 11. While the modal is open, change the transaction data or selected RPC/network client and verify the previous gas limit is cleared until the updated transaction receives a fresh estimate. ## **Screenshots/Recordings** Screenshots were not captured. The change is visible in transient pending and failed estimation states. ### **Before** The modal displayed 21,000 when the transaction gas estimate was unavailable and could reset in-progress fee edits during polling. ### **After** The modal distinguishes pending estimation from failed estimation, explains unavailable editing, supports manual recovery after failure, and preserves in-progress fee edits. ## **Validation** - `yarn lint:changed:fix` - `yarn lint:tsc` - `yarn lint:json` - `yarn circular-deps:check` - 43 targeted Jest tests across four suites covering advanced gas state, both modal variants, and the gas input ## **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 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 how gas limits are chosen and persisted in advanced confirmation modals, including stale-estimate invalidation and manual recovery after failed estimation. > > **Overview** > Advanced gas modals no longer default the gas limit to **21,000** when the transaction has no estimate. They show an empty, disabled field with new copy (`gasLimitEditingUnavailable`) until MetaMask supplies a fresh limit, and **Save** stays off until a valid limit exists. > > A new **`useAdvancedGasLimit`** hook ties the limit to transaction shape and network client (fee fields excluded so polling fee updates do not wipe in-progress edits). Stale limits clear after payload, RPC, or network changes until a new estimate arrives; after **`eth_estimateGas`** fails, the field becomes editable with the existing failure message so users can enter a manual limit and save. > > **`GasInput`** is now controlled via props instead of reading the confirmation context. EIP-1559 and legacy advanced modals share a new **`AdvancedGasFeeModal`** shell for gas limit UI, disabled states, and accessibility (`inputmode="numeric"`, help text linked to Save when unavailable). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit cd48f1d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…Failed to fetch account' (#46704) <!-- 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 console error also appears in the Edit Accounts test, WE have a bug ticket opened here: #46623 Temporarily ignore the error like in this other PR #46624 #46670 ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** 1. Check ci ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="997" height="91" alt="image" src="https://github.com/user-attachments/assets/69579bf3-1a62-4ae8-b6a3-8234ce1a8334" /> ## **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** > Test-only fixture option change with no production or security impact. > > **Overview** > Adds **`ignoredConsoleErrors`** for `[PerpsStreamManager] Failed to fetch account` on the e2e case that locks the wallet while connected to a dapp, with a comment pointing at issue **#46623**. > > This matches the temporary workaround already used in other specs (e.g. edit-account permissions) so the test does not fail on a known, unrelated console error until the underlying bug is fixed. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit efb4c27. 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? --> The Bridge API now returns the native minimum balance that must stay in the source account on quote.feeData.reserve, e.g. the Stellar reserve for a new trustline ( [va-mmcx-bridge-api#1327](consensys-vertical-apps/va-mmcx-bridge-api#1327)). @metamask/bridge-controller exposes it on V2 quotes ( [MetaMask/core#10241](MetaMask/core#10241)). This PR uses it to warn users before a trade fails. Bump @metamask/bridge-controller to ^81.3.0 (deduped with bridge-status-controller). Native source (XLM): the "use max" reserve banner uses the quote reserve, with a fallback to the existing per-chain minimum. The reserve is never counted as a fee or quote cost. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Added a warning in Swap and Bridge when a Stellar quote requires keeping a minimum XLM balance that the account cannot cover ## **Related issues** Fixes: ## **Manual testing steps** 1. XLM source: enter an amount that leaves less than the quote reserve. The reserve banner shows, and "use max" sets balance - fee - reserve. 2. USDC source, not enough XLM: use an account with less than fee + reserve in XLM (e.g. 0.4 XLM for a new trustline). The "buy more XLM" error shows. 3. USDC source, enough XLM: repeat step 2 with enough XLM. No warning shows. 4. Bitcoin: check that the existing chain-minimum banner still works. ## **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** - [w] 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 pre-submit bridge/swap validation and max-amount math; incorrect reserve handling could block valid trades or miss failed ones, though behavior is covered by new tests and stays UI-side. > > **Overview** > Bumps **`@metamask/bridge-controller`** to **^81.3.0** so the UI can read **`quote.feeData.reserve`** (e.g. Stellar minimum XLM for trustlines) from bridge quotes. > > Bridge validation now **prefers the quote-carried reserve** over static per-chain minimums when computing the **“use max” / insufficient native reserve** banner (`getNativeReserve`, updated **`getActiveQuoteInsufficientNativeReserveError`**). That path applies when the quote includes a reserve, not only on Bitcoin. > > **Gas sufficiency** (`hasSufficientGasForQuote`, including analytics) uses new **`resolveGasCheckMinimumBalance`**: for a **native** source, the quote reserve stays in the reserve banner only (not added to the gas minimum); for a **token** source, native balance must cover **fees plus the quote reserve**, surfacing the “buy more native” error when XLM (or similar) is too low. > > Tests cover quote override on BTC, Stellar native vs USDC sources, and metrics gas checks. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a07c200. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…0 cp-13-52-0 (#47054) - fix: money transaction ids default to 0x0 cp-13-52-0 (#47035) <!-- 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** Deposits paid through MM pay's relay strategy were showing a placeholder hash in the money account details screen of `0x0`. This is due to a placeholder hash being persisted by the transaction controller. This PR adds a helper function called getMoneyActivityTransactionHash which tries to find a legit hash to display, in the case that we see this palceholder hash. It looks for: 1. the transaction's own hash, if it's a valid 32-byte hash; 2. otherwise, the hash of the last required transaction Pay submitted for the deposit (the source leg that actually moved the funds); 3. otherwise, metamaskPay.sourceHash, on the payment token's chain. In the longer term we should fix this in the core package. <!-- 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: don't display 0x0 placeholder hash in money account details screens ## **Related issues** Fixes: N/A ## **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** > Display-only change on the Money transaction details screen with fallback logic covered by tests; no changes to signing, submission, or payment execution. > > **Overview** > Fixes Money transaction details showing the **`0x0`** placeholder for MetaMask Pay relay deposits by resolving a real on-chain hash before display, copy, and block explorer links. > > Adds **`getMoneyActivityTransactionHash`**, which prefers the transaction’s own valid hash, then the last **required** Pay source transaction, then **`metamaskPay.sourceHash`** (with the payment chain). The details page loads the required transaction from the store and **omits** the transaction ID row when nothing valid is available. Unit and page tests cover the placeholder and fallback paths. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4088f01. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> [44b714f](44b714f) Co-authored-by: John Whiles <john.whiles@consensys.net>
Builds ready [9343a9f]
⚡ Performance Benchmarks (Total: 🟢 10 pass · 🟡 0 warn · 🔴 3 fail)
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Cherry-picks (10 commits)
Changelog (113 commits since v13.51.0)
AI Test Plan
Cherry-Pick Scenarios (5)High Risk Scenarios (3)1. Deposit Confirmations (stale Max quote block)Risk Level: HIGH Why This Matters: Cherry-pick 47028 blocks deposits on stale quotes; without this, users could confirm with outdated pricing, causing incorrect deposit amounts. Test Steps:
2. Money deposit transaction IDs (0x0 default regression)Risk Level: HIGH Why This Matters: Cherry-pick 47054 fixes transaction IDs defaulting to 0x0; incorrect IDs break traceability, user trust, and dapp deep links. Test Steps:
3. Perps Controller integration (controller v20.0.0)Risk Level: HIGH Why This Matters: Cherry-pick 46999 updates the perps controller; compatibility issues can break trading flows or misreport positions. Test Steps:
Medium Risk Scenarios (2)1. Send Flow Loader on StellarRisk Level: MEDIUM Why This Matters: Cherry-pick 46930 fixes Stellar missing from the send loader; without it, users may be unable to initiate Stellar sends or see broken UI. Test Steps:
2. Arc USDC balance and details (native asset mapping)Risk Level: MEDIUM Why This Matters: Cherry-pick 46933 shows Arc USDC from the native asset; incorrect mapping misreports balances and can confuse users when sending or reviewing activity. Test Steps:
Release Scenarios (12)High Risk Scenarios (5)1. State Migrations (upgrade path, complex wallet state)Risk Level: HIGH Why This Matters: Multiple migration files changed and new migrations (including fail-tx) were added; broken migrations can cause data loss, corrupted activity, or unusable wallets. Test Steps:
2. Migration resilience (interruption and recovery)Risk Level: HIGH Why This Matters: Interrupted migrations can leave state partially transformed; the new migration utils and modal must safely resume to prevent bricking wallets. Test Steps:
3. Privacy & Analytics (MetaMetrics consent and gating)Risk Level: HIGH Why This Matters: Analytics/Metametrics controllers and consent UI changed; incorrect gating could leak user telemetry without consent. Test Steps:
4. Snaps Permissions (install prompts and restricted methods)Risk Level: HIGH Why This Matters: Permission specifications changed; incorrect prompts or enforcement can expose unintended capabilities or block legitimate Snap functionality. Test Steps:
5. Money/Fiat Onramp deposit confirmation (baseline flow)Risk Level: HIGH Why This Matters: Confirmations and controller logic around deposit flows are sensitive; regressions can cause incorrect deposits or misleading UI states. Test Steps:
Medium Risk Scenarios (7)1. Asset List Network Filter and LabelingRisk Level: MEDIUM Why This Matters: Asset list control bar and filter label logic changed; wrong filters or labels mislead users about where funds are. Test Steps:
2. Account Group Balance accuracy with filtersRisk Level: MEDIUM Why This Matters: Account group balance and filtering logic changed; inaccurate totals can cause user confusion and poor decisions. Test Steps:
3. Static Assets (token/network logos and fallbacks)Risk Level: MEDIUM Why This Matters: Static assets controller changes can break icons; visual regressions erode trust and hinder quick identification of assets. Test Steps:
4. Asset Migration (custom/watched tokens and deduplication)Risk Level: MEDIUM Why This Matters: Shared asset migration selectors changed; incorrect transforms can duplicate, hide, or drop user tokens. Test Steps:
5. MetaMetrics settings page behaviorRisk Level: MEDIUM Why This Matters: Consent UI component changed; mis-synced UI and controller states can cause unintended data collection or missed telemetry. Test Steps:
6. Connected sites and approvals post-migrationRisk Level: MEDIUM Why This Matters: Broad controller and migration changes can break site connections or approvals, disrupting dapp usage. Test Steps:
7. Snaps lifecycle (enable/disable/uninstall) after migrationsRisk Level: MEDIUM Why This Matters: Permission spec and controller changes can leave stale Snap states or permissions, reducing security and stability. Test Steps:
Teams Sign-off StatusSigned off: None yet Awaiting sign-off (10): Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-13T14:33:43.992Z AI generated test plan (JSON): test-plan-13.52.0.json |
Builds ready [217c943]
⚡ Performance Benchmarks (Total: 🟢 8 pass · 🟡 3 warn · 🔴 2 fail)
Bundle Size Diffs [🚨 Warning! Bundle size has increased!]
Cherry-picks (11 commits)
Changelog (114 commits since v13.51.0)
AI Test Plan
Cherry-Pick Scenarios (5)High Risk Scenarios (2)1. Perpetuals (Perps) - Trading and CollateralRisk Level: HIGH Why This Matters: Cherry-pick #46999 updates the perps controller to 20.0.0; controller upgrades can break order placement, margin accounting, and position persistence. Test Steps:
2. Money Deposits - Stale Quote BlockingRisk Level: HIGH Why This Matters: Cherry-pick #47028 fixes blocking deposits when the Max quote is stale; without this, users could submit invalid or mispriced deposits. Test Steps:
Medium Risk Scenarios (3)1. Arc USDC - Asset Details and Balance DisplayRisk Level: MEDIUM Why This Matters: Cherry-pick #46933 fixes Arc USDC details sourced from the native asset; incorrect metadata leads to wrong balances, icons, and potential double counting. Test Steps:
2. Stellar Snap - Send Flow LoaderRisk Level: MEDIUM Why This Matters: Cherry-pick #46930 fixes a missing loader in Stellar send; without it, users may see frozen or confusing states during fee/address resolution. Test Steps:
3. Money Transactions - Missing Transaction ID HandlingRisk Level: MEDIUM Why This Matters: Cherry-pick #47054 fixes defaulting Money transaction ids to 0x0; missing ids previously could crash views or break history rendering. Test Steps:
Release Scenarios (9)High Risk Scenarios (5)1. State Migrations - Full Profile UpgradeRisk Level: HIGH Why This Matters: Large changes across many migration scripts (including new helpers and new migrations 229–230) can corrupt user data or lose accounts/tokens during upgrade. Test Steps:
2. State Migrations - Pending/Failed Transaction HandlingRisk Level: HIGH Why This Matters: New fail-tx migration logic can mislabel or lock transactions, breaking core send/confirm flows after upgrade. Test Steps:
3. Migration Modal Resilience and RecoveryRisk Level: HIGH Why This Matters: A crash or reload during migration can corrupt state; new migration framework changes must safely resume or recover. Test Steps:
4. Analytics/Metametrics Consent (Onboarding and Settings)Risk Level: HIGH Why This Matters: Major refactor around analytics/metametrics (controller and UI changes) can cause consent state regressions that block onboarding or break navigation. Test Steps:
5. Snaps Permissions Prompts and EnforcementRisk Level: HIGH Why This Matters: Changes to snaps permission specifications are security-sensitive; incorrect prompts or enforcement can leak account data or over-grant capabilities. Test Steps:
Medium Risk Scenarios (4)1. Assets Migration and De-duplicationRisk Level: MEDIUM Why This Matters: Selector and migration updates for assets can surface duplicates or lose tokens, causing incorrect balances or confusion. Test Steps:
2. Asset List Network Filter and LabelingRisk Level: MEDIUM Why This Matters: Updated filter components and hooks can mislabel filters or show wrong totals, misleading users about their balances. Test Steps:
3. Account Group Balance AccuracyRisk Level: MEDIUM Why This Matters: Changes to balance aggregation components can yield incorrect totals, directly affecting user trust in displayed balances. Test Steps:
4. Rewards Panel and Claim FlowRisk Level: MEDIUM Why This Matters: Rewards-controller changes can break claim flows or show incorrect eligibility, affecting user funds and trust. Test Steps:
Teams Sign-off StatusSigned off: None yet Awaiting sign-off (8): Generated by AI Test Plan Analyzer (gpt-5) at 2026-10-13T17:59:31.868Z AI generated test plan (JSON): test-plan-13.52.0.json |
There was a problem hiding this comment.
Modern web guidance (UI)
One accessibility issue in the DropdownEditor refactor — details inline.
Chrome extensions (app/)
No new MV3 or service-worker issues flagged in this release diff (background TS migration, offscreen Ledger WebHID probe, and stream cleanup look consistent with existing patterns).
Sent by Cursor Automation: Modern web guidance
| referenceElement={referenceElement} | ||
| position={PopoverPosition.Bottom} | ||
| role={PopoverRole.Dialog} |
There was a problem hiding this comment.
ARIA role mismatch (listbox vs dialog): The trigger correctly exposes a listbox popup (aria-haspopup="listbox", aria-controls={listboxId}), and the menu surface uses role="listbox" / role="option". Wrapping that surface in the legacy Popover with role={PopoverRole.Dialog} makes the floating layer a dialog, which conflicts with the combobox/listbox pattern in modern web a11y guidance (interactive listbox should not live inside a modal dialog landmark).
Suggested fix: Drop the dialog role for this control—e.g. render the positioned surface without role="dialog" so only the inner listbox is exposed—or migrate to a combobox/listbox primitive where the popover panel’s top-level role is listbox (not nested in a dialog). If you keep listbox semantics, follow up with roving tabindex / arrow-key support on options.


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