Skip to content

[pull] main from MetaMask:main - #884

Merged
pull[bot] merged 17 commits into
Reality2byte:mainfrom
MetaMask:main
Sep 29, 2026
Merged

pull[bot] merged 17 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

sahar-fehri and others added 17 commits September 29, 2026 08:45
## Explanation

Add the full implementation of `@metamask/advanced-chart-core` — the
platform-agnostic TradingView Advanced Charts WebView engine, ported
from `metamask-mobile`.

Stacked on [#10520](#10520)
(bootstrap/scaffold PR).

### What this PR adds

**Core engine** (`src/core/`)
- `bootstrap.ts` — WebView initialization, state seeding, Phase 1
handler registration
- `bridge.ts` — JSON framing/parsing for host communication, delegates
transport to the active host
- `host.ts` — Injectable `ChartHostTransport` interface with
`setHostTransport`/`getHostTransport`
- `state.ts` — Centralized chart state management
- `dataLifecycle.ts`, `loadLibrary.ts`, `resolution.ts`, `timeUtils.ts`,
`timezone.ts` — Data lifecycle, TradingView library loading, resolution
helpers

**Platform adapters** (`src/platform/`)
- `reactNativeHost.ts` — React Native WebView transport (default,
preserves existing mobile behavior)
- `iframeHost.ts` — Browser/extension iframe transport with origin
allowlisting

**Features** (`src/features/`)
- `indicators/` — Technical indicator overlays, legend, resize, studies,
sub-pane management
- `volume/` — Volume chart overlay

**Widget** (`src/widget/`)
- `initChart.ts`, `datafeed.ts`, `chartType.ts` — TradingView widget
initialization and data feed
- `theme.ts`, `visualOverrides.ts`, `scaleLayout.ts` — Theming and
layout
- `ohlcvIngestion.ts` — OHLCV candle data ingestion
- `priceFormatter.ts`, `tvDomHelpers.ts`, `externalLinkBridge.ts` —
Utilities

**Overlays** (`src/overlays/`)
- `tradeMarkers/` — Trade execution marker rendering with hit-testing
and animation
- `positionLines/` — Open position line overlays
- `socialLeaderboard/` — Social leaderboard overlay
- `focusTime/` — Focus time overlay

**Messages** (`src/messages/`)
- `handler.ts`, `contract.ts` — Inbound message handling and message
contract types

**Pagination** (`src/pagination/`)
- `priceApi.ts`, `rnBacked.ts` — Historical price data pagination

**Entry points**
- `src/index.ts` — Mobile RN WebView IIFE entry (auto-boots with
`createReactNativeHost`)
- `src/host-entry.ts` — Side-effect-free entry for non-mobile hosts
(extension iframe)

### Monorepo changes
- `oxlint.config.ts` — Adds `env: { browser: true }` override for
`packages/advanced-chart-core/**`
- `oxlint-suppressions.json` — Adds suppression entries for vendored
mobile code
- `package.json` — Adds `jest-environment-jsdom` and `./host` subpath
export

### Test coverage
- 40 test suites, 563 tests, all passing
- Coverage across all modules

## References

- Stacked on [#10520](#10520)
(bootstrap)
- Replaces [#9762](#9762)

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Large new chart/WebView surface area tied to RN messaging and
TradingView behavior; regressions would affect in-app charts, though
risk is tempered by extensive tests and largely ported logic.
> 
> **Overview**
> Delivers the full **`@metamask/advanced-chart-core`** WebView engine
(ported from mobile `chartLogic.js`), replacing the package
placeholder/greeter test with a modular bootstrap, RN↔WebView messaging,
centralized state, and TradingView widget lifecycle.
> 
> **Bootstrap and wiring:** `bootstrap()` reads config via injectable
**`ChartHostTransport`** (React Native default in `index.ts`;
**`./host`** export for iframe/extension hosts), registers inbound
handlers (OHLCV, theme, indicators, volume, overlays, pagination),
preloads the TV library, and creates the widget on first OHLCV
data—including initial visible-range timeframe and chart-ready hooks
(crosshair, legend, trade markers, etc.).
> 
> **Tooling:** Jest runs in **`jsdom`** package-wide; oxlint gets a
**browser** env override for this package plus suppressions for
vendored/test patterns. **`package.json`** adds
**`jest-environment-jsdom`**, a **`./host`** subpath export, and drops
unused messenger/typedoc dev scripts.
> 
> **Tests:** Replaces the smoke test with broad unit coverage (core,
bridge, bootstrap dispatch paths, indicators/legend, and related
modules) using test reset hooks and mocked DOM/RN bridge.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d518059. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ssetsController (#10461)

## Explanation

Token metadata, balances, and fiat rates were read from the legacy
per-domain asset controllers (`TokensController`,
`TokenBalancesController`, `TokenRatesController`,
`CurrencyRateController`, `AccountTrackerController`), with an
`assetsUnifyState` feature flag switching some of those reads over to a
bespoke `AssetsController:getStateForTransactionPay` action. That meant
two parallel read paths, a Pay-specific action on `AssetsController`,
and a subscription to four separate `stateChange` events to cover
whichever source happened to be live.

- This PR reads token data directly from `AssetsController` unified
state, resolving the account via `AccountsController`'s
`accountIdByAddress`. The feature-flag branching, the Pay-specific
`getStateForTransactionPay` action, and the legacy
`@metamask/assets-controllers` dependency are all no longer used, as is
the multi-source subscription, replaced by a single
`AssetsController:stateChange`.
- Unified state stores human-readable decimal amounts, whereas callers
of `getTokenBalance` expect raw base units, so balances are shifted by
the token's decimals.
- `AssetsController` becomes the sole source of token metadata. A token
absent from it is reported as unknown rather than being reconstructed
from network configuration or assumed from a derived identifier, so an
unindexed chain is rejected instead of quoting against an assumed symbol
and decimals.

### Performance

Serving Pay from the legacy shape meant projecting unified state into
it, which runs `toChecksumAddress` — and therefore keccak256 — once per
account and once per asset. That projection is memoised on a single
entry keyed by input identity, so the cost is paid in full on the first
read of each load and again on every read after the assets pipeline
updates. Its own docstring notes this dominates CPU profiles during
transaction approval.

Reading unified state directly removes that work rather than caching it:
Pay no longer builds the legacy projection at all, so no address is
checksummed on its behalf. Asset IDs are looked up against the metadata
snapshot in hand — a keyed read for ERC-20s, falling back to a scan only
for natives and for addresses recovered from calldata in a different
case. Because an asset ID is a static property of its chain and address,
a resolved ID is cached on those rather than on the state it came from,
and confirmed against the current state on reuse so that an asset not
yet indexed stays unresolved.

Consumers must delegate `AccountsController:getState`,
`AssetsController:getState`, and `AssetsController:stateChange` to the
Pay messenger, and must have unified asset state populated before using
Pay.

## References

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Breaking integration and payment-path changes: quotes and relay
balance checks depend on unified asset indexing and new messenger
wiring; misconfigured clients could show wrong balances or fail token
resolution.
> 
> **Overview**
> **Breaking change:** Transaction Pay no longer reads token metadata,
balances, or fiat rates from the legacy `@metamask/assets-controllers`
stack or from `AssetsController:getStateForTransactionPay`. Everything
goes through **`AssetsController:getState`**, with wallet addresses
mapped via **`AccountsController:getState`** (`accountIdByAddress`).
> 
> The **`assetsUnifyState`** feature flag and
**`getAssetsUnifyStateFeature`** are removed. Asset refresh for
in-flight Pay transactions now listens only to
**`AssetsController:stateChange`** instead of four separate controller
events. Dependencies drop **`@metamask/assets-controllers`** and add
**`@metamask/accounts-controller`**.
> 
> **`getTokenBalance`**, **`getTokenInfo`**, and **`getTokenFiatRate`**
in `token.ts` are rewritten: balances convert human-readable
**`assetsBalance`** amounts to raw base units using **`assetsInfo`**
decimals; prices come from **`assetsPrice`** (fungible only, stablecoin
USD override preserved). Missing assets are treated as unknown/zero
rather than inferred from network tickers. CAIP-19 keys are resolved
with a small cache and native-token scan logic.
> 
> Tests and messenger mocks are updated to match the new messenger
surface; consumers must wire **`AccountsController:getState`**,
**`AssetsController:getState`**, and **`AssetsController:stateChange`**
and populate unified asset state before Pay runs.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
72691e4. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@jest/globals](https://redirect.github.com/jestjs/jest)
([source](https://redirect.github.com/jestjs/jest/tree/HEAD/packages/jest-globals))
| [`^30.4.1` →
`^30.5.2`](https://renovatebot.com/diffs/npm/@jest%2fglobals/30.4.1/30.5.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@jest%2fglobals/30.5.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@jest%2fglobals/30.4.1/30.5.2?slim=true)
|
| [jest](https://jestjs.io/)
([source](https://redirect.github.com/jestjs/jest/tree/HEAD/packages/jest))
| [`^30.4.2` →
`^30.5.2`](https://renovatebot.com/diffs/npm/jest/30.4.2/30.5.2) |
![age](https://developer.mend.io/api/mc/badges/age/npm/jest/30.5.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest/30.4.2/30.5.2?slim=true)
|
| [jest-environment-jsdom](https://redirect.github.com/jestjs/jest)
([source](https://redirect.github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom))
| [`^30.4.1` →
`^30.5.2`](https://renovatebot.com/diffs/npm/jest-environment-jsdom/30.4.1/30.5.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/jest-environment-jsdom/30.5.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest-environment-jsdom/30.4.1/30.5.2?slim=true)
|
| [jest-environment-node](https://redirect.github.com/jestjs/jest)
([source](https://redirect.github.com/jestjs/jest/tree/HEAD/packages/jest-environment-node))
| [`^30.4.1` →
`^30.5.2`](https://renovatebot.com/diffs/npm/jest-environment-node/30.4.1/30.5.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/jest-environment-node/30.5.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest-environment-node/30.4.1/30.5.2?slim=true)
|

---

### Release Notes

<details>
<summary>jestjs/jest (@&#8203;jest/globals)</summary>

###
[`v30.5.2`](https://redirect.github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3052)

[Compare
Source](https://redirect.github.com/jestjs/jest/compare/v30.5.1...v30.5.2)

##### Features

- `[@jest/transform]` Strip TypeScript types with Node when no
transformer claims a `.ts`, `.mts` or `.cts` file
([#&#8203;16421](https://redirect.github.com/jestjs/jest/pull/16421))

##### Fixes

- `[jest-core, jest-haste-map, jest-transform]` Keep
`require('../package.json')` external when bundling, so `jest --version`
and the transform and haste-map cache keys report the released version
instead of the previous one
([#&#8203;16422](https://redirect.github.com/jestjs/jest/pull/16422))
- `[jest-each]` Escape a table row's keys before building the
`$variable` interpolation `RegExp`, so a column name such as `count(*)`
no longer fails the whole table with `Invalid regular expression`, and a
`.` or `|` in a column name is matched literally
([#&#8203;16345](https://redirect.github.com/jestjs/jest/pull/16345))
- `[@jest/source-map]` Resolve absolute Windows paths in a source map's
`sources` and `sourceRoot` again, instead of appending them to the
transformed file's directory
([#&#8203;16439](https://redirect.github.com/jestjs/jest/pull/16439))

###
[`v30.5.1`](https://redirect.github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3051)

[Compare
Source](https://redirect.github.com/jestjs/jest/compare/v30.5.0...v30.5.1)

##### Fixes

- `[jest-config]` Don't warn about global-only options in the config
that supplies the global config - the root config a project resolves to,
or the first entry of `--projects` when no root config is passed
([#&#8203;16411](https://redirect.github.com/jestjs/jest/pull/16411))
- `[jest-config, jest-types]` Stop accepting `reporters`,
`coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions`
in a project config - they were silently ignored, and now warn like the
other global-only options
([#&#8203;16411](https://redirect.github.com/jestjs/jest/pull/16411))
- `[jest-config, jest-validate]` Warn about `maxWorkers` and
`coverageThreshold` in a project config instead of dropping them without
a word
([#&#8203;16411](https://redirect.github.com/jestjs/jest/pull/16411))
- `[jest-resolve]` Match `moduleNameMapper` patterns against the
specifier as written again (reverting
[#&#8203;16390](https://redirect.github.com/jestjs/jest/pull/16390))
([#&#8203;16417](https://redirect.github.com/jestjs/jest/pull/16417))
- `[jest-runtime]` Resolve package `imports` specifiers like `#dep`
under ESM again
([#&#8203;16413](https://redirect.github.com/jestjs/jest/pull/16413))

##### Chore & Maintenance

- `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option
and link the docs from the `JEST-01` deprecation warning, and document
the option's modes
([#&#8203;16404](https://redirect.github.com/jestjs/jest/pull/16404))

###
[`v30.5.0`](https://redirect.github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3050)

[Compare
Source](https://redirect.github.com/jestjs/jest/compare/v30.4.1...v30.5.0)

##### Features

- `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)`
for configuring return values per argument list, with first-class
asymmetric-matcher support
([#&#8203;16053](https://redirect.github.com/jestjs/jest/pull/16053))
- `[@jest/expect-utils]` Export `AsymmetricMatcher` and
`FunctionParameters` types (previously private to `expect`)
([#&#8203;16053](https://redirect.github.com/jestjs/jest/pull/16053))
- `[jest-circus, jest-core, jest-jasmine2, jest-test-result,
jest-types]` `--collectTests` now expands `test.each`/`describe.each`
cases and reports per-status counts (skipped/todo via the new `wouldRun`
flag for selected tests) plus a summary line that match a real run,
including under `--testNamePattern` and `.only`/`fdescribe` focus on
both the circus and jasmine2 runners
([#&#8203;16259](https://redirect.github.com/jestjs/jest/pull/16259))
- `[jest-circus, jest-environment, jest-runtime, jest-types]` Add
describe-level retries via `jest.retryTimes(..., {entireDescribe:
true})`
([#&#8203;16322](https://redirect.github.com/jestjs/jest/pull/16322))
- `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add
`retryMessages` to `AssertionResult` and export `formatErrorStack`, so
the retry log renders nested `cause` and `AggregateError` sections with
code frames instead of serialized `[cause]:`/`[errors]:` markers
([#&#8203;16316](https://redirect.github.com/jestjs/jest/pull/16316))
- `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to
`Circus.RunResult`, so an unhandled rejection reports its `cause` chain
and `AggregateError` entries with code frames instead of a
pre-serialized stack
([#&#8203;16316](https://redirect.github.com/jestjs/jest/pull/16316))
- `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with
`@parcel/watcher` for the non-watchman watch path
([#&#8203;16188](https://redirect.github.com/jestjs/jest/pull/16188))
- `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove
`jest-pnp-resolver` and unnecessary checks
([#&#8203;15721](https://redirect.github.com/jestjs/jest/pull/15721))
- `[jest-resolve]` Honor Node's `--preserve-symlinks` /
`NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks:
false` to `unrs-resolver`
([#&#8203;16260](https://redirect.github.com/jestjs/jest/pull/16260))
- `[jest-runtime]` Apply automocking and manual `__mocks__` files to
synchronously evaluable ESM graphs on Node 24.9+ - static imports,
dynamic `import()` and `require()` of an ESM file now generate an
automock from the real module's namespace instead of failing with
"Attempting to import a mock without a factory". Graphs that need async
evaluation (top-level await) or an async-only resolver or transformer
still throw
([#&#8203;16391](https://redirect.github.com/jestjs/jest/pull/16391))
- `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox,
so it returns the sandbox `process` and the hooked `node:module` instead
of the host's
([#&#8203;16391](https://redirect.github.com/jestjs/jest/pull/16391))
- `[jest-runtime]` Throw an actionable error from `module.register()`
and `module.registerHooks()` inside a test - the hooks attached to the
loader running Jest itself, never saw the sandboxed requires they were
meant for, and stayed registered for every later test file in the worker
([#&#8203;16391](https://redirect.github.com/jestjs/jest/pull/16391))
- `[jest-runtime]` Surface resolution and import-attribute errors in an
ESM graph before executing any of its CJS dependencies on Node 24.9+,
matching Node's run-nothing-on-a-broken-graph behavior; the legacy
loader on older versions keeps its linking-time execution order
([#&#8203;16391](https://redirect.github.com/jestjs/jest/pull/16391))
- `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an
actionable message for `import source` and `import.source()`, instead of
failing at instantiation with V8's bare "Source phase import object is
not defined"
([#&#8203;16391](https://redirect.github.com/jestjs/jest/pull/16391))
- `[jest-runtime]` Emit the JSON-without-import-attribute deprecation
warning once per test file instead of once per worker, so it is no
longer silently swallowed for every file after the first
([#&#8203;16391](https://redirect.github.com/jestjs/jest/pull/16391))
- `[jest-runtime]` Set `import.meta.main` to `true` in the test file and
`false` in every module it loads, matching Node 24+
([#&#8203;16367](https://redirect.github.com/jestjs/jest/pull/16367))
- `[jest-runtime]` Resolve the `module-sync` export condition, so a
package that exposes its ESM entry point for `require()` loads the same
file Node would
([#&#8203;16336](https://redirect.github.com/jestjs/jest/pull/16336))
- `[jest-snapshot]` Add external snapshot paths to custom reporter
failure details
([#&#8203;16374](https://redirect.github.com/jestjs/jest/pull/16374))

##### Fixes

- `[jest-console, jest-reporters]` `CustomConsole` now buffers console
output so `TestResult.console` is populated for reporters when `verbose`
is enabled, while `GitHubActionsReporter` avoids replaying buffered
output in verbose mode
([#&#8203;16155](https://redirect.github.com/jestjs/jest/pull/16155))
- `[expect, jest-message-util, jest-pattern, jest-regex-util,
jest-util]` Revert `node:` protocol imports to restore
webpack/browser-bundle compatibility
([#&#8203;16167](https://redirect.github.com/jestjs/jest/pull/16167))
- `[expect]` Widen `toMatchObject` and `objectContaining` parameter type
from `Record<string, unknown>` to `object` so class instances are
accepted
([#&#8203;16196](https://redirect.github.com/jestjs/jest/pull/16196))
- `[jest-circus]` Call a generator test body with the shared test
context, so `this` matches what a regular test function receives
([#&#8203;16347](https://redirect.github.com/jestjs/jest/pull/16347))
- `[jest-circus]` Capture the error listeners of the parent process
instead of the in-sandbox `process`, so listeners registered before the
test file survive teardown and sandbox listeners no longer leak onto the
parent
([#&#8203;16347](https://redirect.github.com/jestjs/jest/pull/16347))
- `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo
tests
([#&#8203;16342](https://redirect.github.com/jestjs/jest/pull/16342))
- `[jest-circus]` Prevent late `done()` callbacks from affecting later
test or hook invocations
([#&#8203;16343](https://redirect.github.com/jestjs/jest/pull/16343))
- `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting
`node:assert` failures, instead of always collapsing the diff
([#&#8203;16347](https://redirect.github.com/jestjs/jest/pull/16347))
- `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner
errors of an `AggregateError` into `failureMessages`, `retryReasons` and
`unhandledErrors`, so `--json` output and reporter annotations include
them
([#&#8203;16316](https://redirect.github.com/jestjs/jest/pull/16316))
- `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct
when a test retries
([#&#8203;16344](https://redirect.github.com/jestjs/jest/pull/16344))
- `[@jest/create-cache-key-function]` Include the caller support flags
in the generated key, so a transformer that emits ESM or CJS based on
them no longer shares one cache entry between the two
([#&#8203;16331](https://redirect.github.com/jestjs/jest/pull/16331))
- `[@jest/create-cache-key-function]` Include the stringified project
config in the generated key, so editing a transformer's own settings
invalidates what it cached
([#&#8203;16331](https://redirect.github.com/jestjs/jest/pull/16331))
- `[@jest/transform]` Include the caller support flags in a transform's
cache key, so a file transformed both as ESM and as CJS no longer serves
one shape's output for the other
([#&#8203;16331](https://redirect.github.com/jestjs/jest/pull/16331))
- `[jest-config]` Add missing `findRelatedTests`, `outputFile`, and
`replname` entries to `ValidConfig` so they no longer trigger spurious
"Unknown option" warnings
([#&#8203;16224](https://redirect.github.com/jestjs/jest/pull/16224))
- `[jest-config]` Use `--config` for the global config when multiple
`--projects` are specified
([#&#8203;16273](https://redirect.github.com/jestjs/jest/pull/16273))
- `[jest-core]` Serialize `bigint` values in `--json` and `--outputFile`
output as their literal form (`4n`), instead of failing the run with
`TypeError: Do not know how to serialize a BigInt`
([#&#8203;16338](https://redirect.github.com/jestjs/jest/pull/16338))
- `[jest-core]` Do not report a `CustomGC` async resource (used by N-API
addons such as napi-rs for per-isolate GC bookkeeping) as an open
handle, since it is `napi_unref`'d by the addon and can never keep the
event loop alive
([#&#8203;16379](https://redirect.github.com/jestjs/jest/pull/16379))
- `[jest-each]` Keep a `$&`, `` $` ``, `$'` or `$$` inside a `%p` param
value out of the replacement, so the title shows the value instead of
the text around it
([#&#8203;16338](https://redirect.github.com/jestjs/jest/pull/16338))
- `[jest-each]` Interpolate a `bigint` into a `%j` title as its literal
form (`"4n"`) at any depth, instead of throwing `TypeError: Do not know
how to serialize a BigInt` while collecting the tests
([#&#8203;16338](https://redirect.github.com/jestjs/jest/pull/16338))
- `[jest-environment, jest-runtime]` Bind `sandboxInjectedGlobals` to
the right values when `injectGlobals` is `false`, instead of shifting
every one of them by a position
([#&#8203;16377](https://redirect.github.com/jestjs/jest/pull/16377))
- `[jest-environment-node, jest-util]` Only warn about a conflicting
`globalsCleanup` mode when one was explicitly configured, and follow the
mode that is actually in effect
([#&#8203;16323](https://redirect.github.com/jestjs/jest/pull/16323))
- `[jest-environment-node, jest-util]` Stop resolving lazy globals when
setting up an environment, so Node 26's builtin module globals are no
longer loaded (and no longer emit their deprecation warnings) for every
test file
([#&#8203;16324](https://redirect.github.com/jestjs/jest/pull/16324))
- `[jest-haste-map]` Keep watch mode alive when an outside process
briefly makes a file unreadable on Windows, instead of tearing the
watcher down on `EPERM`
([#&#8203;16295](https://redirect.github.com/jestjs/jest/pull/16295))
- `[jest-haste-map]` Keep indexing when an outside process holds a file
open on Windows, instead of failing the whole crawl on `EPERM`
([#&#8203;16358](https://redirect.github.com/jestjs/jest/pull/16358))
- `[jest-haste-map]` Keep a duplicated manual mock resolving when the
file it pointed at is deleted in watch mode
([#&#8203;16360](https://redirect.github.com/jestjs/jest/pull/16360))
- `[jest-haste-map]` Shut the worker farm down when a duplicate manual
mock aborts the build under `throwOnModuleCollision`
([#&#8203;16354](https://redirect.github.com/jestjs/jest/pull/16354))
- `[jest-haste-map]` Attach the watchman client's `error` listener
before the first command, so a watchman failure falls back to the node
crawler instead of crashing on an unhandled `error` event, and always
end the client
([#&#8203;16355](https://redirect.github.com/jestjs/jest/pull/16355))
- `[jest-haste-map]` Stop delivering watch events after
`WatchmanWatcher` is closed, and route its warnings through the
configured console
([#&#8203;16355](https://redirect.github.com/jestjs/jest/pull/16355))
- `[jest-haste-map]` Restore the nested `duplicates` index correctly in
`ModuleMap.fromJSON`, so a haste collision reported inside a test worker
raises `DuplicateHasteCandidatesError` instead of a `TypeError`
([#&#8203;16353](https://redirect.github.com/jestjs/jest/pull/16353))
- `[jest-haste-map]` Match watched files on a full extension, so
`moduleFileExtensions: ['js']` no longer accepts `foo.mjs`
([#&#8203;16352](https://redirect.github.com/jestjs/jest/pull/16352))
- `[jest-haste-map]` Delimit the fields that make up the haste map cache
key, so two different option sets cannot hash to the same cache file
([#&#8203;16352](https://redirect.github.com/jestjs/jest/pull/16352))
- `[jest-message-util]` Print the inner errors of an `AggregateError`
thrown inside a test
([#&#8203;16316](https://redirect.github.com/jestjs/jest/pull/16316))
- `[jest-message-util]` Indent nested `cause` and `AggregateError`
sections of a test failure by one level per depth, so the nesting is
legible instead of rendering flat
([#&#8203;16316](https://redirect.github.com/jestjs/jest/pull/16316))
- `[jest-message-util]` Color stack traces line by line so blank lines
stay blank
([#&#8203;16316](https://redirect.github.com/jestjs/jest/pull/16316))
- `[jest-message-util]` Detect Jest's own frames without assuming the
checkout directory's name, and cover `@jest/*` packages, so stack traces
and code frames point at user code
([#&#8203;16326](https://redirect.github.com/jestjs/jest/pull/16326))
- `[jest-mock]` `mockResolvedValue` / `mockRejectedValue` now see all
overload return types, so a Promise-returning overload survives even
when a later overload returns a non-Promise (e.g. `pg.Client['end']`)
([#&#8203;16237](https://redirect.github.com/jestjs/jest/pull/16237))
- `[@jest-environment/jsdom-abstract]` Make `@types/jsdom` a peer
dependency
([#&#8203;16166](https://redirect.github.com/jestjs/jest/pull/16166))
- `[jest-mock]` Remove the leftover own accessor descriptor when
restoring a `spyOn` of an inherited getter or setter, so the instance
keeps reflecting the prototype
([#&#8203;16226](https://redirect.github.com/jestjs/jest/pull/16226))
- `[jest-resolve]` Include `extensionsToTreatAsEsm` in the
`shouldLoadAsEsm` cache key, so projects with different extension lists
don't read each other's answers
([#&#8203;16369](https://redirect.github.com/jestjs/jest/pull/16369))
- `[jest-resolve]` Make `getModuleIDAsync` build and cache `data:` URI
module IDs the same way as `getModuleID`
([#&#8203;16370](https://redirect.github.com/jestjs/jest/pull/16370))
- `[jest-resolve]` Keep the `node:` prefix when resolving a core module
asynchronously, so a builtin that only exists prefixed (`node:sea`,
`node:sqlite`, `node:test`, `node:test/reporters`) resolves instead of
failing as a missing bare package
([#&#8203;16388](https://redirect.github.com/jestjs/jest/pull/16388))
- `[jest-resolve]` Look up manual mocks for `node:` protocol specifiers
under the unprefixed name they are stored as
([#&#8203;16388](https://redirect.github.com/jestjs/jest/pull/16388))
- `[jest-resolve]` Apply `moduleNameMapper` consistently to both
spellings of core module specifiers (`fs` vs `node:fs`)
([#&#8203;16390](https://redirect.github.com/jestjs/jest/pull/16390))
- `[jest-resolve]` Keep virtual and ordinary mock module IDs isolated
across test files
([#&#8203;16296](https://redirect.github.com/jestjs/jest/pull/16296))
- `[jest-resolve]` Guard missing `require.resolve.paths`
([#&#8203;16052](https://redirect.github.com/jestjs/jest/pull/16052))
- `[jest-resolve, jest-config, jest-runner]` Support a user resolver
written as an ES module
([#&#8203;16332](https://redirect.github.com/jestjs/jest/pull/16332))
- `[jest-resolve, jest-runtime]` Throw the CJS parse error for ESM
syntax in a `"type": "commonjs"` package or a `.cjs` file instead of
loading it as ESM, matching Node
([#&#8203;16368](https://redirect.github.com/jestjs/jest/pull/16368))
- `[@jest/source-map]` Keep source map sources that name a scheme, such
as `webpack:///`, instead of resolving them into a path that does not
exist
([#&#8203;16327](https://redirect.github.com/jestjs/jest/pull/16327))
- `[@jest/source-map]` Look up `--testLocationInResults` positions at
the right column, and keep a mapping to the first column instead of
discarding it
([#&#8203;16327](https://redirect.github.com/jestjs/jest/pull/16327))
- `[@jest/source-map]` Warn when a source map cannot be parsed, instead
of silently leaving its frames untranslated
([#&#8203;16327](https://redirect.github.com/jestjs/jest/pull/16327))
- `[jest-runner, @jest/source-map]` Keep a source-mapped stack for an
error thrown after the test environment was torn down
([#&#8203;16327](https://redirect.github.com/jestjs/jest/pull/16327))
- `[jest-runtime, @jest/source-map]` Keep source maps past teardown and
past the next test file's `install`, so a stack from a file no earlier
stack mentioned still points at the original source
([#&#8203;16330](https://redirect.github.com/jestjs/jest/pull/16330))
- `[jest-runtime]` Report that no coverage was collected when
`getAllV8CoverageInfoCopy` is called after `teardown`, instead of
returning an empty result
([#&#8203;16385](https://redirect.github.com/jestjs/jest/pull/16385))
- `[jest-runtime]` Cache a CJS module's parsed exports before walking
its re-exports, so two modules that re-export each other no longer
overflow the stack when imported from ESM
([#&#8203;16363](https://redirect.github.com/jestjs/jest/pull/16363))
- `[jest-runtime]` Keep a re-exported ES module's parse failure from
marking the re-exporting CommonJS file as ESM, so `module.exports =
require('./dep.mjs')` loads instead of failing with `module is not
defined`
([#&#8203;16363](https://redirect.github.com/jestjs/jest/pull/16363))
- `[jest-runtime]` Scope module mocks instantiated inside
`jest.isolateModules`/`isolateModulesAsync` to that block, so a mock
first imported there no longer outlives it - matching how CommonJS mocks
already behave
([#&#8203;16365](https://redirect.github.com/jestjs/jest/pull/16365))
- `[jest-runtime]` Suspend module isolation while generating an
automock, so loading the real module to read its shape no longer
populates the isolated registry
([#&#8203;16365](https://redirect.github.com/jestjs/jest/pull/16365))
- `[jest-runtime]` Check a cached ES module's status before `require()`
returns it, so a module whose evaluation threw rethrows that error and
one left linked by a failed sibling is evaluated instead of returning
uninitialized bindings
([#&#8203;16364](https://redirect.github.com/jestjs/jest/pull/16364))
- `[jest-runtime]` Report the original `ERR_REQUIRE_ASYNC_MODULE` when a
`require()` of a top-level-await graph is retried, instead of a spurious
"concurrent `import()`" error
([#&#8203;16364](https://redirect.github.com/jestjs/jest/pull/16364))
- `[jest-runtime]` Throw the evaluation error when another caller's
`import()` of the same module failed while we awaited it, instead of
resolving with the errored module
([#&#8203;16364](https://redirect.github.com/jestjs/jest/pull/16364))
- `[jest-runtime]` Mark the result of `require()`ing an ES module that
has a default export with `__esModule: true` through a live-binding
facade, and serve the same object from `require.cache`, matching Node
([#&#8203;16367](https://redirect.github.com/jestjs/jest/pull/16367))
- `[jest-runtime]` Provide a CommonJS module's exports under the
`'module.exports'` named export when imported from ESM, matching Node
23+
([#&#8203;16367](https://redirect.github.com/jestjs/jest/pull/16367))
- `[jest-runtime]` Give the test file itself a non-null `require.main`
([#&#8203;16367](https://redirect.github.com/jestjs/jest/pull/16367))
- `[jest-runtime]` Populate `module.children` with the modules a file
loads, matching Node
([#&#8203;16368](https://redirect.github.com/jestjs/jest/pull/16368))
- `[jest-runtime]` Provide `import.meta.resolve` and `import.meta.jest`
in `data:` URI modules, accept any-case mediatype parameters, and use
Node's error codes for invalid `data:` URIs
([#&#8203;16368](https://redirect.github.com/jestjs/jest/pull/16368))
- `[jest-runtime]` Key ES modules by full URL, so query and fragment
suffixes create the same module instances as Node and show up in
`import.meta.url`
([#&#8203;16375](https://redirect.github.com/jestjs/jest/pull/16375))
- `[jest-runtime]` Share modules between overlapping graphs when a
CommonJS module `require()`s an ES module mid-load, instead of
evaluating shared dependencies twice
([#&#8203;16375](https://redirect.github.com/jestjs/jest/pull/16375))
- `[jest-runtime]` Throw `ERR_REQUIRE_CYCLE_MODULE` like Node when a
CommonJS module `require()`s an ES module that is still being loaded,
instead of evaluating the module a second time
([#&#8203;16366](https://redirect.github.com/jestjs/jest/pull/16366))
- `[jest-runtime]` Key builtin modules in the ESM registry by one
canonical specifier
([#&#8203;16341](https://redirect.github.com/jestjs/jest/pull/16341))
- `[jest-runtime]` `import.meta.resolve()` for a builtin uses its
`node:` specifier
([#&#8203;16341](https://redirect.github.com/jestjs/jest/pull/16341))
- `[jest-runtime]` Fall back to native ESM when a `.js` file contains
ESM syntax but has no `"type":"module"` marker
([#&#8203;16152](https://redirect.github.com/jestjs/jest/pull/16152))
- `[jest-runtime]` Allow `require()` of ESM-marked files on Node < 24.9
via transform fallback
([#&#8203;16244](https://redirect.github.com/jestjs/jest/pull/16244))
- `[jest-runtime, @jest/transform]` Surface actionable `ERR_REQUIRE_ESM`
error for files with untransformed ESM syntax instead of the generic
"unexpected token" message
([#&#8203;16244](https://redirect.github.com/jestjs/jest/pull/16244))
- `[jest-runtime]` Support older test environments whose `moduleMocker`
does not implement `clearMocksOnScope`
([#&#8203;16169](https://redirect.github.com/jestjs/jest/pull/16169))
- `[jest-runtime]` Apply `jest.unstable_mockModule` when the mocked file
itself is `require()`d, not only when it is imported as a dependency
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Apply `jest.unstable_mockModule` to statically
imported `data:` URIs on Node 24.9+, matching dynamic `import()`
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Run an async `jest.unstable_mockModule` factory once
per module instead of twice, and fail the import instead of crashing the
worker when the factory rejects
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Hide a `require(esm)` module that failed to evaluate
from `require.cache`, as Node does, instead of exposing a namespace with
uninitialized bindings
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Strip the byte-order mark when importing a JSON
module, matching `require()` and Node
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Throw `ERR_REQUIRE_ASYNC_MODULE` when `require(esm)`
runs under an async-only custom resolver, instead of silently resolving
with the default resolver
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Parse imported JSON modules with the test realm's
`JSON`, so their objects pass `instanceof Object` inside the test like
`require()`d JSON does
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Accept every `file:` URL string in the sandboxed
`module.createRequire`, including one with a `localhost` authority, as
Node does
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-runtime]` Point at `{virtual: true}` when `jest.mock` or
`jest.unstable_mockModule` is given a module that cannot be resolved
([#&#8203;16389](https://redirect.github.com/jestjs/jest/pull/16389))
- `[jest-reporters]` Fix coverage report table formatting in CI/GitHub
Actions environments where `process.stdout.columns` is undefined by
falling back to the `COLUMNS` env var or `80` columns in CI, preserving
existing behaviour in other non-TTY environments
([#&#8203;16227](https://redirect.github.com/jestjs/jest/pull/16227))
- `[jest-runtime]` Support CJS-in-ESM exports via `"module.exports"`
named exports
([#&#8203;16277](https://redirect.github.com/jestjs/jest/pull/16277))
- `[jest-snapshot]` Keep a skipped or failed test's hinted snapshots,
instead of reporting them obsolete
([#&#8203;16348](https://redirect.github.com/jestjs/jest/pull/16348))
- `[jest-util]` Stop `globsToMatcher` reusing a cached matcher compiled
with different picomatch options, and keep its `dot: true` default when
`dot` is passed as `undefined`
([#&#8203;16381](https://redirect.github.com/jestjs/jest/pull/16381))
- `[pretty-format]` Move the `react-is` aliases into the `@jest` scope,
so they cannot be shadowed by unrelated packages published under the
alias names
([#&#8203;16333](https://redirect.github.com/jestjs/jest/pull/16333))

##### Chore & Maintenance

- `[docs]` Document the intentional divergences from Node's module
system in the ECMAScript Modules page
([#&#8203;16368](https://redirect.github.com/jestjs/jest/pull/16368))
- `[docs]` Note deprecation of `react-test-renderer` in React Native
tutorial and `pretty-format` README
([#&#8203;16294](https://redirect.github.com/jestjs/jest/pull/16294))
- `[docs]` Use `@testing-library/react-native` in the React Native
tutorial instead of the deprecated `react-test-renderer`
([#&#8203;16318](https://redirect.github.com/jestjs/jest/pull/16318))
- `[babel-jest, @jest/transform]` Update `babel-plugin-istanbul` to v8
([#&#8203;16049](https://redirect.github.com/jestjs/jest/pull/16049))
- `[jest-config, @jest/reporters, jest-runtime]` Update `glob` to v13
([#&#8203;16397](https://redirect.github.com/jestjs/jest/pull/16397))
- `[jest-haste-map]` Refactor massive class into multiple files
([#&#8203;16180](https://redirect.github.com/jestjs/jest/pull/16180))
- `[jest-haste-map]` Drop `walker` dependency; replace hand-rolled
directory recursion in the JS crawler and watcher startup with `fdir`
([#&#8203;16187](https://redirect.github.com/jestjs/jest/pull/16187))
- `[jest-haste-map]` Reuse cached metadata for files whose haste name is
a known duplicate, instead of re-reading and re-parsing them on every
startup
([#&#8203;16351](https://redirect.github.com/jestjs/jest/pull/16351))
- `[jest-haste-map]` Cache the watchman socket path and replace the
`watchman --version` probe with `get-sockname`, so warm runs spawn no
watchman processes
([#&#8203;16386](https://redirect.github.com/jestjs/jest/pull/16386))
- `[jest-resolve]` Store the per-directory package-type lookup in the
cache it reads, so it actually memoizes
([#&#8203;16369](https://redirect.github.com/jestjs/jest/pull/16369))
- `[jest-resolve, jest-runtime]` Cut repeated work on the resolution hot
path: hoist the platform-extension list to construction, memoize
`isCoreModule` and the options cache-key serialization, skip mapper
preparation when no `moduleNameMapper` is configured, run each mapper
regex once, and stop re-parsing `NODE_OPTIONS` on every default-resolver
call
([#&#8203;16371](https://redirect.github.com/jestjs/jest/pull/16371))
- `[jest-resolve]` Cut warm resolution cost to about a third: reuse one
`unrs-resolver` factory per options shape instead of cloning per
resolution, compose the factory cache key from per-array cached strings
instead of serializing options, and stop constructing an `Error` for
misses that `findNodeModule` swallows; add a `__benchmarks__` suite for
the default resolver
([#&#8203;16373](https://redirect.github.com/jestjs/jest/pull/16373))
- `[jest-runner, @jest/source-map]` Replace `source-map-support` with an
implementation in `@jest/source-map`
([#&#8203;16327](https://redirect.github.com/jestjs/jest/pull/16327))
- `[jest-snapshot]` Load babel, semver and synckit lazily, so requiring
the package (which every test process does through `@jest/expect`) no
longer loads \~200 modules that only writing inline snapshots needs
([#&#8203;16387](https://redirect.github.com/jestjs/jest/pull/16387))
- `[jest-runtime]` Reduce per-require overhead: skip module ID
resolution when no mock can apply, answer core modules before probing
for a manual mock, share one `require.cache` proxy across modules, and
cache empty files
([#&#8203;16376](https://redirect.github.com/jestjs/jest/pull/16376))
- `[@jest/source-map]` Deprecate `getCallsite` in favour of
`SourceMapSupport#getCallsite`
([#&#8203;16327](https://redirect.github.com/jestjs/jest/pull/16327))
- `[jest-runtime]` Avoid magical `null` value in ESM loader
([#&#8203;16160](https://redirect.github.com/jestjs/jest/pull/16160))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMDYuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjEwNi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Dev-only dependency alignment; validate CI with `yarn test` after
install, since Jest 30.5 changes haste-map watching and module runtime
behavior.
> 
> **Overview**
> Bumps the monorepo test stack from Jest **30.4.x** to **^30.5.2**
everywhere it is declared: root `jest` and `@jest/globals`, per-package
`jest` devDependencies, and matching **`jest-environment-jsdom`** /
**`jest-environment-node`** where those packages use them.
> 
> Root **LavaMoat `allowScripts`** is adjusted for the upgrade: the
obsolete **`babel-runtime>core-js`** entry is removed, and
**`jest>@jest/core>jest-haste-map>@parcel/watcher#2.6.0`** is added with
install scripts disabled (same pattern as other native transitive deps).
No application or library source changes—only manifest/version pins
(plus lockfile if present outside this diff).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2d7f946. 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-ci[bot] <271559518+metamask-ci[bot]@users.noreply.github.com>
Co-authored-by: Salah-Eddine Saakoun <salah-eddine.saakoun@consensys.net>
## Explanation

In preparation for dropping the `tsx` dependency, I've updated all `.js`
imports to `.ts` imports in the `scripts` folder. We may eventually want
to do this in the packages too, but to keep this pull request small, I
skipped that for now.

Also updated some scripts from `.mts` to `.ts` as `.mts` is not needed
anymore now that the entire workspace is ESM.

## References

<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these
changes better?
Are there client or consumer pull requests to adopt any breaking
changes?

For example:

* Fixes #12345
* Related to #67890
-->

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Tooling-only refactor in CI scripts and dev configs; runtime product
code and package import rules are unchanged.
> 
> **Overview**
> Prepares the repo to eventually drop **`tsx`** by standardizing how
**`scripts/`** is written and invoked.
> 
> **Script entrypoints** that used **`.mts`** are renamed to **`.ts`**
(e.g. `get-changed-workspaces`, `lint-tsconfigs`,
`close-stale-release-prs`, shared **`scripts/lib/workspaces`**). GitHub
Actions, root **`package.json`**, **`yarn.config.cjs`**, and every
workspace **`lint:tsconfigs`** script are updated to call the new paths.
> 
> **Relative imports under `scripts/`** switch from **`.js`** /
**`.mjs`** specifiers to **`.ts`**. **`tsconfig.base.json`** enables
**`allowImportingTsExtensions`**, while **`tsconfig.packages.json`**
explicitly turns it off so published packages stay unchanged.
**`oxlint.config.ts`** adds an **`import/extensions`** override for
**`scripts/**/*.ts`**, and suppression keys are retargeted to the
renamed files.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ddfd6ac. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Explanation

Add functions for deriving X25519 public keys and shared secrets.

React Native benchmark:
```
Finished x25519 public key benchmark: WebCrypto = 3 ms JS = 78 ms
Finished x25519 shared secret benchmark: WebCrypto = 3 ms JS = 90 ms
```

## References

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

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Introduces new cryptographic key-agreement APIs where misuse could
affect secret derivation, though behavior is delegated to WebCrypto with
strict length checks and RFC test vectors.
> 
> **Overview**
> Adds **X25519 key agreement** to `@metamask/cryptography` as a
dedicated subpath export (`@metamask/cryptography/x25519`), exposing
**`getPublicKey`** and **`getSharedSecret`** for 32-byte keys.
> 
> Both operations share a WebCrypto **`deriveBits`** path: raw private
keys are wrapped in a fixed PKCS#8 header before import, public keys use
raw import, and scalar multiplication covers public-key derivation from
the RFC 7748 base point and ECDH-style shared secrets. A small
**`toUint8Array`** helper normalizes `BufferSource` inputs (including
`ArrayBuffer` and `DataView`).
> 
> The changelog documents the new API, and tests cover custom vectors
plus **RFC 7748 Section 6.1** Alice/Bob cases, input-type variants, and
explicit errors for wrong key lengths.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
935bff1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… tests (#10543)

## Explanation

Adds the single main-path **snapshot (source of truth)** test to each
websocket price-update integration suite from #10476, mirroring how the
BNB Chain spam-token v6 suites capture theirs (#10490, later trimmed to
one main-path snapshot per suite):

- `pipeline/buildWsUpdateSources.price-updates.integration.test.ts` — a
fresh default-lane pass (v5, empty wallet, ETH held and USDC acquired in
one websocket event) is captured end-to-end via
`withZeroedTimestamps(response)`.
- `AssetsController.ws-price-updates.integration.test.ts` — the same
scenario booted through the real controller, capturing the settled full
state via `withZeroedTimestamps(state)`.

Each suite gets exactly **one** snapshot (the main path), placed as a
sibling of the brand-new-holdings `describe.each` and running its
default-scenario helper from scratch rather than a `beforeAll`-cached
result — the shape the bsc-spam v6 suites settled on after trimming.

The snapshots capture the full response/state surfaces (balances,
metadata, prices, detected assets) with `lastUpdated` zeroed, so any
future regression in the websocket enrichment pipeline surfaces as a
snapshot diff for review.

Test-only change — no consumer-facing behavior change, so no changelog
entry (carrying the `no-changelog` label).

## References

* Adds snapshot coverage to the websocket price-update suites from
#10476
* Snapshot pattern follows the bsc-spam v6 suites (#10490; single
main-path snapshot per suite)

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Test-only additions with no production code or runtime behavior
changes.
> 
> **Overview**
> Adds **one main-path Jest snapshot test** to each websocket
price-update integration suite, following the same “source of truth”
pattern used for the BNB Chain spam-token v6 suites.
> 
> Each new **`generates snapshot (source of truth)`** case re-runs the
default happy path (empty wallet, single websocket event with ETH +
USDC) independently—not from a shared `beforeAll`—and asserts against a
snapshot after **`withZeroedTimestamps`** so volatile `lastUpdated`
fields do not flake. The pipeline suite snapshots the enriched
**`DataResponse`**; the **`AssetsController`** suite snapshots the
settled full controller state (balances, metadata, prices, preferences,
etc.).
> 
> Committed snapshot files capture the expected shapes so future
regressions in websocket enrichment show up as reviewable diffs.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8db7235. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Explanation

Add utility for generating cryptographically secure random numbers. 

## References

N/A

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> New additive API with input validation and tests; no changes to
existing crypto primitives or consumers.
> 
> **Overview**
> Adds **`getRandomBytes`** to `@metamask/cryptography` as a small
wrapper around `globalThis.crypto.getRandomValues`, returning a
`Uint8Array` of the requested size.
> 
> The function rejects non-positive lengths with a clear error. It is
re-exported from the package entrypoint, covered by unit tests (length,
CSPRNG call, zero-length throw), and noted in the package changelog
under the initial release notes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6aa9eed. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Explanation

Release of new @metamask/advanced-chart-core

## References

<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these
changes better?
Are there client or consumer pull requests to adopt any breaking
changes?

For example:

* Fixes #12345
* Related to #67890
-->

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Version and changelog-only release with no runtime or source changes
in this diff.
> 
> **Overview**
> **Release 1298.0.0** bumps the root `@metamask/core-monorepo` version
and cuts the first stable release of **`@metamask/advanced-chart-core`**
at **1.0.0** (from `0.0.0`).
> 
> The package **CHANGELOG** is updated for the release: unreleased notes
are cleared, a **`[1.0.0]`** section documents the initial TradingView
Advanced Charts WebView engine release (with links to
[#9762](#9762) and
[#10521](#10521)), and
compare/release URL anchors are added for future entries.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a73e267. 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: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com>
## Explanation

Add public key derivation and signing utilities for Ed25519.

React Native benchmarks:
```
Finished ed25519 public key benchmark (cold): WebCrypto = 38 ms JS = 1167 ms

Finished ed25519 signing benchmark using 1000 bytes of data: WebCrypto = 2 ms JS = 102 ms
Finished ed25519 signing benchmark using 5000 bytes of data: WebCrypto = 9 ms JS = 279 ms
Finished ed25519 signing benchmark using 10000 bytes of data: WebCrypto = 2 ms JS = 504 ms

Finished ed25519 verification benchmark using 1000 bytes of data: WebCrypto = 2 ms JS = 89 ms
Finished ed25519 verification benchmark using 5000 bytes of data: WebCrypto = 2 ms JS = 180 ms
Finished ed25519 verification benchmark using 10000 bytes of data: WebCrypto = 1 ms JS = 295 ms
```

## References

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

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Introduces new signing and verification primitives in a cryptography
package; behavior is WebCrypto-backed and test-vector covered, but
consumers must handle keys and signatures correctly.
> 
> **Overview**
> Adds a new **`@metamask/cryptography/ed25519`** export with
**`getPublicKey`**, **`sign`**, and **`verify`**, implemented on
**`crypto.subtle`** with raw 32-byte keys and 64-byte signatures, PKCS#8
wrapping for private keys, and strict length checks.
> 
> Shared **`buildPKCS8Header`** / **`toPKCS8`** helpers in
**`utils.ts`** replace the inline X25519 PKCS8 construction so X25519
and Ed25519 use the same envelope pattern. Changelog and
**`package.json`** exports document the new subpath; tests cover RFC
8032 vector 3 plus **`BufferSource`** variants and invalid key/signature
sizes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3b53a55. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Explanation

Adds `SubscriptionDelegationService:startSubscriptionWithDelegation`,
providing a single-approval subscription checkout flow that:

- Combines Money Account vault permissions with the recurring
subscription permission.
- Creates an immutable, fingerprinted authorization bundle for
confirmation.
- Requests MM Pay funding through `ApprovalController`.
- Ensures Money Account delegation readiness after approval.
- Signs, validates, persists, and registers the subscription delegation.
- Verifies that CHOMP reports the intent as active before creating the
subscription.
- Reuses compatible existing delegations where possible.
- Revalidates trial eligibility before subscription creation.

This also:

- Adds temporary local Money Account readiness contracts until the
owning package exports them.
- Adds canonical EIP-712 typed-data construction, hashing, authority
decoding, and bundle fingerprinting.
- Wires the required actions into the wallet initialization messenger.
- Adds Approval Controller, signature utility, and hashing dependencies.
- Expands unit coverage for approval validation, readiness changes,
delegation reuse, CHOMP failures, and trial eligibility changes.

The authorization bundle is sent to confirmations so the complete
effective permission set can be displayed. The local
`assertTrialEligibility` guard is removed before the backend request.

## References

- Subscription delegation signing and confirmation architecture
contract:
https://docs.google.com/document/d/1caawCgJFoRYVZ9yZuRscLuG7ez7RWvAFLNUu_Qim9uY/edit?tab=t.0#heading=h.36v515jilmbd

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by updating the package
changelog
- [ ] I've introduced breaking changes in this PR and have prepared
draft pull requests for clients and consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Orchestrates user consent, MM Pay funding, delegation signing, and
subscription creation with a breaking messenger contract—errors or
ordering bugs could affect payments and recurring charges.
> 
> **Overview**
> Adds
**`SubscriptionDelegationService:startSubscriptionWithDelegation`**, an
end-to-end Money Account Plus checkout that refreshes subscription
state, ensures vault readiness via
**`MoneyAccountUpgradeController:forceUpgradeAccount`**, shows a single
**`subscription_delegation`** approval (immutable permission bundle +
mUSD funding), then signs/commits the recurring payment delegation
(CHOMP verify, AUS persist, active intent) and calls
**`startSubscriptionWithCrypto`** with **`assertTrialEligibility:
true`**. Optional **`skipApproval`** skips consent/funding when the
caller already handled it.
> 
> **Breaking:** **`SubscriptionDelegationServiceMessenger`** must
delegate **`ApprovalController:addRequest`**,
**`MoneyAccountUpgradeController:forceUpgradeAccount`**, and several
**`SubscriptionController:*`** actions; default **wallet**
initialization is updated accordingly. New dependencies on
**approval-controller** and **money-account-upgrade-controller**.
> 
> **`SubscriptionController:startSubscriptionWithCrypto`** gains
optional **`assertTrialEligibility`** and throws
**`TrialEligibilityChanged`** when trial intent no longer matches
authoritative state after authorization. Supporting exports include
EIP-712 **`typed-data`** helpers and approval/bundle types; CHOMP intent
registration now uses the typed **`cash-subscription`** metadata without
alpha workarounds.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
dafb59d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary

- Add `SocialRealtimeService` for subscribing to Social realtime feed
events through the shared backend WebSocket connection.
- Align the `@metamask/core-backend` dependency with the v11 workspace
package.
- Serialize connection and subscription setup to prevent duplicate
subscriptions during synchronous `CONNECTED` notifications.
- Retry subscription setup when an overlapping activation or cleanup
completes without a live subscription.
- Keep subscription ownership local to `SocialRealtimeService` so
existing backend subscriptions are not adopted or unsubscribed
accidentally.
- Export the service and event types from
`@metamask/social-controllers`.

## Testing

- `yarn workspace @metamask/social-controllers run test --no-coverage`
- `yarn workspace @metamask/social-controllers run build`
- `yarn workspace @metamask/social-controllers run changelog:validate`
- `yarn workspace @metamask/social-controllers run lint:tsconfigs`
- `yarn lint:misc --check
packages/social-controllers/src/SocialRealtimeService.ts
packages/social-controllers/src/SocialRealtimeService.test.ts`
- `yarn lint:oxlint
packages/social-controllers/src/SocialRealtimeService.ts
packages/social-controllers/src/SocialRealtimeService.test.ts
packages/social-controllers/src/index.ts
packages/social-controllers/src/index.test.ts`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> New WebSocket subscription lifecycle and async edge cases (reconnect,
race on deactivate) could affect feed freshness if mis-integrated, but
failures are best-effort and scoped to Social realtime.
> 
> **Overview**
> Adds **`SocialRealtimeService`** to `@metamask/social-controllers` so
clients can receive live Social feed updates over the existing
**`BackendWebSocketService`** connection (channel `social.v1.feed.all`),
without opening a separate socket.
> 
> Consumers call **`setActive(true|false)`** to subscribe/unsubscribe
(e.g. when the feed tab is focused), optionally gated by
**`isEnabled`**. Valid **`feed-item`** payloads are validated and
forwarded to listeners; reconnects trigger resubscription and optional
**`addReconnectListener`** callbacks. Subscription setup is serialized
to avoid duplicates during rapid connect/disconnect and overlapping
activate/deactivate.
> 
> The package now depends on **`@metamask/core-backend` ^11.0.0**,
exports the service and related types from the public index, and
documents the dependency in the monorepo graph. This is a new exported
capability—**`SocialController`** is not wired to it in this PR.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e388abc. 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>
Major release of `@metamask/transaction-pay-controller`.

## Adoption PRs

- Extension: MetaMask/metamask-extension#46706
- Mobile: MetaMask/metamask-mobile#36889
…ing for asset selection (#10536)

## Explanation

<!--
Thanks for your contribution! Take a moment to answer these questions so
that reviewers have the information they need to properly understand
your changes:

* What is the current state of things and why does it need to change?
* What is the solution your changes offer and how does it work?
* Are there any changes whose purpose might not obvious to those
unfamiliar with the domain?
* If your primary goal was to update one package but you found you had
to update another one along the way, why did you do so?
* If you had to upgrade a dependency, why did you do so?
-->

When the user picks an asset that their currently selected provider does
not serve, `setSelectedProviderForAsset` switches to another provider.
Today it always picks the first compatible provider in `providers.data`,
i.e. whatever the API ranks highest. That can move a user away from a
provider they have already bought through (and completed KYC with) to
one they have never used, forcing them through onboarding again for no
reason.

This PR changes how `setSelectedProviderForAsset` chooses the
replacement provider. Among the providers that serve the asset
(excluding the currently selected one), it now picks:

1. The first provider the user has previously completed an order with,
checking the most recent completed order first. This keeps the user on a
provider where they already have an existing KYC relationship.
2. Otherwise, the first provider in `providers.data` (API ranking
order), which is the existing behavior.

The order history comes from the existing private
`#getPreferredProviderIdsFromOrders` helper (completed orders in state,
sorted by `createdAt` descending, deduplicated), which is already used
for headless provider resolution. Provider IDs are compared through
`normalizeHeadlessProviderId` on both sides so that IDs stored on orders
match the IDs in `providers.data` regardless of format. All existing
no-op conditions (providers not loaded, current provider already serves
the asset, no compatible provider) are unchanged.

The JSDoc for `setSelectedProviderForAsset` (and the generated messenger
action type) has been updated to describe the new selection order.

## References

<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these
changes better?
Are there client or consumer pull requests to adopt any breaking
changes?

For example:

* Fixes #12345
* Related to #67890
-->

* Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-4090

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes automatic provider selection during buy flows, which affects
checkout routing and KYC reuse, but the logic is scoped to compatibility
switching with existing no-op guards.
> 
> **Overview**
> When the selected ramp provider does not support the chosen asset,
**`setSelectedProviderForAsset`** no longer always switches to the first
compatible provider in API ranking order.
> 
> Among compatible alternatives, it now picks the provider from the
user’s **most recent completed order** (reusing existing
`#getPreferredProviderIdsFromOrders` and `normalizeHeadlessProviderId`
for ID matching). If none of those providers serve the asset, behavior
is unchanged: it falls back to the first compatible entry in
`providers.data`.
> 
> JSDoc, messenger action types, changelog, and unit tests cover the new
preference order, skipping non-serving prior providers, and API-order
fallback.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
735f51a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com>
## Explanation

The crypto subscription start flow and `getSubscriptions` were both
failing on successful API responses because our response structs did not
match what the Subscription API actually returns.

### Crypto start response shape

`SubscriptionService:startSubscriptionWithCrypto` validated the `POST
/subscriptions/crypto` response against
`StartCryptoSubscriptionResponseStruct` (`{ subscriptionId, status }`).
The API actually returns the full created `Subscription` object (crypto
subscriptions are created immediately, unlike card checkout which
returns a checkout session URL). Because the response never had a
`subscriptionId` field, `create()` threw on every successful call, so
the crypto start flow always failed after the API had already created
the subscription.

This PR:

- Removes `StartCryptoSubscriptionResponseStruct` and validates the
response against `SubscriptionStruct` instead.
- Redefines `StartCryptoSubscriptionResponse` as an alias of
`Subscription`. This is **BREAKING** for consumers reading
`response.subscriptionId`; they should read `response.id` instead.
`response.status` is unchanged. This affects
`SubscriptionService:startSubscriptionWithCrypto`,
`SubscriptionController:startSubscriptionWithCrypto`, and
`SubscriptionDelegationService:startSubscriptionWithDelegation`.

### Optional fields on `Subscription`

`SubscriptionStruct` required `lastInvoice.updatedAt` and
`paymentMethod.card.displayBrand`, but both are optional in the API. Any
subscription with a `lastInvoice` (i.e. anything that has been billed at
least once) failed validation and `getSubscriptions` threw. Both fields
are now optional in the struct and on the `SubscriptionInvoice` /
`SubscriptionCardPaymentMethod` types.

### `awaiting_funds` status

The API returns an `awaiting_funds` status for crypto subscriptions that
were created but whose first invoice has not been funded yet. This
status was not in `SUBSCRIPTION_STATUSES`, so such subscriptions also
failed validation. This PR adds `SUBSCRIPTION_STATUSES.awaitingFunds`
and teaches `SubscriptionController:submitSubscriptionCryptoApproval` to
treat it like `past_due` / `unpaid`: submitting a new approval for a
subscription in this state updates the existing subscription's payment
method instead of attempting to start a new one.

### Tests

- `SubscriptionService.test.ts`: crypto start tests now use full
subscription fixtures; added cases for a missing `updatedAt`, a missing
`displayBrand`, the `awaiting_funds` status, pass-through of additional
subscription fields, and rejection of a non-subscription response.
- `SubscriptionController.test.ts` and
`SubscriptionDelegationService.test.ts`: updated to the new response
shape and added coverage for the `awaiting_funds` branch in
`submitSubscriptionCryptoApproval`.

## References

- Follow-up to #10339 (subscription delegation update), which added the
crypto start flow this fixes.
<!-- Add client PRs adopting the `response.subscriptionId` ->
`response.id` change here -->

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Breaking return type on crypto subscription start affects all
consumers; changes subscription status handling and crypto approval
routing for payment recovery.
> 
> **Overview**
> Fixes crypto subscription and `getSubscriptions` flows that **threw on
successful API responses** because client validation did not match the
Subscription API.
> 
> **Breaking:** `StartCryptoSubscriptionResponse` is now the full
created **`Subscription`** (validated with `SubscriptionStruct`), not `{
subscriptionId, status }`. Callers must use **`response.id`** instead of
`response.subscriptionId` on `startSubscriptionWithCrypto` and
delegation start paths.
> 
> **Validation fixes:** `lastInvoice.updatedAt` and card
**`displayBrand`** are optional so billed subscriptions and card payment
methods no longer fail `getSubscriptions`. Adds
**`SUBSCRIPTION_STATUSES.awaitingFunds`** for crypto subs waiting on
first-invoice funding.
> 
> **Behavior:** `submitSubscriptionCryptoApproval` treats
**`awaiting_funds`** like `past_due` / `unpaid`—a new approval **updates
the existing subscription’s payment method** instead of starting a new
subscription.
> 
> Tests and changelog updated for the new response shape, optional
fields, and the awaiting-funds approval branch.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
82a2b98. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Minor release of `@metamask/ramps-controller` (26.0.1 to 26.1.0).

- Prefer a provider the user has previously completed an order with
(most recent first) over API ranking order when
`setSelectedProviderForAsset` switches providers
([#10536](#10536))

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Version and changelog-only release with a minor dependency bump; no
runtime logic changes in this diff.
> 
> **Overview**
> This PR is a **release cut**, not new feature code in the diff: it
bumps the root monorepo from `1299.0.0` to **`1300.0.0`**, publishes
**`@metamask/ramps-controller` `26.1.0`** (from `26.0.1`), and wires
dependents to that version.
> 
> The **`26.1.0`** changelog records the shipped behavior from
[#10536](#10536): when
**`setSelectedProviderForAsset`** switches providers, selection
**prefers providers the user has completed an order with** (most recent
first) instead of raw API ranking.
**`@metamask/transaction-pay-controller`** updates its dependency to
`^26.1.0` and notes the bump in its changelog; **`yarn.lock`** is
refreshed accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fbef638. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Darius Costolas <10818970+meltingice1337@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…arket (#10414)

> Canonical Mobile consumer: MetaMask/metamask-mobile#36881 now contains
Pro order entry, the temporary venue-lock backport and the locked
picker. The former Mobile split PRs are superseded. Keep this upstream
PR; remove the Mobile patch after adopting a released version and
validating parity. Preference persistence remains separate in #10464.

## Explanation

HyperLiquid binds the margin mode to the asset. `OrderParams.marginMode`
placement is rejected when an open position
(`ORDER_MARGIN_MODE_POSITION_OPEN`) or a resting order / active TWAP
(`ORDER_MARGIN_MODE_ORDER_OPEN`) already fixes the other mode. Clients
could not see that current mode: `Order` and `TwapOrder` carry no margin
mode, and `activeAssetData` is only read inside `#validateMarginMode`.
So a client picker could offer a mode that placement will refuse.

This adds `PerpsController.getMarginModeLock({ symbol, providerId? })`
(plus the `PerpsController:getMarginModeLock` messenger action) and the
optional `PerpsProvider.getMarginModeLock`. It returns `locked` (with
`marginMode` and `reason: 'position' | 'open_order'`), `unlocked`, or a
typed `unavailable` result, and never throws.

- HyperLiquid: the lock detection moved out of `#validateMarginMode`
into `#readMarginModeLock`, which both validation and the new method
use, so the reported lock matches what placement enforces. Validation
behavior is unchanged (same reads, same errors, same order).
- Aggregated provider and controller routing mirror
`getOrderCapabilities` (explicit/default provider, `provider_not_found`,
`provider_not_routable`, `not_implemented`, `provider_unavailable`).
- Lighter implements it from the open position's mode (`UpdateLeverage`
carries the wire mode; a missing field means cross). The existing
position-row read moved into `#readPositionMarginMode`; the
leverage-update path keeps its fallback behavior. Only open positions
lock the mode on Lighter; resting orders are not treated as a lock.

It also adds an optional `supportedMarginModes` to ready order
capabilities, so clients stop inferring margin-mode support from the
provider (HyperLiquid, not HIP-3, not isolated-only). HyperLiquid
reports `['isolated', 'cross']` for main-DEX markets and `['isolated']`
for HIP-3 or isolated-only assets, from a single
`#isCrossMarginSupported` predicate that `#validateMarginMode` also
uses. Omitted means the provider does not report it and clients should
not offer an explicit mode.

## References

- Needed by MetaMask Mobile Perps Pro cross margin (TAT-3524): the Pro
margin-mode picker locks to the venue mode while a resting order or TWAP
exists. Mobile validated this against a backported patch on HyperLiquid
testnet (resting Cross limit order → fresh form reads Cross, Isolated
disabled).

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches HyperLiquid pre-sign margin validation and multi-step venue
reads; behavior is intended to stay equivalent while exposing new
client-facing state.
> 
> **Overview**
> Clients can now query **which margin mode a market is locked to**
(open position, resting order, or active TWAP) via
`PerpsController.getMarginModeLock` and the matching messenger action,
with optional `PerpsProvider.getMarginModeLock` on HyperLiquid and
Lighter. Results are `locked` / `unlocked` / typed `unavailable` and
never throw, using the same provider routing as order capabilities.
> 
> HyperLiquid centralizes lock detection in `#readMarginModeLock`
(shared with pre-sign `#validateMarginMode`) and adds account pinning so
position/order reads cannot mix accounts. **Ready order capabilities**
now optionally include `supportedMarginModes`; HyperLiquid derives
isolated vs cross from `#isCrossMarginSupported` (main DEX vs HIP-3 /
isolated-only metadata), so UIs need not guess from the provider id.
> 
> Lighter locks **only on open positions** (resting orders ignored),
reusing `#readPositionMarginMode` for leverage updates and the new API.
Aggregated routing and tests cover the new surface end-to-end.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1827be4. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Explanation

<!--
Thanks for your contribution! Take a moment to answer these questions so
that reviewers have the information they need to properly understand
your changes:

* What is the current state of things and why does it need to change?
* What is the solution your changes offer and how does it work?
* Are there any changes whose purpose might not obvious to those
unfamiliar with the domain?
* If your primary goal was to update one package but you found you had
to update another one along the way, why did you do so?
* If you had to upgrade a dependency, why did you do so?
-->

- Release major subscription-controller 11.0.0
- Release minor wallet 15.1.0

## References

<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these
changes better?
Are there client or consumer pull requests to adopt any breaking
changes?

For example:

* Fixes #12345
* Related to #67890
-->

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [ ] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> The diff is mechanically low-risk, but it releases
subscription-controller 11.0.0 with breaking payment/delegation APIs and
wallet integration changes that clients must adopt deliberately.
> 
> **Overview**
> This is a **monorepo release cut** (`1300.0.0` → `1301.0.0`) with no
application source changes in the diff—only version bumps, changelog
section headers/links, and `yarn.lock` resolution updates.
> 
> It ships **`@metamask/subscription-controller@11.0.0`** (from
`10.0.1`) and **`@metamask/wallet@15.1.0`** (from `15.0.1`), and
propagates those versions to dependents: **`@metamask/wallet`** and
**`@metamask/perps-controller`** (dev) now depend on
`subscription-controller@^11.0.0`; **`@metamask/wallet-cli`** bumps
`@metamask/wallet` to `^15.1.0`.
> 
> Consumers upgrading via this release inherit the
**already-documented** `11.0.0` subscription changes (e.g. delegation
orchestration, `awaiting_funds`, breaking crypto-start return shape and
delegation messenger requirements) and **`15.1.0` wallet** changes
(extra messenger delegations for `startSubscriptionWithDelegation` plus
the subscription-controller bump).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7e844a4. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Sep 29, 2026
@pull pull Bot added the ⤵️ pull label Sep 29, 2026
@pull
pull Bot merged commit fd2ab1c into Reality2byte:main Sep 29, 2026
1 of 6 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants