Skip to content

feat(account-tree-controller): re-introduce lastSelected metadata#8261

Merged
ccharly merged 4 commits intomainfrom
cc/fix/group-last-selected-metadata
Mar 23, 2026
Merged

feat(account-tree-controller): re-introduce lastSelected metadata#8261
ccharly merged 4 commits intomainfrom
cc/fix/group-last-selected-metadata

Conversation

@ccharly
Copy link
Contributor

@ccharly ccharly commented Mar 20, 2026

Explanation

Some logic still relies on this metadata on accounts. Since we want to deprecate the AccountsController at some point, we need to reintroduce this concept, but at the group level this time.

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
Changes selected-group state transitions and fallback selection logic, which could affect which account group becomes active after removals or restarts. Adds new persisted metadata fields and update paths that must stay consistent across init/reinit and event-driven selection updates.

Overview
Re-introduces a local-only lastSelected timestamp on account group metadata, persisted in accountGroupsMetadata and restored during tree rebuilds (init/reinit). The controller now updates lastSelected whenever a group becomes selected (via setSelectedAccountGroup or AccountsController:selectedAccountChange).

Updates default-group fallback logic to prefer the most recently selected non-empty group, with an EVM-group tiebreaker when timestamps match, and refactors selection syncing to avoid infinite loops. Tests and rule-generated default metadata are updated accordingly.

Written by Cursor Bugbot for commit d00ac94. This will update automatically on new commits. Configure here.

@ccharly ccharly force-pushed the cc/fix/group-last-selected-metadata branch 3 times, most recently from ba6d99f to cc3d9fe Compare March 20, 2026 14:58
@ccharly
Copy link
Contributor Author

ccharly commented Mar 20, 2026

@metamaskbot publish-preview

@github-actions
Copy link
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@5.0.1-preview-cc3d9fe8e
@metamask-previews/accounts-controller@37.0.0-preview-cc3d9fe8e
@metamask-previews/address-book-controller@7.1.0-preview-cc3d9fe8e
@metamask-previews/ai-controllers@0.4.0-preview-cc3d9fe8e
@metamask-previews/analytics-controller@1.0.0-preview-cc3d9fe8e
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-cc3d9fe8e
@metamask-previews/announcement-controller@8.0.0-preview-cc3d9fe8e
@metamask-previews/app-metadata-controller@2.0.0-preview-cc3d9fe8e
@metamask-previews/approval-controller@9.0.0-preview-cc3d9fe8e
@metamask-previews/assets-controller@3.0.0-preview-cc3d9fe8e
@metamask-previews/assets-controllers@101.0.1-preview-cc3d9fe8e
@metamask-previews/base-controller@9.0.0-preview-cc3d9fe8e
@metamask-previews/base-data-service@0.0.0-preview-cc3d9fe8e
@metamask-previews/bridge-controller@69.1.1-preview-cc3d9fe8e
@metamask-previews/bridge-status-controller@70.0.0-preview-cc3d9fe8e
@metamask-previews/build-utils@3.0.4-preview-cc3d9fe8e
@metamask-previews/chain-agnostic-permission@1.4.0-preview-cc3d9fe8e
@metamask-previews/claims-controller@0.4.3-preview-cc3d9fe8e
@metamask-previews/client-controller@1.0.0-preview-cc3d9fe8e
@metamask-previews/compliance-controller@1.0.1-preview-cc3d9fe8e
@metamask-previews/composable-controller@12.0.0-preview-cc3d9fe8e
@metamask-previews/config-registry-controller@0.1.1-preview-cc3d9fe8e
@metamask-previews/connectivity-controller@0.1.0-preview-cc3d9fe8e
@metamask-previews/controller-utils@11.19.0-preview-cc3d9fe8e
@metamask-previews/core-backend@6.2.0-preview-cc3d9fe8e
@metamask-previews/delegation-controller@2.0.2-preview-cc3d9fe8e
@metamask-previews/earn-controller@11.1.2-preview-cc3d9fe8e
@metamask-previews/eip-5792-middleware@3.0.1-preview-cc3d9fe8e
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-cc3d9fe8e
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-cc3d9fe8e
@metamask-previews/ens-controller@19.1.0-preview-cc3d9fe8e
@metamask-previews/error-reporting-service@3.0.1-preview-cc3d9fe8e
@metamask-previews/eth-block-tracker@15.0.1-preview-cc3d9fe8e
@metamask-previews/eth-json-rpc-middleware@23.1.0-preview-cc3d9fe8e
@metamask-previews/eth-json-rpc-provider@6.0.0-preview-cc3d9fe8e
@metamask-previews/foundryup@1.0.1-preview-cc3d9fe8e
@metamask-previews/gas-fee-controller@26.1.0-preview-cc3d9fe8e
@metamask-previews/gator-permissions-controller@2.1.1-preview-cc3d9fe8e
@metamask-previews/geolocation-controller@0.1.1-preview-cc3d9fe8e
@metamask-previews/json-rpc-engine@10.2.3-preview-cc3d9fe8e
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-cc3d9fe8e
@metamask-previews/keyring-controller@25.1.0-preview-cc3d9fe8e
@metamask-previews/logging-controller@8.0.0-preview-cc3d9fe8e
@metamask-previews/message-manager@14.1.0-preview-cc3d9fe8e
@metamask-previews/messenger@0.3.0-preview-cc3d9fe8e
@metamask-previews/multichain-account-service@7.1.0-preview-cc3d9fe8e
@metamask-previews/multichain-api-middleware@1.2.7-preview-cc3d9fe8e
@metamask-previews/multichain-network-controller@3.0.5-preview-cc3d9fe8e
@metamask-previews/multichain-transactions-controller@7.0.2-preview-cc3d9fe8e
@metamask-previews/name-controller@9.1.0-preview-cc3d9fe8e
@metamask-previews/network-controller@30.0.0-preview-cc3d9fe8e
@metamask-previews/network-enablement-controller@5.0.0-preview-cc3d9fe8e
@metamask-previews/notification-services-controller@23.0.0-preview-cc3d9fe8e
@metamask-previews/permission-controller@12.2.1-preview-cc3d9fe8e
@metamask-previews/permission-log-controller@5.0.0-preview-cc3d9fe8e
@metamask-previews/perps-controller@1.3.0-preview-cc3d9fe8e
@metamask-previews/phishing-controller@17.0.0-preview-cc3d9fe8e
@metamask-previews/polling-controller@16.0.3-preview-cc3d9fe8e
@metamask-previews/preferences-controller@23.0.0-preview-cc3d9fe8e
@metamask-previews/profile-metrics-controller@3.1.1-preview-cc3d9fe8e
@metamask-previews/profile-sync-controller@28.0.0-preview-cc3d9fe8e
@metamask-previews/ramps-controller@12.0.0-preview-cc3d9fe8e
@metamask-previews/rate-limit-controller@7.0.0-preview-cc3d9fe8e
@metamask-previews/react-data-query@0.0.0-preview-cc3d9fe8e
@metamask-previews/remote-feature-flag-controller@4.1.0-preview-cc3d9fe8e
@metamask-previews/sample-controllers@4.0.3-preview-cc3d9fe8e
@metamask-previews/seedless-onboarding-controller@9.0.0-preview-cc3d9fe8e
@metamask-previews/selected-network-controller@26.0.3-preview-cc3d9fe8e
@metamask-previews/shield-controller@5.0.2-preview-cc3d9fe8e
@metamask-previews/signature-controller@39.1.0-preview-cc3d9fe8e
@metamask-previews/storage-service@1.0.0-preview-cc3d9fe8e
@metamask-previews/subscription-controller@6.0.2-preview-cc3d9fe8e
@metamask-previews/transaction-controller@63.0.0-preview-cc3d9fe8e
@metamask-previews/transaction-pay-controller@18.0.0-preview-cc3d9fe8e
@metamask-previews/user-operation-controller@41.1.0-preview-cc3d9fe8e

@ccharly ccharly marked this pull request as ready for review March 20, 2026 16:02
@ccharly ccharly requested review from a team as code owners March 20, 2026 16:02
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

@ccharly ccharly force-pushed the cc/fix/group-last-selected-metadata branch from cc3d9fe to f34c64d Compare March 23, 2026 09:27
@ccharly
Copy link
Contributor Author

ccharly commented Mar 23, 2026

@metamaskbot publish-preview

@github-actions
Copy link
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@5.0.1-preview-f34c64d70
@metamask-previews/accounts-controller@37.0.0-preview-f34c64d70
@metamask-previews/address-book-controller@7.1.0-preview-f34c64d70
@metamask-previews/ai-controllers@0.4.0-preview-f34c64d70
@metamask-previews/analytics-controller@1.0.0-preview-f34c64d70
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-f34c64d70
@metamask-previews/announcement-controller@8.0.0-preview-f34c64d70
@metamask-previews/app-metadata-controller@2.0.0-preview-f34c64d70
@metamask-previews/approval-controller@9.0.0-preview-f34c64d70
@metamask-previews/assets-controller@3.0.0-preview-f34c64d70
@metamask-previews/assets-controllers@101.0.1-preview-f34c64d70
@metamask-previews/base-controller@9.0.0-preview-f34c64d70
@metamask-previews/base-data-service@0.0.0-preview-f34c64d70
@metamask-previews/bridge-controller@69.1.1-preview-f34c64d70
@metamask-previews/bridge-status-controller@70.0.0-preview-f34c64d70
@metamask-previews/build-utils@3.0.4-preview-f34c64d70
@metamask-previews/chain-agnostic-permission@1.4.0-preview-f34c64d70
@metamask-previews/claims-controller@0.4.3-preview-f34c64d70
@metamask-previews/client-controller@1.0.0-preview-f34c64d70
@metamask-previews/compliance-controller@1.0.1-preview-f34c64d70
@metamask-previews/composable-controller@12.0.0-preview-f34c64d70
@metamask-previews/config-registry-controller@0.1.1-preview-f34c64d70
@metamask-previews/connectivity-controller@0.1.0-preview-f34c64d70
@metamask-previews/controller-utils@11.19.0-preview-f34c64d70
@metamask-previews/core-backend@6.2.0-preview-f34c64d70
@metamask-previews/delegation-controller@2.0.2-preview-f34c64d70
@metamask-previews/earn-controller@11.1.2-preview-f34c64d70
@metamask-previews/eip-5792-middleware@3.0.1-preview-f34c64d70
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.0-preview-f34c64d70
@metamask-previews/eip1193-permission-middleware@1.0.3-preview-f34c64d70
@metamask-previews/ens-controller@19.1.0-preview-f34c64d70
@metamask-previews/error-reporting-service@3.0.1-preview-f34c64d70
@metamask-previews/eth-block-tracker@15.0.1-preview-f34c64d70
@metamask-previews/eth-json-rpc-middleware@23.1.0-preview-f34c64d70
@metamask-previews/eth-json-rpc-provider@6.0.0-preview-f34c64d70
@metamask-previews/foundryup@1.0.1-preview-f34c64d70
@metamask-previews/gas-fee-controller@26.1.0-preview-f34c64d70
@metamask-previews/gator-permissions-controller@2.1.1-preview-f34c64d70
@metamask-previews/geolocation-controller@0.1.1-preview-f34c64d70
@metamask-previews/json-rpc-engine@10.2.3-preview-f34c64d70
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-f34c64d70
@metamask-previews/keyring-controller@25.1.0-preview-f34c64d70
@metamask-previews/logging-controller@8.0.0-preview-f34c64d70
@metamask-previews/message-manager@14.1.0-preview-f34c64d70
@metamask-previews/messenger@0.3.0-preview-f34c64d70
@metamask-previews/multichain-account-service@7.1.0-preview-f34c64d70
@metamask-previews/multichain-api-middleware@1.2.7-preview-f34c64d70
@metamask-previews/multichain-network-controller@3.0.5-preview-f34c64d70
@metamask-previews/multichain-transactions-controller@7.0.2-preview-f34c64d70
@metamask-previews/name-controller@9.1.0-preview-f34c64d70
@metamask-previews/network-controller@30.0.0-preview-f34c64d70
@metamask-previews/network-enablement-controller@5.0.0-preview-f34c64d70
@metamask-previews/notification-services-controller@23.0.0-preview-f34c64d70
@metamask-previews/permission-controller@12.2.1-preview-f34c64d70
@metamask-previews/permission-log-controller@5.0.0-preview-f34c64d70
@metamask-previews/perps-controller@1.3.0-preview-f34c64d70
@metamask-previews/phishing-controller@17.0.0-preview-f34c64d70
@metamask-previews/polling-controller@16.0.3-preview-f34c64d70
@metamask-previews/preferences-controller@23.0.0-preview-f34c64d70
@metamask-previews/profile-metrics-controller@3.1.1-preview-f34c64d70
@metamask-previews/profile-sync-controller@28.0.0-preview-f34c64d70
@metamask-previews/ramps-controller@12.0.0-preview-f34c64d70
@metamask-previews/rate-limit-controller@7.0.0-preview-f34c64d70
@metamask-previews/react-data-query@0.0.0-preview-f34c64d70
@metamask-previews/remote-feature-flag-controller@4.1.0-preview-f34c64d70
@metamask-previews/sample-controllers@4.0.3-preview-f34c64d70
@metamask-previews/seedless-onboarding-controller@9.0.0-preview-f34c64d70
@metamask-previews/selected-network-controller@26.0.3-preview-f34c64d70
@metamask-previews/shield-controller@5.0.2-preview-f34c64d70
@metamask-previews/signature-controller@39.1.0-preview-f34c64d70
@metamask-previews/storage-service@1.0.0-preview-f34c64d70
@metamask-previews/subscription-controller@6.0.2-preview-f34c64d70
@metamask-previews/transaction-controller@63.0.0-preview-f34c64d70
@metamask-previews/transaction-pay-controller@18.0.0-preview-f34c64d70
@metamask-previews/user-operation-controller@41.1.0-preview-f34c64d70

'AccountsController:setSelectedAccount',
accountToSelect,
);
if (forwardSelectedAccount) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we shouldn't really need that flag given that this method is idempotent. Added it for more fine-grained control still + to be explicit

// track of the most recently selected groups.
const now = Date.now();

/* istanbul ignore next */
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We usually ignore those as there's just here to auto-inject the default state when needed

* @param groupId - The account group ID to select.
*/
setSelectedAccountGroup(groupId: AccountGroupId): void {
this.#setSelectedAccountGroup(groupId);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Created this new private method so we can re-use it with the event handling from the AccountsController

Comment on lines +732 to +743
// Apply persisted lastSelected (plain number, not synced).
if (
persistedGroupMetadata?.lastSelected !== undefined &&
persistedGroupMetadata.lastSelected >= 0
) {
group.metadata.lastSelected = persistedGroupMetadata.lastSelected;
} else {
// Automatiacally inject default value.
state.accountGroupsMetadata[groupId].lastSelected = 0;

group.metadata.lastSelected = 0;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The usual logic for the tree metadata, use the persistent data if any, otherwise we auto-inject the default values.

Comment on lines +366 to +368
state.selectedAccountGroup = this.#getDefaultSelectedAccountGroup(
state.accountTree.wallets, // Re-use updated wallets with metadata here.
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This got flagged by Cursor initially, we need to state.accountTree.wallets now, since #getDefaultSelectedAccountGroup uses group.metadata.lastSelected for its logic and they get populated on the state directly during that state update call.

wallets is not getting updated, thus, we would miss them and not use them.

@ccharly ccharly added this pull request to the merge queue Mar 23, 2026
Merged via the queue into main with commit 42a4251 Mar 23, 2026
326 checks passed
@ccharly ccharly deleted the cc/fix/group-last-selected-metadata branch March 23, 2026 17:10
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.

2 participants