@metamask-previews/account-tree-controller 5.0.1-preview-e0ce55a8c → 5.0.1-preview-1f5463f7b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
+ - Batch multichain account groups creation in backup and sync ([#7907](https://github.com/MetaMask/core/pull/7907))
13
+ - This prevents multiple consecutive tree rebuilds, as well as keyring updates and thus improves performance during the initial backup and sync process.
12
14
  - Use `:accounts{Added,Removed}` batched events to reduce number of state updates ([#8160](https://github.com/MetaMask/core/pull/8160))
13
15
 
14
16
  ## [5.0.1]
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.syncGroupsMetadata = exports.syncGroupMetadata = exports.createLocalGroupsFromUserStorage = exports.createMultichainAccountGroup = void 0;
3
+ exports.syncGroupsMetadata = exports.syncGroupMetadata = exports.createLocalGroupsFromUserStorage = exports.createMultichainAccountGroupsBatch = void 0;
4
+ const account_api_1 = require("@metamask/account-api");
4
5
  const metadata_1 = require("./metadata.cjs");
5
6
  const logger_1 = require("../../logger.cjs");
6
7
  const analytics_1 = require("../analytics/index.cjs");
@@ -8,42 +9,60 @@ const types_1 = require("../types.cjs");
8
9
  const network_operations_1 = require("../user-storage/network-operations.cjs");
9
10
  const utils_1 = require("../utils/index.cjs");
10
11
  /**
11
- * Creates a multichain account group.
12
+ * Creates multiple multichain account groups in batch (from 0 to maxGroupIndex).
13
+ * This is an optimized version that creates all groups in one operation instead of
14
+ * creating them sequentially.
12
15
  *
13
16
  * @param context - The sync context containing controller and messenger.
14
17
  * @param entropySourceId - The entropy source ID.
15
- * @param groupIndex - The group index.
18
+ * @param maxGroupIndex - Number of account groups to create in batch.
16
19
  * @param profileId - The profile ID for analytics.
17
- * @param analyticsAction - The analytics action to log.
20
+ * @param analyticsAction - The analytics action to log for each created group.
21
+ * @returns Array of created group IDs.
18
22
  */
19
- const createMultichainAccountGroup = async (context, entropySourceId, groupIndex, profileId, analyticsAction) => {
23
+ const createMultichainAccountGroupsBatch = async (context, entropySourceId, maxGroupIndex, profileId, analyticsAction) => {
24
+ const numberOfAccountGroupsToCreate = maxGroupIndex + 1; // maxGroupIndex is zero-based, so we add 1 to get the count.
25
+ (0, logger_1.backupAndSyncLogger)(`Creating ${numberOfAccountGroupsToCreate} account groups (batch) for entropy source: ${entropySourceId}`);
26
+ // Capture the set of group indices that already exist before the batch call,
27
+ // so we can correctly identify newly created groups after the call completes.
28
+ const walletId = (0, account_api_1.toMultichainAccountWalletId)(entropySourceId);
29
+ const existingGroupIndices = new Set((0, utils_1.getLocalGroupsForEntropyWallet)(context, walletId).map((group) => group.metadata.entropy.groupIndex));
20
30
  try {
21
- const didGroupAlreadyExist = (0, utils_1.getLocalGroupForEntropyWallet)(context, entropySourceId, groupIndex);
22
- // This will be idempotent so we can create the group even if it already exists
23
- await context.messenger.call('MultichainAccountService:createMultichainAccountGroup', {
31
+ // Call the batched creation method (this is idempotent).
32
+ const groups = await context.messenger.call('MultichainAccountService:createMultichainAccountGroups', {
24
33
  entropySource: entropySourceId,
25
- groupIndex,
34
+ fromGroupIndex: 0,
35
+ toGroupIndex: maxGroupIndex,
26
36
  });
27
- if (!didGroupAlreadyExist) {
28
- context.emitAnalyticsEventFn({
29
- action: analyticsAction,
30
- profileId,
31
- });
37
+ // Contains all groups (existing + newly created).
38
+ for (const group of groups) {
39
+ // TODO: A group should not be null here, but EVM provider might fail to create some groups sometimes, which means
40
+ // we can end up having an "empty group" for some time.
41
+ if (group) {
42
+ const didGroupAlreadyExist = existingGroupIndices.has(group.groupIndex);
43
+ if (!didGroupAlreadyExist) {
44
+ context.emitAnalyticsEventFn({
45
+ action: analyticsAction,
46
+ profileId,
47
+ });
48
+ }
49
+ }
32
50
  }
51
+ (0, logger_1.backupAndSyncLogger)(`Successfully created ${groups.length} groups (batch)`);
33
52
  }
34
53
  catch (error) {
35
54
  // This can happen if the Snap Keyring is not ready yet when invoking
36
- // `MultichainAccountService:createMultichainAccountGroup`.
37
- // Since `MultichainAccountService:createMultichainAccountGroup` will at
55
+ // `MultichainAccountService:createMultichainAccountGroups`.
56
+ // Since `MultichainAccountService:createMultichainAccountGroups` will at
38
57
  // least create the EVM account and the account group before throwing, we can safely
39
58
  // ignore this error and swallow it.
40
59
  // Any missing Snap accounts will be added later with alignment.
41
- (0, logger_1.backupAndSyncLogger)(`Failed to create group ${groupIndex} for entropy ${entropySourceId}:`,
60
+ (0, logger_1.backupAndSyncLogger)(`Failed to create account groups batch:`,
42
61
  // istanbul ignore next
43
62
  error instanceof Error ? error.message : String(error));
44
63
  }
45
64
  };
46
- exports.createMultichainAccountGroup = createMultichainAccountGroup;
65
+ exports.createMultichainAccountGroupsBatch = createMultichainAccountGroupsBatch;
47
66
  /**
48
67
  * Creates local groups from user storage groups.
49
68
  *
@@ -53,12 +72,11 @@ exports.createMultichainAccountGroup = createMultichainAccountGroup;
53
72
  * @param profileId - The profile ID for analytics.
54
73
  */
55
74
  async function createLocalGroupsFromUserStorage(context, groupsFromUserStorage, entropySourceId, profileId) {
56
- const numberOfAccountGroupsToCreate = Math.max(...groupsFromUserStorage.map((g) => g.groupIndex));
75
+ const maxGroupIndex = Math.max(...groupsFromUserStorage.map((group) => group.groupIndex));
57
76
  // Creating multichain account group is idempotent, so we can safely
58
77
  // re-create every groups starting from 0.
59
- for (let groupIndex = 0; groupIndex <= numberOfAccountGroupsToCreate; groupIndex++) {
60
- await (0, exports.createMultichainAccountGroup)(context, entropySourceId, groupIndex, profileId, analytics_1.BackupAndSyncAnalyticsEvent.GroupAdded);
61
- }
78
+ // Use batch creation for better performance.
79
+ await (0, exports.createMultichainAccountGroupsBatch)(context, entropySourceId, maxGroupIndex, profileId, analytics_1.BackupAndSyncAnalyticsEvent.GroupAdded);
62
80
  }
63
81
  exports.createLocalGroupsFromUserStorage = createLocalGroupsFromUserStorage;
64
82
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"group.cjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"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","sourcesContent":["import { compareAndSyncMetadata } from './metadata';\nimport type { AccountGroupMultichainAccountObject } from '../../group';\nimport { backupAndSyncLogger } from '../../logger';\nimport type { AccountWalletEntropyObject } from '../../wallet';\nimport type { BackupAndSyncAnalyticsAction } from '../analytics';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport { UserStorageSyncedWalletGroupSchema } from '../types';\nimport type {\n BackupAndSyncContext,\n UserStorageSyncedWalletGroup,\n} from '../types';\nimport {\n pushGroupToUserStorage,\n pushGroupToUserStorageBatch,\n} from '../user-storage/network-operations';\nimport {\n getLocalGroupForEntropyWallet,\n getLocalGroupsForEntropyWallet,\n} from '../utils';\n\n/**\n * Creates a multichain account group.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param groupIndex - The group index.\n * @param profileId - The profile ID for analytics.\n * @param analyticsAction - The analytics action to log.\n */\nexport const createMultichainAccountGroup = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n groupIndex: number,\n profileId: ProfileId,\n analyticsAction: BackupAndSyncAnalyticsAction,\n) => {\n try {\n const didGroupAlreadyExist = getLocalGroupForEntropyWallet(\n context,\n entropySourceId,\n groupIndex,\n );\n\n // This will be idempotent so we can create the group even if it already exists\n await context.messenger.call(\n 'MultichainAccountService:createMultichainAccountGroup',\n {\n entropySource: entropySourceId,\n groupIndex,\n },\n );\n\n if (!didGroupAlreadyExist) {\n context.emitAnalyticsEventFn({\n action: analyticsAction,\n profileId,\n });\n }\n } catch (error) {\n // This can happen if the Snap Keyring is not ready yet when invoking\n // `MultichainAccountService:createMultichainAccountGroup`.\n // Since `MultichainAccountService:createMultichainAccountGroup` will at\n // least create the EVM account and the account group before throwing, we can safely\n // ignore this error and swallow it.\n // Any missing Snap accounts will be added later with alignment.\n\n backupAndSyncLogger(\n `Failed to create group ${groupIndex} for entropy ${entropySourceId}:`,\n // istanbul ignore next\n error instanceof Error ? error.message : String(error),\n );\n }\n};\n\n/**\n * Creates local groups from user storage groups.\n *\n * @param context - The sync context containing controller and messenger.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function createLocalGroupsFromUserStorage(\n context: BackupAndSyncContext,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const numberOfAccountGroupsToCreate = Math.max(\n ...groupsFromUserStorage.map((g) => g.groupIndex),\n );\n\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n for (\n let groupIndex = 0;\n groupIndex <= numberOfAccountGroupsToCreate;\n groupIndex++\n ) {\n await createMultichainAccountGroup(\n context,\n entropySourceId,\n groupIndex,\n profileId,\n BackupAndSyncAnalyticsEvent.GroupAdded,\n );\n }\n}\n\n/**\n * Syncs group metadata fields and determines if the group needs to be pushed to user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against.\n * @param profileId - The profile ID for analytics.\n * @returns A promise that resolves to true if the group needs to be pushed to user storage.\n */\nasync function syncGroupMetadataAndCheckIfPushNeeded(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null | undefined,\n profileId: ProfileId,\n): Promise<boolean> {\n const groupPersistedMetadata =\n context.controller.state.accountGroupsMetadata[localGroup.id];\n\n if (!groupFromUserStorage) {\n backupAndSyncLogger(\n `Group ${localGroup.id} did not exist in user storage, pushing to user storage...`,\n );\n\n return true;\n }\n\n // Track if we need to push this group to user storage\n let shouldPushGroup = false;\n\n // Compare and sync name metadata\n const shouldPushForName = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.name,\n userStorageMetadata: groupFromUserStorage.name,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.name.schema.value.is(value),\n applyLocalUpdate: (name: string) => {\n context.controller.setAccountGroupName(localGroup.id, name, true);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupRenamed,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForName;\n\n // Compare and sync pinned metadata\n const shouldPushForPinned = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.pinned,\n userStorageMetadata: groupFromUserStorage.pinned,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.pinned.schema.value.is(value),\n applyLocalUpdate: (pinned: boolean) => {\n context.controller.setAccountGroupPinned(localGroup.id, pinned);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupPinnedStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForPinned;\n\n // Compare and sync hidden metadata\n const shouldPushForHidden = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.hidden,\n userStorageMetadata: groupFromUserStorage.hidden,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.hidden.schema.value.is(value),\n applyLocalUpdate: (hidden: boolean) => {\n context.controller.setAccountGroupHidden(localGroup.id, hidden);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupHiddenStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForHidden;\n\n return shouldPushGroup;\n}\n\n/**\n * Syncs a single group's metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against (or null if it doesn't exist).\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupMetadata(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null,\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localGroup,\n groupFromUserStorage,\n profileId,\n );\n\n if (shouldPushGroup) {\n await pushGroupToUserStorage(context, localGroup, entropySourceId);\n }\n}\n\n/**\n * Syncs group metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param wallet - The local wallet containing the groups.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupsMetadata(\n context: BackupAndSyncContext,\n wallet: AccountWalletEntropyObject,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const localSyncableGroupsToBePushedToUserStorage: AccountGroupMultichainAccountObject[] =\n [];\n\n const localSyncableGroups = getLocalGroupsForEntropyWallet(\n context,\n wallet.id,\n );\n\n for (const localSyncableGroup of localSyncableGroups) {\n const groupFromUserStorage = groupsFromUserStorage.find(\n (group) =>\n group.groupIndex === localSyncableGroup.metadata.entropy.groupIndex,\n );\n\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localSyncableGroup,\n groupFromUserStorage,\n profileId,\n );\n\n // Add to push list if any metadata needs to be updated in user storage\n if (shouldPushGroup) {\n localSyncableGroupsToBePushedToUserStorage.push(localSyncableGroup);\n }\n }\n\n // Push all groups that need to be updated to user storage\n if (localSyncableGroupsToBePushedToUserStorage.length > 0) {\n await pushGroupToUserStorageBatch(\n context,\n localSyncableGroupsToBePushedToUserStorage,\n entropySourceId,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"group.cjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"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","sourcesContent":["import { toMultichainAccountWalletId } from '@metamask/account-api';\n\nimport { compareAndSyncMetadata } from './metadata';\nimport type { AccountGroupMultichainAccountObject } from '../../group';\nimport { backupAndSyncLogger } from '../../logger';\nimport type { AccountWalletEntropyObject } from '../../wallet';\nimport type { BackupAndSyncAnalyticsAction } from '../analytics';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport { UserStorageSyncedWalletGroupSchema } from '../types';\nimport type {\n BackupAndSyncContext,\n UserStorageSyncedWalletGroup,\n} from '../types';\nimport {\n pushGroupToUserStorage,\n pushGroupToUserStorageBatch,\n} from '../user-storage/network-operations';\nimport { getLocalGroupsForEntropyWallet } from '../utils';\n\n/**\n * Creates multiple multichain account groups in batch (from 0 to maxGroupIndex).\n * This is an optimized version that creates all groups in one operation instead of\n * creating them sequentially.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param maxGroupIndex - Number of account groups to create in batch.\n * @param profileId - The profile ID for analytics.\n * @param analyticsAction - The analytics action to log for each created group.\n * @returns Array of created group IDs.\n */\nexport const createMultichainAccountGroupsBatch = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n maxGroupIndex: number,\n profileId: ProfileId,\n analyticsAction: BackupAndSyncAnalyticsAction,\n): Promise<void> => {\n const numberOfAccountGroupsToCreate = maxGroupIndex + 1; // maxGroupIndex is zero-based, so we add 1 to get the count.\n backupAndSyncLogger(\n `Creating ${numberOfAccountGroupsToCreate} account groups (batch) for entropy source: ${entropySourceId}`,\n );\n\n // Capture the set of group indices that already exist before the batch call,\n // so we can correctly identify newly created groups after the call completes.\n const walletId = toMultichainAccountWalletId(entropySourceId);\n const existingGroupIndices = new Set(\n getLocalGroupsForEntropyWallet(context, walletId).map(\n (group) => group.metadata.entropy.groupIndex,\n ),\n );\n\n try {\n // Call the batched creation method (this is idempotent).\n const groups = await context.messenger.call(\n 'MultichainAccountService:createMultichainAccountGroups',\n {\n entropySource: entropySourceId,\n fromGroupIndex: 0,\n toGroupIndex: maxGroupIndex,\n },\n );\n\n // Contains all groups (existing + newly created).\n for (const group of groups) {\n // TODO: A group should not be null here, but EVM provider might fail to create some groups sometimes, which means\n // we can end up having an \"empty group\" for some time.\n if (group) {\n const didGroupAlreadyExist = existingGroupIndices.has(group.groupIndex);\n\n if (!didGroupAlreadyExist) {\n context.emitAnalyticsEventFn({\n action: analyticsAction,\n profileId,\n });\n }\n }\n }\n\n backupAndSyncLogger(`Successfully created ${groups.length} groups (batch)`);\n } catch (error) {\n // This can happen if the Snap Keyring is not ready yet when invoking\n // `MultichainAccountService:createMultichainAccountGroups`.\n // Since `MultichainAccountService:createMultichainAccountGroups` will at\n // least create the EVM account and the account group before throwing, we can safely\n // ignore this error and swallow it.\n // Any missing Snap accounts will be added later with alignment.\n\n backupAndSyncLogger(\n `Failed to create account groups batch:`,\n // istanbul ignore next\n error instanceof Error ? error.message : String(error),\n );\n }\n};\n\n/**\n * Creates local groups from user storage groups.\n *\n * @param context - The sync context containing controller and messenger.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function createLocalGroupsFromUserStorage(\n context: BackupAndSyncContext,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const maxGroupIndex = Math.max(\n ...groupsFromUserStorage.map((group) => group.groupIndex),\n );\n\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n // Use batch creation for better performance.\n await createMultichainAccountGroupsBatch(\n context,\n entropySourceId,\n maxGroupIndex,\n profileId,\n BackupAndSyncAnalyticsEvent.GroupAdded,\n );\n}\n\n/**\n * Syncs group metadata fields and determines if the group needs to be pushed to user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against.\n * @param profileId - The profile ID for analytics.\n * @returns A promise that resolves to true if the group needs to be pushed to user storage.\n */\nasync function syncGroupMetadataAndCheckIfPushNeeded(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null | undefined,\n profileId: ProfileId,\n): Promise<boolean> {\n const groupPersistedMetadata =\n context.controller.state.accountGroupsMetadata[localGroup.id];\n\n if (!groupFromUserStorage) {\n backupAndSyncLogger(\n `Group ${localGroup.id} did not exist in user storage, pushing to user storage...`,\n );\n\n return true;\n }\n\n // Track if we need to push this group to user storage\n let shouldPushGroup = false;\n\n // Compare and sync name metadata\n const shouldPushForName = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.name,\n userStorageMetadata: groupFromUserStorage.name,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.name.schema.value.is(value),\n applyLocalUpdate: (name: string) => {\n context.controller.setAccountGroupName(localGroup.id, name, true);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupRenamed,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForName;\n\n // Compare and sync pinned metadata\n const shouldPushForPinned = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.pinned,\n userStorageMetadata: groupFromUserStorage.pinned,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.pinned.schema.value.is(value),\n applyLocalUpdate: (pinned: boolean) => {\n context.controller.setAccountGroupPinned(localGroup.id, pinned);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupPinnedStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForPinned;\n\n // Compare and sync hidden metadata\n const shouldPushForHidden = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.hidden,\n userStorageMetadata: groupFromUserStorage.hidden,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.hidden.schema.value.is(value),\n applyLocalUpdate: (hidden: boolean) => {\n context.controller.setAccountGroupHidden(localGroup.id, hidden);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupHiddenStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForHidden;\n\n return shouldPushGroup;\n}\n\n/**\n * Syncs a single group's metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against (or null if it doesn't exist).\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupMetadata(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null,\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localGroup,\n groupFromUserStorage,\n profileId,\n );\n\n if (shouldPushGroup) {\n await pushGroupToUserStorage(context, localGroup, entropySourceId);\n }\n}\n\n/**\n * Syncs group metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param wallet - The local wallet containing the groups.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupsMetadata(\n context: BackupAndSyncContext,\n wallet: AccountWalletEntropyObject,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const localSyncableGroupsToBePushedToUserStorage: AccountGroupMultichainAccountObject[] =\n [];\n\n const localSyncableGroups = getLocalGroupsForEntropyWallet(\n context,\n wallet.id,\n );\n\n for (const localSyncableGroup of localSyncableGroups) {\n const groupFromUserStorage = groupsFromUserStorage.find(\n (group) =>\n group.groupIndex === localSyncableGroup.metadata.entropy.groupIndex,\n );\n\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localSyncableGroup,\n groupFromUserStorage,\n profileId,\n );\n\n // Add to push list if any metadata needs to be updated in user storage\n if (shouldPushGroup) {\n localSyncableGroupsToBePushedToUserStorage.push(localSyncableGroup);\n }\n }\n\n // Push all groups that need to be updated to user storage\n if (localSyncableGroupsToBePushedToUserStorage.length > 0) {\n await pushGroupToUserStorageBatch(\n context,\n localSyncableGroupsToBePushedToUserStorage,\n entropySourceId,\n );\n }\n}\n"]}
@@ -4,15 +4,18 @@ import type { BackupAndSyncAnalyticsAction } from "../analytics/index.cjs";
4
4
  import type { ProfileId } from "../authentication/index.cjs";
5
5
  import type { BackupAndSyncContext, UserStorageSyncedWalletGroup } from "../types.cjs";
6
6
  /**
7
- * Creates a multichain account group.
7
+ * Creates multiple multichain account groups in batch (from 0 to maxGroupIndex).
8
+ * This is an optimized version that creates all groups in one operation instead of
9
+ * creating them sequentially.
8
10
  *
9
11
  * @param context - The sync context containing controller and messenger.
10
12
  * @param entropySourceId - The entropy source ID.
11
- * @param groupIndex - The group index.
13
+ * @param maxGroupIndex - Number of account groups to create in batch.
12
14
  * @param profileId - The profile ID for analytics.
13
- * @param analyticsAction - The analytics action to log.
15
+ * @param analyticsAction - The analytics action to log for each created group.
16
+ * @returns Array of created group IDs.
14
17
  */
15
- export declare const createMultichainAccountGroup: (context: BackupAndSyncContext, entropySourceId: string, groupIndex: number, profileId: ProfileId, analyticsAction: BackupAndSyncAnalyticsAction) => Promise<void>;
18
+ export declare const createMultichainAccountGroupsBatch: (context: BackupAndSyncContext, entropySourceId: string, maxGroupIndex: number, profileId: ProfileId, analyticsAction: BackupAndSyncAnalyticsAction) => Promise<void>;
16
19
  /**
17
20
  * Creates local groups from user storage groups.
18
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"group.d.cts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mCAAmC,EAAE,wBAAoB;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,yBAAqB;AAC/D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAAqB;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AAEnD,OAAO,KAAK,EACV,oBAAoB,EACpB,4BAA4B,EAC7B,qBAAiB;AAUlB;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,YAC9B,oBAAoB,mBACZ,MAAM,cACX,MAAM,aACP,SAAS,mBACH,4BAA4B,kBAsC9C,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,oBAAoB,EAC7B,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAwFD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,oBAAoB,EAC7B,UAAU,EAAE,mCAAmC,EAC/C,oBAAoB,EAAE,4BAA4B,GAAG,IAAI,EACzD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,0BAA0B,EAClC,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
1
+ {"version":3,"file":"group.d.cts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mCAAmC,EAAE,wBAAoB;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,yBAAqB;AAC/D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAAqB;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AAEnD,OAAO,KAAK,EACV,oBAAoB,EACpB,4BAA4B,EAC7B,qBAAiB;AAOlB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kCAAkC,YACpC,oBAAoB,mBACZ,MAAM,iBACR,MAAM,aACV,SAAS,mBACH,4BAA4B,KAC5C,QAAQ,IAAI,CAyDd,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,oBAAoB,EAC7B,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAef;AAwFD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,oBAAoB,EAC7B,UAAU,EAAE,mCAAmC,EAC/C,oBAAoB,EAAE,4BAA4B,GAAG,IAAI,EACzD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,0BAA0B,EAClC,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -4,15 +4,18 @@ import type { BackupAndSyncAnalyticsAction } from "../analytics/index.mjs";
4
4
  import type { ProfileId } from "../authentication/index.mjs";
5
5
  import type { BackupAndSyncContext, UserStorageSyncedWalletGroup } from "../types.mjs";
6
6
  /**
7
- * Creates a multichain account group.
7
+ * Creates multiple multichain account groups in batch (from 0 to maxGroupIndex).
8
+ * This is an optimized version that creates all groups in one operation instead of
9
+ * creating them sequentially.
8
10
  *
9
11
  * @param context - The sync context containing controller and messenger.
10
12
  * @param entropySourceId - The entropy source ID.
11
- * @param groupIndex - The group index.
13
+ * @param maxGroupIndex - Number of account groups to create in batch.
12
14
  * @param profileId - The profile ID for analytics.
13
- * @param analyticsAction - The analytics action to log.
15
+ * @param analyticsAction - The analytics action to log for each created group.
16
+ * @returns Array of created group IDs.
14
17
  */
15
- export declare const createMultichainAccountGroup: (context: BackupAndSyncContext, entropySourceId: string, groupIndex: number, profileId: ProfileId, analyticsAction: BackupAndSyncAnalyticsAction) => Promise<void>;
18
+ export declare const createMultichainAccountGroupsBatch: (context: BackupAndSyncContext, entropySourceId: string, maxGroupIndex: number, profileId: ProfileId, analyticsAction: BackupAndSyncAnalyticsAction) => Promise<void>;
16
19
  /**
17
20
  * Creates local groups from user storage groups.
18
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"group.d.mts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mCAAmC,EAAE,wBAAoB;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,yBAAqB;AAC/D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAAqB;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AAEnD,OAAO,KAAK,EACV,oBAAoB,EACpB,4BAA4B,EAC7B,qBAAiB;AAUlB;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,YAC9B,oBAAoB,mBACZ,MAAM,cACX,MAAM,aACP,SAAS,mBACH,4BAA4B,kBAsC9C,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,oBAAoB,EAC7B,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAwFD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,oBAAoB,EAC7B,UAAU,EAAE,mCAAmC,EAC/C,oBAAoB,EAAE,4BAA4B,GAAG,IAAI,EACzD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,0BAA0B,EAClC,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
1
+ {"version":3,"file":"group.d.mts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mCAAmC,EAAE,wBAAoB;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,yBAAqB;AAC/D,OAAO,KAAK,EAAE,4BAA4B,EAAE,+BAAqB;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AAEnD,OAAO,KAAK,EACV,oBAAoB,EACpB,4BAA4B,EAC7B,qBAAiB;AAOlB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kCAAkC,YACpC,oBAAoB,mBACZ,MAAM,iBACR,MAAM,aACV,SAAS,mBACH,4BAA4B,KAC5C,QAAQ,IAAI,CAyDd,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,oBAAoB,EAC7B,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAef;AAwFD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,oBAAoB,EAC7B,UAAU,EAAE,mCAAmC,EAC/C,oBAAoB,EAAE,4BAA4B,GAAG,IAAI,EACzD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,0BAA0B,EAClC,qBAAqB,EAAE,4BAA4B,EAAE,EACrD,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -1,41 +1,60 @@
1
+ import { toMultichainAccountWalletId } from "@metamask/account-api";
1
2
  import { compareAndSyncMetadata } from "./metadata.mjs";
2
3
  import { backupAndSyncLogger } from "../../logger.mjs";
3
4
  import { BackupAndSyncAnalyticsEvent } from "../analytics/index.mjs";
4
5
  import { UserStorageSyncedWalletGroupSchema } from "../types.mjs";
5
6
  import { pushGroupToUserStorage, pushGroupToUserStorageBatch } from "../user-storage/network-operations.mjs";
6
- import { getLocalGroupForEntropyWallet, getLocalGroupsForEntropyWallet } from "../utils/index.mjs";
7
+ import { getLocalGroupsForEntropyWallet } from "../utils/index.mjs";
7
8
  /**
8
- * Creates a multichain account group.
9
+ * Creates multiple multichain account groups in batch (from 0 to maxGroupIndex).
10
+ * This is an optimized version that creates all groups in one operation instead of
11
+ * creating them sequentially.
9
12
  *
10
13
  * @param context - The sync context containing controller and messenger.
11
14
  * @param entropySourceId - The entropy source ID.
12
- * @param groupIndex - The group index.
15
+ * @param maxGroupIndex - Number of account groups to create in batch.
13
16
  * @param profileId - The profile ID for analytics.
14
- * @param analyticsAction - The analytics action to log.
17
+ * @param analyticsAction - The analytics action to log for each created group.
18
+ * @returns Array of created group IDs.
15
19
  */
16
- export const createMultichainAccountGroup = async (context, entropySourceId, groupIndex, profileId, analyticsAction) => {
20
+ export const createMultichainAccountGroupsBatch = async (context, entropySourceId, maxGroupIndex, profileId, analyticsAction) => {
21
+ const numberOfAccountGroupsToCreate = maxGroupIndex + 1; // maxGroupIndex is zero-based, so we add 1 to get the count.
22
+ backupAndSyncLogger(`Creating ${numberOfAccountGroupsToCreate} account groups (batch) for entropy source: ${entropySourceId}`);
23
+ // Capture the set of group indices that already exist before the batch call,
24
+ // so we can correctly identify newly created groups after the call completes.
25
+ const walletId = toMultichainAccountWalletId(entropySourceId);
26
+ const existingGroupIndices = new Set(getLocalGroupsForEntropyWallet(context, walletId).map((group) => group.metadata.entropy.groupIndex));
17
27
  try {
18
- const didGroupAlreadyExist = getLocalGroupForEntropyWallet(context, entropySourceId, groupIndex);
19
- // This will be idempotent so we can create the group even if it already exists
20
- await context.messenger.call('MultichainAccountService:createMultichainAccountGroup', {
28
+ // Call the batched creation method (this is idempotent).
29
+ const groups = await context.messenger.call('MultichainAccountService:createMultichainAccountGroups', {
21
30
  entropySource: entropySourceId,
22
- groupIndex,
31
+ fromGroupIndex: 0,
32
+ toGroupIndex: maxGroupIndex,
23
33
  });
24
- if (!didGroupAlreadyExist) {
25
- context.emitAnalyticsEventFn({
26
- action: analyticsAction,
27
- profileId,
28
- });
34
+ // Contains all groups (existing + newly created).
35
+ for (const group of groups) {
36
+ // TODO: A group should not be null here, but EVM provider might fail to create some groups sometimes, which means
37
+ // we can end up having an "empty group" for some time.
38
+ if (group) {
39
+ const didGroupAlreadyExist = existingGroupIndices.has(group.groupIndex);
40
+ if (!didGroupAlreadyExist) {
41
+ context.emitAnalyticsEventFn({
42
+ action: analyticsAction,
43
+ profileId,
44
+ });
45
+ }
46
+ }
29
47
  }
48
+ backupAndSyncLogger(`Successfully created ${groups.length} groups (batch)`);
30
49
  }
31
50
  catch (error) {
32
51
  // This can happen if the Snap Keyring is not ready yet when invoking
33
- // `MultichainAccountService:createMultichainAccountGroup`.
34
- // Since `MultichainAccountService:createMultichainAccountGroup` will at
52
+ // `MultichainAccountService:createMultichainAccountGroups`.
53
+ // Since `MultichainAccountService:createMultichainAccountGroups` will at
35
54
  // least create the EVM account and the account group before throwing, we can safely
36
55
  // ignore this error and swallow it.
37
56
  // Any missing Snap accounts will be added later with alignment.
38
- backupAndSyncLogger(`Failed to create group ${groupIndex} for entropy ${entropySourceId}:`,
57
+ backupAndSyncLogger(`Failed to create account groups batch:`,
39
58
  // istanbul ignore next
40
59
  error instanceof Error ? error.message : String(error));
41
60
  }
@@ -49,12 +68,11 @@ export const createMultichainAccountGroup = async (context, entropySourceId, gro
49
68
  * @param profileId - The profile ID for analytics.
50
69
  */
51
70
  export async function createLocalGroupsFromUserStorage(context, groupsFromUserStorage, entropySourceId, profileId) {
52
- const numberOfAccountGroupsToCreate = Math.max(...groupsFromUserStorage.map((g) => g.groupIndex));
71
+ const maxGroupIndex = Math.max(...groupsFromUserStorage.map((group) => group.groupIndex));
53
72
  // Creating multichain account group is idempotent, so we can safely
54
73
  // re-create every groups starting from 0.
55
- for (let groupIndex = 0; groupIndex <= numberOfAccountGroupsToCreate; groupIndex++) {
56
- await createMultichainAccountGroup(context, entropySourceId, groupIndex, profileId, BackupAndSyncAnalyticsEvent.GroupAdded);
57
- }
74
+ // Use batch creation for better performance.
75
+ await createMultichainAccountGroupsBatch(context, entropySourceId, maxGroupIndex, profileId, BackupAndSyncAnalyticsEvent.GroupAdded);
58
76
  }
59
77
  /**
60
78
  * Syncs group metadata fields and determines if the group needs to be pushed to user storage.
@@ -1 +1 @@
1
- {"version":3,"file":"group.mjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,uBAAmB;AAEpD,OAAO,EAAE,mBAAmB,EAAE,yBAAqB;AAGnD,OAAO,EAAE,2BAA2B,EAAE,+BAAqB;AAE3D,OAAO,EAAE,kCAAkC,EAAE,qBAAiB;AAK9D,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC5B,+CAA2C;AAC5C,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC/B,2BAAiB;AAElB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,EAC/C,OAA6B,EAC7B,eAAuB,EACvB,UAAkB,EAClB,SAAoB,EACpB,eAA6C,EAC7C,EAAE;IACF,IAAI,CAAC;QACH,MAAM,oBAAoB,GAAG,6BAA6B,CACxD,OAAO,EACP,eAAe,EACf,UAAU,CACX,CAAC;QAEF,+EAA+E;QAC/E,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAC1B,uDAAuD,EACvD;YACE,aAAa,EAAE,eAAe;YAC9B,UAAU;SACX,CACF,CAAC;QAEF,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,OAAO,CAAC,oBAAoB,CAAC;gBAC3B,MAAM,EAAE,eAAe;gBACvB,SAAS;aACV,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qEAAqE;QACrE,2DAA2D;QAC3D,wEAAwE;QACxE,oFAAoF;QACpF,oCAAoC;QACpC,gEAAgE;QAEhE,mBAAmB,CACjB,0BAA0B,UAAU,gBAAgB,eAAe,GAAG;QACtE,uBAAuB;QACvB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,OAA6B,EAC7B,qBAAqD,EACrD,eAAuB,EACvB,SAAoB;IAEpB,MAAM,6BAA6B,GAAG,IAAI,CAAC,GAAG,CAC5C,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAClD,CAAC;IAEF,oEAAoE;IACpE,0CAA0C;IAC1C,KACE,IAAI,UAAU,GAAG,CAAC,EAClB,UAAU,IAAI,6BAA6B,EAC3C,UAAU,EAAE,EACZ,CAAC;QACD,MAAM,4BAA4B,CAChC,OAAO,EACP,eAAe,EACf,UAAU,EACV,SAAS,EACT,2BAA2B,CAAC,UAAU,CACvC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,qCAAqC,CAClD,OAA6B,EAC7B,UAA+C,EAC/C,oBAAqE,EACrE,SAAoB;IAEpB,MAAM,sBAAsB,GAC1B,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAEhE,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,mBAAmB,CACjB,SAAS,UAAU,CAAC,EAAE,4DAA4D,CACnF,CAAC;QAEF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sDAAsD;IACtD,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,iCAAiC;IACjC,MAAM,iBAAiB,GAAG,MAAM,sBAAsB,CAAC;QACrD,OAAO;QACP,aAAa,EAAE,sBAAsB,EAAE,IAAI;QAC3C,mBAAmB,EAAE,oBAAoB,CAAC,IAAI;QAC9C,wBAAwB,EAAE,CAAC,KAAK,EAAE,EAAE,CAClC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;QACvE,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE;YACjC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACpE,CAAC;QACD,SAAS,EAAE;YACT,MAAM,EAAE,2BAA2B,CAAC,YAAY;YAChD,SAAS;SACV;KACF,CAAC,CAAC;IAEH,eAAe,KAAf,eAAe,GAAK,iBAAiB,EAAC;IAEtC,mCAAmC;IACnC,MAAM,mBAAmB,GAAG,MAAM,sBAAsB,CAAC;QACvD,OAAO;QACP,aAAa,EAAE,sBAAsB,EAAE,MAAM;QAC7C,mBAAmB,EAAE,oBAAoB,CAAC,MAAM;QAChD,wBAAwB,EAAE,CAAC,KAAK,EAAE,EAAE,CAClC,kCAAkC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;QACzE,gBAAgB,EAAE,CAAC,MAAe,EAAE,EAAE;YACpC,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,UAAU,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAClE,CAAC;QACD,SAAS,EAAE;YACT,MAAM,EAAE,2BAA2B,CAAC,wBAAwB;YAC5D,SAAS;SACV;KACF,CAAC,CAAC;IAEH,eAAe,KAAf,eAAe,GAAK,mBAAmB,EAAC;IAExC,mCAAmC;IACnC,MAAM,mBAAmB,GAAG,MAAM,sBAAsB,CAAC;QACvD,OAAO;QACP,aAAa,EAAE,sBAAsB,EAAE,MAAM;QAC7C,mBAAmB,EAAE,oBAAoB,CAAC,MAAM;QAChD,wBAAwB,EAAE,CAAC,KAAK,EAAE,EAAE,CAClC,kCAAkC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;QACzE,gBAAgB,EAAE,CAAC,MAAe,EAAE,EAAE;YACpC,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,UAAU,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAClE,CAAC;QACD,SAAS,EAAE;YACT,MAAM,EAAE,2BAA2B,CAAC,wBAAwB;YAC5D,SAAS;SACV;KACF,CAAC,CAAC;IAEH,eAAe,KAAf,eAAe,GAAK,mBAAmB,EAAC;IAExC,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAA6B,EAC7B,UAA+C,EAC/C,oBAAyD,EACzD,eAAuB,EACvB,SAAoB;IAEpB,MAAM,eAAe,GAAG,MAAM,qCAAqC,CACjE,OAAO,EACP,UAAU,EACV,oBAAoB,EACpB,SAAS,CACV,CAAC;IAEF,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,sBAAsB,CAAC,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA6B,EAC7B,MAAkC,EAClC,qBAAqD,EACrD,eAAuB,EACvB,SAAoB;IAEpB,MAAM,0CAA0C,GAC9C,EAAE,CAAC;IAEL,MAAM,mBAAmB,GAAG,8BAA8B,CACxD,OAAO,EACP,MAAM,CAAC,EAAE,CACV,CAAC;IAEF,KAAK,MAAM,kBAAkB,IAAI,mBAAmB,EAAE,CAAC;QACrD,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,IAAI,CACrD,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,UAAU,KAAK,kBAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CACtE,CAAC;QAEF,MAAM,eAAe,GAAG,MAAM,qCAAqC,CACjE,OAAO,EACP,kBAAkB,EAClB,oBAAoB,EACpB,SAAS,CACV,CAAC;QAEF,uEAAuE;QACvE,IAAI,eAAe,EAAE,CAAC;YACpB,0CAA0C,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,0DAA0D;IAC1D,IAAI,0CAA0C,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,2BAA2B,CAC/B,OAAO,EACP,0CAA0C,EAC1C,eAAe,CAChB,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { compareAndSyncMetadata } from './metadata';\nimport type { AccountGroupMultichainAccountObject } from '../../group';\nimport { backupAndSyncLogger } from '../../logger';\nimport type { AccountWalletEntropyObject } from '../../wallet';\nimport type { BackupAndSyncAnalyticsAction } from '../analytics';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport { UserStorageSyncedWalletGroupSchema } from '../types';\nimport type {\n BackupAndSyncContext,\n UserStorageSyncedWalletGroup,\n} from '../types';\nimport {\n pushGroupToUserStorage,\n pushGroupToUserStorageBatch,\n} from '../user-storage/network-operations';\nimport {\n getLocalGroupForEntropyWallet,\n getLocalGroupsForEntropyWallet,\n} from '../utils';\n\n/**\n * Creates a multichain account group.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param groupIndex - The group index.\n * @param profileId - The profile ID for analytics.\n * @param analyticsAction - The analytics action to log.\n */\nexport const createMultichainAccountGroup = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n groupIndex: number,\n profileId: ProfileId,\n analyticsAction: BackupAndSyncAnalyticsAction,\n) => {\n try {\n const didGroupAlreadyExist = getLocalGroupForEntropyWallet(\n context,\n entropySourceId,\n groupIndex,\n );\n\n // This will be idempotent so we can create the group even if it already exists\n await context.messenger.call(\n 'MultichainAccountService:createMultichainAccountGroup',\n {\n entropySource: entropySourceId,\n groupIndex,\n },\n );\n\n if (!didGroupAlreadyExist) {\n context.emitAnalyticsEventFn({\n action: analyticsAction,\n profileId,\n });\n }\n } catch (error) {\n // This can happen if the Snap Keyring is not ready yet when invoking\n // `MultichainAccountService:createMultichainAccountGroup`.\n // Since `MultichainAccountService:createMultichainAccountGroup` will at\n // least create the EVM account and the account group before throwing, we can safely\n // ignore this error and swallow it.\n // Any missing Snap accounts will be added later with alignment.\n\n backupAndSyncLogger(\n `Failed to create group ${groupIndex} for entropy ${entropySourceId}:`,\n // istanbul ignore next\n error instanceof Error ? error.message : String(error),\n );\n }\n};\n\n/**\n * Creates local groups from user storage groups.\n *\n * @param context - The sync context containing controller and messenger.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function createLocalGroupsFromUserStorage(\n context: BackupAndSyncContext,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const numberOfAccountGroupsToCreate = Math.max(\n ...groupsFromUserStorage.map((g) => g.groupIndex),\n );\n\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n for (\n let groupIndex = 0;\n groupIndex <= numberOfAccountGroupsToCreate;\n groupIndex++\n ) {\n await createMultichainAccountGroup(\n context,\n entropySourceId,\n groupIndex,\n profileId,\n BackupAndSyncAnalyticsEvent.GroupAdded,\n );\n }\n}\n\n/**\n * Syncs group metadata fields and determines if the group needs to be pushed to user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against.\n * @param profileId - The profile ID for analytics.\n * @returns A promise that resolves to true if the group needs to be pushed to user storage.\n */\nasync function syncGroupMetadataAndCheckIfPushNeeded(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null | undefined,\n profileId: ProfileId,\n): Promise<boolean> {\n const groupPersistedMetadata =\n context.controller.state.accountGroupsMetadata[localGroup.id];\n\n if (!groupFromUserStorage) {\n backupAndSyncLogger(\n `Group ${localGroup.id} did not exist in user storage, pushing to user storage...`,\n );\n\n return true;\n }\n\n // Track if we need to push this group to user storage\n let shouldPushGroup = false;\n\n // Compare and sync name metadata\n const shouldPushForName = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.name,\n userStorageMetadata: groupFromUserStorage.name,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.name.schema.value.is(value),\n applyLocalUpdate: (name: string) => {\n context.controller.setAccountGroupName(localGroup.id, name, true);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupRenamed,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForName;\n\n // Compare and sync pinned metadata\n const shouldPushForPinned = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.pinned,\n userStorageMetadata: groupFromUserStorage.pinned,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.pinned.schema.value.is(value),\n applyLocalUpdate: (pinned: boolean) => {\n context.controller.setAccountGroupPinned(localGroup.id, pinned);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupPinnedStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForPinned;\n\n // Compare and sync hidden metadata\n const shouldPushForHidden = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.hidden,\n userStorageMetadata: groupFromUserStorage.hidden,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.hidden.schema.value.is(value),\n applyLocalUpdate: (hidden: boolean) => {\n context.controller.setAccountGroupHidden(localGroup.id, hidden);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupHiddenStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForHidden;\n\n return shouldPushGroup;\n}\n\n/**\n * Syncs a single group's metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against (or null if it doesn't exist).\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupMetadata(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null,\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localGroup,\n groupFromUserStorage,\n profileId,\n );\n\n if (shouldPushGroup) {\n await pushGroupToUserStorage(context, localGroup, entropySourceId);\n }\n}\n\n/**\n * Syncs group metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param wallet - The local wallet containing the groups.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupsMetadata(\n context: BackupAndSyncContext,\n wallet: AccountWalletEntropyObject,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const localSyncableGroupsToBePushedToUserStorage: AccountGroupMultichainAccountObject[] =\n [];\n\n const localSyncableGroups = getLocalGroupsForEntropyWallet(\n context,\n wallet.id,\n );\n\n for (const localSyncableGroup of localSyncableGroups) {\n const groupFromUserStorage = groupsFromUserStorage.find(\n (group) =>\n group.groupIndex === localSyncableGroup.metadata.entropy.groupIndex,\n );\n\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localSyncableGroup,\n groupFromUserStorage,\n profileId,\n );\n\n // Add to push list if any metadata needs to be updated in user storage\n if (shouldPushGroup) {\n localSyncableGroupsToBePushedToUserStorage.push(localSyncableGroup);\n }\n }\n\n // Push all groups that need to be updated to user storage\n if (localSyncableGroupsToBePushedToUserStorage.length > 0) {\n await pushGroupToUserStorageBatch(\n context,\n localSyncableGroupsToBePushedToUserStorage,\n entropySourceId,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"group.mjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/group.ts"],"names":[],"mappings":"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","sourcesContent":["import { toMultichainAccountWalletId } from '@metamask/account-api';\n\nimport { compareAndSyncMetadata } from './metadata';\nimport type { AccountGroupMultichainAccountObject } from '../../group';\nimport { backupAndSyncLogger } from '../../logger';\nimport type { AccountWalletEntropyObject } from '../../wallet';\nimport type { BackupAndSyncAnalyticsAction } from '../analytics';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport { UserStorageSyncedWalletGroupSchema } from '../types';\nimport type {\n BackupAndSyncContext,\n UserStorageSyncedWalletGroup,\n} from '../types';\nimport {\n pushGroupToUserStorage,\n pushGroupToUserStorageBatch,\n} from '../user-storage/network-operations';\nimport { getLocalGroupsForEntropyWallet } from '../utils';\n\n/**\n * Creates multiple multichain account groups in batch (from 0 to maxGroupIndex).\n * This is an optimized version that creates all groups in one operation instead of\n * creating them sequentially.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param maxGroupIndex - Number of account groups to create in batch.\n * @param profileId - The profile ID for analytics.\n * @param analyticsAction - The analytics action to log for each created group.\n * @returns Array of created group IDs.\n */\nexport const createMultichainAccountGroupsBatch = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n maxGroupIndex: number,\n profileId: ProfileId,\n analyticsAction: BackupAndSyncAnalyticsAction,\n): Promise<void> => {\n const numberOfAccountGroupsToCreate = maxGroupIndex + 1; // maxGroupIndex is zero-based, so we add 1 to get the count.\n backupAndSyncLogger(\n `Creating ${numberOfAccountGroupsToCreate} account groups (batch) for entropy source: ${entropySourceId}`,\n );\n\n // Capture the set of group indices that already exist before the batch call,\n // so we can correctly identify newly created groups after the call completes.\n const walletId = toMultichainAccountWalletId(entropySourceId);\n const existingGroupIndices = new Set(\n getLocalGroupsForEntropyWallet(context, walletId).map(\n (group) => group.metadata.entropy.groupIndex,\n ),\n );\n\n try {\n // Call the batched creation method (this is idempotent).\n const groups = await context.messenger.call(\n 'MultichainAccountService:createMultichainAccountGroups',\n {\n entropySource: entropySourceId,\n fromGroupIndex: 0,\n toGroupIndex: maxGroupIndex,\n },\n );\n\n // Contains all groups (existing + newly created).\n for (const group of groups) {\n // TODO: A group should not be null here, but EVM provider might fail to create some groups sometimes, which means\n // we can end up having an \"empty group\" for some time.\n if (group) {\n const didGroupAlreadyExist = existingGroupIndices.has(group.groupIndex);\n\n if (!didGroupAlreadyExist) {\n context.emitAnalyticsEventFn({\n action: analyticsAction,\n profileId,\n });\n }\n }\n }\n\n backupAndSyncLogger(`Successfully created ${groups.length} groups (batch)`);\n } catch (error) {\n // This can happen if the Snap Keyring is not ready yet when invoking\n // `MultichainAccountService:createMultichainAccountGroups`.\n // Since `MultichainAccountService:createMultichainAccountGroups` will at\n // least create the EVM account and the account group before throwing, we can safely\n // ignore this error and swallow it.\n // Any missing Snap accounts will be added later with alignment.\n\n backupAndSyncLogger(\n `Failed to create account groups batch:`,\n // istanbul ignore next\n error instanceof Error ? error.message : String(error),\n );\n }\n};\n\n/**\n * Creates local groups from user storage groups.\n *\n * @param context - The sync context containing controller and messenger.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function createLocalGroupsFromUserStorage(\n context: BackupAndSyncContext,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const maxGroupIndex = Math.max(\n ...groupsFromUserStorage.map((group) => group.groupIndex),\n );\n\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n // Use batch creation for better performance.\n await createMultichainAccountGroupsBatch(\n context,\n entropySourceId,\n maxGroupIndex,\n profileId,\n BackupAndSyncAnalyticsEvent.GroupAdded,\n );\n}\n\n/**\n * Syncs group metadata fields and determines if the group needs to be pushed to user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against.\n * @param profileId - The profile ID for analytics.\n * @returns A promise that resolves to true if the group needs to be pushed to user storage.\n */\nasync function syncGroupMetadataAndCheckIfPushNeeded(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null | undefined,\n profileId: ProfileId,\n): Promise<boolean> {\n const groupPersistedMetadata =\n context.controller.state.accountGroupsMetadata[localGroup.id];\n\n if (!groupFromUserStorage) {\n backupAndSyncLogger(\n `Group ${localGroup.id} did not exist in user storage, pushing to user storage...`,\n );\n\n return true;\n }\n\n // Track if we need to push this group to user storage\n let shouldPushGroup = false;\n\n // Compare and sync name metadata\n const shouldPushForName = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.name,\n userStorageMetadata: groupFromUserStorage.name,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.name.schema.value.is(value),\n applyLocalUpdate: (name: string) => {\n context.controller.setAccountGroupName(localGroup.id, name, true);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupRenamed,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForName;\n\n // Compare and sync pinned metadata\n const shouldPushForPinned = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.pinned,\n userStorageMetadata: groupFromUserStorage.pinned,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.pinned.schema.value.is(value),\n applyLocalUpdate: (pinned: boolean) => {\n context.controller.setAccountGroupPinned(localGroup.id, pinned);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupPinnedStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForPinned;\n\n // Compare and sync hidden metadata\n const shouldPushForHidden = await compareAndSyncMetadata({\n context,\n localMetadata: groupPersistedMetadata?.hidden,\n userStorageMetadata: groupFromUserStorage.hidden,\n validateUserStorageValue: (value) =>\n UserStorageSyncedWalletGroupSchema.schema.hidden.schema.value.is(value),\n applyLocalUpdate: (hidden: boolean) => {\n context.controller.setAccountGroupHidden(localGroup.id, hidden);\n },\n analytics: {\n action: BackupAndSyncAnalyticsEvent.GroupHiddenStatusChanged,\n profileId,\n },\n });\n\n shouldPushGroup ||= shouldPushForHidden;\n\n return shouldPushGroup;\n}\n\n/**\n * Syncs a single group's metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param localGroup - The local group to sync.\n * @param groupFromUserStorage - The group from user storage to compare against (or null if it doesn't exist).\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupMetadata(\n context: BackupAndSyncContext,\n localGroup: AccountGroupMultichainAccountObject,\n groupFromUserStorage: UserStorageSyncedWalletGroup | null,\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localGroup,\n groupFromUserStorage,\n profileId,\n );\n\n if (shouldPushGroup) {\n await pushGroupToUserStorage(context, localGroup, entropySourceId);\n }\n}\n\n/**\n * Syncs group metadata between local and user storage.\n *\n * @param context - The sync context containing controller and messenger.\n * @param wallet - The local wallet containing the groups.\n * @param groupsFromUserStorage - Array of groups from user storage.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport async function syncGroupsMetadata(\n context: BackupAndSyncContext,\n wallet: AccountWalletEntropyObject,\n groupsFromUserStorage: UserStorageSyncedWalletGroup[],\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> {\n const localSyncableGroupsToBePushedToUserStorage: AccountGroupMultichainAccountObject[] =\n [];\n\n const localSyncableGroups = getLocalGroupsForEntropyWallet(\n context,\n wallet.id,\n );\n\n for (const localSyncableGroup of localSyncableGroups) {\n const groupFromUserStorage = groupsFromUserStorage.find(\n (group) =>\n group.groupIndex === localSyncableGroup.metadata.entropy.groupIndex,\n );\n\n const shouldPushGroup = await syncGroupMetadataAndCheckIfPushNeeded(\n context,\n localSyncableGroup,\n groupFromUserStorage,\n profileId,\n );\n\n // Add to push list if any metadata needs to be updated in user storage\n if (shouldPushGroup) {\n localSyncableGroupsToBePushedToUserStorage.push(localSyncableGroup);\n }\n }\n\n // Push all groups that need to be updated to user storage\n if (localSyncableGroupsToBePushedToUserStorage.length > 0) {\n await pushGroupToUserStorageBatch(\n context,\n localSyncableGroupsToBePushedToUserStorage,\n entropySourceId,\n );\n }\n}\n"]}
@@ -36,10 +36,9 @@ const performLegacyAccountSyncing = async (context, entropySourceId, profileId)
36
36
  if (numberOfAccountGroupsToCreate > 0) {
37
37
  // Creating multichain account group is idempotent, so we can safely
38
38
  // re-create every groups starting from 0.
39
- for (let i = 0; i < numberOfAccountGroupsToCreate; i++) {
40
- (0, logger_1.backupAndSyncLogger)(`Creating account group ${i} for legacy account`);
41
- await (0, group_1.createMultichainAccountGroup)(context, entropySourceId, i, profileId, analytics_1.BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount);
42
- }
39
+ // Use batch creation for better performance.
40
+ const maxGroupIndex = numberOfAccountGroupsToCreate - 1; // Group index is zero-based.
41
+ await (0, group_1.createMultichainAccountGroupsBatch)(context, entropySourceId, maxGroupIndex, profileId, analytics_1.BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount);
43
42
  }
44
43
  // 3. Rename account groups if needed
45
44
  const localAccountGroups = (0, utils_1.getLocalGroupsForEntropyWallet)(context, (0, account_api_1.toMultichainAccountWalletId)(entropySourceId));
@@ -1 +1 @@
1
- {"version":3,"file":"legacy.cjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":";;;AAAA,uDAAoE;AACpE,uEAAkF;AAElF,uCAAuD;AACvD,6CAAmD;AACnD,sDAA2D;AAG3D,4DAAkE;AAClE,8CAA0D;AAE1D;;;;;;;;;;GAUG;AACI,MAAM,2BAA2B,GAAG,KAAK,EAC9C,OAA6B,EAC7B,eAAuB,EACvB,SAAoB,EACpB,EAAE;IACF,qCAAqC;IACrC,MAAM,6BAA6B,GAAG,MAAM,IAAA,8CAA+B,EACzE,OAAO,EACP,eAAe,CAChB,CAAC;IACF,IAAI,6BAA6B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,IAAA,4BAAmB,EAAC,qDAAqD,CAAC,CAAC;QAE3E,OAAO,CAAC,oBAAoB,CAAC;YAC3B,MAAM,EAAE,uCAA2B,CAAC,iBAAiB;YACrD,SAAS;SACV,CAAC,CAAC;QAEH,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,6BAA6B,GAAG,6BAA6B,CAAC,MAAM,CAAC;IAE3E,IAAA,4BAAmB,EACjB,YAAY,6BAA6B,qCAAqC,CAC/E,CAAC;IAEF,IAAI,6BAA6B,GAAG,CAAC,EAAE,CAAC;QACtC,oEAAoE;QACpE,0CAA0C;QAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,6BAA6B,EAAE,CAAC,EAAE,EAAE,CAAC;YACvD,IAAA,4BAAmB,EAAC,0BAA0B,CAAC,qBAAqB,CAAC,CAAC;YACtE,MAAM,IAAA,oCAA4B,EAChC,OAAO,EACP,eAAe,EACf,CAAC,EACD,SAAS,EACT,uCAA2B,CAAC,2BAA2B,CACxD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,MAAM,kBAAkB,GAAG,IAAA,sCAA8B,EACvD,OAAO,EACP,IAAA,yCAA2B,EAAC,eAAe,CAAC,CAC7C,CAAC;IACF,KAAK,MAAM,aAAa,IAAI,6BAA6B,EAAE,CAAC;QAC1D,UAAU;QACV,iBAAiB;QACjB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC;QAC/B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACb,IAAA,4BAAmB,EACjB,qEAAqE,IAAI,CAAC,SAAS,CACjF,aAAa,CACd,EAAE,CACJ,CAAC;YACF,SAAS;QACX,CAAC;QAED,IAAI,CAAC,EAAE,CAAC;YACN,4DAA4D;YAC5D,MAAM,cAAc,GAAG,IAAA,uDAAiC,EAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACnD,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CACxC,CAAC;YACF,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAE/D,OAAO,CAAC,oBAAoB,CAAC;oBAC3B,MAAM,EAAE,uCAA2B,CAAC,kBAAkB;oBACtD,SAAS;oBACT,qBAAqB,EAAE,wBAAwB,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE;iBACvE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,oBAAoB,CAAC;QAC3B,MAAM,EAAE,uCAA2B,CAAC,iBAAiB;QACrD,SAAS;KACV,CAAC,CAAC;AACL,CAAC,CAAC;AAnFW,QAAA,2BAA2B,+BAmFtC","sourcesContent":["import { toMultichainAccountWalletId } from '@metamask/account-api';\nimport { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\n\nimport { createMultichainAccountGroup } from './group';\nimport { backupAndSyncLogger } from '../../logger';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport type { BackupAndSyncContext } from '../types';\nimport { getAllLegacyUserStorageAccounts } from '../user-storage';\nimport { getLocalGroupsForEntropyWallet } from '../utils';\n\n/**\n * Performs a stripped down version of legacy account syncing, replacing the current\n * UserStorageController:syncInternalAccountsWithUserStorage call.\n * This ensures legacy (V1) account syncing data is correctly migrated to\n * the new AccountTreeController data structure. It should only happen\n * once per wallet.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport const performLegacyAccountSyncing = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n profileId: ProfileId,\n) => {\n // 1. Get legacy account syncing data\n const legacyAccountsFromUserStorage = await getAllLegacyUserStorageAccounts(\n context,\n entropySourceId,\n );\n if (legacyAccountsFromUserStorage.length === 0) {\n backupAndSyncLogger('No legacy accounts, skipping legacy account syncing');\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n\n return;\n }\n\n // 2. Create account groups accordingly\n const numberOfAccountGroupsToCreate = legacyAccountsFromUserStorage.length;\n\n backupAndSyncLogger(\n `Creating ${numberOfAccountGroupsToCreate} account groups for legacy accounts`,\n );\n\n if (numberOfAccountGroupsToCreate > 0) {\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n for (let i = 0; i < numberOfAccountGroupsToCreate; i++) {\n backupAndSyncLogger(`Creating account group ${i} for legacy account`);\n await createMultichainAccountGroup(\n context,\n entropySourceId,\n i,\n profileId,\n BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount,\n );\n }\n }\n\n // 3. Rename account groups if needed\n const localAccountGroups = getLocalGroupsForEntropyWallet(\n context,\n toMultichainAccountWalletId(entropySourceId),\n );\n for (const legacyAccount of legacyAccountsFromUserStorage) {\n // n: name\n // a: EVM address\n const { n, a } = legacyAccount;\n if (!a || !n) {\n backupAndSyncLogger(\n `Legacy account data is missing name or address, skipping account: ${JSON.stringify(\n legacyAccount,\n )}`,\n );\n continue;\n }\n\n if (n) {\n // Find the local group that corresponds to this EVM address\n const localAccountId = getUUIDFromAddressOfNormalAccount(a);\n const localGroup = localAccountGroups.find((group) =>\n group.accounts.includes(localAccountId),\n );\n if (localGroup) {\n context.controller.setAccountGroupName(localGroup.id, n, true);\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacyGroupRenamed,\n profileId,\n additionalDescription: `Renamed legacy group ${localGroup.id} to ${n}`,\n });\n }\n }\n }\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n};\n"]}
1
+ {"version":3,"file":"legacy.cjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":";;;AAAA,uDAAoE;AACpE,uEAAkF;AAElF,uCAA6D;AAC7D,6CAAmD;AACnD,sDAA2D;AAG3D,4DAAkE;AAClE,8CAA0D;AAE1D;;;;;;;;;;GAUG;AACI,MAAM,2BAA2B,GAAG,KAAK,EAC9C,OAA6B,EAC7B,eAAuB,EACvB,SAAoB,EACL,EAAE;IACjB,qCAAqC;IACrC,MAAM,6BAA6B,GAAG,MAAM,IAAA,8CAA+B,EACzE,OAAO,EACP,eAAe,CAChB,CAAC;IACF,IAAI,6BAA6B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,IAAA,4BAAmB,EAAC,qDAAqD,CAAC,CAAC;QAE3E,OAAO,CAAC,oBAAoB,CAAC;YAC3B,MAAM,EAAE,uCAA2B,CAAC,iBAAiB;YACrD,SAAS;SACV,CAAC,CAAC;QAEH,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,6BAA6B,GAAG,6BAA6B,CAAC,MAAM,CAAC;IAE3E,IAAA,4BAAmB,EACjB,YAAY,6BAA6B,qCAAqC,CAC/E,CAAC;IAEF,IAAI,6BAA6B,GAAG,CAAC,EAAE,CAAC;QACtC,oEAAoE;QACpE,0CAA0C;QAC1C,6CAA6C;QAC7C,MAAM,aAAa,GAAG,6BAA6B,GAAG,CAAC,CAAC,CAAC,6BAA6B;QACtF,MAAM,IAAA,0CAAkC,EACtC,OAAO,EACP,eAAe,EACf,aAAa,EACb,SAAS,EACT,uCAA2B,CAAC,2BAA2B,CACxD,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,MAAM,kBAAkB,GAAG,IAAA,sCAA8B,EACvD,OAAO,EACP,IAAA,yCAA2B,EAAC,eAAe,CAAC,CAC7C,CAAC;IACF,KAAK,MAAM,aAAa,IAAI,6BAA6B,EAAE,CAAC;QAC1D,UAAU;QACV,iBAAiB;QACjB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC;QAC/B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACb,IAAA,4BAAmB,EACjB,qEAAqE,IAAI,CAAC,SAAS,CACjF,aAAa,CACd,EAAE,CACJ,CAAC;YACF,SAAS;QACX,CAAC;QAED,IAAI,CAAC,EAAE,CAAC;YACN,4DAA4D;YAC5D,MAAM,cAAc,GAAG,IAAA,uDAAiC,EAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACnD,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CACxC,CAAC;YACF,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAE/D,OAAO,CAAC,oBAAoB,CAAC;oBAC3B,MAAM,EAAE,uCAA2B,CAAC,kBAAkB;oBACtD,SAAS;oBACT,qBAAqB,EAAE,wBAAwB,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE;iBACvE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,oBAAoB,CAAC;QAC3B,MAAM,EAAE,uCAA2B,CAAC,iBAAiB;QACrD,SAAS;KACV,CAAC,CAAC;AACL,CAAC,CAAC;AAlFW,QAAA,2BAA2B,+BAkFtC","sourcesContent":["import { toMultichainAccountWalletId } from '@metamask/account-api';\nimport { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\n\nimport { createMultichainAccountGroupsBatch } from './group';\nimport { backupAndSyncLogger } from '../../logger';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport type { BackupAndSyncContext } from '../types';\nimport { getAllLegacyUserStorageAccounts } from '../user-storage';\nimport { getLocalGroupsForEntropyWallet } from '../utils';\n\n/**\n * Performs a stripped down version of legacy account syncing, replacing the current\n * UserStorageController:syncInternalAccountsWithUserStorage call.\n * This ensures legacy (V1) account syncing data is correctly migrated to\n * the new AccountTreeController data structure. It should only happen\n * once per wallet.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport const performLegacyAccountSyncing = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> => {\n // 1. Get legacy account syncing data\n const legacyAccountsFromUserStorage = await getAllLegacyUserStorageAccounts(\n context,\n entropySourceId,\n );\n if (legacyAccountsFromUserStorage.length === 0) {\n backupAndSyncLogger('No legacy accounts, skipping legacy account syncing');\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n\n return;\n }\n\n // 2. Create account groups accordingly\n const numberOfAccountGroupsToCreate = legacyAccountsFromUserStorage.length;\n\n backupAndSyncLogger(\n `Creating ${numberOfAccountGroupsToCreate} account groups for legacy accounts`,\n );\n\n if (numberOfAccountGroupsToCreate > 0) {\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n // Use batch creation for better performance.\n const maxGroupIndex = numberOfAccountGroupsToCreate - 1; // Group index is zero-based.\n await createMultichainAccountGroupsBatch(\n context,\n entropySourceId,\n maxGroupIndex,\n profileId,\n BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount,\n );\n }\n\n // 3. Rename account groups if needed\n const localAccountGroups = getLocalGroupsForEntropyWallet(\n context,\n toMultichainAccountWalletId(entropySourceId),\n );\n for (const legacyAccount of legacyAccountsFromUserStorage) {\n // n: name\n // a: EVM address\n const { n, a } = legacyAccount;\n if (!a || !n) {\n backupAndSyncLogger(\n `Legacy account data is missing name or address, skipping account: ${JSON.stringify(\n legacyAccount,\n )}`,\n );\n continue;\n }\n\n if (n) {\n // Find the local group that corresponds to this EVM address\n const localAccountId = getUUIDFromAddressOfNormalAccount(a);\n const localGroup = localAccountGroups.find((group) =>\n group.accounts.includes(localAccountId),\n );\n if (localGroup) {\n context.controller.setAccountGroupName(localGroup.id, n, true);\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacyGroupRenamed,\n profileId,\n additionalDescription: `Renamed legacy group ${localGroup.id} to ${n}`,\n });\n }\n }\n }\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"legacy.d.cts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAiB;AAIrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,YAC7B,oBAAoB,mBACZ,MAAM,aACZ,SAAS,kBAgFrB,CAAC"}
1
+ {"version":3,"file":"legacy.d.cts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAiB;AAIrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,YAC7B,oBAAoB,mBACZ,MAAM,aACZ,SAAS,KACnB,QAAQ,IAAI,CA8Ed,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"legacy.d.mts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAiB;AAIrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,YAC7B,oBAAoB,mBACZ,MAAM,aACZ,SAAS,kBAgFrB,CAAC"}
1
+ {"version":3,"file":"legacy.d.mts","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,oCAA0B;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAiB;AAIrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,YAC7B,oBAAoB,mBACZ,MAAM,aACZ,SAAS,KACnB,QAAQ,IAAI,CA8Ed,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { toMultichainAccountWalletId } from "@metamask/account-api";
2
2
  import { getUUIDFromAddressOfNormalAccount } from "@metamask/accounts-controller";
3
- import { createMultichainAccountGroup } from "./group.mjs";
3
+ import { createMultichainAccountGroupsBatch } from "./group.mjs";
4
4
  import { backupAndSyncLogger } from "../../logger.mjs";
5
5
  import { BackupAndSyncAnalyticsEvent } from "../analytics/index.mjs";
6
6
  import { getAllLegacyUserStorageAccounts } from "../user-storage/index.mjs";
@@ -33,10 +33,9 @@ export const performLegacyAccountSyncing = async (context, entropySourceId, prof
33
33
  if (numberOfAccountGroupsToCreate > 0) {
34
34
  // Creating multichain account group is idempotent, so we can safely
35
35
  // re-create every groups starting from 0.
36
- for (let i = 0; i < numberOfAccountGroupsToCreate; i++) {
37
- backupAndSyncLogger(`Creating account group ${i} for legacy account`);
38
- await createMultichainAccountGroup(context, entropySourceId, i, profileId, BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount);
39
- }
36
+ // Use batch creation for better performance.
37
+ const maxGroupIndex = numberOfAccountGroupsToCreate - 1; // Group index is zero-based.
38
+ await createMultichainAccountGroupsBatch(context, entropySourceId, maxGroupIndex, profileId, BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount);
40
39
  }
41
40
  // 3. Rename account groups if needed
42
41
  const localAccountGroups = getLocalGroupsForEntropyWallet(context, toMultichainAccountWalletId(entropySourceId));
@@ -1 +1 @@
1
- {"version":3,"file":"legacy.mjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,8BAA8B;AACpE,OAAO,EAAE,iCAAiC,EAAE,sCAAsC;AAElF,OAAO,EAAE,4BAA4B,EAAE,oBAAgB;AACvD,OAAO,EAAE,mBAAmB,EAAE,yBAAqB;AACnD,OAAO,EAAE,2BAA2B,EAAE,+BAAqB;AAG3D,OAAO,EAAE,+BAA+B,EAAE,kCAAwB;AAClE,OAAO,EAAE,8BAA8B,EAAE,2BAAiB;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,OAA6B,EAC7B,eAAuB,EACvB,SAAoB,EACpB,EAAE;IACF,qCAAqC;IACrC,MAAM,6BAA6B,GAAG,MAAM,+BAA+B,CACzE,OAAO,EACP,eAAe,CAChB,CAAC;IACF,IAAI,6BAA6B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,mBAAmB,CAAC,qDAAqD,CAAC,CAAC;QAE3E,OAAO,CAAC,oBAAoB,CAAC;YAC3B,MAAM,EAAE,2BAA2B,CAAC,iBAAiB;YACrD,SAAS;SACV,CAAC,CAAC;QAEH,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,6BAA6B,GAAG,6BAA6B,CAAC,MAAM,CAAC;IAE3E,mBAAmB,CACjB,YAAY,6BAA6B,qCAAqC,CAC/E,CAAC;IAEF,IAAI,6BAA6B,GAAG,CAAC,EAAE,CAAC;QACtC,oEAAoE;QACpE,0CAA0C;QAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,6BAA6B,EAAE,CAAC,EAAE,EAAE,CAAC;YACvD,mBAAmB,CAAC,0BAA0B,CAAC,qBAAqB,CAAC,CAAC;YACtE,MAAM,4BAA4B,CAChC,OAAO,EACP,eAAe,EACf,CAAC,EACD,SAAS,EACT,2BAA2B,CAAC,2BAA2B,CACxD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,MAAM,kBAAkB,GAAG,8BAA8B,CACvD,OAAO,EACP,2BAA2B,CAAC,eAAe,CAAC,CAC7C,CAAC;IACF,KAAK,MAAM,aAAa,IAAI,6BAA6B,EAAE,CAAC;QAC1D,UAAU;QACV,iBAAiB;QACjB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC;QAC/B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACb,mBAAmB,CACjB,qEAAqE,IAAI,CAAC,SAAS,CACjF,aAAa,CACd,EAAE,CACJ,CAAC;YACF,SAAS;QACX,CAAC;QAED,IAAI,CAAC,EAAE,CAAC;YACN,4DAA4D;YAC5D,MAAM,cAAc,GAAG,iCAAiC,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACnD,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CACxC,CAAC;YACF,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAE/D,OAAO,CAAC,oBAAoB,CAAC;oBAC3B,MAAM,EAAE,2BAA2B,CAAC,kBAAkB;oBACtD,SAAS;oBACT,qBAAqB,EAAE,wBAAwB,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE;iBACvE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,oBAAoB,CAAC;QAC3B,MAAM,EAAE,2BAA2B,CAAC,iBAAiB;QACrD,SAAS;KACV,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { toMultichainAccountWalletId } from '@metamask/account-api';\nimport { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\n\nimport { createMultichainAccountGroup } from './group';\nimport { backupAndSyncLogger } from '../../logger';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport type { BackupAndSyncContext } from '../types';\nimport { getAllLegacyUserStorageAccounts } from '../user-storage';\nimport { getLocalGroupsForEntropyWallet } from '../utils';\n\n/**\n * Performs a stripped down version of legacy account syncing, replacing the current\n * UserStorageController:syncInternalAccountsWithUserStorage call.\n * This ensures legacy (V1) account syncing data is correctly migrated to\n * the new AccountTreeController data structure. It should only happen\n * once per wallet.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport const performLegacyAccountSyncing = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n profileId: ProfileId,\n) => {\n // 1. Get legacy account syncing data\n const legacyAccountsFromUserStorage = await getAllLegacyUserStorageAccounts(\n context,\n entropySourceId,\n );\n if (legacyAccountsFromUserStorage.length === 0) {\n backupAndSyncLogger('No legacy accounts, skipping legacy account syncing');\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n\n return;\n }\n\n // 2. Create account groups accordingly\n const numberOfAccountGroupsToCreate = legacyAccountsFromUserStorage.length;\n\n backupAndSyncLogger(\n `Creating ${numberOfAccountGroupsToCreate} account groups for legacy accounts`,\n );\n\n if (numberOfAccountGroupsToCreate > 0) {\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n for (let i = 0; i < numberOfAccountGroupsToCreate; i++) {\n backupAndSyncLogger(`Creating account group ${i} for legacy account`);\n await createMultichainAccountGroup(\n context,\n entropySourceId,\n i,\n profileId,\n BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount,\n );\n }\n }\n\n // 3. Rename account groups if needed\n const localAccountGroups = getLocalGroupsForEntropyWallet(\n context,\n toMultichainAccountWalletId(entropySourceId),\n );\n for (const legacyAccount of legacyAccountsFromUserStorage) {\n // n: name\n // a: EVM address\n const { n, a } = legacyAccount;\n if (!a || !n) {\n backupAndSyncLogger(\n `Legacy account data is missing name or address, skipping account: ${JSON.stringify(\n legacyAccount,\n )}`,\n );\n continue;\n }\n\n if (n) {\n // Find the local group that corresponds to this EVM address\n const localAccountId = getUUIDFromAddressOfNormalAccount(a);\n const localGroup = localAccountGroups.find((group) =>\n group.accounts.includes(localAccountId),\n );\n if (localGroup) {\n context.controller.setAccountGroupName(localGroup.id, n, true);\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacyGroupRenamed,\n profileId,\n additionalDescription: `Renamed legacy group ${localGroup.id} to ${n}`,\n });\n }\n }\n }\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n};\n"]}
1
+ {"version":3,"file":"legacy.mjs","sourceRoot":"","sources":["../../../src/backup-and-sync/syncing/legacy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,8BAA8B;AACpE,OAAO,EAAE,iCAAiC,EAAE,sCAAsC;AAElF,OAAO,EAAE,kCAAkC,EAAE,oBAAgB;AAC7D,OAAO,EAAE,mBAAmB,EAAE,yBAAqB;AACnD,OAAO,EAAE,2BAA2B,EAAE,+BAAqB;AAG3D,OAAO,EAAE,+BAA+B,EAAE,kCAAwB;AAClE,OAAO,EAAE,8BAA8B,EAAE,2BAAiB;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,OAA6B,EAC7B,eAAuB,EACvB,SAAoB,EACL,EAAE;IACjB,qCAAqC;IACrC,MAAM,6BAA6B,GAAG,MAAM,+BAA+B,CACzE,OAAO,EACP,eAAe,CAChB,CAAC;IACF,IAAI,6BAA6B,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,mBAAmB,CAAC,qDAAqD,CAAC,CAAC;QAE3E,OAAO,CAAC,oBAAoB,CAAC;YAC3B,MAAM,EAAE,2BAA2B,CAAC,iBAAiB;YACrD,SAAS;SACV,CAAC,CAAC;QAEH,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,6BAA6B,GAAG,6BAA6B,CAAC,MAAM,CAAC;IAE3E,mBAAmB,CACjB,YAAY,6BAA6B,qCAAqC,CAC/E,CAAC;IAEF,IAAI,6BAA6B,GAAG,CAAC,EAAE,CAAC;QACtC,oEAAoE;QACpE,0CAA0C;QAC1C,6CAA6C;QAC7C,MAAM,aAAa,GAAG,6BAA6B,GAAG,CAAC,CAAC,CAAC,6BAA6B;QACtF,MAAM,kCAAkC,CACtC,OAAO,EACP,eAAe,EACf,aAAa,EACb,SAAS,EACT,2BAA2B,CAAC,2BAA2B,CACxD,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,MAAM,kBAAkB,GAAG,8BAA8B,CACvD,OAAO,EACP,2BAA2B,CAAC,eAAe,CAAC,CAC7C,CAAC;IACF,KAAK,MAAM,aAAa,IAAI,6BAA6B,EAAE,CAAC;QAC1D,UAAU;QACV,iBAAiB;QACjB,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC;QAC/B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACb,mBAAmB,CACjB,qEAAqE,IAAI,CAAC,SAAS,CACjF,aAAa,CACd,EAAE,CACJ,CAAC;YACF,SAAS;QACX,CAAC;QAED,IAAI,CAAC,EAAE,CAAC;YACN,4DAA4D;YAC5D,MAAM,cAAc,GAAG,iCAAiC,CAAC,CAAC,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACnD,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CACxC,CAAC;YACF,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAE/D,OAAO,CAAC,oBAAoB,CAAC;oBAC3B,MAAM,EAAE,2BAA2B,CAAC,kBAAkB;oBACtD,SAAS;oBACT,qBAAqB,EAAE,wBAAwB,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE;iBACvE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,oBAAoB,CAAC;QAC3B,MAAM,EAAE,2BAA2B,CAAC,iBAAiB;QACrD,SAAS;KACV,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { toMultichainAccountWalletId } from '@metamask/account-api';\nimport { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\n\nimport { createMultichainAccountGroupsBatch } from './group';\nimport { backupAndSyncLogger } from '../../logger';\nimport { BackupAndSyncAnalyticsEvent } from '../analytics';\nimport type { ProfileId } from '../authentication';\nimport type { BackupAndSyncContext } from '../types';\nimport { getAllLegacyUserStorageAccounts } from '../user-storage';\nimport { getLocalGroupsForEntropyWallet } from '../utils';\n\n/**\n * Performs a stripped down version of legacy account syncing, replacing the current\n * UserStorageController:syncInternalAccountsWithUserStorage call.\n * This ensures legacy (V1) account syncing data is correctly migrated to\n * the new AccountTreeController data structure. It should only happen\n * once per wallet.\n *\n * @param context - The sync context containing controller and messenger.\n * @param entropySourceId - The entropy source ID.\n * @param profileId - The profile ID for analytics.\n */\nexport const performLegacyAccountSyncing = async (\n context: BackupAndSyncContext,\n entropySourceId: string,\n profileId: ProfileId,\n): Promise<void> => {\n // 1. Get legacy account syncing data\n const legacyAccountsFromUserStorage = await getAllLegacyUserStorageAccounts(\n context,\n entropySourceId,\n );\n if (legacyAccountsFromUserStorage.length === 0) {\n backupAndSyncLogger('No legacy accounts, skipping legacy account syncing');\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n\n return;\n }\n\n // 2. Create account groups accordingly\n const numberOfAccountGroupsToCreate = legacyAccountsFromUserStorage.length;\n\n backupAndSyncLogger(\n `Creating ${numberOfAccountGroupsToCreate} account groups for legacy accounts`,\n );\n\n if (numberOfAccountGroupsToCreate > 0) {\n // Creating multichain account group is idempotent, so we can safely\n // re-create every groups starting from 0.\n // Use batch creation for better performance.\n const maxGroupIndex = numberOfAccountGroupsToCreate - 1; // Group index is zero-based.\n await createMultichainAccountGroupsBatch(\n context,\n entropySourceId,\n maxGroupIndex,\n profileId,\n BackupAndSyncAnalyticsEvent.LegacyGroupAddedFromAccount,\n );\n }\n\n // 3. Rename account groups if needed\n const localAccountGroups = getLocalGroupsForEntropyWallet(\n context,\n toMultichainAccountWalletId(entropySourceId),\n );\n for (const legacyAccount of legacyAccountsFromUserStorage) {\n // n: name\n // a: EVM address\n const { n, a } = legacyAccount;\n if (!a || !n) {\n backupAndSyncLogger(\n `Legacy account data is missing name or address, skipping account: ${JSON.stringify(\n legacyAccount,\n )}`,\n );\n continue;\n }\n\n if (n) {\n // Find the local group that corresponds to this EVM address\n const localAccountId = getUUIDFromAddressOfNormalAccount(a);\n const localGroup = localAccountGroups.find((group) =>\n group.accounts.includes(localAccountId),\n );\n if (localGroup) {\n context.controller.setAccountGroupName(localGroup.id, n, true);\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacyGroupRenamed,\n profileId,\n additionalDescription: `Renamed legacy group ${localGroup.id} to ${n}`,\n });\n }\n }\n }\n\n context.emitAnalyticsEventFn({\n action: BackupAndSyncAnalyticsEvent.LegacySyncingDone,\n profileId,\n });\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountsAddedEvent,\n AccountsControllerAccountsRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedMultichainAccountAction,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n AccountsControllerSetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { MultichainAccountServiceCreateMultichainAccountGroupAction } from '@metamask/multichain-account-service';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\n\nimport type { controllerName } from './AccountTreeController';\nimport type { AccountTreeControllerMethodActions } from './AccountTreeController-method-action-types';\nimport type {\n BackupAndSyncAnalyticsEventPayload,\n BackupAndSyncEmitAnalyticsEventParams,\n} from './backup-and-sync/analytics';\nimport type {\n AccountGroupObject,\n AccountTreeGroupPersistedMetadata,\n} from './group';\nimport type {\n AccountWalletObject,\n AccountTreeWalletPersistedMetadata,\n} from './wallet';\nimport type { MultichainAccountServiceWalletStatusChangeEvent } from '../../multichain-account-service/src/types';\n\n// Backward compatibility aliases using indexed access types\n/**\n * @deprecated Use AccountTreeGroupMetadata for tree objects or AccountTreeGroupPersistedMetadata for controller state\n */\nexport type AccountGroupMetadata = AccountGroupObject['metadata'];\n\n/**\n * @deprecated Use AccountTreeWalletMetadata for tree objects or AccountTreeWalletPersistedMetadata for controller state\n */\nexport type AccountWalletMetadata = AccountWalletObject['metadata'];\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n selectedAccountGroup: AccountGroupId | '';\n };\n isAccountTreeSyncingInProgress: boolean;\n hasAccountTreeSyncingSyncedAtLeastOnce: boolean;\n /** Persistent metadata for account groups (names, pinning, hiding, sync timestamps) */\n accountGroupsMetadata: Record<\n AccountGroupId,\n AccountTreeGroupPersistedMetadata\n >;\n /** Persistent metadata for account wallets (names, sync timestamps) */\n accountWalletsMetadata: Record<\n AccountWalletId,\n AccountTreeWalletPersistedMetadata\n >;\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedMultichainAccountAction\n | AccountsControllerListMultichainAccountsAction\n | AccountsControllerSetSelectedAccountAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap\n | UserStorageController.UserStorageControllerGetStateAction\n | UserStorageController.UserStorageControllerPerformGetStorageAction\n | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction\n | UserStorageController.UserStorageControllerPerformSetStorageAction\n | UserStorageController.UserStorageControllerPerformBatchSetStorageAction\n | AuthenticationController.AuthenticationControllerGetSessionProfileAction\n | MultichainAccountServiceCreateMultichainAccountGroupAction;\n\nexport type AccountTreeControllerActions =\n | AccountTreeControllerGetStateAction\n | AccountTreeControllerMethodActions;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\n/**\n * Represents the `AccountTreeController:accountTreeChange` event.\n * This event is emitted when nodes (wallets, groups, or accounts) are added or removed.\n */\nexport type AccountTreeControllerAccountTreeChangeEvent = {\n type: `${typeof controllerName}:accountTreeChange`;\n payload: [AccountTreeControllerState['accountTree']];\n};\n\n/**\n * Represents the `AccountTreeController:selectedAccountGroupChange` event.\n * This event is emitted when the selected account group changes.\n */\nexport type AccountTreeControllerSelectedAccountGroupChangeEvent = {\n type: `${typeof controllerName}:selectedAccountGroupChange`;\n payload: [AccountGroupId | '', AccountGroupId | ''];\n};\n\nexport type AllowedEvents =\n | AccountsControllerAccountsAddedEvent\n | AccountsControllerAccountsRemovedEvent\n | AccountsControllerSelectedAccountChangeEvent\n | UserStorageController.UserStorageControllerStateChangeEvent\n | MultichainAccountServiceWalletStatusChangeEvent;\n\nexport type AccountTreeControllerEvents =\n | AccountTreeControllerStateChangeEvent\n | AccountTreeControllerAccountTreeChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent;\n\nexport type AccountTreeControllerMessenger = Messenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents\n>;\n\nexport type AccountTreeControllerConfig = {\n trace?: TraceCallback;\n backupAndSync?: {\n onBackupAndSyncEvent?: (event: BackupAndSyncAnalyticsEventPayload) => void;\n };\n accountOrderCallbacks?: {\n isHiddenAccount?: (accountId: AccountId) => boolean;\n isPinnedAccount?: (accountId: AccountId) => boolean;\n };\n};\n\nexport type AccountTreeControllerInternalBackupAndSyncConfig = {\n emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => void;\n};\n"]}
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountsAddedEvent,\n AccountsControllerAccountsRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedMultichainAccountAction,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n AccountsControllerSetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n MultichainAccountServiceCreateMultichainAccountGroupAction,\n MultichainAccountServiceCreateMultichainAccountGroupsAction,\n} from '@metamask/multichain-account-service';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\n\nimport type { controllerName } from './AccountTreeController';\nimport type { AccountTreeControllerMethodActions } from './AccountTreeController-method-action-types';\nimport type {\n BackupAndSyncAnalyticsEventPayload,\n BackupAndSyncEmitAnalyticsEventParams,\n} from './backup-and-sync/analytics';\nimport type {\n AccountGroupObject,\n AccountTreeGroupPersistedMetadata,\n} from './group';\nimport type {\n AccountWalletObject,\n AccountTreeWalletPersistedMetadata,\n} from './wallet';\nimport type { MultichainAccountServiceWalletStatusChangeEvent } from '../../multichain-account-service/src/types';\n\n// Backward compatibility aliases using indexed access types\n/**\n * @deprecated Use AccountTreeGroupMetadata for tree objects or AccountTreeGroupPersistedMetadata for controller state\n */\nexport type AccountGroupMetadata = AccountGroupObject['metadata'];\n\n/**\n * @deprecated Use AccountTreeWalletMetadata for tree objects or AccountTreeWalletPersistedMetadata for controller state\n */\nexport type AccountWalletMetadata = AccountWalletObject['metadata'];\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n selectedAccountGroup: AccountGroupId | '';\n };\n isAccountTreeSyncingInProgress: boolean;\n hasAccountTreeSyncingSyncedAtLeastOnce: boolean;\n /** Persistent metadata for account groups (names, pinning, hiding, sync timestamps) */\n accountGroupsMetadata: Record<\n AccountGroupId,\n AccountTreeGroupPersistedMetadata\n >;\n /** Persistent metadata for account wallets (names, sync timestamps) */\n accountWalletsMetadata: Record<\n AccountWalletId,\n AccountTreeWalletPersistedMetadata\n >;\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedMultichainAccountAction\n | AccountsControllerListMultichainAccountsAction\n | AccountsControllerSetSelectedAccountAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap\n | UserStorageController.UserStorageControllerGetStateAction\n | UserStorageController.UserStorageControllerPerformGetStorageAction\n | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction\n | UserStorageController.UserStorageControllerPerformSetStorageAction\n | UserStorageController.UserStorageControllerPerformBatchSetStorageAction\n | AuthenticationController.AuthenticationControllerGetSessionProfileAction\n | MultichainAccountServiceCreateMultichainAccountGroupAction\n | MultichainAccountServiceCreateMultichainAccountGroupsAction;\n\nexport type AccountTreeControllerActions =\n | AccountTreeControllerGetStateAction\n | AccountTreeControllerMethodActions;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\n/**\n * Represents the `AccountTreeController:accountTreeChange` event.\n * This event is emitted when nodes (wallets, groups, or accounts) are added or removed.\n */\nexport type AccountTreeControllerAccountTreeChangeEvent = {\n type: `${typeof controllerName}:accountTreeChange`;\n payload: [AccountTreeControllerState['accountTree']];\n};\n\n/**\n * Represents the `AccountTreeController:selectedAccountGroupChange` event.\n * This event is emitted when the selected account group changes.\n */\nexport type AccountTreeControllerSelectedAccountGroupChangeEvent = {\n type: `${typeof controllerName}:selectedAccountGroupChange`;\n payload: [AccountGroupId | '', AccountGroupId | ''];\n};\n\nexport type AllowedEvents =\n | AccountsControllerAccountsAddedEvent\n | AccountsControllerAccountsRemovedEvent\n | AccountsControllerSelectedAccountChangeEvent\n | UserStorageController.UserStorageControllerStateChangeEvent\n | MultichainAccountServiceWalletStatusChangeEvent;\n\nexport type AccountTreeControllerEvents =\n | AccountTreeControllerStateChangeEvent\n | AccountTreeControllerAccountTreeChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent;\n\nexport type AccountTreeControllerMessenger = Messenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents\n>;\n\nexport type AccountTreeControllerConfig = {\n trace?: TraceCallback;\n backupAndSync?: {\n onBackupAndSyncEvent?: (event: BackupAndSyncAnalyticsEventPayload) => void;\n };\n accountOrderCallbacks?: {\n isHiddenAccount?: (accountId: AccountId) => boolean;\n isPinnedAccount?: (accountId: AccountId) => boolean;\n };\n};\n\nexport type AccountTreeControllerInternalBackupAndSyncConfig = {\n emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => void;\n};\n"]}
package/dist/types.d.cts CHANGED
@@ -4,7 +4,7 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@meta
4
4
  import type { TraceCallback } from "@metamask/controller-utils";
5
5
  import type { KeyringControllerGetStateAction } from "@metamask/keyring-controller";
6
6
  import type { Messenger } from "@metamask/messenger";
7
- import type { MultichainAccountServiceCreateMultichainAccountGroupAction } from "@metamask/multichain-account-service";
7
+ import type { MultichainAccountServiceCreateMultichainAccountGroupAction, MultichainAccountServiceCreateMultichainAccountGroupsAction } from "@metamask/multichain-account-service";
8
8
  import type { AuthenticationController, UserStorageController } from "@metamask/profile-sync-controller";
9
9
  import type { GetSnap as SnapControllerGetSnap } from "@metamask/snaps-controllers";
10
10
  import type { controllerName } from "./AccountTreeController.cjs";
@@ -36,7 +36,7 @@ export type AccountTreeControllerState = {
36
36
  accountWalletsMetadata: Record<AccountWalletId, AccountTreeWalletPersistedMetadata>;
37
37
  };
38
38
  export type AccountTreeControllerGetStateAction = ControllerGetStateAction<typeof controllerName, AccountTreeControllerState>;
39
- export type AllowedActions = AccountsControllerGetAccountAction | AccountsControllerGetSelectedMultichainAccountAction | AccountsControllerListMultichainAccountsAction | AccountsControllerSetSelectedAccountAction | KeyringControllerGetStateAction | SnapControllerGetSnap | UserStorageController.UserStorageControllerGetStateAction | UserStorageController.UserStorageControllerPerformGetStorageAction | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction | UserStorageController.UserStorageControllerPerformSetStorageAction | UserStorageController.UserStorageControllerPerformBatchSetStorageAction | AuthenticationController.AuthenticationControllerGetSessionProfileAction | MultichainAccountServiceCreateMultichainAccountGroupAction;
39
+ export type AllowedActions = AccountsControllerGetAccountAction | AccountsControllerGetSelectedMultichainAccountAction | AccountsControllerListMultichainAccountsAction | AccountsControllerSetSelectedAccountAction | KeyringControllerGetStateAction | SnapControllerGetSnap | UserStorageController.UserStorageControllerGetStateAction | UserStorageController.UserStorageControllerPerformGetStorageAction | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction | UserStorageController.UserStorageControllerPerformSetStorageAction | UserStorageController.UserStorageControllerPerformBatchSetStorageAction | AuthenticationController.AuthenticationControllerGetSessionProfileAction | MultichainAccountServiceCreateMultichainAccountGroupAction | MultichainAccountServiceCreateMultichainAccountGroupsAction;
40
40
  export type AccountTreeControllerActions = AccountTreeControllerGetStateAction | AccountTreeControllerMethodActions;
41
41
  export type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, AccountTreeControllerState>;
42
42
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.d.mts CHANGED
@@ -4,7 +4,7 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@meta
4
4
  import type { TraceCallback } from "@metamask/controller-utils";
5
5
  import type { KeyringControllerGetStateAction } from "@metamask/keyring-controller";
6
6
  import type { Messenger } from "@metamask/messenger";
7
- import type { MultichainAccountServiceCreateMultichainAccountGroupAction } from "@metamask/multichain-account-service";
7
+ import type { MultichainAccountServiceCreateMultichainAccountGroupAction, MultichainAccountServiceCreateMultichainAccountGroupsAction } from "@metamask/multichain-account-service";
8
8
  import type { AuthenticationController, UserStorageController } from "@metamask/profile-sync-controller";
9
9
  import type { GetSnap as SnapControllerGetSnap } from "@metamask/snaps-controllers";
10
10
  import type { controllerName } from "./AccountTreeController.mjs";
@@ -36,7 +36,7 @@ export type AccountTreeControllerState = {
36
36
  accountWalletsMetadata: Record<AccountWalletId, AccountTreeWalletPersistedMetadata>;
37
37
  };
38
38
  export type AccountTreeControllerGetStateAction = ControllerGetStateAction<typeof controllerName, AccountTreeControllerState>;
39
- export type AllowedActions = AccountsControllerGetAccountAction | AccountsControllerGetSelectedMultichainAccountAction | AccountsControllerListMultichainAccountsAction | AccountsControllerSetSelectedAccountAction | KeyringControllerGetStateAction | SnapControllerGetSnap | UserStorageController.UserStorageControllerGetStateAction | UserStorageController.UserStorageControllerPerformGetStorageAction | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction | UserStorageController.UserStorageControllerPerformSetStorageAction | UserStorageController.UserStorageControllerPerformBatchSetStorageAction | AuthenticationController.AuthenticationControllerGetSessionProfileAction | MultichainAccountServiceCreateMultichainAccountGroupAction;
39
+ export type AllowedActions = AccountsControllerGetAccountAction | AccountsControllerGetSelectedMultichainAccountAction | AccountsControllerListMultichainAccountsAction | AccountsControllerSetSelectedAccountAction | KeyringControllerGetStateAction | SnapControllerGetSnap | UserStorageController.UserStorageControllerGetStateAction | UserStorageController.UserStorageControllerPerformGetStorageAction | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction | UserStorageController.UserStorageControllerPerformSetStorageAction | UserStorageController.UserStorageControllerPerformBatchSetStorageAction | AuthenticationController.AuthenticationControllerGetSessionProfileAction | MultichainAccountServiceCreateMultichainAccountGroupAction | MultichainAccountServiceCreateMultichainAccountGroupsAction;
40
40
  export type AccountTreeControllerActions = AccountTreeControllerGetStateAction | AccountTreeControllerMethodActions;
41
41
  export type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, AccountTreeControllerState>;
42
42
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountsAddedEvent,\n AccountsControllerAccountsRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedMultichainAccountAction,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n AccountsControllerSetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { MultichainAccountServiceCreateMultichainAccountGroupAction } from '@metamask/multichain-account-service';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\n\nimport type { controllerName } from './AccountTreeController';\nimport type { AccountTreeControllerMethodActions } from './AccountTreeController-method-action-types';\nimport type {\n BackupAndSyncAnalyticsEventPayload,\n BackupAndSyncEmitAnalyticsEventParams,\n} from './backup-and-sync/analytics';\nimport type {\n AccountGroupObject,\n AccountTreeGroupPersistedMetadata,\n} from './group';\nimport type {\n AccountWalletObject,\n AccountTreeWalletPersistedMetadata,\n} from './wallet';\nimport type { MultichainAccountServiceWalletStatusChangeEvent } from '../../multichain-account-service/src/types';\n\n// Backward compatibility aliases using indexed access types\n/**\n * @deprecated Use AccountTreeGroupMetadata for tree objects or AccountTreeGroupPersistedMetadata for controller state\n */\nexport type AccountGroupMetadata = AccountGroupObject['metadata'];\n\n/**\n * @deprecated Use AccountTreeWalletMetadata for tree objects or AccountTreeWalletPersistedMetadata for controller state\n */\nexport type AccountWalletMetadata = AccountWalletObject['metadata'];\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n selectedAccountGroup: AccountGroupId | '';\n };\n isAccountTreeSyncingInProgress: boolean;\n hasAccountTreeSyncingSyncedAtLeastOnce: boolean;\n /** Persistent metadata for account groups (names, pinning, hiding, sync timestamps) */\n accountGroupsMetadata: Record<\n AccountGroupId,\n AccountTreeGroupPersistedMetadata\n >;\n /** Persistent metadata for account wallets (names, sync timestamps) */\n accountWalletsMetadata: Record<\n AccountWalletId,\n AccountTreeWalletPersistedMetadata\n >;\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedMultichainAccountAction\n | AccountsControllerListMultichainAccountsAction\n | AccountsControllerSetSelectedAccountAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap\n | UserStorageController.UserStorageControllerGetStateAction\n | UserStorageController.UserStorageControllerPerformGetStorageAction\n | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction\n | UserStorageController.UserStorageControllerPerformSetStorageAction\n | UserStorageController.UserStorageControllerPerformBatchSetStorageAction\n | AuthenticationController.AuthenticationControllerGetSessionProfileAction\n | MultichainAccountServiceCreateMultichainAccountGroupAction;\n\nexport type AccountTreeControllerActions =\n | AccountTreeControllerGetStateAction\n | AccountTreeControllerMethodActions;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\n/**\n * Represents the `AccountTreeController:accountTreeChange` event.\n * This event is emitted when nodes (wallets, groups, or accounts) are added or removed.\n */\nexport type AccountTreeControllerAccountTreeChangeEvent = {\n type: `${typeof controllerName}:accountTreeChange`;\n payload: [AccountTreeControllerState['accountTree']];\n};\n\n/**\n * Represents the `AccountTreeController:selectedAccountGroupChange` event.\n * This event is emitted when the selected account group changes.\n */\nexport type AccountTreeControllerSelectedAccountGroupChangeEvent = {\n type: `${typeof controllerName}:selectedAccountGroupChange`;\n payload: [AccountGroupId | '', AccountGroupId | ''];\n};\n\nexport type AllowedEvents =\n | AccountsControllerAccountsAddedEvent\n | AccountsControllerAccountsRemovedEvent\n | AccountsControllerSelectedAccountChangeEvent\n | UserStorageController.UserStorageControllerStateChangeEvent\n | MultichainAccountServiceWalletStatusChangeEvent;\n\nexport type AccountTreeControllerEvents =\n | AccountTreeControllerStateChangeEvent\n | AccountTreeControllerAccountTreeChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent;\n\nexport type AccountTreeControllerMessenger = Messenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents\n>;\n\nexport type AccountTreeControllerConfig = {\n trace?: TraceCallback;\n backupAndSync?: {\n onBackupAndSyncEvent?: (event: BackupAndSyncAnalyticsEventPayload) => void;\n };\n accountOrderCallbacks?: {\n isHiddenAccount?: (accountId: AccountId) => boolean;\n isPinnedAccount?: (accountId: AccountId) => boolean;\n };\n};\n\nexport type AccountTreeControllerInternalBackupAndSyncConfig = {\n emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => void;\n};\n"]}
1
+ {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountsAddedEvent,\n AccountsControllerAccountsRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedMultichainAccountAction,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n AccountsControllerSetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n MultichainAccountServiceCreateMultichainAccountGroupAction,\n MultichainAccountServiceCreateMultichainAccountGroupsAction,\n} from '@metamask/multichain-account-service';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\n\nimport type { controllerName } from './AccountTreeController';\nimport type { AccountTreeControllerMethodActions } from './AccountTreeController-method-action-types';\nimport type {\n BackupAndSyncAnalyticsEventPayload,\n BackupAndSyncEmitAnalyticsEventParams,\n} from './backup-and-sync/analytics';\nimport type {\n AccountGroupObject,\n AccountTreeGroupPersistedMetadata,\n} from './group';\nimport type {\n AccountWalletObject,\n AccountTreeWalletPersistedMetadata,\n} from './wallet';\nimport type { MultichainAccountServiceWalletStatusChangeEvent } from '../../multichain-account-service/src/types';\n\n// Backward compatibility aliases using indexed access types\n/**\n * @deprecated Use AccountTreeGroupMetadata for tree objects or AccountTreeGroupPersistedMetadata for controller state\n */\nexport type AccountGroupMetadata = AccountGroupObject['metadata'];\n\n/**\n * @deprecated Use AccountTreeWalletMetadata for tree objects or AccountTreeWalletPersistedMetadata for controller state\n */\nexport type AccountWalletMetadata = AccountWalletObject['metadata'];\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n selectedAccountGroup: AccountGroupId | '';\n };\n isAccountTreeSyncingInProgress: boolean;\n hasAccountTreeSyncingSyncedAtLeastOnce: boolean;\n /** Persistent metadata for account groups (names, pinning, hiding, sync timestamps) */\n accountGroupsMetadata: Record<\n AccountGroupId,\n AccountTreeGroupPersistedMetadata\n >;\n /** Persistent metadata for account wallets (names, sync timestamps) */\n accountWalletsMetadata: Record<\n AccountWalletId,\n AccountTreeWalletPersistedMetadata\n >;\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedMultichainAccountAction\n | AccountsControllerListMultichainAccountsAction\n | AccountsControllerSetSelectedAccountAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap\n | UserStorageController.UserStorageControllerGetStateAction\n | UserStorageController.UserStorageControllerPerformGetStorageAction\n | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction\n | UserStorageController.UserStorageControllerPerformSetStorageAction\n | UserStorageController.UserStorageControllerPerformBatchSetStorageAction\n | AuthenticationController.AuthenticationControllerGetSessionProfileAction\n | MultichainAccountServiceCreateMultichainAccountGroupAction\n | MultichainAccountServiceCreateMultichainAccountGroupsAction;\n\nexport type AccountTreeControllerActions =\n | AccountTreeControllerGetStateAction\n | AccountTreeControllerMethodActions;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\n/**\n * Represents the `AccountTreeController:accountTreeChange` event.\n * This event is emitted when nodes (wallets, groups, or accounts) are added or removed.\n */\nexport type AccountTreeControllerAccountTreeChangeEvent = {\n type: `${typeof controllerName}:accountTreeChange`;\n payload: [AccountTreeControllerState['accountTree']];\n};\n\n/**\n * Represents the `AccountTreeController:selectedAccountGroupChange` event.\n * This event is emitted when the selected account group changes.\n */\nexport type AccountTreeControllerSelectedAccountGroupChangeEvent = {\n type: `${typeof controllerName}:selectedAccountGroupChange`;\n payload: [AccountGroupId | '', AccountGroupId | ''];\n};\n\nexport type AllowedEvents =\n | AccountsControllerAccountsAddedEvent\n | AccountsControllerAccountsRemovedEvent\n | AccountsControllerSelectedAccountChangeEvent\n | UserStorageController.UserStorageControllerStateChangeEvent\n | MultichainAccountServiceWalletStatusChangeEvent;\n\nexport type AccountTreeControllerEvents =\n | AccountTreeControllerStateChangeEvent\n | AccountTreeControllerAccountTreeChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent;\n\nexport type AccountTreeControllerMessenger = Messenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents\n>;\n\nexport type AccountTreeControllerConfig = {\n trace?: TraceCallback;\n backupAndSync?: {\n onBackupAndSyncEvent?: (event: BackupAndSyncAnalyticsEventPayload) => void;\n };\n accountOrderCallbacks?: {\n isHiddenAccount?: (accountId: AccountId) => boolean;\n isPinnedAccount?: (accountId: AccountId) => boolean;\n };\n};\n\nexport type AccountTreeControllerInternalBackupAndSyncConfig = {\n emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => void;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/account-tree-controller",
3
- "version": "5.0.1-preview-e0ce55a8c",
3
+ "version": "5.0.1-preview-1f5463f7b",
4
4
  "description": "Controller to group account together based on some pre-defined rules",
5
5
  "keywords": [
6
6
  "MetaMask",