@metamask-previews/account-tree-controller 2.0.0-preview-55f130d1 → 2.0.0-preview-3d9bbf60
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 +6 -0
- package/dist/AccountTreeController.cjs +219 -104
- package/dist/AccountTreeController.cjs.map +1 -1
- package/dist/AccountTreeController.d.cts +0 -12
- package/dist/AccountTreeController.d.cts.map +1 -1
- package/dist/AccountTreeController.d.mts +0 -12
- package/dist/AccountTreeController.d.mts.map +1 -1
- package/dist/AccountTreeController.mjs +221 -106
- package/dist/AccountTreeController.mjs.map +1 -1
- package/dist/rules/entropy.cjs +53 -69
- package/dist/rules/entropy.cjs.map +1 -1
- package/dist/rules/entropy.d.cts +24 -12
- package/dist/rules/entropy.d.cts.map +1 -1
- package/dist/rules/entropy.d.mts +24 -12
- package/dist/rules/entropy.d.mts.map +1 -1
- package/dist/rules/entropy.mjs +49 -67
- package/dist/rules/entropy.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +3 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +3 -3
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **BREAKING:** Use `MultichainAccountService` to build multichain account (BIP-44) nodes ([#6646](https://github.com/MetaMask/core/pull/6646))
|
|
13
|
+
- Previously, the controller was using a similar matching logic for BIP-44 accounts, which was redundant with the logic from this service.
|
|
14
|
+
- Wallets and groups are now directly consumed from the service, making the service be the source of truth for accounts related to BIP-44.
|
|
15
|
+
|
|
10
16
|
## [2.0.0]
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -10,10 +10,11 @@ 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_accountOrderCallbacks, _AccountTreeController_initialized,
|
|
13
|
+
var _AccountTreeController_instances, _AccountTreeController_accountIdToContext, _AccountTreeController_groupIdToWalletId, _AccountTreeController_backupAndSyncService, _AccountTreeController_rules, _AccountTreeController_trace, _AccountTreeController_backupAndSyncConfig, _AccountTreeController_accountOrderCallbacks, _AccountTreeController_initialized, _AccountTreeController_getSnapRule, _AccountTreeController_getKeyringRule, _AccountTreeController_getDefaultAccountWalletName, _AccountTreeController_applyAccountWalletMetadata, _AccountTreeController_getComputedAccountGroupName, _AccountTreeController_getDefaultAccountGroupPrefix, _AccountTreeController_getDefaultAccountGroupName, _AccountTreeController_applyAccountGroupMetadata, _AccountTreeController_handleAccountAdded, _AccountTreeController_handleAccountRemoved, _AccountTreeController_pruneEmptyGroupAndWallet, _AccountTreeController_sortAccountsOfGroup, _AccountTreeController_insertAccount, _AccountTreeController_insertOrUpdateMultichainAccountWalletAndGroup, _AccountTreeController_getMultichainAccountWallets, _AccountTreeController_listAccounts, _AccountTreeController_assertAccountGroupExists, _AccountTreeController_assertAccountWalletExists, _AccountTreeController_assertAccountGroupNameIsUnique, _AccountTreeController_getDefaultSelectedAccountGroup, _AccountTreeController_handleSelectedAccountChange, _AccountTreeController_handleMultichainAccountGroupCreatedOrUpdated, _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");
|
|
17
|
+
const account_api_2 = require("@metamask/account-api");
|
|
17
18
|
const base_controller_1 = require("@metamask/base-controller");
|
|
18
19
|
const keyring_api_1 = require("@metamask/keyring-api");
|
|
19
20
|
const utils_1 = require("@metamask/utils");
|
|
@@ -118,7 +119,7 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
118
119
|
// Rules to apply to construct the wallets tree.
|
|
119
120
|
__classPrivateFieldSet(this, _AccountTreeController_rules, [
|
|
120
121
|
// 1. We group by entropy-source
|
|
121
|
-
|
|
122
|
+
// NOTE: This is now done by consuming the `MultichainAccountService` wallets and groups.
|
|
122
123
|
// 2. We group by Snap ID
|
|
123
124
|
new snap_1.SnapRule(this.messenger),
|
|
124
125
|
// 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)
|
|
@@ -149,6 +150,12 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
149
150
|
this.messenger.subscribe('UserStorageController:stateChange', (userStorageControllerState) => {
|
|
150
151
|
__classPrivateFieldGet(this, _AccountTreeController_backupAndSyncService, "f").handleUserStorageStateChange(userStorageControllerState);
|
|
151
152
|
});
|
|
153
|
+
this.messenger.subscribe('MultichainAccountService:multichainAccountGroupCreated', (group) => {
|
|
154
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleMultichainAccountGroupCreatedOrUpdated).call(this, group);
|
|
155
|
+
});
|
|
156
|
+
this.messenger.subscribe('MultichainAccountService:multichainAccountGroupUpdated', (group) => {
|
|
157
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleMultichainAccountGroupCreatedOrUpdated).call(this, group);
|
|
158
|
+
});
|
|
152
159
|
this.messenger.subscribe('MultichainAccountService:walletStatusChange', (walletId, status) => {
|
|
153
160
|
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleMultichainAccountWalletStatusChange).call(this, walletId, status);
|
|
154
161
|
});
|
|
@@ -168,6 +175,7 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
168
175
|
return;
|
|
169
176
|
}
|
|
170
177
|
(0, logger_1.projectLogger)('Initializing...');
|
|
178
|
+
// For now, we always re-compute all wallets, we do not re-use the existing state.
|
|
171
179
|
const wallets = {};
|
|
172
180
|
// Clear mappings for fresh rebuild.
|
|
173
181
|
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").clear();
|
|
@@ -175,6 +183,12 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
175
183
|
// Keep the current selected group to check if it's still part of the tree
|
|
176
184
|
// after rebuilding it.
|
|
177
185
|
const previousSelectedAccountGroup = this.state.accountTree.selectedAccountGroup;
|
|
186
|
+
// Insert all multichain account wallet/groups.
|
|
187
|
+
for (const wallet of __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getMultichainAccountWallets).call(this)) {
|
|
188
|
+
for (const group of wallet.getMultichainAccountGroups()) {
|
|
189
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insertOrUpdateMultichainAccountWalletAndGroup).call(this, wallets, wallet, group);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
178
192
|
// There's no guarantee that accounts would be sorted by their import time
|
|
179
193
|
// with `listMultichainAccounts`. We have to sort them here before constructing
|
|
180
194
|
// the tree.
|
|
@@ -187,9 +201,14 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
187
201
|
// won't be enough and we would have to use group properties instead (like group
|
|
188
202
|
// index or maybe introduce a `importTime` at group level).
|
|
189
203
|
const accounts = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_listAccounts).call(this).sort((a, b) => a.metadata.importTime - b.metadata.importTime);
|
|
190
|
-
//
|
|
204
|
+
// Insert all other kind of accounts (private keys, HW, other Snap accounts, etc.).
|
|
191
205
|
for (const account of accounts) {
|
|
192
|
-
|
|
206
|
+
// BIP-44 accounts are owned byt the `MultichainAccountService`, so we have to skip them
|
|
207
|
+
// here, since we've already added wallets/groups for each of them.
|
|
208
|
+
if ((0, account_api_1.isBip44Account)(account)) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insertAccount).call(this, wallets, account);
|
|
193
212
|
}
|
|
194
213
|
// Once we have the account tree, we can apply persisted metadata (names + UI states).
|
|
195
214
|
let previousSelectedAccountGroupStillExists = false;
|
|
@@ -561,12 +580,19 @@ class AccountTreeController extends base_controller_1.BaseController {
|
|
|
561
580
|
}
|
|
562
581
|
}
|
|
563
582
|
exports.AccountTreeController = AccountTreeController;
|
|
564
|
-
_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_accountOrderCallbacks = new WeakMap(), _AccountTreeController_initialized = new WeakMap(), _AccountTreeController_instances = new WeakSet(),
|
|
583
|
+
_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_accountOrderCallbacks = new WeakMap(), _AccountTreeController_initialized = new WeakMap(), _AccountTreeController_instances = new WeakSet(), _AccountTreeController_getSnapRule = function _AccountTreeController_getSnapRule() {
|
|
565
584
|
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[0];
|
|
566
|
-
}, _AccountTreeController_getSnapRule = function _AccountTreeController_getSnapRule() {
|
|
567
|
-
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[1];
|
|
568
585
|
}, _AccountTreeController_getKeyringRule = function _AccountTreeController_getKeyringRule() {
|
|
569
|
-
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[
|
|
586
|
+
return __classPrivateFieldGet(this, _AccountTreeController_rules, "f")[1];
|
|
587
|
+
}, _AccountTreeController_getDefaultAccountWalletName = function _AccountTreeController_getDefaultAccountWalletName(wallet) {
|
|
588
|
+
switch (wallet.type) {
|
|
589
|
+
case account_api_1.AccountWalletType.Entropy:
|
|
590
|
+
return (0, entropy_1.getEntropyDefaultAccountWalletName)(this.messenger, wallet);
|
|
591
|
+
case account_api_1.AccountWalletType.Snap:
|
|
592
|
+
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapRule).call(this).getDefaultAccountWalletName(wallet);
|
|
593
|
+
default:
|
|
594
|
+
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getKeyringRule).call(this).getDefaultAccountWalletName(wallet);
|
|
595
|
+
}
|
|
570
596
|
}, _AccountTreeController_applyAccountWalletMetadata = function _AccountTreeController_applyAccountWalletMetadata(state, walletId) {
|
|
571
597
|
const wallet = state.accountTree.wallets[walletId];
|
|
572
598
|
const persistedMetadata = state.accountWalletsMetadata[walletId];
|
|
@@ -576,29 +602,9 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
576
602
|
}
|
|
577
603
|
else if (!wallet.metadata.name) {
|
|
578
604
|
// Generate default name if none exists
|
|
579
|
-
|
|
580
|
-
wallet.metadata.name =
|
|
581
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getEntropyRule).call(this).getDefaultAccountWalletName(wallet);
|
|
582
|
-
}
|
|
583
|
-
else if (wallet.type === account_api_1.AccountWalletType.Snap) {
|
|
584
|
-
wallet.metadata.name =
|
|
585
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapRule).call(this).getDefaultAccountWalletName(wallet);
|
|
586
|
-
}
|
|
587
|
-
else {
|
|
588
|
-
wallet.metadata.name =
|
|
589
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getKeyringRule).call(this).getDefaultAccountWalletName(wallet);
|
|
590
|
-
}
|
|
605
|
+
wallet.metadata.name = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultAccountWalletName).call(this, wallet);
|
|
591
606
|
(0, logger_1.projectLogger)(`[${wallet.id}] Set default name to: "${wallet.metadata.name}"`);
|
|
592
607
|
}
|
|
593
|
-
}, _AccountTreeController_getRuleForWallet = function _AccountTreeController_getRuleForWallet(wallet) {
|
|
594
|
-
switch (wallet.type) {
|
|
595
|
-
case account_api_1.AccountWalletType.Entropy:
|
|
596
|
-
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getEntropyRule).call(this);
|
|
597
|
-
case account_api_1.AccountWalletType.Snap:
|
|
598
|
-
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapRule).call(this);
|
|
599
|
-
default:
|
|
600
|
-
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getKeyringRule).call(this);
|
|
601
|
-
}
|
|
602
608
|
}, _AccountTreeController_getComputedAccountGroupName = function _AccountTreeController_getComputedAccountGroupName(wallet, group) {
|
|
603
609
|
let proposedName = ''; // Empty means there's no computed name for this group.
|
|
604
610
|
for (const id of group.accounts) {
|
|
@@ -623,11 +629,18 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
623
629
|
proposedName = this.resolveNameConflict(wallet, group.id, proposedName);
|
|
624
630
|
}
|
|
625
631
|
return proposedName;
|
|
632
|
+
}, _AccountTreeController_getDefaultAccountGroupPrefix = function _AccountTreeController_getDefaultAccountGroupPrefix(wallet) {
|
|
633
|
+
switch (wallet.type) {
|
|
634
|
+
case account_api_1.AccountWalletType.Entropy:
|
|
635
|
+
return (0, entropy_1.getEntropyDefaultAccountGroupPrefix)();
|
|
636
|
+
case account_api_1.AccountWalletType.Snap:
|
|
637
|
+
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapRule).call(this).getDefaultAccountGroupPrefix(wallet);
|
|
638
|
+
default:
|
|
639
|
+
return __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getKeyringRule).call(this).getDefaultAccountGroupPrefix(wallet);
|
|
640
|
+
}
|
|
626
641
|
}, _AccountTreeController_getDefaultAccountGroupName = function _AccountTreeController_getDefaultAccountGroupName(state, wallet, group, nextNaturalNameIndex) {
|
|
627
|
-
// Get the appropriate rule for this wallet type
|
|
628
|
-
const rule = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getRuleForWallet).call(this, wallet);
|
|
629
642
|
// Get the prefix for groups of this wallet
|
|
630
|
-
const namePrefix =
|
|
643
|
+
const namePrefix = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultAccountGroupPrefix).call(this, wallet);
|
|
631
644
|
// Parse the highest account index being used (similar to accounts-controller)
|
|
632
645
|
let highestNameIndex = 0;
|
|
633
646
|
for (const { id: otherGroupId } of Object.values(wallet.groups)) {
|
|
@@ -753,10 +766,15 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
753
766
|
if (!__classPrivateFieldGet(this, _AccountTreeController_initialized, "f")) {
|
|
754
767
|
return;
|
|
755
768
|
}
|
|
769
|
+
if ((0, account_api_1.isBip44Account)(account)) {
|
|
770
|
+
// We're skipping BIP-44 accounts since we rely on the `MultichainAccountService` to do
|
|
771
|
+
// the grouping of wallets/groups directly.
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
756
774
|
// Check if this account is already known by the tree to avoid double-insertion.
|
|
757
775
|
if (!__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").has(account.id)) {
|
|
758
776
|
this.update((state) => {
|
|
759
|
-
__classPrivateFieldGet(this, _AccountTreeController_instances, "m",
|
|
777
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insertAccount).call(this, state.accountTree.wallets, account);
|
|
760
778
|
const context = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(account.id);
|
|
761
779
|
if (context) {
|
|
762
780
|
const { walletId, groupId } = context;
|
|
@@ -779,33 +797,40 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
779
797
|
const context = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(accountId);
|
|
780
798
|
if (context) {
|
|
781
799
|
const { walletId, groupId } = context;
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
800
|
+
// If it's in the context, then `group` should be defined.
|
|
801
|
+
const group = this.state.accountTree.wallets[walletId]?.groups[groupId];
|
|
802
|
+
(0, utils_1.assert)(group, 'Account group associated with a context cannot be undefined');
|
|
803
|
+
// We're only considering non-BIP-44 accounts for single account events.
|
|
804
|
+
if (group.type !== account_api_2.AccountGroupType.MultichainAccount) {
|
|
805
|
+
const index = group.accounts.indexOf(accountId);
|
|
806
|
+
if (index !== -1) {
|
|
807
|
+
let selectedAccountGroupChanged = false;
|
|
808
|
+
const previousSelectedAccountGroup = this.state.accountTree.selectedAccountGroup;
|
|
809
|
+
this.update((state) => {
|
|
810
|
+
const accounts = state.accountTree.wallets[walletId]?.groups[groupId].accounts;
|
|
811
|
+
// Effectively remove account from the group and state.
|
|
789
812
|
accounts.splice(index, 1);
|
|
790
|
-
//
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
//
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
813
|
+
// If there's no more account, we have to prune the group and maybe select
|
|
814
|
+
// a new account group too.
|
|
815
|
+
if (accounts.length === 0) {
|
|
816
|
+
// Check if we need to update selectedAccountGroup after removal
|
|
817
|
+
if (state.accountTree.selectedAccountGroup === groupId) {
|
|
818
|
+
// The currently selected group is now empty, find a new group to select
|
|
819
|
+
const newSelectedAccountGroup = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getDefaultAccountGroupId).call(this, state.accountTree.wallets);
|
|
820
|
+
state.accountTree.selectedAccountGroup =
|
|
821
|
+
newSelectedAccountGroup;
|
|
822
|
+
selectedAccountGroupChanged =
|
|
823
|
+
newSelectedAccountGroup !== previousSelectedAccountGroup;
|
|
824
|
+
}
|
|
825
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_pruneEmptyGroupAndWallet).call(this, state, walletId, groupId);
|
|
798
826
|
}
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
|
|
827
|
+
});
|
|
828
|
+
this.messenger.publish(`${exports.controllerName}:accountTreeChange`, this.state.accountTree);
|
|
829
|
+
// Emit selectedAccountGroupChange event if the selected group changed
|
|
830
|
+
if (selectedAccountGroupChanged) {
|
|
831
|
+
this.messenger.publish(`${exports.controllerName}:selectedAccountGroupChange`, this.state.accountTree.selectedAccountGroup, previousSelectedAccountGroup);
|
|
802
832
|
}
|
|
803
833
|
}
|
|
804
|
-
});
|
|
805
|
-
this.messenger.publish(`${exports.controllerName}:accountTreeChange`, this.state.accountTree);
|
|
806
|
-
// Emit selectedAccountGroupChange event if the selected group changed
|
|
807
|
-
if (selectedAccountGroupChanged) {
|
|
808
|
-
this.messenger.publish(`${exports.controllerName}:selectedAccountGroupChange`, this.state.accountTree.selectedAccountGroup, previousSelectedAccountGroup);
|
|
809
834
|
}
|
|
810
835
|
// Clear reverse-mapping for that account.
|
|
811
836
|
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").delete(accountId);
|
|
@@ -822,9 +847,23 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
822
847
|
delete state.accountWalletsMetadata[walletId];
|
|
823
848
|
}
|
|
824
849
|
return state;
|
|
825
|
-
},
|
|
826
|
-
|
|
827
|
-
|
|
850
|
+
}, _AccountTreeController_sortAccountsOfGroup = function _AccountTreeController_sortAccountsOfGroup(group) {
|
|
851
|
+
group.accounts.sort(
|
|
852
|
+
/* istanbul ignore next: Comparator branch execution (a===id vs b===id)
|
|
853
|
+
* and return attribution vary across engines; final ordering is covered
|
|
854
|
+
* by behavior tests. Ignoring the entire comparator avoids flaky line
|
|
855
|
+
* coverage without reducing scenario coverage.
|
|
856
|
+
*/
|
|
857
|
+
(a, b) => {
|
|
858
|
+
const aSortOrder = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(a)?.sortOrder;
|
|
859
|
+
const bSortOrder = __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").get(b)?.sortOrder;
|
|
860
|
+
return (aSortOrder ?? group_1.MAX_SORT_ORDER) - (bSortOrder ?? group_1.MAX_SORT_ORDER);
|
|
861
|
+
});
|
|
862
|
+
}, _AccountTreeController_insertAccount = function _AccountTreeController_insertAccount(wallets, account) {
|
|
863
|
+
// Those are owned by the `MultichainAccountService`, so they should be already handled
|
|
864
|
+
// by `#insertOrUpdateMultichainAccountWalletAndGroup` method.
|
|
865
|
+
(0, utils_1.assert)(!(0, account_api_1.isBip44Account)(account), 'BIP-44 accounts cannot be inserted explicitly');
|
|
866
|
+
const result = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapRule).call(this).match(account) ??
|
|
828
867
|
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getKeyringRule).call(this).match(account); // This one cannot fail.
|
|
829
868
|
// Update controller's state.
|
|
830
869
|
const walletId = result.wallet.id;
|
|
@@ -843,62 +882,119 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
843
882
|
// the union tag `result.wallet.type`.
|
|
844
883
|
};
|
|
845
884
|
wallet = wallets[walletId];
|
|
846
|
-
// Trigger atomic sync for new wallet (only for entropy wallets)
|
|
847
|
-
if (wallet.type === account_api_1.AccountWalletType.Entropy) {
|
|
848
|
-
__classPrivateFieldGet(this, _AccountTreeController_backupAndSyncService, "f").enqueueSingleWalletSync(walletId);
|
|
849
|
-
}
|
|
850
885
|
}
|
|
851
886
|
const groupId = result.group.id;
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
887
|
+
(0, utils_1.assert)(result.group.type === account_api_2.AccountGroupType.SingleAccount, `Account insertion should always result in a "${account_api_2.AccountGroupType.SingleAccount}" group type`);
|
|
888
|
+
(0, utils_1.assert)(!wallet.groups[groupId], 'Single account insertion cannot re-use existing group');
|
|
889
|
+
(0, logger_1.projectLogger)(`[${walletId}] Add new group: [${groupId}]`);
|
|
890
|
+
const group = {
|
|
891
|
+
...result.group,
|
|
892
|
+
// Type-wise, we are guaranteed to always have at least 1 account.
|
|
893
|
+
accounts: [account.id],
|
|
894
|
+
metadata: {
|
|
895
|
+
name: '',
|
|
896
|
+
...{ pinned: false, hidden: false },
|
|
897
|
+
...result.group.metadata, // Allow rules to override defaults
|
|
898
|
+
},
|
|
899
|
+
// We do need to type-cast since we're not narrowing `result` with
|
|
900
|
+
// the union tag `result.group.type`.
|
|
901
|
+
};
|
|
902
|
+
wallet.groups[groupId] = group;
|
|
903
|
+
// Map group ID to its containing wallet ID for efficient direct access
|
|
904
|
+
__classPrivateFieldGet(this, _AccountTreeController_groupIdToWalletId, "f").set(groupId, walletId);
|
|
905
|
+
(0, logger_1.projectLogger)(`[${groupId}] Add new account: { id: "${account.id}", type: "${account.type}", address: "${account.address}"`);
|
|
906
|
+
// Update the reverse mapping for this account.
|
|
907
|
+
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").set(account.id, {
|
|
908
|
+
walletId: wallet.id,
|
|
909
|
+
groupId: group.id,
|
|
910
|
+
sortOrder: group_1.ACCOUNT_TYPE_TO_SORT_ORDER[account.type],
|
|
911
|
+
});
|
|
912
|
+
// We need to do this at every insertion because race conditions can happen
|
|
913
|
+
// during the account creation process where one provider completes before the other.
|
|
914
|
+
// The discovery process in the service can also lead to some accounts being created "out of order".
|
|
915
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_sortAccountsOfGroup).call(this, group);
|
|
916
|
+
}, _AccountTreeController_insertOrUpdateMultichainAccountWalletAndGroup = function _AccountTreeController_insertOrUpdateMultichainAccountWalletAndGroup(wallets, multichainAccountWallet, multichainAccountGroup) {
|
|
917
|
+
const walletId = multichainAccountWallet.id;
|
|
918
|
+
const groupId = multichainAccountGroup.id;
|
|
919
|
+
let wallet = null;
|
|
920
|
+
let group = null;
|
|
921
|
+
// Check type, mainly to infer proper wallet object type.
|
|
922
|
+
const walletObject = wallets[walletId];
|
|
923
|
+
if (walletObject && walletObject.type === account_api_1.AccountWalletType.Entropy) {
|
|
924
|
+
wallet = walletObject;
|
|
925
|
+
group = wallet.groups[groupId];
|
|
926
|
+
}
|
|
927
|
+
// We always re-use the account list from the group (if accounts get
|
|
928
|
+
// added/removed/re-ordered within the group).
|
|
929
|
+
const accounts = multichainAccountGroup.getAccounts();
|
|
930
|
+
const accountIds = accounts
|
|
931
|
+
// For now, we need this type-cast because `getAccounts` do not have the same
|
|
932
|
+
// type-constraint (uses string[] instead of [string; ...string])
|
|
933
|
+
.map((account) => account.id);
|
|
934
|
+
// Create the group object first, to inject it in the wallet in case this wallet is
|
|
935
|
+
// not part of the tree yet.
|
|
855
936
|
if (!group) {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
accounts: [id],
|
|
937
|
+
group = {
|
|
938
|
+
id: multichainAccountGroup.id,
|
|
939
|
+
type: multichainAccountGroup.type,
|
|
940
|
+
accounts: accountIds,
|
|
861
941
|
metadata: {
|
|
942
|
+
entropy: {
|
|
943
|
+
groupIndex: multichainAccountGroup.groupIndex,
|
|
944
|
+
},
|
|
862
945
|
name: '',
|
|
863
|
-
|
|
864
|
-
|
|
946
|
+
pinned: false,
|
|
947
|
+
hidden: false,
|
|
865
948
|
},
|
|
866
|
-
// We do need to type-cast since we're not narrowing `result` with
|
|
867
|
-
// the union tag `result.group.type`.
|
|
868
949
|
};
|
|
869
|
-
group = wallet.groups[groupId];
|
|
870
|
-
// Map group ID to its containing wallet ID for efficient direct access
|
|
871
|
-
__classPrivateFieldGet(this, _AccountTreeController_groupIdToWalletId, "f").set(groupId, walletId);
|
|
872
|
-
// Trigger atomic sync for new group (only for entropy wallets)
|
|
873
|
-
if (wallet.type === account_api_1.AccountWalletType.Entropy) {
|
|
874
|
-
__classPrivateFieldGet(this, _AccountTreeController_backupAndSyncService, "f").enqueueSingleGroupSync(groupId);
|
|
875
|
-
}
|
|
876
950
|
}
|
|
877
951
|
else {
|
|
878
|
-
group
|
|
879
|
-
//
|
|
880
|
-
//
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
952
|
+
// We clear existing contexts for previous accounts of that group because:
|
|
953
|
+
// - Accounts might have been removed
|
|
954
|
+
// - Accounts context mapping will get updated below
|
|
955
|
+
group.accounts.forEach((accountId) => __classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").delete(accountId));
|
|
956
|
+
group.accounts = accountIds;
|
|
957
|
+
}
|
|
958
|
+
if (!wallet) {
|
|
959
|
+
wallet = {
|
|
960
|
+
id: multichainAccountWallet.id,
|
|
961
|
+
type: multichainAccountWallet.type,
|
|
962
|
+
status: multichainAccountWallet.status,
|
|
963
|
+
groups: {
|
|
964
|
+
[group.id]: group,
|
|
965
|
+
},
|
|
966
|
+
metadata: {
|
|
967
|
+
entropy: {
|
|
968
|
+
id: multichainAccountWallet.entropySource,
|
|
969
|
+
},
|
|
970
|
+
name: '', // Will get updated later.
|
|
971
|
+
},
|
|
972
|
+
};
|
|
973
|
+
wallets[walletId] = wallet;
|
|
974
|
+
// Trigger atomic sync for new wallet.
|
|
975
|
+
__classPrivateFieldGet(this, _AccountTreeController_backupAndSyncService, "f").enqueueSingleWalletSync(walletId);
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
wallet.groups[group.id] = group;
|
|
979
|
+
// Trigger atomic sync for new group.
|
|
980
|
+
__classPrivateFieldGet(this, _AccountTreeController_backupAndSyncService, "f").enqueueSingleGroupSync(groupId);
|
|
981
|
+
}
|
|
982
|
+
// Map group ID to its containing wallet ID for efficient direct access
|
|
983
|
+
__classPrivateFieldGet(this, _AccountTreeController_groupIdToWalletId, "f").set(groupId, walletId);
|
|
984
|
+
// Update the reverse mapping for all accounts account.
|
|
985
|
+
for (const account of accounts) {
|
|
986
|
+
__classPrivateFieldGet(this, _AccountTreeController_accountIdToContext, "f").set(account.id, {
|
|
987
|
+
walletId: wallet.id,
|
|
988
|
+
groupId: group.id,
|
|
989
|
+
sortOrder: group_1.ACCOUNT_TYPE_TO_SORT_ORDER[account.type],
|
|
893
990
|
});
|
|
894
991
|
}
|
|
895
|
-
|
|
896
|
-
//
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
});
|
|
992
|
+
// We need to do this at every insertion because race conditions can happen
|
|
993
|
+
// during the account creation process where one provider completes before the other.
|
|
994
|
+
// The discovery process in the service can also lead to some accounts being created "out of order".
|
|
995
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_sortAccountsOfGroup).call(this, group);
|
|
996
|
+
}, _AccountTreeController_getMultichainAccountWallets = function _AccountTreeController_getMultichainAccountWallets() {
|
|
997
|
+
return this.messenger.call('MultichainAccountService:getMultichainAccountWallets');
|
|
902
998
|
}, _AccountTreeController_listAccounts = function _AccountTreeController_listAccounts() {
|
|
903
999
|
return this.messenger.call('AccountsController:listMultichainAccounts');
|
|
904
1000
|
}, _AccountTreeController_assertAccountGroupExists = function _AccountTreeController_assertAccountGroupExists(groupId) {
|
|
@@ -943,6 +1039,25 @@ _AccountTreeController_accountIdToContext = new WeakMap(), _AccountTreeControlle
|
|
|
943
1039
|
state.accountTree.selectedAccountGroup = groupId;
|
|
944
1040
|
});
|
|
945
1041
|
this.messenger.publish(`${exports.controllerName}:selectedAccountGroupChange`, groupId, previousSelectedAccountGroup);
|
|
1042
|
+
}, _AccountTreeController_handleMultichainAccountGroupCreatedOrUpdated = function _AccountTreeController_handleMultichainAccountGroupCreatedOrUpdated(multichainAccountGroup) {
|
|
1043
|
+
// We wait for the first `init` to be called to actually build up the tree and
|
|
1044
|
+
// mutate it. We expect the caller to first update the `AccountsController` state
|
|
1045
|
+
// to force the migration of accounts, and then call `init`.
|
|
1046
|
+
if (!__classPrivateFieldGet(this, _AccountTreeController_initialized, "f")) {
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
this.update((state) => {
|
|
1050
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insertOrUpdateMultichainAccountWalletAndGroup).call(this, state.accountTree.wallets, multichainAccountGroup.wallet, multichainAccountGroup);
|
|
1051
|
+
const wallet = state.accountTree.wallets[multichainAccountGroup.wallet.id];
|
|
1052
|
+
if (wallet) {
|
|
1053
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountWalletMetadata).call(this, state, wallet.id);
|
|
1054
|
+
const group = wallet.groups[multichainAccountGroup.id];
|
|
1055
|
+
if (group) {
|
|
1056
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_applyAccountGroupMetadata).call(this, state, wallet.id, group.id);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
this.messenger.publish(`${exports.controllerName}:accountTreeChange`, this.state.accountTree);
|
|
946
1061
|
}, _AccountTreeController_handleMultichainAccountWalletStatusChange = function _AccountTreeController_handleMultichainAccountWalletStatusChange(walletId, walletStatus) {
|
|
947
1062
|
this.update((state) => {
|
|
948
1063
|
const wallet = state.accountTree.wallets[walletId];
|