Skip to content

feat(account-tree-controller): persist accountTree#8437

Merged
ccharly merged 3 commits intomainfrom
cc/feat/persistent-account-tree
Apr 14, 2026
Merged

feat(account-tree-controller): persist accountTree#8437
ccharly merged 3 commits intomainfrom
cc/feat/persistent-account-tree

Conversation

@ccharly
Copy link
Copy Markdown
Contributor

@ccharly ccharly commented Apr 13, 2026

Explanation

We used to not persist the account-tree before and we were re-constructing it "fresh" upon init. However, some other controllers are dependent on the tree and have to wait for it to be built before consuming it.

Since the tree should never really change between lock/unlock, that's ok to have a on-disk copy of it to speedup consumers.

We will still try to re-construct it during init though (in case rules have changed or that new accounts have appeared that went unnoticed).

References

N/A

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
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Persists and rehydrates core controller state, which can affect startup/lock-unlock behavior and introduce stale/mismatched tree data if persisted state diverges from current accounts.

Overview
AccountTreeController now persists accountTree (state metadata persist: true) instead of always recomputing it on init.

The controller constructor now pre-initializes internal reverse lookup maps from the persisted tree via #initTreeContext, allowing methods like getAccountContext, getAccountGroupObject, and getAccountsFromSelectedAccountGroup to work before init() runs.

Tests and snapshots are updated to cover pre-populated persisted state behavior and the new persisted-state surface, and the changelog documents the new persistence behavior.

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

@salimtb
Copy link
Copy Markdown
Contributor

salimtb commented Apr 13, 2026

@metamaskbot publish-preview

@github-actions
Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.0.0-preview-5e1e04b55
@metamask-previews/accounts-controller@37.2.0-preview-5e1e04b55
@metamask-previews/address-book-controller@7.1.1-preview-5e1e04b55
@metamask-previews/ai-controllers@0.6.3-preview-5e1e04b55
@metamask-previews/analytics-controller@1.0.1-preview-5e1e04b55
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-5e1e04b55
@metamask-previews/announcement-controller@8.1.0-preview-5e1e04b55
@metamask-previews/app-metadata-controller@2.0.1-preview-5e1e04b55
@metamask-previews/approval-controller@9.0.1-preview-5e1e04b55
@metamask-previews/assets-controller@5.0.0-preview-5e1e04b55
@metamask-previews/assets-controllers@103.1.1-preview-5e1e04b55
@metamask-previews/base-controller@9.0.1-preview-5e1e04b55
@metamask-previews/base-data-service@0.1.1-preview-5e1e04b55
@metamask-previews/bridge-controller@70.0.1-preview-5e1e04b55
@metamask-previews/bridge-status-controller@70.0.5-preview-5e1e04b55
@metamask-previews/build-utils@3.0.4-preview-5e1e04b55
@metamask-previews/chain-agnostic-permission@1.5.0-preview-5e1e04b55
@metamask-previews/claims-controller@0.5.0-preview-5e1e04b55
@metamask-previews/client-controller@1.0.1-preview-5e1e04b55
@metamask-previews/compliance-controller@2.0.0-preview-5e1e04b55
@metamask-previews/composable-controller@12.0.1-preview-5e1e04b55
@metamask-previews/config-registry-controller@0.2.0-preview-5e1e04b55
@metamask-previews/connectivity-controller@0.2.0-preview-5e1e04b55
@metamask-previews/controller-utils@11.20.0-preview-5e1e04b55
@metamask-previews/core-backend@6.2.1-preview-5e1e04b55
@metamask-previews/delegation-controller@2.1.0-preview-5e1e04b55
@metamask-previews/earn-controller@11.2.1-preview-5e1e04b55
@metamask-previews/eip-5792-middleware@3.0.3-preview-5e1e04b55
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-5e1e04b55
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-5e1e04b55
@metamask-previews/ens-controller@19.1.1-preview-5e1e04b55
@metamask-previews/eth-block-tracker@15.0.1-preview-5e1e04b55
@metamask-previews/eth-json-rpc-middleware@23.1.1-preview-5e1e04b55
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-5e1e04b55
@metamask-previews/foundryup@1.0.1-preview-5e1e04b55
@metamask-previews/gas-fee-controller@26.1.1-preview-5e1e04b55
@metamask-previews/gator-permissions-controller@3.0.1-preview-5e1e04b55
@metamask-previews/geolocation-controller@0.1.2-preview-5e1e04b55
@metamask-previews/json-rpc-engine@10.2.4-preview-5e1e04b55
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-5e1e04b55
@metamask-previews/keyring-controller@25.2.0-preview-5e1e04b55
@metamask-previews/logging-controller@8.0.1-preview-5e1e04b55
@metamask-previews/message-manager@14.1.1-preview-5e1e04b55
@metamask-previews/messenger@1.1.1-preview-5e1e04b55
@metamask-previews/messenger-cli@0.1.0-preview-5e1e04b55
@metamask-previews/money-account-controller@0.1.0-preview-5e1e04b55
@metamask-previews/multichain-account-service@8.0.1-preview-5e1e04b55
@metamask-previews/multichain-api-middleware@2.0.0-preview-5e1e04b55
@metamask-previews/multichain-network-controller@3.0.6-preview-5e1e04b55
@metamask-previews/multichain-transactions-controller@7.0.4-preview-5e1e04b55
@metamask-previews/name-controller@9.1.1-preview-5e1e04b55
@metamask-previews/network-controller@30.0.1-preview-5e1e04b55
@metamask-previews/network-enablement-controller@5.0.2-preview-5e1e04b55
@metamask-previews/notification-services-controller@23.0.1-preview-5e1e04b55
@metamask-previews/permission-controller@12.3.0-preview-5e1e04b55
@metamask-previews/permission-log-controller@5.1.0-preview-5e1e04b55
@metamask-previews/perps-controller@3.0.0-preview-5e1e04b55
@metamask-previews/phishing-controller@17.1.1-preview-5e1e04b55
@metamask-previews/polling-controller@16.0.4-preview-5e1e04b55
@metamask-previews/preferences-controller@23.1.0-preview-5e1e04b55
@metamask-previews/profile-metrics-controller@3.1.3-preview-5e1e04b55
@metamask-previews/profile-sync-controller@28.0.2-preview-5e1e04b55
@metamask-previews/ramps-controller@13.1.0-preview-5e1e04b55
@metamask-previews/rate-limit-controller@7.0.1-preview-5e1e04b55
@metamask-previews/react-data-query@0.2.0-preview-5e1e04b55
@metamask-previews/remote-feature-flag-controller@4.2.0-preview-5e1e04b55
@metamask-previews/sample-controllers@4.0.4-preview-5e1e04b55
@metamask-previews/seedless-onboarding-controller@9.1.0-preview-5e1e04b55
@metamask-previews/selected-network-controller@26.1.0-preview-5e1e04b55
@metamask-previews/shield-controller@5.1.1-preview-5e1e04b55
@metamask-previews/signature-controller@39.1.2-preview-5e1e04b55
@metamask-previews/social-controllers@0.1.0-preview-5e1e04b55
@metamask-previews/storage-service@1.0.1-preview-5e1e04b55
@metamask-previews/subscription-controller@6.1.2-preview-5e1e04b55
@metamask-previews/transaction-controller@64.1.0-preview-5e1e04b55
@metamask-previews/transaction-pay-controller@19.1.0-preview-5e1e04b55
@metamask-previews/user-operation-controller@41.2.0-preview-5e1e04b55

@ccharly ccharly marked this pull request as ready for review April 13, 2026 16:44
@ccharly ccharly requested review from a team as code owners April 13, 2026 16:44
for (const accountId of group.accounts) {
// The `AccountsController` also persists its accounts, so we
// can fetch them too!
const account = this.messenger.call(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We can reduce this to one call by getting all the accounts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I initially wanted to use :getAccounts, but didn't want to introduce a breaking change for this

However, I see we still have the old listMultichainAccounts, so we can probably use that + make a Map from it for fast indexing!

Good idea, let me change this!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@montelaidev beat me to it. I would prefer the one getAccounts call as well. I don't think it makes sense to rebuild essentially what is the same map to avoid a breaking change

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

something like this:

        const accounts = this.messenger.call(
          'AccountsController:getAccounts',
          group.accounts,
        );

        group.accounts.forEach((accountId, idx) => {
          const account = accounts[idx];
          let sortOrder = MAX_SORT_ORDER;
          if (account) {
            sortOrder = ACCOUNT_TYPE_TO_SORT_ORDER[account.type];
          }

          this.#accountIdToContext.set(accountId, {
            walletId,
            groupId,
            sortOrder,
          });
        });

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I went for :listMultichainAccounts since adding :getAccounts would involve a breaking change for this controller and I'd like to keep it non-breaking for now to avoid the bubbling effect with this change 😅

Though, with :listMultichainAccounts + a Map we can get something pretty similar (I went for that).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can always change that later, but my goal for now is to unblock the assets team, we can introduce :getAccounts later for sure 👍

@ccharly ccharly added this pull request to the merge queue Apr 14, 2026
Merged via the queue into main with commit ec1b5fc Apr 14, 2026
665 of 675 checks passed
@ccharly ccharly deleted the cc/feat/persistent-account-tree branch April 14, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants