Skip to content

release: sync stable to main for version 13.39.2 - #44453

Merged
metamask-ci[bot] merged 16 commits into
mainfrom
stable-main-13.39.2
Jul 14, 2026
Merged

metamask-ci[bot] merged 16 commits into
mainfrom
stable-main-13.39.2

Conversation

@sleepytanya

@sleepytanya sleepytanya commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Description

This PR syncs the stable branch to main for version 13.39.2.

Synchronization Process:

Fetches the latest changes from the remote repository
Resets the branch to match the stable branch
Attempts to merge changes from main into the branch
Handles merge conflicts if they occur
File Preservation:

Preserves specific files from the stable branch:

CHANGELOG.md
android/app/build.gradle
ios/MetaMask.xcodeproj/project.pbxproj
package.json
Indicates the next version candidate of main to 13.39.2

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

  1. Go to this page...

Screenshots/Recordings

Before

After

Pre-merge author checklist

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.

Note

Low Risk
Documentation-only changelog and release-link updates; no application code in this diff.

Overview
Prepares 13.39.2 release notes in CHANGELOG.md and refreshes compare links so [Unreleased] tracks v13.39.2...HEAD.

Documents 13.39.2 with a Fixed entry for a Firefox memory leak where closed MetaMask popup windows were retained in memory, increasing extension memory use on each popup open (#44352).

Also adds the 13.39.1 section (Added: Robinhood Chain as a featured network, #44346) and new version anchor links for 13.39.1 and 13.39.2.

Reviewed by Cursor Bugbot for commit 3d015e0. Bugbot is set up for automated code reviews on this repo. Configure here.

metamaskbot and others added 15 commits July 10, 2026 10:42
- chore(assets): add robinhood svg (#44191)

## **Description**

Adds the Robinhood brand SVG asset at `app/images/robinhood.svg` for
upcoming wallet/provider UI usage.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

1. N/A — static asset only; no runtime wiring in this PR.

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
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
- [ ] 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**
> Static SVG only; no logic, imports, or behavior changes in this PR.
> 
> **Overview**
> Adds a new static brand asset at `app/images/robinhood.svg` (60×60
Robinhood icon on lime `#CCFF00` with rounded corners).
> 
> There is **no application wiring** in this PR—the SVG is intended for
follow-up wallet/provider UI work.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c184dad. 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>
[d4ce5e4](d4ce5e4)

Co-authored-by: @gandalfg <36696601+adaOctopus@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…eatured network (#44346)

- feat(networks): add Robinhood Chain as featured network (#44310)

## **Description**

Adds Robinhood Chain (chain ID `0x1237` / 4663) as a featured network in
MetaMask Extension. Users can discover and add Robinhood Chain from the
network list without manually entering RPC details.

Changes in `shared/constants/network.ts`:
- Added `CHAIN_IDS.ROBINHOOD_CHAIN`
- Added `ROBINHOOD_CHAIN_DISPLAY_NAME` and `ROBINHOOD_CHAIN_IMAGE_URL`
- Wired display name, currency (ETH), and image maps
- Added `FEATURED_RPCS` entry with Robinhood mainnet RPC and Blockscout
explorer

## **Changelog**

CHANGELOG entry: Added Robinhood Chain as a featured network

## **Related issues**

Fixes:

## **Manual testing steps**

1. Open MetaMask Extension
2. Click the network selector dropdown
3. Browse the featured/popular network list
4. Verify Robinhood Chain appears with the Robinhood logo and ETH as the
currency symbol
5. Add Robinhood Chain and verify the RPC connects and the block
explorer link works

## **Screenshots/Recordings**

### **Before**

Robinhood Chain not present in featured networks list.

### **After**

Robinhood Chain appears in featured networks list with correct logo, ETH
ticker, and chain ID `0x1237`.

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

## **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**
> Routine featured-network constants and UI list wiring; no changes to
auth, signing, or transaction logic beyond exposing a new default RPC
URL.
> 
> **Overview**
> Adds **Robinhood Chain** (`0x1237`) as a discoverable featured network
so users can add it from the network list without manual RPC setup.
> 
> In `shared/constants/network.ts`, the PR introduces
`CHAIN_IDS.ROBINHOOD_CHAIN`, display name and `robinhood.svg` branding,
and hooks the chain into the usual display name, currency (**ETH**),
network image, and native token image maps. A new `FEATURED_RPCS` entry
points at `https://rpc.mainnet.chain.robinhood.com` and Blockscout at
`https://robinhoodchain.blockscout.com` (custom RPC, no Infura
failover).
> 
> `shared/constants/network.test.ts` expects Robinhood in the featured
RPC chain ID map, and the network list menu snapshots include the
**Additional networks** row for `popular-network-0x1237`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
094a758. 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>
[ea6632b](ea6632b)

Co-authored-by: @gandalfg <36696601+adaOctopus@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ctrl bump (#44357)

- feat: add Robinhood Infura RPC + assets ctrl bump cp-13.39.1 (#44331)
…ps cp-13.39.1 cp-13.40.0 (#44358)

- fix: copy fixes for musd convert and perps cp-13.40.0 (#44332)
…ts for non-EVM search imports cp-13.39.1 cp-13.40.0 (#44362)

- fix(token-management): seed unified assets for non-EVM search imports cp-13.39.1 cp-13.40.0 (#44361)
… leak by avoiding `DocumentPictureInPicture` instantiation in Snow hook cp-13.39.2 (#44401)

- fix: Fix Firefox detatched-window memory leak by avoiding
`DocumentPictureInPicture` instantiation in Snow hook cp-13.39.2
(#44352)

## **Motivation**

On Firefox, every closed MetaMask window (popup, notification, home) is
retained in memory
([#42891](#42891)
and recent internal reports).

- **Rate:** ~70 detached window entries (~105MB, fresh test wallet) per
popup open/close, linear with use. 30 cycles leave **3.56GB** (13.37.0)
/ **3.31GB** (13.38.1) of detached documents, surviving forced GC.
State-heavy wallets multiply every retained document.
- **Mechanism** (heap-graph traced, intervention-tested): Snow's
picture-in-picture hook reads
`win?.documentPictureInPicture?.requestWindow` in every window. The read
lazily instantiates a per-window `DocumentPictureInPicture`, and
Firefox's cycle collector fails to break the instance's
preserved-wrapper cycle after window close, pinning the entire realm.
- **Why now:** Firefox shipped the API in 151 (May 2026). The April-2023
hook was dormant until users auto-updated. The collection failure itself
is a Gecko defect (upstream filing in progress; prior art: [Bugzilla
1902438](https://bugzilla.mozilla.org/show_bug.cgi?id=1902438)), but
this fix does not depend on Mozilla.

## **Description**

Applies the upstream Snow fix
([LavaMoat/snow#171](LavaMoat/snow#171)) as a
Yarn patch: the hook moves from the per-window instance to
`DocumentPictureInPicture.prototype`, reached through the interface
object, which does not invoke the instance-creating getter.

- Call semantics unchanged: instance lookup falls through to the patched
prototype, `this` stays the instance, same wrapped native. Snow's PiP
realm monitoring is preserved.
- The patch covers `snow.prod.js` and `snow.js` in addition to
`src/request.js`: the extension consumes Snow's prebuilt bundle as a
LavaMoat static shim (`LavamoatPlugin`), and webpack never processes
`@lavamoat/snow/**`.
- **Interim:** remove this patch when `@lavamoat/snow` is bumped to a
release containing the upstream fix. The bump is the removal trigger.

## **Cherry-pick candidacy**

- Affected population: every Firefox user on 151+ (effectively the whole
Firefox base via auto-update). Reproduces from a fresh wallet in five
popup opens. No workaround short of a browser restart.
- Proposed: next RC, with a hotfix on the current production line worth
considering.
- Snow is security-team-owned. Their sign-off on shipping a patched Snow
is part of this review.

## **Verification**

| Check | Result |
|---|---|
| Intervention: official 13.37.0 artifact, only this hook changed, 30
cycles | **+2,100 docs (3.35GB) → -13 (1.6MB total)**. Hook is the sole
delta, so this is also the causal proof |
| This PR's CI artifact (`d4dd55f`), probed directly | Patched hook
present; 5 cycles: +7 KB-scale entries (1.1MB) vs +345 docs (+534MB)
stock |
| Field | Original reporter confirms the leak is gone on this PR's CI
build |
| Independent repro | Manual steps + automated probe:

https://github.com/MajorLift/snow/tree/verification/pip-realm-leak/verification
|

## **Related issues**

Fixes: #42891

## **Manual testing steps**

1. Install this PR's Firefox build (metamaskbot comment) in a fresh
profile via `about:debugging` → Load Temporary Add-on. Onboard with a
test SRP.
2. Confirm the fix is live: extension console →
`DocumentPictureInPicture.prototype.requestWindow.name` → `"open"`
(stock: `"requestWindow"`).
3. Open/close the popup five times, visiting activity or a swap view on
a few opens.
4. `about:memory` → Minimize memory usage → Measure → filter `detached`:
no `moz-extension` UI-document cohorts (stock: ~70 entries / ~105MB per
cycle).

## **Screenshots/Recordings**

Heap-graph traces, memory reports, and retaining-path analysis: see the
verification bundle above.

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

CHANGELOG entry: Fixed a memory leak on Firefox where closed MetaMask
windows were retained in memory, growing extension memory use with every
popup open
[942441b](942441b)

Co-authored-by: Jongsun Suh <jongsun.suh@icloud.com>
## **Description**

1. **Split the entry sets.** `nullUnsafeEntries` (`scripts/inpage.js`,
`bootstrap`) run fully outside LavaMoat with no runtime added.
`service-worker.ts` stays in the `unsafe` layer (so its module + static
bootstrap imports are excluded from wrapping) **but** its chunk now runs
in `safe` mode so it carries the LavaMoat runtime.
2. **SES in the SW bundle.** The MV3 SW is self-contained and loads no
shared `runtime` chunk, so `service-worker.js` is added to
`inlineLockdown` — SES is inlined into its own bundle so the wrapped
background has hardened intrinsics + `Compartment`/`harden` available.
3. **Layer boundary at the dynamic import.**
`lavamoatBackgroundLayerRule` re-layers `background.js` (and, by
inheritance, its whole graph) out of `unsafe` into a `background` layer
so it gets wrapped, and `lavamoatUnsafeLayerRule` now `exclude`s
`background.js` so the boundary module itself is wrapped rather than
excluded.
4. **Scuttling on the SW global.** Defense-in-depth parity with the UI
`runtime` and `scripts/contentscript.js` chunks: `scuttleGlobalThis` is
enabled for the SW with an exception list for the globals the
*unwrapped* bootstrap and webpack's `importScripts` chunk loader touch
live after scuttling (`importScripts`, `console`, `performance`, timers,
and the Sentry cluster). Dependency containment does **not** depend on
scuttling — it comes from the Compartments — so wrapped deps still can't
reach the real global regardless.
5. **Policies regenerated.**
`lavamoat/webpack/mv3/{main,flask,beta,experimental}/policy.json` were
regenerated to include the now-wrapped background dependency graph
(~1198 → ~1594 resources). MV2 policies are untouched.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: <!-- add the sev1 security ticket link -->

## **Manual testing steps**

1. Build the MV3 Chrome bundle with LavaMoat: `yarn
webpack:lavamoat:build`.
2. Load `dist/chrome` unpacked in Chrome, open the **service worker**
inspector
3. Confirm the service worker installs and reaches `MetaMask
initialization complete` with **no** `inaccessible under scuttling mode`
/ missing-global / policy errors.
4. **Containment check**: temporarily patch a background dependency
(e.g.`node_modules/loglevel/lib/loglevel.js`) with:

   ```js
   console.log('probe', {
     clients: typeof globalThis.clients,
     registration: typeof globalThis.registration,
     serviceWorker: typeof globalThis.serviceWorker,
     keyCount: Object.keys(globalThis).length,
   });
   ```

Rebuild, reload, and confirm in the SW console that
`clients`/`registration`/`serviceWorker` are `"undefined"` and
`keyCount` is small (the dep sees its policy-scoped Compartment global).

## **Screenshots/Recordings**

N/A — no UI changes. Behavioral verification is the service-worker
console output described in Manual testing steps.

### **Before**

A background dependency could see globals outside of its intended scope.

### **After**

A wrapped background dependency sees only its Compartment global.

## **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 <!-- follow-up: regression guard
asserting background.js resolves out of the `unsafe` layer / SW chunks
contain the LavaMoat wrapper -->
- [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]
> **High Risk**
> Changes MV3 extension sandboxing for the service worker and background
(LavaMoat layers, SES lockdown, global scuttling); misconfiguration
could break SW startup or weaken containment.
> 
> **Overview**
> Fixes MV3 so **`background.js` and its dependency graph run inside
LavaMoat** instead of inheriting the service worker’s unwrapped `unsafe`
layer.
> 
> **Webpack / LavaMoat plugin:** `service-worker.ts` is removed from
fully unwrapped entries but stays on the `unsafe` layer for bootstrap
imports; its chunk now uses **`safe` mode** with an embedded LavaMoat
runtime. **`service-worker.js`** is added to **`inlineLockdown`** (SES
inlined in the SW bundle). A new **`background` webpack layer**
re-layers `app/scripts/background.js` out of `unsafe`, and the unsafe
exclude-loader **`exclude`s** that path so the boundary module is
wrapped. Shared **`scuttleGlobalThis`** exceptions are centralized; the
SW chunk enables scuttling with **`importScripts`** (and shared
exceptions) allowed.
> 
> **Tests:** New `plugins.LavamoatPlugin.test.ts` guards layer regexes,
SW `safe` mode, and plugin rule registration.
> 
> **Policies:** MV3 `policy.json` (e.g. beta) is regenerated for the
wrapped background graph; **`policy-override.json`** updates across
flavors add entries such as
`@metamask/assets-controllers>@tanstack/query-core`, `centrifuge`, and
gridplus `zod`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c251e94. 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: Norbert Elter <72046715+itsyoboieltr@users.noreply.github.com>
Co-authored-by: Howard Braham <howrad@gmail.com>
This PR updates the change log for 13.39.2. (Hotfix - no test plan
generated.)

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
Co-authored-by: Mark Stacey <mark.stacey@consensys.net>
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamask-ci metamask-ci Bot added the team-delivery Release delivery team label Jul 14, 2026
@github-actions
github-actions Bot force-pushed the stable-main-13.39.2 branch from 99890f7 to 3d015e0 Compare July 14, 2026 19:06
@sleepytanya sleepytanya changed the title Stable main 13.39.2 release: sync stable to main for version 13.39.2 Jul 14, 2026
@sleepytanya

Copy link
Copy Markdown
Contributor Author

policy-bot: approve

@sleepytanya

Copy link
Copy Markdown
Contributor Author

Merge my PR

@sleepytanya

Copy link
Copy Markdown
Contributor Author

Merge my PR

@metamask-ci
metamask-ci Bot merged commit bef6d69 into main Jul 14, 2026
61 of 71 checks passed
@metamask-ci
metamask-ci Bot deleted the stable-main-13.39.2 branch July 14, 2026 19:22
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 14, 2026
@metamaskbot metamaskbot added the release-13.41.0 Issue or pull request that will be included in release 13.41.0 label Jul 17, 2026
@gauthierpetetin

Copy link
Copy Markdown
Contributor

No release label on PR. Adding release label release-13.41.0 on PR, as PR was added to branch 13.41.0 when release was cut.

This branch was previously deployed

1 inactive deployment
pr-comment — 3d015e00 Deployed Jul 14, 2026 by github-actions[bot] via identify-codeowners #71232
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.41.0 Issue or pull request that will be included in release 13.41.0 risk:low size-S team-delivery Release delivery team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants