Skip to content

Conversation

fabiobozzo
Copy link
Contributor

@fabiobozzo fabiobozzo commented Sep 15, 2025

Explanation

CRITICAL FIX: Resolves a severe multi-wallet account naming bug that caused duplicate, inconsistent, and confusing account group names across different seed phrases (SRPs).

Current Problem

Users importing multiple seed phrases experienced catastrophic naming issues:

  • Duplicate names: Multiple "Account 2", "Account 3" within the same wallet
  • Missing "Account 1": Some wallets would start at "Account 2"
  • Cross-wallet confusion: Second SRP incorrectly showing "Account 3" when it should be "Account 1"
  • Inconsistent after restart: Names would change unpredictably on app restart

Root Cause

The account group naming logic had critical flaws:

  1. Broken alphabetical sorting: Used Object.keys(wallet.groups).sort() which caused conflicts and duplicates in multi-wallet scenarios
  2. Unsafe entropy access: Could throw TypeError when accessing group.metadata.entropy.groupIndex without null checks
  3. Negative index bug: Empty wallets would get -1 index, causing invalid "Account 0" names

Solution

Implemented a robust fix with comprehensive improvements:

  1. Per-wallet sequential numbering: Each wallet maintains independent "Account 1", "Account 2", etc. numbering with dynamic pattern detection that works with any naming convention ("Account N", "Imported Account N", etc.)
  2. Smart conflict resolution: Universal conflict detection with while loop that finds next available unique name, handles user renames, and ensures unique sequential names
  3. Entropy-aware indexing: For multichain groups, prioritizes actual groupIndex from entropy metadata when available with safe null checks
  4. Starting point optimization: Begins name checking at wallet.groups.length to minimize iterations and improve efficiency
  5. AutoHandleConflict integration: Added optional autoHandleConflict parameter to setAccountGroupName() for automated conflict resolution with suffix generation ("Account 1 (2)", "Account 1 (3)", etc.) - ready for Backup & Sync integration

References

Fixes:

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, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

CRITICAL FIX for account group naming inconsistencies across multiple wallets.

Issues Fixed:
- Duplicate account names (Account 2, Account 2, Account 3...)
- Missing Account 1 in some wallets
- Non-sequential numbering and random order
- Second SRP incorrectly showing 'Account 3' instead of 'Account 1'

Root Cause:
The alphabetical sorting of group IDs was fundamentally broken for
multi-wallet scenarios. Different wallets would conflict and produce
inconsistent, duplicate names.

Solution:
1. For entropy groups: Use the actual groupIndex from metadata
2. Persist assigned names immediately to ensure consistency
3. Track used numbers per wallet to avoid duplicates
4. Each wallet now has independent sequential numbering

Changes:
- Removed broken alphabetical sorting logic
- Implemented proper per-wallet numbering
- Added name persistence on first assignment
- Added comprehensive tests for multi-wallet scenarios
- Fixed wallet metadata types

This ensures each wallet has its own 'Account 1', 'Account 2', etc.,
and names remain consistent across app restarts.
… issues

- Use object destructuring for better code quality
- Remove conditionals in tests by using deterministic array access
- Simplify test assertions to avoid optional chaining in tests
- Restore import from @metamask/account-api instead of defining locally
- Remove unnecessary local type definition
- Keep only the changes needed for the naming bug fix
Issues Fixed:
1. Global indexing across wallets - now each wallet has independent numbering
2. Lost EVM account names - now preserves computed names like 'Main Account'

Changes:
- Use per-wallet sequential numbering for ALL wallet types instead of global entropy.groupIndex
- Only persist default names, not computed names from existing EVM accounts
- Each wallet now correctly shows: Account 1, Account 2, Account 3...
- Preserves original EVM account names when they exist
Root Cause of Extension Crash:
- Nested state updates during tree building caused state corruption
- Over-aggressive name persistence broke existing functionality

Solution:
- Reverted to simpler approach: use entropy.groupIndex for consistent naming
- Removed complex per-wallet tracking and nested state updates
- Preserved EVM account names while fixing the core alphabetical sorting bug
- Fixed test to use empty account names for proper default naming behavior

Key Changes:
- Use group.metadata.entropy.groupIndex instead of alphabetical sort position
- No automatic name persistence (avoids state corruption during init)
- Preserves existing behavior while fixing the core naming inconsistency
- Each entropy group gets correct sequential numbering based on its groupIndex

This fixes the multi-wallet naming bug without breaking extension startup.
fabiobozzo added a commit that referenced this pull request Sep 15, 2025
Clarified the changelog entry to include a reference to the related pull request (#6601) that addresses the account group naming inconsistency caused by using alphabetical sorting instead of the actual groupIndex. This ensures accurate sequential numbering across wallets.
fabiobozzo and others added 2 commits September 15, 2025 15:02
- Fix prettier formatting for import statement
- Import AccountGroupType as value instead of type to use in comparison
- Ensure proper enum comparison instead of string literal
@fabiobozzo
Copy link
Contributor Author

@ccharly I've simplified my approach, please re-review 🙏

@fabiobozzo fabiobozzo requested a review from ccharly September 15, 2025 13:03
- Add proper PR reference to the critical multi-wallet naming bug fix
- Ensures changelog check passes with proper documentation
- Add istanbul ignore comment for the defensive fallback that should never be reached
- This brings coverage back to 100% for all metrics (statements, branches, lines)
- The fallback handles edge cases where group.id is not found in sortedGroupIds
- Move 'Changed' section before 'Fixed' section as per Keep a Changelog standard
- Ensures changelog validation passes with proper section ordering
@fabiobozzo fabiobozzo changed the title Fix/account group names consistency fix(account-tree-controller): address group names consistency bug Sep 15, 2025
@fabiobozzo fabiobozzo marked this pull request as ready for review September 15, 2025 15:00
@fabiobozzo fabiobozzo requested review from a team as code owners September 15, 2025 15:00
fabiobozzo and others added 2 commits September 19, 2025 11:15
…lication

- Update the loop to iterate over state.accountTree.wallets instead of wallets variable.
- Ensures consistency in accessing wallet data during metadata application.
- Skip computed names to fix global numbering bug from accounts-controller
- All accounts now use proper per-wallet sequential naming (Account 1, 2, 3...)
- Maintain 100% test coverage and implement all code review feedback
- Phase 1 fix - computed names will be re-added in future PR with proper migration
fabiobozzo and others added 2 commits September 19, 2025 13:15
Co-authored-by: Charly Chevalier <charly.chevalier@consensys.net>
@fabiobozzo fabiobozzo requested a review from ccharly September 19, 2025 11:16
@MetaMask MetaMask deleted a comment from github-actions bot Sep 19, 2025
Comment on lines +1115 to +1118
/* istanbul ignore next */
if (!state.accountGroupsMetadata[groupId]) {
state.accountGroupsMetadata[groupId] = {};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is ok for now, we can refactor that later.

@fabiobozzo
Copy link
Contributor Author

@metamaskbot publish-preview

Copy link
Contributor

@ccharly ccharly left a comment

Choose a reason for hiding this comment

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

LGTM (haven't reviewed the test though)

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "0.17.0-preview-3cc47b4c",
  "@metamask-previews/accounts-controller": "33.1.0-preview-3cc47b4c",
  "@metamask-previews/address-book-controller": "6.1.1-preview-3cc47b4c",
  "@metamask-previews/announcement-controller": "7.0.3-preview-3cc47b4c",
  "@metamask-previews/app-metadata-controller": "1.0.0-preview-3cc47b4c",
  "@metamask-previews/approval-controller": "7.1.3-preview-3cc47b4c",
  "@metamask-previews/assets-controllers": "75.2.0-preview-3cc47b4c",
  "@metamask-previews/base-controller": "8.4.0-preview-3cc47b4c",
  "@metamask-previews/bridge-controller": "43.1.0-preview-3cc47b4c",
  "@metamask-previews/bridge-status-controller": "43.1.0-preview-3cc47b4c",
  "@metamask-previews/build-utils": "3.0.3-preview-3cc47b4c",
  "@metamask-previews/chain-agnostic-permission": "1.1.1-preview-3cc47b4c",
  "@metamask-previews/composable-controller": "11.0.0-preview-3cc47b4c",
  "@metamask-previews/controller-utils": "11.14.0-preview-3cc47b4c",
  "@metamask-previews/delegation-controller": "0.7.0-preview-3cc47b4c",
  "@metamask-previews/earn-controller": "7.0.0-preview-3cc47b4c",
  "@metamask-previews/eip-5792-middleware": "1.2.0-preview-3cc47b4c",
  "@metamask-previews/eip1193-permission-middleware": "1.0.0-preview-3cc47b4c",
  "@metamask-previews/ens-controller": "17.0.1-preview-3cc47b4c",
  "@metamask-previews/error-reporting-service": "2.0.0-preview-3cc47b4c",
  "@metamask-previews/eth-json-rpc-provider": "4.1.8-preview-3cc47b4c",
  "@metamask-previews/foundryup": "1.0.1-preview-3cc47b4c",
  "@metamask-previews/gas-fee-controller": "24.0.0-preview-3cc47b4c",
  "@metamask-previews/gator-permissions-controller": "0.2.0-preview-3cc47b4c",
  "@metamask-previews/json-rpc-engine": "10.0.3-preview-3cc47b4c",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.7-preview-3cc47b4c",
  "@metamask-previews/keyring-controller": "23.1.0-preview-3cc47b4c",
  "@metamask-previews/logging-controller": "6.0.4-preview-3cc47b4c",
  "@metamask-previews/message-manager": "12.0.2-preview-3cc47b4c",
  "@metamask-previews/messenger": "0.3.0-preview-3cc47b4c",
  "@metamask-previews/multichain-account-service": "0.10.0-preview-3cc47b4c",
  "@metamask-previews/multichain-api-middleware": "1.0.0-preview-3cc47b4c",
  "@metamask-previews/multichain-network-controller": "0.12.0-preview-3cc47b4c",
  "@metamask-previews/multichain-transactions-controller": "5.0.0-preview-3cc47b4c",
  "@metamask-previews/name-controller": "8.0.3-preview-3cc47b4c",
  "@metamask-previews/network-controller": "24.1.0-preview-3cc47b4c",
  "@metamask-previews/network-enablement-controller": "1.2.0-preview-3cc47b4c",
  "@metamask-previews/notification-services-controller": "18.1.0-preview-3cc47b4c",
  "@metamask-previews/permission-controller": "11.0.6-preview-3cc47b4c",
  "@metamask-previews/permission-log-controller": "4.0.0-preview-3cc47b4c",
  "@metamask-previews/phishing-controller": "13.1.0-preview-3cc47b4c",
  "@metamask-previews/polling-controller": "14.0.0-preview-3cc47b4c",
  "@metamask-previews/preferences-controller": "19.0.0-preview-3cc47b4c",
  "@metamask-previews/profile-sync-controller": "25.0.0-preview-3cc47b4c",
  "@metamask-previews/rate-limit-controller": "6.0.3-preview-3cc47b4c",
  "@metamask-previews/remote-feature-flag-controller": "1.7.0-preview-3cc47b4c",
  "@metamask-previews/sample-controllers": "1.0.0-preview-3cc47b4c",
  "@metamask-previews/seedless-onboarding-controller": "4.0.0-preview-3cc47b4c",
  "@metamask-previews/selected-network-controller": "24.0.0-preview-3cc47b4c",
  "@metamask-previews/shield-controller": "0.1.2-preview-3cc47b4c",
  "@metamask-previews/signature-controller": "33.0.0-preview-3cc47b4c",
  "@metamask-previews/subscription-controller": "0.1.0-preview-3cc47b4c",
  "@metamask-previews/token-search-discovery-controller": "3.3.0-preview-3cc47b4c",
  "@metamask-previews/transaction-controller": "60.4.0-preview-3cc47b4c",
  "@metamask-previews/user-operation-controller": "39.0.0-preview-3cc47b4c"
}

}

// Use the higher of the two: highest parsed index or computed index
proposedNameIndex = Math.max(highestAccountNameIndex, proposedNameIndex);
Copy link

Choose a reason for hiding this comment

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

Bug: Account Group Naming Inconsistency

The default naming for account groups, especially entropy-based ones, is inconsistent. The logic incorrectly uses Math.max to determine the starting index for new group names, which can lead to non-sequential names (e.g., 'Account 3' instead of 'Account 1' for the first account) and prevents entropy groups from consistently mapping their groupIndex to Account N+1.

Additional Locations (1)

Fix in Cursor Fix in Web

@ccharly ccharly merged commit 20d17ba into main Sep 19, 2025
239 checks passed
@ccharly ccharly deleted the fix/account-group-names-consistency branch September 19, 2025 12:03
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