@metamask-previews/account-tree-controller 0.0.0-preview-d9a49231
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 +10 -0
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/dist/AccountTreeController.cjs +258 -0
- package/dist/AccountTreeController.cjs.map +1 -0
- package/dist/AccountTreeController.d.cts +92 -0
- package/dist/AccountTreeController.d.cts.map +1 -0
- package/dist/AccountTreeController.d.mts +92 -0
- package/dist/AccountTreeController.d.mts.map +1 -0
- package/dist/AccountTreeController.mjs +250 -0
- package/dist/AccountTreeController.mjs.map +1 -0
- package/dist/index.cjs +6 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/names.cjs +43 -0
- package/dist/names.cjs.map +1 -0
- package/dist/names.d.cts +9 -0
- package/dist/names.d.cts.map +1 -0
- package/dist/names.d.mts +9 -0
- package/dist/names.d.mts.map +1 -0
- package/dist/names.mjs +39 -0
- package/dist/names.mjs.map +1 -0
- package/package.json +86 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
[Unreleased]: https://github.com/MetaMask/core/
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MetaMask
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# `@metamask/account-tree-controller`
|
|
2
|
+
|
|
3
|
+
Manages account wallets according to pre-defined grouping rules (entropy source, Snap IDs, keyring types) and organize wallets/groups of accounts in a tree structure.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`yarn add @metamask/account-tree-controller`
|
|
8
|
+
|
|
9
|
+
or
|
|
10
|
+
|
|
11
|
+
`npm install @metamask/account-tree-controller`
|
|
12
|
+
|
|
13
|
+
## Contributing
|
|
14
|
+
|
|
15
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
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
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _AccountTreeController_instances, _AccountTreeController_reverse, _AccountTreeController_rules, _AccountTreeController_handleAccountAdded, _AccountTreeController_handleAccountRemoved, _AccountTreeController_hasKeyringType, _AccountTreeController_matchGroupByEntropySource, _AccountTreeController_matchGroupBySnapId, _AccountTreeController_matchGroupByKeyringType, _AccountTreeController_getSnapName, _AccountTreeController_getEntropySourceName, _AccountTreeController_insert, _AccountTreeController_listAccounts;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.AccountTreeController = exports.toDefaultAccountGroupId = exports.toAccountGroupId = exports.toAccountGroupRootId = exports.DEFAULT_ACCOUNT_GROUP_NAME = exports.DEFAULT_ACCOUNT_GROUP_UNIQUE_ID = exports.getDefaultAccountTreeControllerState = exports.AccountGroupRootCategory = void 0;
|
|
16
|
+
const base_controller_1 = require("@metamask/base-controller");
|
|
17
|
+
const keyring_controller_1 = require("@metamask/keyring-controller");
|
|
18
|
+
const snaps_utils_1 = require("@metamask/snaps-utils");
|
|
19
|
+
const names_1 = require("./names.cjs");
|
|
20
|
+
const controllerName = 'AccountTreeController';
|
|
21
|
+
var AccountGroupRootCategory;
|
|
22
|
+
(function (AccountGroupRootCategory) {
|
|
23
|
+
AccountGroupRootCategory["Entropy"] = "entropy";
|
|
24
|
+
AccountGroupRootCategory["Snap"] = "snap";
|
|
25
|
+
AccountGroupRootCategory["Keyring"] = "keyring";
|
|
26
|
+
AccountGroupRootCategory["Default"] = "default";
|
|
27
|
+
})(AccountGroupRootCategory || (exports.AccountGroupRootCategory = AccountGroupRootCategory = {}));
|
|
28
|
+
const accountTreeControllerMetadata = {
|
|
29
|
+
accountTrees: {
|
|
30
|
+
persist: false,
|
|
31
|
+
anonymous: false,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Gets default state of the `AccountTreeController`.
|
|
36
|
+
*
|
|
37
|
+
* @returns The default state of the `AccountTreeController`.
|
|
38
|
+
*/
|
|
39
|
+
function getDefaultAccountTreeControllerState() {
|
|
40
|
+
return {
|
|
41
|
+
accountTrees: {
|
|
42
|
+
roots: {},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
exports.getDefaultAccountTreeControllerState = getDefaultAccountTreeControllerState;
|
|
47
|
+
// TODO: For now we use this for the 2nd-level of the tree until we implements proper multichain accounts.
|
|
48
|
+
exports.DEFAULT_ACCOUNT_GROUP_UNIQUE_ID = 'default'; // This might need to be re-evaluated based on new structure
|
|
49
|
+
exports.DEFAULT_ACCOUNT_GROUP_NAME = 'Default';
|
|
50
|
+
/**
|
|
51
|
+
* Convert a unique ID to a group root ID for a given category.
|
|
52
|
+
*
|
|
53
|
+
* @param category - The category of the account group root.
|
|
54
|
+
* @param id - The unique ID.
|
|
55
|
+
* @returns The group root ID.
|
|
56
|
+
*/
|
|
57
|
+
function toAccountGroupRootId(category, id) {
|
|
58
|
+
return `${category}:${id}`;
|
|
59
|
+
}
|
|
60
|
+
exports.toAccountGroupRootId = toAccountGroupRootId;
|
|
61
|
+
/**
|
|
62
|
+
* Convert a group root ID and a unique ID to a group ID.
|
|
63
|
+
*
|
|
64
|
+
* @param groupRootId - The group root ID.
|
|
65
|
+
* @param id - The unique ID.
|
|
66
|
+
* @returns The group ID.
|
|
67
|
+
*/
|
|
68
|
+
function toAccountGroupId(groupRootId, id) {
|
|
69
|
+
return `${groupRootId}:${id}`;
|
|
70
|
+
}
|
|
71
|
+
exports.toAccountGroupId = toAccountGroupId;
|
|
72
|
+
/**
|
|
73
|
+
* Convert a group root ID to the default group ID.
|
|
74
|
+
*
|
|
75
|
+
* @param groupRootId - The group root ID.
|
|
76
|
+
* @returns The default group ID.
|
|
77
|
+
*/
|
|
78
|
+
function toDefaultAccountGroupId(groupRootId) {
|
|
79
|
+
return toAccountGroupId(groupRootId, exports.DEFAULT_ACCOUNT_GROUP_UNIQUE_ID);
|
|
80
|
+
}
|
|
81
|
+
exports.toDefaultAccountGroupId = toDefaultAccountGroupId;
|
|
82
|
+
class AccountTreeController extends base_controller_1.BaseController {
|
|
83
|
+
/**
|
|
84
|
+
* Constructor for AccountTreeController.
|
|
85
|
+
*
|
|
86
|
+
* @param options - The controller options.
|
|
87
|
+
* @param options.messenger - The messenger object.
|
|
88
|
+
* @param options.state - Initial state to set on this controller
|
|
89
|
+
*/
|
|
90
|
+
constructor({ messenger, state, }) {
|
|
91
|
+
super({
|
|
92
|
+
messenger,
|
|
93
|
+
name: controllerName,
|
|
94
|
+
metadata: accountTreeControllerMetadata,
|
|
95
|
+
state: {
|
|
96
|
+
...getDefaultAccountTreeControllerState(),
|
|
97
|
+
...state,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
_AccountTreeController_instances.add(this);
|
|
101
|
+
_AccountTreeController_reverse.set(this, void 0);
|
|
102
|
+
_AccountTreeController_rules.set(this, void 0);
|
|
103
|
+
// Reverse map to allow fast node access from an account ID.
|
|
104
|
+
__classPrivateFieldSet(this, _AccountTreeController_reverse, new Map(), "f");
|
|
105
|
+
// Rules to apply to construct the wallets tree.
|
|
106
|
+
__classPrivateFieldSet(this, _AccountTreeController_rules, [
|
|
107
|
+
// 1. We group by entropy-source
|
|
108
|
+
(account) => __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_matchGroupByEntropySource).call(this, account),
|
|
109
|
+
// 2. We group by Snap ID
|
|
110
|
+
(account) => __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_matchGroupBySnapId).call(this, account),
|
|
111
|
+
// 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)
|
|
112
|
+
(account) => __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_matchGroupByKeyringType).call(this, account),
|
|
113
|
+
], "f");
|
|
114
|
+
this.messagingSystem.subscribe('AccountsController:accountAdded', (account) => {
|
|
115
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleAccountAdded).call(this, account);
|
|
116
|
+
});
|
|
117
|
+
this.messagingSystem.subscribe('AccountsController:accountRemoved', (accountId) => {
|
|
118
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleAccountRemoved).call(this, accountId);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
init() {
|
|
122
|
+
const roots = {};
|
|
123
|
+
// For now, we always re-compute all wallets, we do not re-use the existing state.
|
|
124
|
+
for (const account of __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_listAccounts).call(this)) {
|
|
125
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, roots, account);
|
|
126
|
+
}
|
|
127
|
+
this.update((state) => {
|
|
128
|
+
state.accountTrees.roots = roots;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.AccountTreeController = AccountTreeController;
|
|
133
|
+
_AccountTreeController_reverse = new WeakMap(), _AccountTreeController_rules = new WeakMap(), _AccountTreeController_instances = new WeakSet(), _AccountTreeController_handleAccountAdded = function _AccountTreeController_handleAccountAdded(account) {
|
|
134
|
+
this.update((state) => {
|
|
135
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, state.accountTrees.roots, account);
|
|
136
|
+
});
|
|
137
|
+
}, _AccountTreeController_handleAccountRemoved = function _AccountTreeController_handleAccountRemoved(accountId) {
|
|
138
|
+
const found = __classPrivateFieldGet(this, _AccountTreeController_reverse, "f").get(accountId);
|
|
139
|
+
if (found) {
|
|
140
|
+
const { walletId, groupId } = found;
|
|
141
|
+
this.update((state) => {
|
|
142
|
+
const { accounts } = state.accountTrees.roots[walletId].groups[groupId];
|
|
143
|
+
const index = accounts.indexOf(accountId);
|
|
144
|
+
if (index !== -1) {
|
|
145
|
+
accounts.splice(index, 1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}, _AccountTreeController_hasKeyringType = function _AccountTreeController_hasKeyringType(account, type) {
|
|
150
|
+
return account.metadata.keyring.type === type;
|
|
151
|
+
}, _AccountTreeController_matchGroupByEntropySource = function _AccountTreeController_matchGroupByEntropySource(account) {
|
|
152
|
+
let entropySource;
|
|
153
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasKeyringType).call(this, account, keyring_controller_1.KeyringTypes.hd)) {
|
|
154
|
+
// TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?
|
|
155
|
+
if (!account.options.entropySource) {
|
|
156
|
+
console.warn("! Found an HD account with no entropy source: account won't be associated to its wallet");
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
entropySource = account.options.entropySource;
|
|
160
|
+
}
|
|
161
|
+
// TODO: For now, we're not checking if the Snap is a preinstalled one, and we probably should...
|
|
162
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasKeyringType).call(this, account, keyring_controller_1.KeyringTypes.snap) &&
|
|
163
|
+
account.metadata.snap?.enabled) {
|
|
164
|
+
// Not all Snaps have an entropy-source and options are not typed yet, so we have to check manually here.
|
|
165
|
+
if (account.options.entropySource) {
|
|
166
|
+
// We blindly trust the `entropySource` for now, but it could be wrong since it comes from a Snap.
|
|
167
|
+
entropySource = account.options.entropySource;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!entropySource) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
// We check if we can get the name for that entropy source, if not this means this entropy does not match
|
|
174
|
+
// any HD keyrings, thus, is invalid (this account will be grouped by another rule).
|
|
175
|
+
const entropySourceName = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getEntropySourceName).call(this, entropySource);
|
|
176
|
+
if (!entropySourceName) {
|
|
177
|
+
console.warn('! Tried to name a wallet using an unknown entropy, this should not be possible.');
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
category: AccountGroupRootCategory.Entropy,
|
|
182
|
+
id: toAccountGroupRootId(AccountGroupRootCategory.Entropy, entropySource),
|
|
183
|
+
name: entropySourceName,
|
|
184
|
+
};
|
|
185
|
+
}, _AccountTreeController_matchGroupBySnapId = function _AccountTreeController_matchGroupBySnapId(account) {
|
|
186
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasKeyringType).call(this, account, keyring_controller_1.KeyringTypes.snap) &&
|
|
187
|
+
account.metadata.snap &&
|
|
188
|
+
account.metadata.snap.enabled) {
|
|
189
|
+
const { id } = account.metadata.snap;
|
|
190
|
+
return {
|
|
191
|
+
category: AccountGroupRootCategory.Snap,
|
|
192
|
+
id: toAccountGroupRootId(AccountGroupRootCategory.Snap, id),
|
|
193
|
+
name: __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapName).call(this, id),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}, _AccountTreeController_matchGroupByKeyringType = function _AccountTreeController_matchGroupByKeyringType(account) {
|
|
198
|
+
const { type } = account.metadata.keyring;
|
|
199
|
+
return {
|
|
200
|
+
category: AccountGroupRootCategory.Keyring,
|
|
201
|
+
id: toAccountGroupRootId(AccountGroupRootCategory.Keyring, type),
|
|
202
|
+
name: (0, names_1.getAccountGroupRootNameFromKeyringType)(type),
|
|
203
|
+
};
|
|
204
|
+
}, _AccountTreeController_getSnapName = function _AccountTreeController_getSnapName(snapId) {
|
|
205
|
+
const snap = this.messagingSystem.call('SnapController:get', snapId);
|
|
206
|
+
const snapName = snap
|
|
207
|
+
? // TODO: Handle localization here, but that's a "client thing", so we don't have a `core` controller
|
|
208
|
+
// to refer too.
|
|
209
|
+
snap.manifest.proposedName
|
|
210
|
+
: (0, snaps_utils_1.stripSnapPrefix)(snapId);
|
|
211
|
+
return `Snap: ${snapName}`;
|
|
212
|
+
}, _AccountTreeController_getEntropySourceName = function _AccountTreeController_getEntropySourceName(entropySource) {
|
|
213
|
+
const { keyrings } = this.messagingSystem.call('KeyringController:getState');
|
|
214
|
+
const index = keyrings
|
|
215
|
+
.filter((keyring) => keyring.type === keyring_controller_1.KeyringTypes.hd)
|
|
216
|
+
.findIndex((keyring) => keyring.metadata.id === entropySource);
|
|
217
|
+
if (index === -1) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
return `Wallet ${index + 1}`; // Use human indexing.
|
|
221
|
+
}, _AccountTreeController_insert = function _AccountTreeController_insert(roots, account) {
|
|
222
|
+
for (const rule of __classPrivateFieldGet(this, _AccountTreeController_rules, "f")) {
|
|
223
|
+
const match = rule(account);
|
|
224
|
+
if (!match) {
|
|
225
|
+
// No match for that rule, we go to the next one.
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const walletId = match.id;
|
|
229
|
+
const walletName = match.name;
|
|
230
|
+
const groupId = toDefaultAccountGroupId(walletId); // Use a single-group for now until multichain accounts is supported.
|
|
231
|
+
const groupName = exports.DEFAULT_ACCOUNT_GROUP_NAME;
|
|
232
|
+
if (!roots[walletId]) {
|
|
233
|
+
roots[walletId] = {
|
|
234
|
+
id: walletId,
|
|
235
|
+
groups: {
|
|
236
|
+
[groupId]: {
|
|
237
|
+
id: groupId,
|
|
238
|
+
accounts: [],
|
|
239
|
+
metadata: { name: groupName },
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
metadata: {
|
|
243
|
+
name: walletName,
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
roots[walletId].groups[groupId].accounts.push(account.id);
|
|
248
|
+
// Update the reverse mapping for this account.
|
|
249
|
+
__classPrivateFieldGet(this, _AccountTreeController_reverse, "f").set(account.id, {
|
|
250
|
+
walletId,
|
|
251
|
+
groupId,
|
|
252
|
+
});
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
}, _AccountTreeController_listAccounts = function _AccountTreeController_listAccounts() {
|
|
256
|
+
return this.messagingSystem.call('AccountsController:listMultichainAccounts');
|
|
257
|
+
};
|
|
258
|
+
//# sourceMappingURL=AccountTreeController.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountTreeController.cjs","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAOA,+DAKmC;AAEnC,qEAA4D;AAI5D,uDAAwD;AAExD,uCAAiE;AAEjE,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAE/C,IAAY,wBAKX;AALD,WAAY,wBAAwB;IAClC,+CAAmB,CAAA;IACnB,yCAAa,CAAA;IACb,+CAAmB,CAAA;IACnB,+CAAmB,CAAA;AACrB,CAAC,EALW,wBAAwB,wCAAxB,wBAAwB,QAKnC;AAqFD,MAAM,6BAA6B,GACjC;IACE,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,KAAK;KACjB;CACF,CAAC;AAEJ;;;;GAIG;AACH,SAAgB,oCAAoC;IAClD,OAAO;QACL,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;KACF,CAAC;AACJ,CAAC;AAND,oFAMC;AAED,0GAA0G;AAC7F,QAAA,+BAA+B,GAAW,SAAS,CAAC,CAAC,4DAA4D;AACjH,QAAA,0BAA0B,GAAW,SAAS,CAAC;AAE5D;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAClC,QAAkC,EAClC,EAAU;IAEV,OAAO,GAAG,QAAQ,IAAI,EAAE,EAAE,CAAC;AAC7B,CAAC;AALD,oDAKC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAC9B,WAA+B,EAC/B,EAAU;IAEV,OAAO,GAAG,WAAW,IAAI,EAAE,EAAE,CAAC;AAChC,CAAC;AALD,4CAKC;AAED;;;;;GAKG;AACH,SAAgB,uBAAuB,CACrC,WAA+B;IAE/B,OAAO,gBAAgB,CAAC,WAAW,EAAE,uCAA+B,CAAC,CAAC;AACxE,CAAC;AAJD,0DAIC;AAED,MAAa,qBAAsB,SAAQ,gCAI1C;IAKC;;;;;;OAMG;IACH,YAAY,EACV,SAAS,EACT,KAAK,GAIN;QACC,KAAK,CAAC;YACJ,SAAS;YACT,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,6BAA6B;YACvC,KAAK,EAAE;gBACL,GAAG,oCAAoC,EAAE;gBACzC,GAAG,KAAK;aACT;SACF,CAAC,CAAC;;QA1BI,iDAAgD;QAEhD,+CAAuC;QA0B9C,4DAA4D;QAC5D,uBAAA,IAAI,kCAAY,IAAI,GAAG,EAAE,MAAA,CAAC;QAE1B,gDAAgD;QAChD,uBAAA,IAAI,gCAAU;YACZ,gCAAgC;YAChC,CAAC,OAAwB,EAAE,EAAE,CAAC,uBAAA,IAAI,0FAA2B,MAA/B,IAAI,EAA4B,OAAO,CAAC;YACtE,yBAAyB;YACzB,CAAC,OAAwB,EAAE,EAAE,CAAC,uBAAA,IAAI,mFAAoB,MAAxB,IAAI,EAAqB,OAAO,CAAC;YAC/D,8FAA8F;YAC9F,CAAC,OAAwB,EAAE,EAAE,CAAC,uBAAA,IAAI,wFAAyB,MAA7B,IAAI,EAA0B,OAAO,CAAC;SACrE,MAAA,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,iCAAiC,EACjC,CAAC,OAAO,EAAE,EAAE;YACV,uBAAA,IAAI,mFAAoB,MAAxB,IAAI,EAAqB,OAAO,CAAC,CAAC;QACpC,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,mCAAmC,EACnC,CAAC,SAAS,EAAE,EAAE;YACZ,uBAAA,IAAI,qFAAsB,MAA1B,IAAI,EAAuB,SAAS,CAAC,CAAC;QACxC,CAAC,CACF,CAAC;IACJ,CAAC;IAED,IAAI;QACF,MAAM,KAAK,GAAG,EAAE,CAAC;QAEjB,kFAAkF;QAClF,KAAK,MAAM,OAAO,IAAI,uBAAA,IAAI,6EAAc,MAAlB,IAAI,CAAgB,EAAE;YAC1C,uBAAA,IAAI,uEAAQ,MAAZ,IAAI,EAAS,KAAK,EAAE,OAAO,CAAC,CAAC;SAC9B;QAED,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;CA0LF;AAlQD,sDAkQC;+OAxLqB,OAAwB;IAC1C,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QACpB,uBAAA,IAAI,uEAAQ,MAAZ,IAAI,EAAS,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,qGAEqB,SAAoB;IACxC,MAAM,KAAK,GAAG,uBAAA,IAAI,sCAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAE3C,IAAI,KAAK,EAAE;QACT,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAExE,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE;gBAChB,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;aAC3B;QACH,CAAC,CAAC,CAAC;KACJ;AACH,CAAC,yFAEe,OAAwB,EAAE,IAAkB;IAC1D,OAAO,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAM,IAAe,CAAC;AAC5D,CAAC,+GAGC,OAAwB;IAExB,IAAI,aAAiC,CAAC;IAEtC,IAAI,uBAAA,IAAI,+EAAgB,MAApB,IAAI,EAAiB,OAAO,EAAE,iCAAY,CAAC,EAAE,CAAC,EAAE;QAClD,iHAAiH;QACjH,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE;YAClC,OAAO,CAAC,IAAI,CACV,yFAAyF,CAC1F,CAAC;YACF,OAAO,SAAS,CAAC;SAClB;QAED,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,aAAuB,CAAC;KACzD;IAED,iGAAiG;IACjG,IACE,uBAAA,IAAI,+EAAgB,MAApB,IAAI,EAAiB,OAAO,EAAE,iCAAY,CAAC,IAAI,CAAC;QAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAC9B;QACA,yGAAyG;QACzG,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE;YACjC,kGAAkG;YAClG,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,aAAuB,CAAC;SACzD;KACF;IAED,IAAI,CAAC,aAAa,EAAE;QAClB,OAAO,SAAS,CAAC;KAClB;IAED,yGAAyG;IACzG,oFAAoF;IACpF,MAAM,iBAAiB,GAAG,uBAAA,IAAI,qFAAsB,MAA1B,IAAI,EAAuB,aAAa,CAAC,CAAC;IACpE,IAAI,CAAC,iBAAiB,EAAE;QACtB,OAAO,CAAC,IAAI,CACV,iFAAiF,CAClF,CAAC;QACF,OAAO,SAAS,CAAC;KAClB;IAED,OAAO;QACL,QAAQ,EAAE,wBAAwB,CAAC,OAAO;QAC1C,EAAE,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,OAAO,EAAE,aAAa,CAAC;QACzE,IAAI,EAAE,iBAAiB;KACxB,CAAC;AACJ,CAAC,iGAGC,OAAwB;IAExB,IACE,uBAAA,IAAI,+EAAgB,MAApB,IAAI,EAAiB,OAAO,EAAE,iCAAY,CAAC,IAAI,CAAC;QAChD,OAAO,CAAC,QAAQ,CAAC,IAAI;QACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAC7B;QACA,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAErC,OAAO;YACL,QAAQ,EAAE,wBAAwB,CAAC,IAAI;YACvC,EAAE,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3D,IAAI,EAAE,uBAAA,IAAI,4EAAa,MAAjB,IAAI,EAAc,EAAY,CAAC;SACtC,CAAC;KACH;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,2GAGC,OAAwB;IAExB,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAE1C,OAAO;QACL,QAAQ,EAAE,wBAAwB,CAAC,OAAO;QAC1C,EAAE,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,OAAO,EAAE,IAAI,CAAC;QAChE,IAAI,EAAE,IAAA,8CAAsC,EAAC,IAAoB,CAAC;KACnE,CAAC;AACJ,CAAC,mFAEY,MAAc;IACzB,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,IAAI;QACnB,CAAC,CAAC,oGAAoG;YACpG,gBAAgB;YAChB,IAAI,CAAC,QAAQ,CAAC,YAAY;QAC5B,CAAC,CAAC,IAAA,6BAAe,EAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,SAAS,QAAQ,EAAE,CAAC;AAC7B,CAAC,qGAEqB,aAAqB;IACzC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC5C,4BAA4B,CAC7B,CAAC;IAEF,MAAM,KAAK,GAAG,QAAQ;SACnB,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAM,iCAAY,CAAC,EAAa,CAAC;SACjE,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC;IAEjE,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE;QAChB,OAAO,SAAS,CAAC;KAClB;IAED,OAAO,UAAU,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,sBAAsB;AACtD,CAAC,yEAGC,KAAqE,EACrE,OAAwB;IAExB,KAAK,MAAM,IAAI,IAAI,uBAAA,IAAI,oCAAO,EAAE;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAE5B,IAAI,CAAC,KAAK,EAAE;YACV,iDAAiD;YACjD,SAAS;SACV;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC;QAC9B,MAAM,OAAO,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,qEAAqE;QACxH,MAAM,SAAS,GAAG,kCAA0B,CAAC;QAE7C,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;YACpB,KAAK,CAAC,QAAQ,CAAC,GAAG;gBAChB,EAAE,EAAE,QAAQ;gBACZ,MAAM,EAAE;oBACN,CAAC,OAAO,CAAC,EAAE;wBACT,EAAE,EAAE,OAAO;wBACX,QAAQ,EAAE,EAAE;wBACZ,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;qBAC9B;iBACF;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,UAAU;iBACjB;aACF,CAAC;SACH;QACD,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAE1D,+CAA+C;QAC/C,uBAAA,IAAI,sCAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE;YAC5B,QAAQ;YACR,OAAO;SACR,CAAC,CAAC;QAEH,OAAO;KACR;AACH,CAAC;IAGC,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAC9B,2CAA2C,CACvB,CAAC;AACzB,CAAC","sourcesContent":["import type {\n AccountId,\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type { StateMetadata } from '@metamask/base-controller';\nimport {\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n BaseController,\n} from '@metamask/base-controller';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { stripSnapPrefix } from '@metamask/snaps-utils';\n\nimport { getAccountGroupRootNameFromKeyringType } from './names';\n\nconst controllerName = 'AccountTreeController';\n\nexport enum AccountGroupRootCategory {\n Entropy = 'entropy',\n Snap = 'snap',\n Keyring = 'keyring',\n Default = 'default', // TODO: Remove `default` once we have multichain accounts.\n}\n\ntype AccountTreeRuleMatch = {\n category: AccountGroupRootCategory;\n id: AccountGroupRootId;\n name: string;\n};\n\ntype AccountReverseMapping = {\n walletId: AccountGroupRootId;\n groupId: AccountGroupId;\n};\n\ntype AccountGroupRootRuleFunction = (\n account: InternalAccount,\n) => AccountTreeRuleMatch | undefined;\n\nexport type AccountGroupRootId = `${AccountGroupRootCategory}:${string}`;\nexport type AccountGroupId = `${AccountGroupRootId}:${string}`;\n\n// Do not export this one, we just use it to have a common type interface between group and wallet metadata.\ntype Metadata = {\n name: string;\n};\n\nexport type AccountGroupRootMetadata = Metadata;\n\nexport type AccountGroupMetadata = Metadata;\n\nexport type AccountGroup = {\n id: AccountGroupId;\n // Blockchain Accounts:\n accounts: AccountId[];\n metadata: AccountGroupMetadata;\n};\n\nexport type AccountGroupRoot = {\n id: AccountGroupRootId;\n // Account groups OR Multichain accounts (once available).\n groups: {\n [accountGroup: AccountGroupId]: AccountGroup;\n };\n metadata: AccountGroupMetadata; // Assuming Metadata is a defined type\n};\n\nexport type AccountTreeControllerState = {\n accountTrees: {\n roots: {\n // Wallets:\n [accountGroupRoot: AccountGroupRootId]: AccountGroupRoot;\n },\n };\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerListMultichainAccountsAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap;\n\nexport type AccountTreeControllerActions = never;\n\nexport type AccountTreeControllerChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent;\n\nexport type AccountTreeControllerEvents = never;\n\nexport type AccountTreeControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\nconst accountTreeControllerMetadata: StateMetadata<AccountTreeControllerState> =\n {\n accountTrees: {\n persist: false, // We do re-recompute this state everytime.\n anonymous: false,\n },\n };\n\n/**\n * Gets default state of the `AccountTreeController`.\n *\n * @returns The default state of the `AccountTreeController`.\n */\nexport function getDefaultAccountTreeControllerState(): AccountTreeControllerState {\n return {\n accountTrees: {\n roots: {},\n },\n };\n}\n\n// TODO: For now we use this for the 2nd-level of the tree until we implements proper multichain accounts.\nexport const DEFAULT_ACCOUNT_GROUP_UNIQUE_ID: string = 'default'; // This might need to be re-evaluated based on new structure\nexport const DEFAULT_ACCOUNT_GROUP_NAME: string = 'Default';\n\n/**\n * Convert a unique ID to a group root ID for a given category.\n *\n * @param category - The category of the account group root.\n * @param id - The unique ID.\n * @returns The group root ID.\n */\nexport function toAccountGroupRootId(\n category: AccountGroupRootCategory,\n id: string,\n): AccountGroupRootId {\n return `${category}:${id}`;\n}\n\n/**\n * Convert a group root ID and a unique ID to a group ID.\n *\n * @param groupRootId - The group root ID.\n * @param id - The unique ID.\n * @returns The group ID.\n */\nexport function toAccountGroupId(\n groupRootId: AccountGroupRootId,\n id: string,\n): AccountGroupId {\n return `${groupRootId}:${id}`;\n}\n\n/**\n * Convert a group root ID to the default group ID.\n *\n * @param groupRootId - The group root ID.\n * @returns The default group ID.\n */\nexport function toDefaultAccountGroupId(\n groupRootId: AccountGroupRootId,\n): AccountGroupId {\n return toAccountGroupId(groupRootId, DEFAULT_ACCOUNT_GROUP_UNIQUE_ID);\n}\n\nexport class AccountTreeController extends BaseController<\n typeof controllerName,\n AccountTreeControllerState,\n AccountTreeControllerMessenger\n> {\n readonly #reverse: Map<AccountId, AccountReverseMapping>;\n\n readonly #rules: AccountGroupRootRuleFunction[];\n\n /**\n * Constructor for AccountTreeController.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger object.\n * @param options.state - Initial state to set on this controller\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AccountTreeControllerMessenger;\n state?: Partial<AccountTreeControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: accountTreeControllerMetadata,\n state: {\n ...getDefaultAccountTreeControllerState(),\n ...state,\n },\n });\n\n // Reverse map to allow fast node access from an account ID.\n this.#reverse = new Map();\n\n // Rules to apply to construct the wallets tree.\n this.#rules = [\n // 1. We group by entropy-source\n (account: InternalAccount) => this.#matchGroupByEntropySource(account),\n // 2. We group by Snap ID\n (account: InternalAccount) => this.#matchGroupBySnapId(account),\n // 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)\n (account: InternalAccount) => this.#matchGroupByKeyringType(account),\n ];\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account) => {\n this.#handleAccountAdded(account);\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (accountId) => {\n this.#handleAccountRemoved(accountId);\n },\n );\n }\n\n init() {\n const roots = {};\n\n // For now, we always re-compute all wallets, we do not re-use the existing state.\n for (const account of this.#listAccounts()) {\n this.#insert(roots, account);\n }\n\n this.update((state) => {\n state.accountTrees.roots = roots;\n });\n }\n\n #handleAccountAdded(account: InternalAccount) {\n this.update((state) => {\n this.#insert(state.accountTrees.roots, account);\n });\n }\n\n #handleAccountRemoved(accountId: AccountId) {\n const found = this.#reverse.get(accountId);\n\n if (found) {\n const { walletId, groupId } = found;\n this.update((state) => {\n const { accounts } = state.accountTrees.roots[walletId].groups[groupId];\n\n const index = accounts.indexOf(accountId);\n if (index !== -1) {\n accounts.splice(index, 1);\n }\n });\n }\n }\n\n #hasKeyringType(account: InternalAccount, type: KeyringTypes): boolean {\n return account.metadata.keyring.type === (type as string);\n }\n\n #matchGroupByEntropySource(\n account: InternalAccount,\n ): AccountTreeRuleMatch | undefined {\n let entropySource: string | undefined;\n\n if (this.#hasKeyringType(account, KeyringTypes.hd)) {\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found an HD account with no entropy source: account won't be associated to its wallet\",\n );\n return undefined;\n }\n\n entropySource = account.options.entropySource as string;\n }\n\n // TODO: For now, we're not checking if the Snap is a preinstalled one, and we probably should...\n if (\n this.#hasKeyringType(account, KeyringTypes.snap) &&\n account.metadata.snap?.enabled\n ) {\n // Not all Snaps have an entropy-source and options are not typed yet, so we have to check manually here.\n if (account.options.entropySource) {\n // We blindly trust the `entropySource` for now, but it could be wrong since it comes from a Snap.\n entropySource = account.options.entropySource as string;\n }\n }\n\n if (!entropySource) {\n return undefined;\n }\n\n // We check if we can get the name for that entropy source, if not this means this entropy does not match\n // any HD keyrings, thus, is invalid (this account will be grouped by another rule).\n const entropySourceName = this.#getEntropySourceName(entropySource);\n if (!entropySourceName) {\n console.warn(\n '! Tried to name a wallet using an unknown entropy, this should not be possible.',\n );\n return undefined;\n }\n\n return {\n category: AccountGroupRootCategory.Entropy,\n id: toAccountGroupRootId(AccountGroupRootCategory.Entropy, entropySource),\n name: entropySourceName,\n };\n }\n\n #matchGroupBySnapId(\n account: InternalAccount,\n ): AccountTreeRuleMatch | undefined {\n if (\n this.#hasKeyringType(account, KeyringTypes.snap) &&\n account.metadata.snap &&\n account.metadata.snap.enabled\n ) {\n const { id } = account.metadata.snap;\n\n return {\n category: AccountGroupRootCategory.Snap,\n id: toAccountGroupRootId(AccountGroupRootCategory.Snap, id),\n name: this.#getSnapName(id as SnapId),\n };\n }\n\n return undefined;\n }\n\n #matchGroupByKeyringType(\n account: InternalAccount,\n ): AccountTreeRuleMatch | undefined {\n const { type } = account.metadata.keyring;\n\n return {\n category: AccountGroupRootCategory.Keyring,\n id: toAccountGroupRootId(AccountGroupRootCategory.Keyring, type),\n name: getAccountGroupRootNameFromKeyringType(type as KeyringTypes),\n };\n }\n\n #getSnapName(snapId: SnapId): string {\n const snap = this.messagingSystem.call('SnapController:get', snapId);\n const snapName = snap\n ? // TODO: Handle localization here, but that's a \"client thing\", so we don't have a `core` controller\n // to refer too.\n snap.manifest.proposedName\n : stripSnapPrefix(snapId);\n\n return `Snap: ${snapName}`;\n }\n\n #getEntropySourceName(entropySource: string): string | undefined {\n const { keyrings } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n\n const index = keyrings\n .filter((keyring) => keyring.type === (KeyringTypes.hd as string))\n .findIndex((keyring) => keyring.metadata.id === entropySource);\n\n if (index === -1) {\n return undefined;\n }\n\n return `Wallet ${index + 1}`; // Use human indexing.\n }\n\n #insert(\n roots: { [accountGroupRootId: AccountGroupRootId]: AccountGroupRoot },\n account: InternalAccount,\n ) {\n for (const rule of this.#rules) {\n const match = rule(account);\n\n if (!match) {\n // No match for that rule, we go to the next one.\n continue;\n }\n\n const walletId = match.id;\n const walletName = match.name;\n const groupId = toDefaultAccountGroupId(walletId); // Use a single-group for now until multichain accounts is supported.\n const groupName = DEFAULT_ACCOUNT_GROUP_NAME;\n\n if (!roots[walletId]) {\n roots[walletId] = {\n id: walletId,\n groups: {\n [groupId]: {\n id: groupId,\n accounts: [],\n metadata: { name: groupName },\n },\n },\n metadata: {\n name: walletName,\n },\n };\n }\n roots[walletId].groups[groupId].accounts.push(account.id);\n\n // Update the reverse mapping for this account.\n this.#reverse.set(account.id, {\n walletId,\n groupId,\n });\n\n return;\n }\n }\n\n #listAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n ) as InternalAccount[];\n }\n}\n"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { AccountId, AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction } from "@metamask/accounts-controller";
|
|
2
|
+
import { type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger, BaseController } from "@metamask/base-controller";
|
|
3
|
+
import type { KeyringControllerGetStateAction } from "@metamask/keyring-controller";
|
|
4
|
+
import type { GetSnap as SnapControllerGetSnap } from "@metamask/snaps-controllers";
|
|
5
|
+
declare const controllerName = "AccountTreeController";
|
|
6
|
+
export declare enum AccountGroupRootCategory {
|
|
7
|
+
Entropy = "entropy",
|
|
8
|
+
Snap = "snap",
|
|
9
|
+
Keyring = "keyring",
|
|
10
|
+
Default = "default"
|
|
11
|
+
}
|
|
12
|
+
export type AccountGroupRootId = `${AccountGroupRootCategory}:${string}`;
|
|
13
|
+
export type AccountGroupId = `${AccountGroupRootId}:${string}`;
|
|
14
|
+
type Metadata = {
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
export type AccountGroupRootMetadata = Metadata;
|
|
18
|
+
export type AccountGroupMetadata = Metadata;
|
|
19
|
+
export type AccountGroup = {
|
|
20
|
+
id: AccountGroupId;
|
|
21
|
+
accounts: AccountId[];
|
|
22
|
+
metadata: AccountGroupMetadata;
|
|
23
|
+
};
|
|
24
|
+
export type AccountGroupRoot = {
|
|
25
|
+
id: AccountGroupRootId;
|
|
26
|
+
groups: {
|
|
27
|
+
[accountGroup: AccountGroupId]: AccountGroup;
|
|
28
|
+
};
|
|
29
|
+
metadata: AccountGroupMetadata;
|
|
30
|
+
};
|
|
31
|
+
export type AccountTreeControllerState = {
|
|
32
|
+
accountTrees: {
|
|
33
|
+
roots: {
|
|
34
|
+
[accountGroupRoot: AccountGroupRootId]: AccountGroupRoot;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export type AccountTreeControllerGetStateAction = ControllerGetStateAction<typeof controllerName, AccountTreeControllerState>;
|
|
39
|
+
export type AllowedActions = AccountsControllerListMultichainAccountsAction | KeyringControllerGetStateAction | SnapControllerGetSnap;
|
|
40
|
+
export type AccountTreeControllerActions = never;
|
|
41
|
+
export type AccountTreeControllerChangeEvent = ControllerStateChangeEvent<typeof controllerName, AccountTreeControllerState>;
|
|
42
|
+
export type AllowedEvents = AccountsControllerAccountAddedEvent | AccountsControllerAccountRemovedEvent;
|
|
43
|
+
export type AccountTreeControllerEvents = never;
|
|
44
|
+
export type AccountTreeControllerMessenger = RestrictedMessenger<typeof controllerName, AccountTreeControllerActions | AllowedActions, AccountTreeControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
|
|
45
|
+
/**
|
|
46
|
+
* Gets default state of the `AccountTreeController`.
|
|
47
|
+
*
|
|
48
|
+
* @returns The default state of the `AccountTreeController`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getDefaultAccountTreeControllerState(): AccountTreeControllerState;
|
|
51
|
+
export declare const DEFAULT_ACCOUNT_GROUP_UNIQUE_ID: string;
|
|
52
|
+
export declare const DEFAULT_ACCOUNT_GROUP_NAME: string;
|
|
53
|
+
/**
|
|
54
|
+
* Convert a unique ID to a group root ID for a given category.
|
|
55
|
+
*
|
|
56
|
+
* @param category - The category of the account group root.
|
|
57
|
+
* @param id - The unique ID.
|
|
58
|
+
* @returns The group root ID.
|
|
59
|
+
*/
|
|
60
|
+
export declare function toAccountGroupRootId(category: AccountGroupRootCategory, id: string): AccountGroupRootId;
|
|
61
|
+
/**
|
|
62
|
+
* Convert a group root ID and a unique ID to a group ID.
|
|
63
|
+
*
|
|
64
|
+
* @param groupRootId - The group root ID.
|
|
65
|
+
* @param id - The unique ID.
|
|
66
|
+
* @returns The group ID.
|
|
67
|
+
*/
|
|
68
|
+
export declare function toAccountGroupId(groupRootId: AccountGroupRootId, id: string): AccountGroupId;
|
|
69
|
+
/**
|
|
70
|
+
* Convert a group root ID to the default group ID.
|
|
71
|
+
*
|
|
72
|
+
* @param groupRootId - The group root ID.
|
|
73
|
+
* @returns The default group ID.
|
|
74
|
+
*/
|
|
75
|
+
export declare function toDefaultAccountGroupId(groupRootId: AccountGroupRootId): AccountGroupId;
|
|
76
|
+
export declare class AccountTreeController extends BaseController<typeof controllerName, AccountTreeControllerState, AccountTreeControllerMessenger> {
|
|
77
|
+
#private;
|
|
78
|
+
/**
|
|
79
|
+
* Constructor for AccountTreeController.
|
|
80
|
+
*
|
|
81
|
+
* @param options - The controller options.
|
|
82
|
+
* @param options.messenger - The messenger object.
|
|
83
|
+
* @param options.state - Initial state to set on this controller
|
|
84
|
+
*/
|
|
85
|
+
constructor({ messenger, state, }: {
|
|
86
|
+
messenger: AccountTreeControllerMessenger;
|
|
87
|
+
state?: Partial<AccountTreeControllerState>;
|
|
88
|
+
});
|
|
89
|
+
init(): void;
|
|
90
|
+
}
|
|
91
|
+
export {};
|
|
92
|
+
//# sourceMappingURL=AccountTreeController.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountTreeController.d.cts","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { AccountId, AccountsControllerAccountAddedEvent, AccountsControllerAccountRemovedEvent, AccountsControllerListMultichainAccountsAction } from "@metamask/accounts-controller";
|
|
2
|
+
import { type ControllerGetStateAction, type ControllerStateChangeEvent, type RestrictedMessenger, BaseController } from "@metamask/base-controller";
|
|
3
|
+
import type { KeyringControllerGetStateAction } from "@metamask/keyring-controller";
|
|
4
|
+
import type { GetSnap as SnapControllerGetSnap } from "@metamask/snaps-controllers";
|
|
5
|
+
declare const controllerName = "AccountTreeController";
|
|
6
|
+
export declare enum AccountGroupRootCategory {
|
|
7
|
+
Entropy = "entropy",
|
|
8
|
+
Snap = "snap",
|
|
9
|
+
Keyring = "keyring",
|
|
10
|
+
Default = "default"
|
|
11
|
+
}
|
|
12
|
+
export type AccountGroupRootId = `${AccountGroupRootCategory}:${string}`;
|
|
13
|
+
export type AccountGroupId = `${AccountGroupRootId}:${string}`;
|
|
14
|
+
type Metadata = {
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
export type AccountGroupRootMetadata = Metadata;
|
|
18
|
+
export type AccountGroupMetadata = Metadata;
|
|
19
|
+
export type AccountGroup = {
|
|
20
|
+
id: AccountGroupId;
|
|
21
|
+
accounts: AccountId[];
|
|
22
|
+
metadata: AccountGroupMetadata;
|
|
23
|
+
};
|
|
24
|
+
export type AccountGroupRoot = {
|
|
25
|
+
id: AccountGroupRootId;
|
|
26
|
+
groups: {
|
|
27
|
+
[accountGroup: AccountGroupId]: AccountGroup;
|
|
28
|
+
};
|
|
29
|
+
metadata: AccountGroupMetadata;
|
|
30
|
+
};
|
|
31
|
+
export type AccountTreeControllerState = {
|
|
32
|
+
accountTrees: {
|
|
33
|
+
roots: {
|
|
34
|
+
[accountGroupRoot: AccountGroupRootId]: AccountGroupRoot;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export type AccountTreeControllerGetStateAction = ControllerGetStateAction<typeof controllerName, AccountTreeControllerState>;
|
|
39
|
+
export type AllowedActions = AccountsControllerListMultichainAccountsAction | KeyringControllerGetStateAction | SnapControllerGetSnap;
|
|
40
|
+
export type AccountTreeControllerActions = never;
|
|
41
|
+
export type AccountTreeControllerChangeEvent = ControllerStateChangeEvent<typeof controllerName, AccountTreeControllerState>;
|
|
42
|
+
export type AllowedEvents = AccountsControllerAccountAddedEvent | AccountsControllerAccountRemovedEvent;
|
|
43
|
+
export type AccountTreeControllerEvents = never;
|
|
44
|
+
export type AccountTreeControllerMessenger = RestrictedMessenger<typeof controllerName, AccountTreeControllerActions | AllowedActions, AccountTreeControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
|
|
45
|
+
/**
|
|
46
|
+
* Gets default state of the `AccountTreeController`.
|
|
47
|
+
*
|
|
48
|
+
* @returns The default state of the `AccountTreeController`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getDefaultAccountTreeControllerState(): AccountTreeControllerState;
|
|
51
|
+
export declare const DEFAULT_ACCOUNT_GROUP_UNIQUE_ID: string;
|
|
52
|
+
export declare const DEFAULT_ACCOUNT_GROUP_NAME: string;
|
|
53
|
+
/**
|
|
54
|
+
* Convert a unique ID to a group root ID for a given category.
|
|
55
|
+
*
|
|
56
|
+
* @param category - The category of the account group root.
|
|
57
|
+
* @param id - The unique ID.
|
|
58
|
+
* @returns The group root ID.
|
|
59
|
+
*/
|
|
60
|
+
export declare function toAccountGroupRootId(category: AccountGroupRootCategory, id: string): AccountGroupRootId;
|
|
61
|
+
/**
|
|
62
|
+
* Convert a group root ID and a unique ID to a group ID.
|
|
63
|
+
*
|
|
64
|
+
* @param groupRootId - The group root ID.
|
|
65
|
+
* @param id - The unique ID.
|
|
66
|
+
* @returns The group ID.
|
|
67
|
+
*/
|
|
68
|
+
export declare function toAccountGroupId(groupRootId: AccountGroupRootId, id: string): AccountGroupId;
|
|
69
|
+
/**
|
|
70
|
+
* Convert a group root ID to the default group ID.
|
|
71
|
+
*
|
|
72
|
+
* @param groupRootId - The group root ID.
|
|
73
|
+
* @returns The default group ID.
|
|
74
|
+
*/
|
|
75
|
+
export declare function toDefaultAccountGroupId(groupRootId: AccountGroupRootId): AccountGroupId;
|
|
76
|
+
export declare class AccountTreeController extends BaseController<typeof controllerName, AccountTreeControllerState, AccountTreeControllerMessenger> {
|
|
77
|
+
#private;
|
|
78
|
+
/**
|
|
79
|
+
* Constructor for AccountTreeController.
|
|
80
|
+
*
|
|
81
|
+
* @param options - The controller options.
|
|
82
|
+
* @param options.messenger - The messenger object.
|
|
83
|
+
* @param options.state - Initial state to set on this controller
|
|
84
|
+
*/
|
|
85
|
+
constructor({ messenger, state, }: {
|
|
86
|
+
messenger: AccountTreeControllerMessenger;
|
|
87
|
+
state?: Partial<AccountTreeControllerState>;
|
|
88
|
+
});
|
|
89
|
+
init(): void;
|
|
90
|
+
}
|
|
91
|
+
export {};
|
|
92
|
+
//# sourceMappingURL=AccountTreeController.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountTreeController.d.mts","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,mCAAmC,EACnC,qCAAqC,EACrC,8CAA8C,EAC/C,sCAAsC;AAEvC,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,cAAc,EACf,kCAAkC;AACnC,OAAO,KAAK,EAAE,+BAA+B,EAAE,qCAAqC;AAGpF,OAAO,KAAK,EAAE,OAAO,IAAI,qBAAqB,EAAE,oCAAoC;AAMpF,QAAA,MAAM,cAAc,0BAA0B,CAAC;AAE/C,oBAAY,wBAAwB;IAClC,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAiBD,MAAM,MAAM,kBAAkB,GAAG,GAAG,wBAAwB,IAAI,MAAM,EAAE,CAAC;AACzE,MAAM,MAAM,cAAc,GAAG,GAAG,kBAAkB,IAAI,MAAM,EAAE,CAAC;AAG/D,KAAK,QAAQ,GAAG;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;AAEhD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAE5C,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,cAAc,CAAC;IAEnB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,QAAQ,EAAE,oBAAoB,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,kBAAkB,CAAC;IAEvB,MAAM,EAAE;QACN,CAAC,YAAY,EAAE,cAAc,GAAG,YAAY,CAAC;KAC9C,CAAC;IACF,QAAQ,EAAE,oBAAoB,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,YAAY,EAAE;QACZ,KAAK,EAAE;YAEL,CAAC,gBAAgB,EAAE,kBAAkB,GAAG,gBAAgB,CAAC;SAC1D,CAAC;KACH,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GACtB,8CAA8C,GAC9C,+BAA+B,GAC/B,qBAAqB,CAAC;AAE1B,MAAM,MAAM,4BAA4B,GAAG,KAAK,CAAC;AAEjD,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GACrB,mCAAmC,GACnC,qCAAqC,CAAC;AAE1C,MAAM,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEhD,MAAM,MAAM,8BAA8B,GAAG,mBAAmB,CAC9D,OAAO,cAAc,EACrB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,EAC3C,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAUF;;;;GAIG;AACH,wBAAgB,oCAAoC,IAAI,0BAA0B,CAMjF;AAGD,eAAO,MAAM,+BAA+B,EAAE,MAAkB,CAAC;AACjE,eAAO,MAAM,0BAA0B,EAAE,MAAkB,CAAC;AAE5D;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,wBAAwB,EAClC,EAAE,EAAE,MAAM,GACT,kBAAkB,CAEpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,kBAAkB,EAC/B,EAAE,EAAE,MAAM,GACT,cAAc,CAEhB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,kBAAkB,GAC9B,cAAc,CAEhB;AAED,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;;IAKC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;KAC7C;IAuCD,IAAI;CAqML"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
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");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _AccountTreeController_instances, _AccountTreeController_reverse, _AccountTreeController_rules, _AccountTreeController_handleAccountAdded, _AccountTreeController_handleAccountRemoved, _AccountTreeController_hasKeyringType, _AccountTreeController_matchGroupByEntropySource, _AccountTreeController_matchGroupBySnapId, _AccountTreeController_matchGroupByKeyringType, _AccountTreeController_getSnapName, _AccountTreeController_getEntropySourceName, _AccountTreeController_insert, _AccountTreeController_listAccounts;
|
|
13
|
+
import { BaseController } from "@metamask/base-controller";
|
|
14
|
+
import { KeyringTypes } from "@metamask/keyring-controller";
|
|
15
|
+
import { stripSnapPrefix } from "@metamask/snaps-utils";
|
|
16
|
+
import { getAccountGroupRootNameFromKeyringType } from "./names.mjs";
|
|
17
|
+
const controllerName = 'AccountTreeController';
|
|
18
|
+
export var AccountGroupRootCategory;
|
|
19
|
+
(function (AccountGroupRootCategory) {
|
|
20
|
+
AccountGroupRootCategory["Entropy"] = "entropy";
|
|
21
|
+
AccountGroupRootCategory["Snap"] = "snap";
|
|
22
|
+
AccountGroupRootCategory["Keyring"] = "keyring";
|
|
23
|
+
AccountGroupRootCategory["Default"] = "default";
|
|
24
|
+
})(AccountGroupRootCategory || (AccountGroupRootCategory = {}));
|
|
25
|
+
const accountTreeControllerMetadata = {
|
|
26
|
+
accountTrees: {
|
|
27
|
+
persist: false,
|
|
28
|
+
anonymous: false,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Gets default state of the `AccountTreeController`.
|
|
33
|
+
*
|
|
34
|
+
* @returns The default state of the `AccountTreeController`.
|
|
35
|
+
*/
|
|
36
|
+
export function getDefaultAccountTreeControllerState() {
|
|
37
|
+
return {
|
|
38
|
+
accountTrees: {
|
|
39
|
+
roots: {},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// TODO: For now we use this for the 2nd-level of the tree until we implements proper multichain accounts.
|
|
44
|
+
export const DEFAULT_ACCOUNT_GROUP_UNIQUE_ID = 'default'; // This might need to be re-evaluated based on new structure
|
|
45
|
+
export const DEFAULT_ACCOUNT_GROUP_NAME = 'Default';
|
|
46
|
+
/**
|
|
47
|
+
* Convert a unique ID to a group root ID for a given category.
|
|
48
|
+
*
|
|
49
|
+
* @param category - The category of the account group root.
|
|
50
|
+
* @param id - The unique ID.
|
|
51
|
+
* @returns The group root ID.
|
|
52
|
+
*/
|
|
53
|
+
export function toAccountGroupRootId(category, id) {
|
|
54
|
+
return `${category}:${id}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Convert a group root ID and a unique ID to a group ID.
|
|
58
|
+
*
|
|
59
|
+
* @param groupRootId - The group root ID.
|
|
60
|
+
* @param id - The unique ID.
|
|
61
|
+
* @returns The group ID.
|
|
62
|
+
*/
|
|
63
|
+
export function toAccountGroupId(groupRootId, id) {
|
|
64
|
+
return `${groupRootId}:${id}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Convert a group root ID to the default group ID.
|
|
68
|
+
*
|
|
69
|
+
* @param groupRootId - The group root ID.
|
|
70
|
+
* @returns The default group ID.
|
|
71
|
+
*/
|
|
72
|
+
export function toDefaultAccountGroupId(groupRootId) {
|
|
73
|
+
return toAccountGroupId(groupRootId, DEFAULT_ACCOUNT_GROUP_UNIQUE_ID);
|
|
74
|
+
}
|
|
75
|
+
export class AccountTreeController extends BaseController {
|
|
76
|
+
/**
|
|
77
|
+
* Constructor for AccountTreeController.
|
|
78
|
+
*
|
|
79
|
+
* @param options - The controller options.
|
|
80
|
+
* @param options.messenger - The messenger object.
|
|
81
|
+
* @param options.state - Initial state to set on this controller
|
|
82
|
+
*/
|
|
83
|
+
constructor({ messenger, state, }) {
|
|
84
|
+
super({
|
|
85
|
+
messenger,
|
|
86
|
+
name: controllerName,
|
|
87
|
+
metadata: accountTreeControllerMetadata,
|
|
88
|
+
state: {
|
|
89
|
+
...getDefaultAccountTreeControllerState(),
|
|
90
|
+
...state,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
_AccountTreeController_instances.add(this);
|
|
94
|
+
_AccountTreeController_reverse.set(this, void 0);
|
|
95
|
+
_AccountTreeController_rules.set(this, void 0);
|
|
96
|
+
// Reverse map to allow fast node access from an account ID.
|
|
97
|
+
__classPrivateFieldSet(this, _AccountTreeController_reverse, new Map(), "f");
|
|
98
|
+
// Rules to apply to construct the wallets tree.
|
|
99
|
+
__classPrivateFieldSet(this, _AccountTreeController_rules, [
|
|
100
|
+
// 1. We group by entropy-source
|
|
101
|
+
(account) => __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_matchGroupByEntropySource).call(this, account),
|
|
102
|
+
// 2. We group by Snap ID
|
|
103
|
+
(account) => __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_matchGroupBySnapId).call(this, account),
|
|
104
|
+
// 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)
|
|
105
|
+
(account) => __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_matchGroupByKeyringType).call(this, account),
|
|
106
|
+
], "f");
|
|
107
|
+
this.messagingSystem.subscribe('AccountsController:accountAdded', (account) => {
|
|
108
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleAccountAdded).call(this, account);
|
|
109
|
+
});
|
|
110
|
+
this.messagingSystem.subscribe('AccountsController:accountRemoved', (accountId) => {
|
|
111
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_handleAccountRemoved).call(this, accountId);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
init() {
|
|
115
|
+
const roots = {};
|
|
116
|
+
// For now, we always re-compute all wallets, we do not re-use the existing state.
|
|
117
|
+
for (const account of __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_listAccounts).call(this)) {
|
|
118
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, roots, account);
|
|
119
|
+
}
|
|
120
|
+
this.update((state) => {
|
|
121
|
+
state.accountTrees.roots = roots;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
_AccountTreeController_reverse = new WeakMap(), _AccountTreeController_rules = new WeakMap(), _AccountTreeController_instances = new WeakSet(), _AccountTreeController_handleAccountAdded = function _AccountTreeController_handleAccountAdded(account) {
|
|
126
|
+
this.update((state) => {
|
|
127
|
+
__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_insert).call(this, state.accountTrees.roots, account);
|
|
128
|
+
});
|
|
129
|
+
}, _AccountTreeController_handleAccountRemoved = function _AccountTreeController_handleAccountRemoved(accountId) {
|
|
130
|
+
const found = __classPrivateFieldGet(this, _AccountTreeController_reverse, "f").get(accountId);
|
|
131
|
+
if (found) {
|
|
132
|
+
const { walletId, groupId } = found;
|
|
133
|
+
this.update((state) => {
|
|
134
|
+
const { accounts } = state.accountTrees.roots[walletId].groups[groupId];
|
|
135
|
+
const index = accounts.indexOf(accountId);
|
|
136
|
+
if (index !== -1) {
|
|
137
|
+
accounts.splice(index, 1);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}, _AccountTreeController_hasKeyringType = function _AccountTreeController_hasKeyringType(account, type) {
|
|
142
|
+
return account.metadata.keyring.type === type;
|
|
143
|
+
}, _AccountTreeController_matchGroupByEntropySource = function _AccountTreeController_matchGroupByEntropySource(account) {
|
|
144
|
+
let entropySource;
|
|
145
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasKeyringType).call(this, account, KeyringTypes.hd)) {
|
|
146
|
+
// TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?
|
|
147
|
+
if (!account.options.entropySource) {
|
|
148
|
+
console.warn("! Found an HD account with no entropy source: account won't be associated to its wallet");
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
entropySource = account.options.entropySource;
|
|
152
|
+
}
|
|
153
|
+
// TODO: For now, we're not checking if the Snap is a preinstalled one, and we probably should...
|
|
154
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasKeyringType).call(this, account, KeyringTypes.snap) &&
|
|
155
|
+
account.metadata.snap?.enabled) {
|
|
156
|
+
// Not all Snaps have an entropy-source and options are not typed yet, so we have to check manually here.
|
|
157
|
+
if (account.options.entropySource) {
|
|
158
|
+
// We blindly trust the `entropySource` for now, but it could be wrong since it comes from a Snap.
|
|
159
|
+
entropySource = account.options.entropySource;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!entropySource) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
// We check if we can get the name for that entropy source, if not this means this entropy does not match
|
|
166
|
+
// any HD keyrings, thus, is invalid (this account will be grouped by another rule).
|
|
167
|
+
const entropySourceName = __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getEntropySourceName).call(this, entropySource);
|
|
168
|
+
if (!entropySourceName) {
|
|
169
|
+
console.warn('! Tried to name a wallet using an unknown entropy, this should not be possible.');
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
category: AccountGroupRootCategory.Entropy,
|
|
174
|
+
id: toAccountGroupRootId(AccountGroupRootCategory.Entropy, entropySource),
|
|
175
|
+
name: entropySourceName,
|
|
176
|
+
};
|
|
177
|
+
}, _AccountTreeController_matchGroupBySnapId = function _AccountTreeController_matchGroupBySnapId(account) {
|
|
178
|
+
if (__classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_hasKeyringType).call(this, account, KeyringTypes.snap) &&
|
|
179
|
+
account.metadata.snap &&
|
|
180
|
+
account.metadata.snap.enabled) {
|
|
181
|
+
const { id } = account.metadata.snap;
|
|
182
|
+
return {
|
|
183
|
+
category: AccountGroupRootCategory.Snap,
|
|
184
|
+
id: toAccountGroupRootId(AccountGroupRootCategory.Snap, id),
|
|
185
|
+
name: __classPrivateFieldGet(this, _AccountTreeController_instances, "m", _AccountTreeController_getSnapName).call(this, id),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}, _AccountTreeController_matchGroupByKeyringType = function _AccountTreeController_matchGroupByKeyringType(account) {
|
|
190
|
+
const { type } = account.metadata.keyring;
|
|
191
|
+
return {
|
|
192
|
+
category: AccountGroupRootCategory.Keyring,
|
|
193
|
+
id: toAccountGroupRootId(AccountGroupRootCategory.Keyring, type),
|
|
194
|
+
name: getAccountGroupRootNameFromKeyringType(type),
|
|
195
|
+
};
|
|
196
|
+
}, _AccountTreeController_getSnapName = function _AccountTreeController_getSnapName(snapId) {
|
|
197
|
+
const snap = this.messagingSystem.call('SnapController:get', snapId);
|
|
198
|
+
const snapName = snap
|
|
199
|
+
? // TODO: Handle localization here, but that's a "client thing", so we don't have a `core` controller
|
|
200
|
+
// to refer too.
|
|
201
|
+
snap.manifest.proposedName
|
|
202
|
+
: stripSnapPrefix(snapId);
|
|
203
|
+
return `Snap: ${snapName}`;
|
|
204
|
+
}, _AccountTreeController_getEntropySourceName = function _AccountTreeController_getEntropySourceName(entropySource) {
|
|
205
|
+
const { keyrings } = this.messagingSystem.call('KeyringController:getState');
|
|
206
|
+
const index = keyrings
|
|
207
|
+
.filter((keyring) => keyring.type === KeyringTypes.hd)
|
|
208
|
+
.findIndex((keyring) => keyring.metadata.id === entropySource);
|
|
209
|
+
if (index === -1) {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
return `Wallet ${index + 1}`; // Use human indexing.
|
|
213
|
+
}, _AccountTreeController_insert = function _AccountTreeController_insert(roots, account) {
|
|
214
|
+
for (const rule of __classPrivateFieldGet(this, _AccountTreeController_rules, "f")) {
|
|
215
|
+
const match = rule(account);
|
|
216
|
+
if (!match) {
|
|
217
|
+
// No match for that rule, we go to the next one.
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const walletId = match.id;
|
|
221
|
+
const walletName = match.name;
|
|
222
|
+
const groupId = toDefaultAccountGroupId(walletId); // Use a single-group for now until multichain accounts is supported.
|
|
223
|
+
const groupName = DEFAULT_ACCOUNT_GROUP_NAME;
|
|
224
|
+
if (!roots[walletId]) {
|
|
225
|
+
roots[walletId] = {
|
|
226
|
+
id: walletId,
|
|
227
|
+
groups: {
|
|
228
|
+
[groupId]: {
|
|
229
|
+
id: groupId,
|
|
230
|
+
accounts: [],
|
|
231
|
+
metadata: { name: groupName },
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
metadata: {
|
|
235
|
+
name: walletName,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
roots[walletId].groups[groupId].accounts.push(account.id);
|
|
240
|
+
// Update the reverse mapping for this account.
|
|
241
|
+
__classPrivateFieldGet(this, _AccountTreeController_reverse, "f").set(account.id, {
|
|
242
|
+
walletId,
|
|
243
|
+
groupId,
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}, _AccountTreeController_listAccounts = function _AccountTreeController_listAccounts() {
|
|
248
|
+
return this.messagingSystem.call('AccountsController:listMultichainAccounts');
|
|
249
|
+
};
|
|
250
|
+
//# sourceMappingURL=AccountTreeController.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccountTreeController.mjs","sourceRoot":"","sources":["../src/AccountTreeController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountId,\n AccountsControllerAccountAddedEvent,\n AccountsControllerAccountRemovedEvent,\n AccountsControllerListMultichainAccountsAction,\n} from '@metamask/accounts-controller';\nimport type { StateMetadata } from '@metamask/base-controller';\nimport {\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n type RestrictedMessenger,\n BaseController,\n} from '@metamask/base-controller';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { GetSnap as SnapControllerGetSnap } from '@metamask/snaps-controllers';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport { stripSnapPrefix } from '@metamask/snaps-utils';\n\nimport { getAccountGroupRootNameFromKeyringType } from './names';\n\nconst controllerName = 'AccountTreeController';\n\nexport enum AccountGroupRootCategory {\n Entropy = 'entropy',\n Snap = 'snap',\n Keyring = 'keyring',\n Default = 'default', // TODO: Remove `default` once we have multichain accounts.\n}\n\ntype AccountTreeRuleMatch = {\n category: AccountGroupRootCategory;\n id: AccountGroupRootId;\n name: string;\n};\n\ntype AccountReverseMapping = {\n walletId: AccountGroupRootId;\n groupId: AccountGroupId;\n};\n\ntype AccountGroupRootRuleFunction = (\n account: InternalAccount,\n) => AccountTreeRuleMatch | undefined;\n\nexport type AccountGroupRootId = `${AccountGroupRootCategory}:${string}`;\nexport type AccountGroupId = `${AccountGroupRootId}:${string}`;\n\n// Do not export this one, we just use it to have a common type interface between group and wallet metadata.\ntype Metadata = {\n name: string;\n};\n\nexport type AccountGroupRootMetadata = Metadata;\n\nexport type AccountGroupMetadata = Metadata;\n\nexport type AccountGroup = {\n id: AccountGroupId;\n // Blockchain Accounts:\n accounts: AccountId[];\n metadata: AccountGroupMetadata;\n};\n\nexport type AccountGroupRoot = {\n id: AccountGroupRootId;\n // Account groups OR Multichain accounts (once available).\n groups: {\n [accountGroup: AccountGroupId]: AccountGroup;\n };\n metadata: AccountGroupMetadata; // Assuming Metadata is a defined type\n};\n\nexport type AccountTreeControllerState = {\n accountTrees: {\n roots: {\n // Wallets:\n [accountGroupRoot: AccountGroupRootId]: AccountGroupRoot;\n },\n };\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerListMultichainAccountsAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnap;\n\nexport type AccountTreeControllerActions = never;\n\nexport type AccountTreeControllerChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedEvents =\n | AccountsControllerAccountAddedEvent\n | AccountsControllerAccountRemovedEvent;\n\nexport type AccountTreeControllerEvents = never;\n\nexport type AccountTreeControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\nconst accountTreeControllerMetadata: StateMetadata<AccountTreeControllerState> =\n {\n accountTrees: {\n persist: false, // We do re-recompute this state everytime.\n anonymous: false,\n },\n };\n\n/**\n * Gets default state of the `AccountTreeController`.\n *\n * @returns The default state of the `AccountTreeController`.\n */\nexport function getDefaultAccountTreeControllerState(): AccountTreeControllerState {\n return {\n accountTrees: {\n roots: {},\n },\n };\n}\n\n// TODO: For now we use this for the 2nd-level of the tree until we implements proper multichain accounts.\nexport const DEFAULT_ACCOUNT_GROUP_UNIQUE_ID: string = 'default'; // This might need to be re-evaluated based on new structure\nexport const DEFAULT_ACCOUNT_GROUP_NAME: string = 'Default';\n\n/**\n * Convert a unique ID to a group root ID for a given category.\n *\n * @param category - The category of the account group root.\n * @param id - The unique ID.\n * @returns The group root ID.\n */\nexport function toAccountGroupRootId(\n category: AccountGroupRootCategory,\n id: string,\n): AccountGroupRootId {\n return `${category}:${id}`;\n}\n\n/**\n * Convert a group root ID and a unique ID to a group ID.\n *\n * @param groupRootId - The group root ID.\n * @param id - The unique ID.\n * @returns The group ID.\n */\nexport function toAccountGroupId(\n groupRootId: AccountGroupRootId,\n id: string,\n): AccountGroupId {\n return `${groupRootId}:${id}`;\n}\n\n/**\n * Convert a group root ID to the default group ID.\n *\n * @param groupRootId - The group root ID.\n * @returns The default group ID.\n */\nexport function toDefaultAccountGroupId(\n groupRootId: AccountGroupRootId,\n): AccountGroupId {\n return toAccountGroupId(groupRootId, DEFAULT_ACCOUNT_GROUP_UNIQUE_ID);\n}\n\nexport class AccountTreeController extends BaseController<\n typeof controllerName,\n AccountTreeControllerState,\n AccountTreeControllerMessenger\n> {\n readonly #reverse: Map<AccountId, AccountReverseMapping>;\n\n readonly #rules: AccountGroupRootRuleFunction[];\n\n /**\n * Constructor for AccountTreeController.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger object.\n * @param options.state - Initial state to set on this controller\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AccountTreeControllerMessenger;\n state?: Partial<AccountTreeControllerState>;\n }) {\n super({\n messenger,\n name: controllerName,\n metadata: accountTreeControllerMetadata,\n state: {\n ...getDefaultAccountTreeControllerState(),\n ...state,\n },\n });\n\n // Reverse map to allow fast node access from an account ID.\n this.#reverse = new Map();\n\n // Rules to apply to construct the wallets tree.\n this.#rules = [\n // 1. We group by entropy-source\n (account: InternalAccount) => this.#matchGroupByEntropySource(account),\n // 2. We group by Snap ID\n (account: InternalAccount) => this.#matchGroupBySnapId(account),\n // 3. We group by wallet type (this rule cannot fail and will group all non-matching accounts)\n (account: InternalAccount) => this.#matchGroupByKeyringType(account),\n ];\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountAdded',\n (account) => {\n this.#handleAccountAdded(account);\n },\n );\n\n this.messagingSystem.subscribe(\n 'AccountsController:accountRemoved',\n (accountId) => {\n this.#handleAccountRemoved(accountId);\n },\n );\n }\n\n init() {\n const roots = {};\n\n // For now, we always re-compute all wallets, we do not re-use the existing state.\n for (const account of this.#listAccounts()) {\n this.#insert(roots, account);\n }\n\n this.update((state) => {\n state.accountTrees.roots = roots;\n });\n }\n\n #handleAccountAdded(account: InternalAccount) {\n this.update((state) => {\n this.#insert(state.accountTrees.roots, account);\n });\n }\n\n #handleAccountRemoved(accountId: AccountId) {\n const found = this.#reverse.get(accountId);\n\n if (found) {\n const { walletId, groupId } = found;\n this.update((state) => {\n const { accounts } = state.accountTrees.roots[walletId].groups[groupId];\n\n const index = accounts.indexOf(accountId);\n if (index !== -1) {\n accounts.splice(index, 1);\n }\n });\n }\n }\n\n #hasKeyringType(account: InternalAccount, type: KeyringTypes): boolean {\n return account.metadata.keyring.type === (type as string);\n }\n\n #matchGroupByEntropySource(\n account: InternalAccount,\n ): AccountTreeRuleMatch | undefined {\n let entropySource: string | undefined;\n\n if (this.#hasKeyringType(account, KeyringTypes.hd)) {\n // TODO: Maybe use superstruct to validate the structure of HD account since they are not strongly-typed for now?\n if (!account.options.entropySource) {\n console.warn(\n \"! Found an HD account with no entropy source: account won't be associated to its wallet\",\n );\n return undefined;\n }\n\n entropySource = account.options.entropySource as string;\n }\n\n // TODO: For now, we're not checking if the Snap is a preinstalled one, and we probably should...\n if (\n this.#hasKeyringType(account, KeyringTypes.snap) &&\n account.metadata.snap?.enabled\n ) {\n // Not all Snaps have an entropy-source and options are not typed yet, so we have to check manually here.\n if (account.options.entropySource) {\n // We blindly trust the `entropySource` for now, but it could be wrong since it comes from a Snap.\n entropySource = account.options.entropySource as string;\n }\n }\n\n if (!entropySource) {\n return undefined;\n }\n\n // We check if we can get the name for that entropy source, if not this means this entropy does not match\n // any HD keyrings, thus, is invalid (this account will be grouped by another rule).\n const entropySourceName = this.#getEntropySourceName(entropySource);\n if (!entropySourceName) {\n console.warn(\n '! Tried to name a wallet using an unknown entropy, this should not be possible.',\n );\n return undefined;\n }\n\n return {\n category: AccountGroupRootCategory.Entropy,\n id: toAccountGroupRootId(AccountGroupRootCategory.Entropy, entropySource),\n name: entropySourceName,\n };\n }\n\n #matchGroupBySnapId(\n account: InternalAccount,\n ): AccountTreeRuleMatch | undefined {\n if (\n this.#hasKeyringType(account, KeyringTypes.snap) &&\n account.metadata.snap &&\n account.metadata.snap.enabled\n ) {\n const { id } = account.metadata.snap;\n\n return {\n category: AccountGroupRootCategory.Snap,\n id: toAccountGroupRootId(AccountGroupRootCategory.Snap, id),\n name: this.#getSnapName(id as SnapId),\n };\n }\n\n return undefined;\n }\n\n #matchGroupByKeyringType(\n account: InternalAccount,\n ): AccountTreeRuleMatch | undefined {\n const { type } = account.metadata.keyring;\n\n return {\n category: AccountGroupRootCategory.Keyring,\n id: toAccountGroupRootId(AccountGroupRootCategory.Keyring, type),\n name: getAccountGroupRootNameFromKeyringType(type as KeyringTypes),\n };\n }\n\n #getSnapName(snapId: SnapId): string {\n const snap = this.messagingSystem.call('SnapController:get', snapId);\n const snapName = snap\n ? // TODO: Handle localization here, but that's a \"client thing\", so we don't have a `core` controller\n // to refer too.\n snap.manifest.proposedName\n : stripSnapPrefix(snapId);\n\n return `Snap: ${snapName}`;\n }\n\n #getEntropySourceName(entropySource: string): string | undefined {\n const { keyrings } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n\n const index = keyrings\n .filter((keyring) => keyring.type === (KeyringTypes.hd as string))\n .findIndex((keyring) => keyring.metadata.id === entropySource);\n\n if (index === -1) {\n return undefined;\n }\n\n return `Wallet ${index + 1}`; // Use human indexing.\n }\n\n #insert(\n roots: { [accountGroupRootId: AccountGroupRootId]: AccountGroupRoot },\n account: InternalAccount,\n ) {\n for (const rule of this.#rules) {\n const match = rule(account);\n\n if (!match) {\n // No match for that rule, we go to the next one.\n continue;\n }\n\n const walletId = match.id;\n const walletName = match.name;\n const groupId = toDefaultAccountGroupId(walletId); // Use a single-group for now until multichain accounts is supported.\n const groupName = DEFAULT_ACCOUNT_GROUP_NAME;\n\n if (!roots[walletId]) {\n roots[walletId] = {\n id: walletId,\n groups: {\n [groupId]: {\n id: groupId,\n accounts: [],\n metadata: { name: groupName },\n },\n },\n metadata: {\n name: walletName,\n },\n };\n }\n roots[walletId].groups[groupId].accounts.push(account.id);\n\n // Update the reverse mapping for this account.\n this.#reverse.set(account.id, {\n walletId,\n groupId,\n });\n\n return;\n }\n }\n\n #listAccounts(): InternalAccount[] {\n return this.messagingSystem.call(\n 'AccountsController:listMultichainAccounts',\n ) as InternalAccount[];\n }\n}\n"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AccountTreeController = void 0;
|
|
4
|
+
var AccountTreeController_1 = require("./AccountTreeController.cjs");
|
|
5
|
+
Object.defineProperty(exports, "AccountTreeController", { enumerable: true, get: function () { return AccountTreeController_1.AccountTreeController; } });
|
|
6
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAcA,qEAAgE;AAAvD,8HAAA,qBAAqB,OAAA","sourcesContent":["export type {\n AccountGroupRoot as AccountTree,\n AccountGroupRootId as AccountTreeId,\n AccountGroupRootMetadata as AccountTreeMetadata,\n AccountTreeControllerState,\n AccountTreeControllerGetStateAction,\n AccountTreeControllerActions,\n AccountTreeControllerChangeEvent,\n AccountTreeControllerEvents,\n AccountTreeControllerMessenger,\n AccountGroup,\n AccountGroupId,\n AccountGroupMetadata,\n} from './AccountTreeController';\nexport { AccountTreeController } from './AccountTreeController';\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { AccountGroupRoot as AccountTree, AccountGroupRootId as AccountTreeId, AccountGroupRootMetadata as AccountTreeMetadata, AccountTreeControllerState, AccountTreeControllerGetStateAction, AccountTreeControllerActions, AccountTreeControllerChangeEvent, AccountTreeControllerEvents, AccountTreeControllerMessenger, AccountGroup, AccountGroupId, AccountGroupMetadata, } from "./AccountTreeController.cjs";
|
|
2
|
+
export { AccountTreeController } from "./AccountTreeController.cjs";
|
|
3
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,IAAI,WAAW,EAC/B,kBAAkB,IAAI,aAAa,EACnC,wBAAwB,IAAI,mBAAmB,EAC/C,0BAA0B,EAC1B,mCAAmC,EACnC,4BAA4B,EAC5B,gCAAgC,EAChC,2BAA2B,EAC3B,8BAA8B,EAC9B,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,oCAAgC;AACjC,OAAO,EAAE,qBAAqB,EAAE,oCAAgC"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { AccountGroupRoot as AccountTree, AccountGroupRootId as AccountTreeId, AccountGroupRootMetadata as AccountTreeMetadata, AccountTreeControllerState, AccountTreeControllerGetStateAction, AccountTreeControllerActions, AccountTreeControllerChangeEvent, AccountTreeControllerEvents, AccountTreeControllerMessenger, AccountGroup, AccountGroupId, AccountGroupMetadata, } from "./AccountTreeController.mjs";
|
|
2
|
+
export { AccountTreeController } from "./AccountTreeController.mjs";
|
|
3
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,IAAI,WAAW,EAC/B,kBAAkB,IAAI,aAAa,EACnC,wBAAwB,IAAI,mBAAmB,EAC/C,0BAA0B,EAC1B,mCAAmC,EACnC,4BAA4B,EAC5B,gCAAgC,EAChC,2BAA2B,EAC3B,8BAA8B,EAC9B,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,oCAAgC;AACjC,OAAO,EAAE,qBAAqB,EAAE,oCAAgC"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,qBAAqB,EAAE,oCAAgC","sourcesContent":["export type {\n AccountGroupRoot as AccountTree,\n AccountGroupRootId as AccountTreeId,\n AccountGroupRootMetadata as AccountTreeMetadata,\n AccountTreeControllerState,\n AccountTreeControllerGetStateAction,\n AccountTreeControllerActions,\n AccountTreeControllerChangeEvent,\n AccountTreeControllerEvents,\n AccountTreeControllerMessenger,\n AccountGroup,\n AccountGroupId,\n AccountGroupMetadata,\n} from './AccountTreeController';\nexport { AccountTreeController } from './AccountTreeController';\n"]}
|
package/dist/names.cjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAccountGroupRootNameFromKeyringType = void 0;
|
|
4
|
+
const keyring_controller_1 = require("@metamask/keyring-controller");
|
|
5
|
+
/**
|
|
6
|
+
* Get wallet name from a keyring type.
|
|
7
|
+
*
|
|
8
|
+
* @param type - Keyring's type.
|
|
9
|
+
* @returns Wallet name.
|
|
10
|
+
*/
|
|
11
|
+
function getAccountGroupRootNameFromKeyringType(type) {
|
|
12
|
+
switch (type) {
|
|
13
|
+
case keyring_controller_1.KeyringTypes.simple: {
|
|
14
|
+
return 'Private Keys';
|
|
15
|
+
}
|
|
16
|
+
case keyring_controller_1.KeyringTypes.hd: {
|
|
17
|
+
return 'HD Wallet';
|
|
18
|
+
}
|
|
19
|
+
case keyring_controller_1.KeyringTypes.trezor: {
|
|
20
|
+
return 'Trezor';
|
|
21
|
+
}
|
|
22
|
+
case keyring_controller_1.KeyringTypes.oneKey: {
|
|
23
|
+
return 'OneKey';
|
|
24
|
+
}
|
|
25
|
+
case keyring_controller_1.KeyringTypes.ledger: {
|
|
26
|
+
return 'Ledger';
|
|
27
|
+
}
|
|
28
|
+
case keyring_controller_1.KeyringTypes.lattice: {
|
|
29
|
+
return 'Lattice';
|
|
30
|
+
}
|
|
31
|
+
case keyring_controller_1.KeyringTypes.qr: {
|
|
32
|
+
return 'QR';
|
|
33
|
+
}
|
|
34
|
+
case keyring_controller_1.KeyringTypes.snap: {
|
|
35
|
+
return 'Snap Wallet';
|
|
36
|
+
}
|
|
37
|
+
default: {
|
|
38
|
+
return 'Unknown';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.getAccountGroupRootNameFromKeyringType = getAccountGroupRootNameFromKeyringType;
|
|
43
|
+
//# sourceMappingURL=names.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.cjs","sourceRoot":"","sources":["../src/names.ts"],"names":[],"mappings":";;;AAAA,qEAA4D;AAE5D;;;;;GAKG;AACH,SAAgB,sCAAsC,CAAC,IAAkB;IACvE,QAAQ,IAAI,EAAE;QACZ,KAAK,iCAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,cAAc,CAAC;SACvB;QACD,KAAK,iCAAY,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,WAAW,CAAC;SACpB;QACD,KAAK,iCAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,iCAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,iCAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,iCAAY,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,SAAS,CAAC;SAClB;QACD,KAAK,iCAAY,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,IAAI,CAAC;SACb;QACD,KAAK,iCAAY,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,aAAa,CAAC;SACtB;QACD,OAAO,CAAC,CAAC;YACP,OAAO,SAAS,CAAC;SAClB;KACF;AACH,CAAC;AA9BD,wFA8BC","sourcesContent":["import { KeyringTypes } from '@metamask/keyring-controller';\n\n/**\n * Get wallet name from a keyring type.\n *\n * @param type - Keyring's type.\n * @returns Wallet name.\n */\nexport function getAccountGroupRootNameFromKeyringType(type: KeyringTypes) {\n switch (type) {\n case KeyringTypes.simple: {\n return 'Private Keys';\n }\n case KeyringTypes.hd: {\n return 'HD Wallet';\n }\n case KeyringTypes.trezor: {\n return 'Trezor';\n }\n case KeyringTypes.oneKey: {\n return 'OneKey';\n }\n case KeyringTypes.ledger: {\n return 'Ledger';\n }\n case KeyringTypes.lattice: {\n return 'Lattice';\n }\n case KeyringTypes.qr: {\n return 'QR';\n }\n case KeyringTypes.snap: {\n return 'Snap Wallet';\n }\n default: {\n return 'Unknown';\n }\n }\n}\n"]}
|
package/dist/names.d.cts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { KeyringTypes } from "@metamask/keyring-controller";
|
|
2
|
+
/**
|
|
3
|
+
* Get wallet name from a keyring type.
|
|
4
|
+
*
|
|
5
|
+
* @param type - Keyring's type.
|
|
6
|
+
* @returns Wallet name.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getAccountGroupRootNameFromKeyringType(type: KeyringTypes): "Private Keys" | "HD Wallet" | "Trezor" | "OneKey" | "Ledger" | "Lattice" | "QR" | "Snap Wallet" | "Unknown";
|
|
9
|
+
//# sourceMappingURL=names.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.d.cts","sourceRoot":"","sources":["../src/names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,qCAAqC;AAE5D;;;;;GAKG;AACH,wBAAgB,sCAAsC,CAAC,IAAI,EAAE,YAAY,gHA8BxE"}
|
package/dist/names.d.mts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { KeyringTypes } from "@metamask/keyring-controller";
|
|
2
|
+
/**
|
|
3
|
+
* Get wallet name from a keyring type.
|
|
4
|
+
*
|
|
5
|
+
* @param type - Keyring's type.
|
|
6
|
+
* @returns Wallet name.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getAccountGroupRootNameFromKeyringType(type: KeyringTypes): "Private Keys" | "HD Wallet" | "Trezor" | "OneKey" | "Ledger" | "Lattice" | "QR" | "Snap Wallet" | "Unknown";
|
|
9
|
+
//# sourceMappingURL=names.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.d.mts","sourceRoot":"","sources":["../src/names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,qCAAqC;AAE5D;;;;;GAKG;AACH,wBAAgB,sCAAsC,CAAC,IAAI,EAAE,YAAY,gHA8BxE"}
|
package/dist/names.mjs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { KeyringTypes } from "@metamask/keyring-controller";
|
|
2
|
+
/**
|
|
3
|
+
* Get wallet name from a keyring type.
|
|
4
|
+
*
|
|
5
|
+
* @param type - Keyring's type.
|
|
6
|
+
* @returns Wallet name.
|
|
7
|
+
*/
|
|
8
|
+
export function getAccountGroupRootNameFromKeyringType(type) {
|
|
9
|
+
switch (type) {
|
|
10
|
+
case KeyringTypes.simple: {
|
|
11
|
+
return 'Private Keys';
|
|
12
|
+
}
|
|
13
|
+
case KeyringTypes.hd: {
|
|
14
|
+
return 'HD Wallet';
|
|
15
|
+
}
|
|
16
|
+
case KeyringTypes.trezor: {
|
|
17
|
+
return 'Trezor';
|
|
18
|
+
}
|
|
19
|
+
case KeyringTypes.oneKey: {
|
|
20
|
+
return 'OneKey';
|
|
21
|
+
}
|
|
22
|
+
case KeyringTypes.ledger: {
|
|
23
|
+
return 'Ledger';
|
|
24
|
+
}
|
|
25
|
+
case KeyringTypes.lattice: {
|
|
26
|
+
return 'Lattice';
|
|
27
|
+
}
|
|
28
|
+
case KeyringTypes.qr: {
|
|
29
|
+
return 'QR';
|
|
30
|
+
}
|
|
31
|
+
case KeyringTypes.snap: {
|
|
32
|
+
return 'Snap Wallet';
|
|
33
|
+
}
|
|
34
|
+
default: {
|
|
35
|
+
return 'Unknown';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=names.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.mjs","sourceRoot":"","sources":["../src/names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,qCAAqC;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,sCAAsC,CAAC,IAAkB;IACvE,QAAQ,IAAI,EAAE;QACZ,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,cAAc,CAAC;SACvB;QACD,KAAK,YAAY,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,WAAW,CAAC;SACpB;QACD,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC;YACxB,OAAO,QAAQ,CAAC;SACjB;QACD,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,SAAS,CAAC;SAClB;QACD,KAAK,YAAY,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,IAAI,CAAC;SACb;QACD,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;YACtB,OAAO,aAAa,CAAC;SACtB;QACD,OAAO,CAAC,CAAC;YACP,OAAO,SAAS,CAAC;SAClB;KACF;AACH,CAAC","sourcesContent":["import { KeyringTypes } from '@metamask/keyring-controller';\n\n/**\n * Get wallet name from a keyring type.\n *\n * @param type - Keyring's type.\n * @returns Wallet name.\n */\nexport function getAccountGroupRootNameFromKeyringType(type: KeyringTypes) {\n switch (type) {\n case KeyringTypes.simple: {\n return 'Private Keys';\n }\n case KeyringTypes.hd: {\n return 'HD Wallet';\n }\n case KeyringTypes.trezor: {\n return 'Trezor';\n }\n case KeyringTypes.oneKey: {\n return 'OneKey';\n }\n case KeyringTypes.ledger: {\n return 'Ledger';\n }\n case KeyringTypes.lattice: {\n return 'Lattice';\n }\n case KeyringTypes.qr: {\n return 'QR';\n }\n case KeyringTypes.snap: {\n return 'Snap Wallet';\n }\n default: {\n return 'Unknown';\n }\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metamask-previews/account-tree-controller",
|
|
3
|
+
"version": "0.0.0-preview-d9a49231",
|
|
4
|
+
"description": "Controller to group account together based on some pre-defined rules",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"MetaMask",
|
|
7
|
+
"Ethereum"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/MetaMask/core/tree/main/packages/account-tree-controller#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/MetaMask/core/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/MetaMask/core.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/index.d.mts",
|
|
23
|
+
"default": "./dist/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/index.d.cts",
|
|
27
|
+
"default": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.cjs",
|
|
33
|
+
"types": "./dist/index.d.cts",
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references",
|
|
39
|
+
"build:docs": "typedoc",
|
|
40
|
+
"changelog:update": "../../scripts/update-changelog.sh @metamask/account-tree-controller",
|
|
41
|
+
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/account-tree-controller",
|
|
42
|
+
"publish:preview": "yarn npm publish --tag preview",
|
|
43
|
+
"since-latest-release": "../../scripts/since-latest-release.sh",
|
|
44
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",
|
|
45
|
+
"test:clean": "NODE_OPTIONS=--experimental-vm-modules jest --clearCache",
|
|
46
|
+
"test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose",
|
|
47
|
+
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@metamask/base-controller": "^8.0.1",
|
|
51
|
+
"@metamask/snaps-sdk": "^6.22.0",
|
|
52
|
+
"@metamask/snaps-utils": "^9.2.0",
|
|
53
|
+
"lodash": "^4.17.21"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@metamask/accounts-controller": "^29.0.0",
|
|
57
|
+
"@metamask/auto-changelog": "^3.4.4",
|
|
58
|
+
"@metamask/keyring-api": "^17.4.0",
|
|
59
|
+
"@metamask/keyring-controller": "^22.0.0",
|
|
60
|
+
"@metamask/providers": "^21.0.0",
|
|
61
|
+
"@metamask/snaps-controllers": "^11.2.1",
|
|
62
|
+
"@types/jest": "^27.4.1",
|
|
63
|
+
"@types/lodash": "^4.14.191",
|
|
64
|
+
"deepmerge": "^4.2.2",
|
|
65
|
+
"jest": "^27.5.1",
|
|
66
|
+
"ts-jest": "^27.1.4",
|
|
67
|
+
"typedoc": "^0.24.8",
|
|
68
|
+
"typedoc-plugin-missing-exports": "^2.0.0",
|
|
69
|
+
"typescript": "~5.2.2",
|
|
70
|
+
"webextension-polyfill": "^0.12.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"@metamask/accounts-controller": "^29.0.0",
|
|
74
|
+
"@metamask/keyring-controller": "^22.0.0",
|
|
75
|
+
"@metamask/providers": "^21.0.0",
|
|
76
|
+
"@metamask/snaps-controllers": "^11.0.0",
|
|
77
|
+
"webextension-polyfill": "^0.10.0 || ^0.11.0 || ^0.12.0"
|
|
78
|
+
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": "^18.18 || >=20"
|
|
81
|
+
},
|
|
82
|
+
"publishConfig": {
|
|
83
|
+
"access": "public",
|
|
84
|
+
"registry": "https://registry.npmjs.org/"
|
|
85
|
+
}
|
|
86
|
+
}
|