Repository navigation
feat(wallet): initialize AssetsController by default and defer messenger reads to init - #10885
dawnseeker8 wants to merge 40 commits into
Conversation
Export an AssetsController initialization config so clients can register it after NetworkEnablementController, which the wallet does not initialize yet. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@metamaskbot publish-preview |
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
…et-assets-controller Co-authored-by: Cursor <cursoragent@cursor.com>
…ontroller' into feat/assets-3641-wallet-assets-controller
|
@metamaskbot publish-preview |
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
…Mask#10997) ## Explanation `@metamask/wallet` now constructs `NetworkEnablementController` during default initialization. The constructor only needs a messenger and optional persisted state, so there is no new `instanceOptions` field. ### Breaking change `Wallet.init()` calls `NetworkEnablementController.init()`. That method reads `MultichainNetworkController:getState`. The wallet does not construct `MultichainNetworkController`, so each client must register that action on the wallet messenger before `wallet.init()`. `NetworkEnablementController` is a default initialization configuration and is not exported. Construction order for `AssetsController` is handled in MetaMask#10885 by moving the `NetworkEnablementController:getState` read into `AssetsController.init()`. ### What this pull request changes - Add `NetworkEnablementController` to the default initialization configurations. - Delegate `NetworkController:getState`, `MultichainNetworkController:getState`, and `ConfigRegistryController:getState`, plus the network and transaction events the controller subscribes to. - Import `@metamask/slip44` with a JSON import attribute so Node.js 22 and 24 do not throw `ERR_IMPORT_ATTRIBUTE_MISSING` when loading `NetworkEnablementController`. - Generate the CODEOWNERS entry from `codeowners.ts`. `@metamask/wallet-cli` was removed on `main` (MetaMask#11001), so this pull request no longer changes that package. `AssetsController` initialization stays in MetaMask#10885 and will be updated after this merges. ## References * [ASSETS-4169](https://consensyssoftware.atlassian.net/browse/ASSETS-4169) * Follow-up: MetaMask#10885 ## 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 [ASSETS-4169]: https://consensyssoftware.atlassian.net/browse/ASSETS-4169?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Breaking wallet init contract: clients must pre-register `MultichainNetworkController:getState` or initialization fails; otherwise changes are localized wiring and a Node ESM import fix. > > **Overview** > **`@metamask/wallet` now wires `NetworkEnablementController` into default initialization**, so `Wallet.init()` constructs it alongside the other default controllers. The new `networkEnablementController` configuration delegates messenger actions (`ConfigRegistryController:getState`, `NetworkController:getState`, **`MultichainNetworkController:getState`**) and network/transaction events the controller listens to. **Breaking:** the wallet does not create `MultichainNetworkController`, so hosts must register `MultichainNetworkController:getState` on the wallet root messenger before `wallet.init()`. > > The package adds `@metamask/network-enablement-controller` (^7.0.2), exports the init config from the instances barrel, and updates CODEOWNERS/`codeowners.ts` for the new initialization path. > > **`@metamask/network-enablement-controller`** fixes Node 22/24 ESM loading by importing `@metamask/slip44` with `with { type: 'json' }` in `Slip44Service`, avoiding `ERR_IMPORT_ATTRIBUTE_MISSING` when the wallet daemon loads the controller. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 41650ee. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
…et-assets-controller Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # packages/wallet/CHANGELOG.md
AssetsController can be constructed before NetworkEnablementController exists. init() and the stateChange subscription apply enabled chains once that state is available. Co-authored-by: Cursor <cursoragent@cursor.com>
The new test used a widened CAIP-19 id and an extra publish argument, which lint:tsc:check treats as unsuppressed errors. Co-authored-by: Cursor <cursoragent@cursor.com>
The new assertions used a short cast parameter and nullish fallbacks, which oxlint reports as unsuppressed violations. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@metamaskbot publish-preview |
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
Changelog checks only accept the open pull request under Unreleased, and oxfmt needs the enabled-chain assertion wrapped. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@metamaskbot publish-preview |
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@metamaskbot publish-preview |
…ithub.com/MetaMask/core into feat/assets-3641-wallet-assets-controller Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
Allow the second event payload on test publishes, and let staked messenger fixtures omit mockProvider so the constructor test can override only the enabled network map. Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
…et-assets-controller Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com> # Conflicts: # yarn.lock
…et-assets-controller Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # packages/assets-controller/CHANGELOG.md
Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
…rce.ts Co-authored-by: Christian Tran <christian.trn@gmail.com>
Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
…et-assets-controller Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # packages/assets-controller/CHANGELOG.md
Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3862d52. Configure here.
…ontroller' into feat/assets-3641-wallet-assets-controller Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
| let enabledNetworkMap: NetworkEnablementControllerState['enabledNetworkMap']; | ||
| try { | ||
| ({ enabledNetworkMap } = this.messenger.call( | ||
| 'NetworkEnablementController:getState', | ||
| )); | ||
| } catch (error) { | ||
| if (!isUnregisteredActionError(error)) { | ||
| throw error; | ||
| } | ||
| log( | ||
| 'NetworkEnablementController:getState is not registered yet. Enabled chains are applied from NetworkEnablementController:stateChange.', | ||
| { error }, | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| this.#enabledChains = this.#extractEnabledChains(enabledNetworkMap); |
There was a problem hiding this comment.
Please feel free to remove some init. For example
this.#enabledChains = this.#extractEnabledChains(enabledNetworkMap);
Might not be needed. we can just call enabled chains when needed. Instead of caching it in the AssetsController
| } catch (error) { | ||
| if (!isUnregisteredActionError(error)) { | ||
| throw error; | ||
| } |
AssetsControllerInstanceOptions already requires queryApiClient, and WalletOptions requires instanceOptions.assetsController, so omitting the client is a type error. Remove the runtime throw and the test that asserted it. Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>
|
@metamaskbot publish-preview |
|
Preview builds have been published. Learn how to use preview builds in other projects. Expand for full list of packages and versions. |
…et-assets-controller Keep both Unreleased assets-controller changelog entries. Call AssetsController.init() in the launchpad filtering integration test so supported-network discovery still runs after messenger reads moved out of the constructor. Co-authored-by: Xiaoming Wang <dawnseeker8@users.noreply.github.com>

Explanation
@metamask/assets-controlleris published as its own package and is not part of@metamask/walletinitialization. ASSETS-3641 asks the wallet package to include it in the shared initialization flow.This adds an opt-in
assetsControllerinitialization configuration and theAssetsControllerInstanceOptionstype. It is not registered in the default configurations.AccountTreeControllerandSnapControllerare still missing from the defaults, so registeringAssetsControllerby default would fail during construction.NetworkEnablementControlleris already a default (#10997).A consumer passes
assetsControllerthroughinitializationConfigurationsand suppliesinstanceOptions.assetsController. That option requiresqueryApiClient. The child messenger delegates every action and event declared byAssetsControllerMessenger. IfqueryApiClientis missing, initialization throws. Caller configurations are constructed before the defaultNetworkEnablementController.AssetsControllerused to callNetworkEnablementController:getStatein its constructor, so construction failed unless that action was already registered. Construction now subscribes toNetworkEnablementController:stateChangefirst and only readsgetStatewhen the action is registered. The newinit()reads enabled chains once every controller exists.Wallet.init()calls thatinit(). Later enablement changes still arrive onstateChange.init()is not a messenger action.RpcDataSourceandStakedBalanceDataSourcealso readNetworkController:getStateandNetworkEnablementController:getStateonly at construction. When the wallet constructsAssetsControllerbefore those controllers, both reads fail and active chains stay empty until a laterstateChange.init()now refreshes both data sources.StakedBalanceDataSourcegainsrefreshActiveChainsFromNetworkEnablementState(), matching the existingRpcDataSource.refreshActiveChainsFromNetworkState().@metamask/assets-controlleris added as a@metamask/walletdependency at^20.0.1, matching the current workspace version, plus a TypeScript project reference. Ownership of the new instance directory is@MetaMask/metamask-assets.Preview builds, publishing, and Extension/Mobile adoption stay out of this PR. Registering
AssetsControlleras a default waits on the remaining controllers.References
@metamask/assets-controllerinto the Core Wallet packageNetworkEnablementController: #10997Checklist
Note
High Risk
Multiple breaking changes affect wallet bootstrap (new required options, default controller, messenger collisions) and assets lifecycle (mandatory init(), new event subscription and account-selection behavior).
Reviewed by Cursor Bugbot for commit e5624fd. Bugbot is set up for automated code reviews on this repo. Configure here.
Explanation
@metamask/assets-controlleris now part of@metamask/walletdefault initialization. ASSETS-3641 asks the wallet package to include it in the shared initialization flow.AssetsControlleris constructed with the other default controllers.instanceOptions.assetsController.queryApiClientis required byAssetsControllerInstanceOptions. The child messenger delegates every action and event declared byAssetsControllerMessenger.AccountTreeControllerandSnapControllerare still not Wallet defaults. Construction does not call them, so Wallet construction succeeds while they are absent:AccountTreeController:getAccountsFromSelectedAccountGroupand fall back toAccountsController:getSelectedAccountwhen that action is not registered. A registered handler that throws still throws.AccountTreeController:isInitializedas initialized, so tracking is not blocked on a controller the host has not installed. Other errors still throw.AccountActivityDataSourceuses the same selected-account fallback.SnapDataSource.init(). WhenSnapControlleris not registered, active snap chains stay empty. LaterSnapController:snapInstalledand permission changes rediscover.AssetsControllerand its data sources do not call messenger actions in their constructors.Wallet.init()callsAssetsController.init()after every controller has been constructed.init():NetworkEnablementController:getStateRpcDataSource.refreshActiveChainsFromNetworkState()(NetworkController:getState)StakedBalanceDataSource.refreshActiveChainsFromNetworkEnablementState()(NetworkEnablementController:getState)SnapDataSource.init()(SnapController:getRunnableSnapsandPermissionController:getPermissions)AccountsApiDataSource.init()(supported networks, thenRemoteFeatureFlagController:getState)Subscriptions stay in the constructors. The Multicall3 address lookup is a callback stored for a later balance fetch;
MulticallClientdoes not invoke it during construction.Hosts that already register
AssetsControlleron the wallet root messenger must remove that registration before upgrading, or messenger registration will collide.References
@metamask/assets-controllerinto the Core Wallet packageNetworkEnablementController: #10997Checklist