@metamask-previews/account-tree-controller 1.0.0-preview-5a701133 → 1.2.0-preview-c20b7569
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 +40 -3
- package/dist/AccountTreeController.cjs +131 -60
- package/dist/AccountTreeController.cjs.map +1 -1
- package/dist/AccountTreeController.d.cts +13 -1
- package/dist/AccountTreeController.d.cts.map +1 -1
- package/dist/AccountTreeController.d.mts +13 -1
- package/dist/AccountTreeController.d.mts.map +1 -1
- package/dist/AccountTreeController.mjs +133 -62
- package/dist/AccountTreeController.mjs.map +1 -1
- package/dist/backup-and-sync/syncing/group.cjs +1 -1
- package/dist/backup-and-sync/syncing/group.cjs.map +1 -1
- package/dist/backup-and-sync/syncing/group.mjs +1 -1
- package/dist/backup-and-sync/syncing/group.mjs.map +1 -1
- package/dist/backup-and-sync/syncing/legacy.cjs +1 -1
- package/dist/backup-and-sync/syncing/legacy.cjs.map +1 -1
- package/dist/backup-and-sync/syncing/legacy.mjs +1 -1
- package/dist/backup-and-sync/syncing/legacy.mjs.map +1 -1
- package/dist/group.cjs +17 -1
- package/dist/group.cjs.map +1 -1
- package/dist/group.d.cts +7 -0
- package/dist/group.d.cts.map +1 -1
- package/dist/group.d.mts +7 -0
- package/dist/group.d.mts.map +1 -1
- package/dist/group.mjs +16 -0
- package/dist/group.mjs.map +1 -1
- package/dist/rule.cjs +6 -5
- package/dist/rule.cjs.map +1 -1
- package/dist/rule.d.cts +8 -8
- package/dist/rule.d.cts.map +1 -1
- package/dist/rule.d.mts +8 -8
- package/dist/rule.d.mts.map +1 -1
- package/dist/rule.mjs +6 -5
- package/dist/rule.mjs.map +1 -1
- package/dist/rules/entropy.cjs +2 -2
- package/dist/rules/entropy.cjs.map +1 -1
- package/dist/rules/entropy.d.cts +1 -1
- package/dist/rules/entropy.d.cts.map +1 -1
- package/dist/rules/entropy.d.mts +1 -1
- package/dist/rules/entropy.d.mts.map +1 -1
- package/dist/rules/entropy.mjs +2 -2
- package/dist/rules/entropy.mjs.map +1 -1
- package/dist/rules/keyring.cjs +44 -3
- package/dist/rules/keyring.cjs.map +1 -1
- package/dist/rules/keyring.d.cts +8 -1
- package/dist/rules/keyring.d.cts.map +1 -1
- package/dist/rules/keyring.d.mts +8 -1
- package/dist/rules/keyring.d.mts.map +1 -1
- package/dist/rules/keyring.mjs +42 -2
- package/dist/rules/keyring.mjs.map +1 -1
- package/dist/rules/snap.cjs +3 -5
- package/dist/rules/snap.cjs.map +1 -1
- package/dist/rules/snap.d.cts +1 -3
- package/dist/rules/snap.d.cts.map +1 -1
- package/dist/rules/snap.d.mts +1 -3
- package/dist/rules/snap.d.mts.map +1 -1
- package/dist/rules/snap.mjs +3 -5
- package/dist/rules/snap.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -9,8 +9,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Fixed
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
12
|
+
- Prevent `:account{Added,Removed}` to used if `init` has not been called yet ([#6717](https://github.com/MetaMask/core/pull/6717))
|
|
13
|
+
- We now wait for internal accounts to be fully ready (before `init` gets called).
|
|
14
|
+
- This should also enforce account group ordering, since all accounts will be ready to consume right away.
|
|
15
|
+
|
|
16
|
+
## [1.2.0]
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Add `reinit` method ([#6709](https://github.com/MetaMask/core/pull/6709))
|
|
21
|
+
- This method can be used if we change the entire list of accounts of the `AccountsController` and want to re-initilize the tree with it.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Implicitly call `init` before mutating the tree ([#6709](https://github.com/MetaMask/core/pull/6709))
|
|
26
|
+
- This ensure the tree is always using existing accounts before inserting/removing any new accounts if `init` has not been called yet.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Fix use of unknown `group.metadata.name` when checking for group name uniqueness ([#6706](https://github.com/MetaMask/core/pull/6706))
|
|
31
|
+
- Added logic that prevents an account within a group from being out of order ([#6683](https://github.com/MetaMask/core/pull/6683))
|
|
32
|
+
|
|
33
|
+
## [1.1.0]
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Set the `setAccountGroupName`'s option `autoHandleConflict` to `true` for all backup & sync operations ([#6697](https://github.com/MetaMask/core/pull/6697))
|
|
38
|
+
- Add new group naming for non-HD keyring accounts ([#6679](https://github.com/MetaMask/core/pull/6679)), ([#6696](https://github.com/MetaMask/core/pull/6696))
|
|
39
|
+
- Hardware-wallet account groups are now named: "Ledger|Trezor|QR|Lattice|OneKey Account N".
|
|
40
|
+
- Private key account groups are now named: "Imported Account N".
|
|
41
|
+
- Snap account groups are now named: "Snap Account N".
|
|
42
|
+
- Account group names now use natural indexing as a fallback ([#6677](https://github.com/MetaMask/core/pull/6677)), ([#6679](https://github.com/MetaMask/core/pull/6679)), ([#6696](https://github.com/MetaMask/core/pull/6696))
|
|
43
|
+
- If a user names his accounts without any indexes, we would just use the number of accounts to compute the next available index.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Fix group naming for non-HD keyring accounts ([#6677](https://github.com/MetaMask/core/pull/6677)), ([#6679](https://github.com/MetaMask/core/pull/6679))
|
|
48
|
+
- Previously, the first non-HD keyring account would start as `Account 2` as opposed to `Account 1` and thus subsequent group names were off as well.
|
|
14
49
|
|
|
15
50
|
## [1.0.0]
|
|
16
51
|
|
|
@@ -294,7 +329,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
294
329
|
- Initial release ([#5847](https://github.com/MetaMask/core/pull/5847))
|
|
295
330
|
- Grouping accounts into 3 main categories: Entropy source, Snap ID, keyring types.
|
|
296
331
|
|
|
297
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@1.
|
|
332
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@1.2.0...HEAD
|
|
333
|
+
[1.2.0]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@1.1.0...@metamask/account-tree-controller@1.2.0
|
|
334
|
+
[1.1.0]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@1.0.0...@metamask/account-tree-controller@1.1.0
|
|
298
335
|
[1.0.0]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@0.18.1...@metamask/account-tree-controller@1.0.0
|
|
299
336
|
[0.18.1]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@0.18.0...@metamask/account-tree-controller@0.18.1
|
|
300
337
|
[0.18.0]: https://github.com/MetaMask/core/compare/@metamask/account-tree-controller@0.17.0...@metamask/account-tree-controller@0.18.0
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _AccountTreeController_instances, _AccountTreeController_accountIdToContext, _AccountTreeController_groupIdToWalletId, _AccountTreeController_backupAndSyncService, _AccountTreeController_rules, _AccountTreeController_trace, _AccountTreeController_backupAndSyncConfig, _AccountTreeController_getEntropyRule, _AccountTreeController_getSnapRule, _AccountTreeController_getKeyringRule, _AccountTreeController_applyAccountWalletMetadata, _AccountTreeController_getRuleForWallet, _AccountTreeController_applyAccountGroupMetadata, _AccountTreeController_handleAccountAdded, _AccountTreeController_handleAccountRemoved, _AccountTreeController_pruneEmptyGroupAndWallet, _AccountTreeController_insert, _AccountTreeController_listAccounts, _AccountTreeController_assertAccountGroupExists, _AccountTreeController_assertAccountWalletExists, _AccountTreeController_assertAccountGroupNameIsUnique, _AccountTreeController_getDefaultSelectedAccountGroup, _AccountTreeController_handleSelectedAccountChange, _AccountTreeController_handleMultichainAccountWalletStatusChange, _AccountTreeController_getAccountGroup, _AccountTreeController_getDefaultAccountFromAccountGroupId, _AccountTreeController_getDefaultAccountGroupId, _AccountTreeController_registerMessageHandlers, _AccountTreeController_createBackupAndSyncContext;
|
|
13
|
+
var _AccountTreeController_instances, _AccountTreeController_accountIdToContext, _AccountTreeController_groupIdToWalletId, _AccountTreeController_backupAndSyncService, _AccountTreeController_rules, _AccountTreeController_trace, _AccountTreeController_backupAndSyncConfig, _AccountTreeController_initialized, _AccountTreeController_getEntropyRule, _AccountTreeController_getSnapRule, _AccountTreeController_getKeyringRule, _AccountTreeController_applyAccountWalletMetadata, _AccountTreeController_getRuleForWallet, _AccountTreeController_applyAccountGroupMetadata, _AccountTreeController_handleAccountAdded, _AccountTreeController_handleAccountRemoved, _AccountTreeController_pruneEmptyGroupAndWallet, _AccountTreeController_insert, _AccountTreeController_listAccounts, _AccountTreeController_assertAccountGroupExists, _AccountTreeController_assertAccountWalletExists, _AccountTreeController_assertAccountGroupNameIsUnique, _AccountTreeController_getDefaultSelectedAccountGroup, _AccountTreeController_handleSelectedAccountChange, _AccountTreeController_handleMultichainAccountWalletStatusChange, _AccountTreeController_getAccountGroup, _AccountTreeController_getDefaultAccountFromAccountGroupId, _AccountTreeController_getDefaultAccountGroupId, _AccountTreeController_registerMessageHandlers, _AccountTreeController_createBackupAndSyncContext;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.AccountTreeController = exports.getDefaultAccountTreeControllerState = exports.controllerName = void 0;
|
|
16
16
|
const account_api_1 = require("@metamask/account-api");
|
|
@@ -103,6 +103,9 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
103
103
|
_AccountTreeController_rules.set(this, void 0);
|
|
104
104
|
_AccountTreeController_trace.set(this, void 0);
|
|
105
105
|
_AccountTreeController_backupAndSyncConfig.set(this, void 0);
|
|
106
|
+
_AccountTreeController_initialized.set(this, void 0);
|
|
107
|
+
// This will be set to true upon the first `init` call.
|
|
108
|
+
__classPrivateFieldSet(this, _AccountTreeController_initialized, false, "f");
|
|
106
109
|
// Reverse map to allow fast node access from an account ID.
|
|
107
110
|
__classPrivateFieldSet(this, _AccountTreeController_accountIdToContext, new Map(), "f");
|
|
108
111
|
// Reverse map to allow fast wallet node access from a group ID.
|
|
@@ -152,6 +155,11 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
152
155
|
* state with it.
|
|
153
156
|
*/
|
|
154
157
|
init() {
|
|
158
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_initialized, "f")) {
|
|
159
|
+
// We prevent re-initilializing the state multiple times. Though, we can use
|
|
160
|
+
// `reinit` to re-init everything from scratch.
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
155
163
|
const wallets = {};
|
|
156
164
|
// Clear mappings for fresh rebuild.
|
|
157
165
|
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").clear();
|
|
@@ -165,20 +173,28 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
165
173
|
}
|
|
166
174
|
// Once we have the account tree, we can apply persisted metadata (names + UI states).
|
|
167
175
|
let previousSelectedAccountGroupStillExists = false;
|
|
168
|
-
for (const wallet of Object.values(wallets)) {
|
|
169
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountWalletMetadata).call(this, wallet);
|
|
170
|
-
for (const group of Object.values(wallet.groups)) {
|
|
171
|
-
if (group.id === previousSelectedAccountGroup) {
|
|
172
|
-
previousSelectedAccountGroupStillExists = true;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
176
|
this.update((state) => {
|
|
177
177
|
state.accountTree.wallets = wallets;
|
|
178
178
|
// Apply group metadata within the state update
|
|
179
179
|
for (const wallet of Object.values(state.accountTree.wallets)) {
|
|
180
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountWalletMetadata).call(this, state, wallet.id);
|
|
181
|
+
// Used for default group default names (so we use human-indexing here).
|
|
182
|
+
let nextNaturalNameIndex = 1;
|
|
180
183
|
for (const group of Object.values(wallet.groups)) {
|
|
181
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountGroupMetadata).call(this, state, wallet.id, group.id
|
|
184
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountGroupMetadata).call(this, state, wallet.id, group.id,
|
|
185
|
+
// FIXME: We should not need this kind of logic if we were not inserting accounts
|
|
186
|
+
// 1 by 1. Instead, we should be inserting wallets and groups directly. This would
|
|
187
|
+
// allow us to naturally insert a group in the tree AND update its metadata right
|
|
188
|
+
// away...
|
|
189
|
+
// But here, we have to wait for the entire group to be ready before updating
|
|
190
|
+
// its metadata (mainly because we're dealing with single accounts rather than entire
|
|
191
|
+
// groups).
|
|
192
|
+
// That is why we need this kind of extra parameter.
|
|
193
|
+
nextNaturalNameIndex);
|
|
194
|
+
if (group.id === previousSelectedAccountGroup) {
|
|
195
|
+
previousSelectedAccountGroupStillExists = true;
|
|
196
|
+
}
|
|
197
|
+
nextNaturalNameIndex += 1;
|
|
182
198
|
}
|
|
183
199
|
}
|
|
184
200
|
if (!previousSelectedAccountGroupStillExists ||
|
|
@@ -197,6 +213,17 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
197
213
|
this.state.accountTree.selectedAccountGroup) {
|
|
198
214
|
this.messagingSystem.publish(`${exports.controllerName}:selectedAccountGroupChange`, this.state.accountTree.selectedAccountGroup, previousSelectedAccountGroup);
|
|
199
215
|
}
|
|
216
|
+
__classPrivateFieldSet(this, _AccountTreeController_initialized, true, "f");
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Re-initialize the controller's state.
|
|
220
|
+
*
|
|
221
|
+
* This is done in one single (atomic) `update` block to avoid having a temporary
|
|
222
|
+
* cleared state. Use this when you need to force a full re-init even if already initialized.
|
|
223
|
+
*/
|
|
224
|
+
reinit() {
|
|
225
|
+
__classPrivateFieldSet(this, _AccountTreeController_initialized, false, "f");
|
|
226
|
+
this.init();
|
|
200
227
|
}
|
|
201
228
|
/**
|
|
202
229
|
* Gets the account wallet object from its ID.
|
|
@@ -468,6 +495,8 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
468
495
|
};
|
|
469
496
|
});
|
|
470
497
|
__classPrivateFieldGet(this, _AccountTreeController_backupAndSyncService, "f").clearState();
|
|
498
|
+
// So we know we have to call `init` again.
|
|
499
|
+
__classPrivateFieldSet(this, _AccountTreeController_initialized, false, "f");
|
|
471
500
|
}
|
|
472
501
|
/**
|
|
473
502
|
* Bi-directionally syncs the account tree with user storage.
|
|
@@ -500,14 +529,15 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
500
529
|
}
|
|
501
530
|
}
|
|
502
531
|
exports.AccountTreeController = AccountTreeController;
|
|
503
|
-
_AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeController_groupIdToWalletId = new WeakMap(), _AccountTreeController_backupAndSyncService = new WeakMap(), _AccountTreeController_rules = new WeakMap(), _AccountTreeController_trace = new WeakMap(), _AccountTreeController_backupAndSyncConfig = new WeakMap(), _AccountTreeController_instances = new WeakSet(), _AccountTreeController_getEntropyRule = function _AccountTreeController_getEntropyRule() {
|
|
532
|
+
_AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeController_groupIdToWalletId = new WeakMap(), _AccountTreeController_backupAndSyncService = new WeakMap(), _AccountTreeController_rules = new WeakMap(), _AccountTreeController_trace = new WeakMap(), _AccountTreeController_backupAndSyncConfig = new WeakMap(), _AccountTreeController_initialized = new WeakMap(), _AccountTreeController_instances = new WeakSet(), _AccountTreeController_getEntropyRule = function _AccountTreeController_getEntropyRule() {
|
|
504
533
|
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[0];
|
|
505
534
|
}, _AccountTreeController_getSnapRule = function _AccountTreeController_getSnapRule() {
|
|
506
535
|
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[1];
|
|
507
536
|
}, _AccountTreeController_getKeyringRule = function _AccountTreeController_getKeyringRule() {
|
|
508
537
|
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[2];
|
|
509
|
-
}, _AccountTreeController_applyAccountWalletMetadata = function _AccountTreeController_applyAccountWalletMetadata(
|
|
510
|
-
const
|
|
538
|
+
}, _AccountTreeController_applyAccountWalletMetadata = function _AccountTreeController_applyAccountWalletMetadata(state, walletId) {
|
|
539
|
+
const wallet = state.accountTree.wallets[walletId];
|
|
540
|
+
const persistedMetadata = state.accountWalletsMetadata[walletId];
|
|
511
541
|
// Apply persisted name if available (including empty strings)
|
|
512
542
|
if (persistedMetadata?.name !== undefined) {
|
|
513
543
|
wallet.metadata.name = persistedMetadata.name.value;
|
|
@@ -536,8 +566,8 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
536
566
|
default:
|
|
537
567
|
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getKeyringRule).call(this);
|
|
538
568
|
}
|
|
539
|
-
}, _AccountTreeController_applyAccountGroupMetadata = function _AccountTreeController_applyAccountGroupMetadata(state, walletId, groupId) {
|
|
540
|
-
var _a
|
|
569
|
+
}, _AccountTreeController_applyAccountGroupMetadata = function _AccountTreeController_applyAccountGroupMetadata(state, walletId, groupId, nextNaturalNameIndex) {
|
|
570
|
+
var _a;
|
|
541
571
|
const wallet = state.accountTree.wallets[walletId];
|
|
542
572
|
const group = wallet.groups[groupId];
|
|
543
573
|
const persistedGroupMetadata = state.accountGroupsMetadata[group.id];
|
|
@@ -549,58 +579,65 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
549
579
|
else if (!group.metadata.name) {
|
|
550
580
|
// Get the appropriate rule for this wallet type
|
|
551
581
|
const rule = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getRuleForWallet).call(this, wallet);
|
|
582
|
+
// Get the prefix for groups of this wallet
|
|
583
|
+
const namePrefix = rule.getDefaultAccountGroupPrefix(wallet);
|
|
552
584
|
// Skip computed names for now - use default naming with per-wallet logic
|
|
553
585
|
// TODO: Implement computed names in a future iteration
|
|
554
|
-
// Generate default name and ensure it's unique within the wallet
|
|
555
|
-
let proposedName = '';
|
|
556
|
-
let proposedNameIndex;
|
|
557
586
|
// Parse the highest account index being used (similar to accounts-controller)
|
|
558
|
-
let
|
|
559
|
-
for (const
|
|
587
|
+
let highestNameIndex = 0;
|
|
588
|
+
for (const { id: otherGroupId } of Object.values(wallet.groups)) {
|
|
560
589
|
// Skip the current group being processed
|
|
561
|
-
if (
|
|
590
|
+
if (otherGroupId === groupId) {
|
|
562
591
|
continue;
|
|
563
592
|
}
|
|
593
|
+
// We always get the name from the persisted map, since `init` will clear the
|
|
594
|
+
// `state.accountTree.wallets`, thus, given empty `group.metadata.name`.
|
|
595
|
+
// NOTE: If the other group has not been named yet, we just use an empty name.
|
|
596
|
+
const otherGroupName = state.accountGroupsMetadata[otherGroupId]?.name?.value ?? '';
|
|
564
597
|
// Parse the existing group name to extract the numeric index
|
|
565
|
-
|
|
566
|
-
// use different patterns like "Trezor N", "Ledger N" per keyringTypeToName().
|
|
567
|
-
// We'll enhance this to handle all keyring types in a future iteration.
|
|
568
|
-
const nameMatch = existingGroup.metadata.name.match(/Account (\d+)$/u);
|
|
598
|
+
const nameMatch = otherGroupName.match(/account\s+(\d+)$/iu);
|
|
569
599
|
if (nameMatch) {
|
|
570
600
|
const nameIndex = parseInt(nameMatch[1], 10);
|
|
571
|
-
if (nameIndex >
|
|
572
|
-
|
|
601
|
+
if (nameIndex > highestNameIndex) {
|
|
602
|
+
highestNameIndex = nameIndex;
|
|
573
603
|
}
|
|
574
604
|
}
|
|
575
605
|
}
|
|
576
|
-
//
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
606
|
+
// We just use the highest known index no matter the wallet type.
|
|
607
|
+
//
|
|
608
|
+
// For entropy-based wallets (bip44), if a multichain account group with group index 1
|
|
609
|
+
// is inserted before another one with group index 0, then the naming will be:
|
|
610
|
+
// - "Account 1" (group index 1)
|
|
611
|
+
// - "Account 2" (group index 0)
|
|
612
|
+
// This naming makes more sense for the end-user.
|
|
613
|
+
//
|
|
614
|
+
// For other type of wallets, since those wallets can create arbitrary gaps, we still
|
|
615
|
+
// rely on the highest know index to avoid back-filling account with "old names".
|
|
616
|
+
let proposedNameIndex = Math.max(
|
|
617
|
+
// Use + 1 to use the next available index.
|
|
618
|
+
highestNameIndex + 1,
|
|
619
|
+
// In case all accounts have been renamed differently than the usual "Account <index>"
|
|
620
|
+
// pattern, we want to use the next "natural" index, which is just the number of groups
|
|
621
|
+
// in that wallet (e.g. ["Account A", "Another Account"], next natural index would be
|
|
622
|
+
// "Account 3" in this case).
|
|
623
|
+
nextNaturalNameIndex ?? Object.keys(wallet.groups).length);
|
|
588
624
|
// Find a unique name by checking for conflicts and incrementing if needed
|
|
589
|
-
let
|
|
625
|
+
let proposedNameExists;
|
|
626
|
+
let proposedName = '';
|
|
590
627
|
do {
|
|
591
|
-
proposedName =
|
|
628
|
+
proposedName = `${namePrefix} ${proposedNameIndex}`;
|
|
592
629
|
// Check if this name already exists in the wallet (excluding current group)
|
|
593
|
-
|
|
630
|
+
proposedNameExists = !(0, group_1.isAccountGroupNameUniqueFromWallet)(wallet, group.id, proposedName);
|
|
594
631
|
/* istanbul ignore next */
|
|
595
|
-
if (
|
|
632
|
+
if (proposedNameExists) {
|
|
596
633
|
proposedNameIndex += 1; // Try next number
|
|
597
634
|
}
|
|
598
|
-
} while (
|
|
635
|
+
} while (proposedNameExists);
|
|
599
636
|
state.accountTree.wallets[walletId].groups[groupId].metadata.name =
|
|
600
637
|
proposedName;
|
|
601
638
|
// Persist the generated name to ensure consistency
|
|
602
|
-
(_a = state.accountGroupsMetadata)[
|
|
603
|
-
state.accountGroupsMetadata[
|
|
639
|
+
(_a = state.accountGroupsMetadata)[groupId] ?? (_a[groupId] = {});
|
|
640
|
+
state.accountGroupsMetadata[groupId].name = {
|
|
604
641
|
value: proposedName,
|
|
605
642
|
// The `lastUpdatedAt` field is used for backup and sync, when comparing local names
|
|
606
643
|
// with backed up names. In this case, the generated name should never take precedence
|
|
@@ -616,20 +653,36 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
616
653
|
group.metadata.hidden = persistedGroupMetadata.hidden.value;
|
|
617
654
|
}
|
|
618
655
|
}, _AccountTreeController_handleAccountAdded = function _AccountTreeController_handleAccountAdded(account) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
656
|
+
// We wait for the first `init` to be called to actually build up the tree and
|
|
657
|
+
// mutate it. We expect the caller to first update the `AccountsController` state
|
|
658
|
+
// to force the migration of accounts, and then call `init`.
|
|
659
|
+
if (!__classPrivateFieldGet(this, _AccountTreeController_initialized, "f")) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
// Check if this account got already added by `#initAtLeastOnce`, if not, then we
|
|
663
|
+
// can proceed.
|
|
664
|
+
if (!__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").has(account.id)) {
|
|
665
|
+
this.update((state) => {
|
|
666
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, state.accountTree.wallets, account);
|
|
667
|
+
const context = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(account.id);
|
|
668
|
+
if (context) {
|
|
669
|
+
const { walletId, groupId } = context;
|
|
670
|
+
const wallet = state.accountTree.wallets[walletId];
|
|
671
|
+
if (wallet) {
|
|
672
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountWalletMetadata).call(this, state, walletId);
|
|
673
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountGroupMetadata).call(this, state, walletId, groupId);
|
|
674
|
+
}
|
|
628
675
|
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
676
|
+
});
|
|
677
|
+
this.messagingSystem.publish(`${exports.controllerName}:accountTreeChange`, this.state.accountTree);
|
|
678
|
+
}
|
|
632
679
|
}, _AccountTreeController_handleAccountRemoved = function _AccountTreeController_handleAccountRemoved(accountId) {
|
|
680
|
+
// We wait for the first `init` to be called to actually build up the tree and
|
|
681
|
+
// mutate it. We expect the caller to first update the `AccountsController` state
|
|
682
|
+
// to force the migration of accounts, and then call `init`.
|
|
683
|
+
if (!__classPrivateFieldGet(this, _AccountTreeController_initialized, "f")) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
633
686
|
const context = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(accountId);
|
|
634
687
|
if (context) {
|
|
635
688
|
const { walletId, groupId } = context;
|
|
@@ -701,11 +754,13 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
701
754
|
}
|
|
702
755
|
const groupId = result.group.id;
|
|
703
756
|
let group = wallet.groups[groupId];
|
|
757
|
+
const { type, id } = account;
|
|
758
|
+
const sortOrder = group_1.ACCOUNT_TYPE_TO_SORT_ORDER[type];
|
|
704
759
|
if (!group) {
|
|
705
760
|
wallet.groups[groupId] = {
|
|
706
761
|
...result.group,
|
|
707
762
|
// Type-wise, we are guaranteed to always have at least 1 account.
|
|
708
|
-
accounts: [
|
|
763
|
+
accounts: [id],
|
|
709
764
|
metadata: {
|
|
710
765
|
name: '',
|
|
711
766
|
...{ pinned: false, hidden: false },
|
|
@@ -723,12 +778,28 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
723
778
|
}
|
|
724
779
|
}
|
|
725
780
|
else {
|
|
726
|
-
group.accounts.push(
|
|
781
|
+
group.accounts.push(id);
|
|
782
|
+
// We need to do this at every insertion because race conditions can happen
|
|
783
|
+
// during the account creation process where one provider completes before the other.
|
|
784
|
+
// The discovery process in the service can also lead to some accounts being created "out of order".
|
|
785
|
+
const { accounts } = group;
|
|
786
|
+
accounts.sort(
|
|
787
|
+
/* istanbul ignore next: Comparator branch execution (a===id vs b===id)
|
|
788
|
+
* and return attribution vary across engines; final ordering is covered
|
|
789
|
+
* by behavior tests. Ignoring the entire comparator avoids flaky line
|
|
790
|
+
* coverage without reducing scenario coverage.
|
|
791
|
+
*/
|
|
792
|
+
(a, b) => {
|
|
793
|
+
const aSortOrder = a === id ? sortOrder : __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(a)?.sortOrder;
|
|
794
|
+
const bSortOrder = b === id ? sortOrder : __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(b)?.sortOrder;
|
|
795
|
+
return ((aSortOrder ?? group_1.MAX_SORT_ORDER) - (bSortOrder ?? group_1.MAX_SORT_ORDER));
|
|
796
|
+
});
|
|
727
797
|
}
|
|
728
798
|
// Update the reverse mapping for this account.
|
|
729
799
|
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").set(account.id, {
|
|
730
800
|
walletId: wallet.id,
|
|
731
801
|
groupId: group.id,
|
|
802
|
+
sortOrder,
|
|
732
803
|
});
|
|
733
804
|
}, _AccountTreeController_listAccounts = function _AccountTreeController_listAccounts() {
|
|
734
805
|
return this.messagingSystem.call('AccountsController:listMultichainAccounts');
|