@metamask/accounts-controller 39.1.1 → 40.0.0

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/{AccountsController-method-action-types.d.mts → AccountsController-method-action-types.d.ts} +2 -2
  3. package/dist/AccountsController-method-action-types.d.ts.map +1 -0
  4. package/dist/{AccountsController-method-action-types.mjs → AccountsController-method-action-types.js} +1 -1
  5. package/dist/AccountsController-method-action-types.js.map +1 -0
  6. package/dist/{AccountsController.d.mts → AccountsController.d.ts} +11 -11
  7. package/dist/AccountsController.d.ts.map +1 -0
  8. package/dist/AccountsController.js +855 -0
  9. package/dist/AccountsController.js.map +1 -0
  10. package/dist/{index.d.cts → index.d.ts} +5 -5
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +3 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/logger.d.ts +4 -0
  15. package/dist/logger.d.ts.map +1 -0
  16. package/dist/{logger.mjs → logger.js} +2 -2
  17. package/dist/logger.js.map +1 -0
  18. package/dist/{types.d.cts → types.d.ts} +4 -4
  19. package/dist/types.d.ts.map +1 -0
  20. package/dist/{types.mjs → types.js} +1 -1
  21. package/dist/types.js.map +1 -0
  22. package/dist/{typing.d.cts → typing.d.ts} +4 -4
  23. package/dist/typing.d.ts.map +1 -0
  24. package/dist/typing.js +2 -0
  25. package/dist/typing.js.map +1 -0
  26. package/dist/{utils.d.mts → utils.d.ts} +11 -9
  27. package/dist/utils.d.ts.map +1 -0
  28. package/dist/{utils.mjs → utils.js} +7 -7
  29. package/dist/utils.js.map +1 -0
  30. package/package.json +19 -23
  31. package/dist/AccountsController-method-action-types.cjs +0 -7
  32. package/dist/AccountsController-method-action-types.cjs.map +0 -1
  33. package/dist/AccountsController-method-action-types.d.cts +0 -177
  34. package/dist/AccountsController-method-action-types.d.cts.map +0 -1
  35. package/dist/AccountsController-method-action-types.d.mts.map +0 -1
  36. package/dist/AccountsController-method-action-types.mjs.map +0 -1
  37. package/dist/AccountsController.cjs +0 -771
  38. package/dist/AccountsController.cjs.map +0 -1
  39. package/dist/AccountsController.d.cts +0 -312
  40. package/dist/AccountsController.d.cts.map +0 -1
  41. package/dist/AccountsController.d.mts.map +0 -1
  42. package/dist/AccountsController.mjs +0 -767
  43. package/dist/AccountsController.mjs.map +0 -1
  44. package/dist/index.cjs +0 -13
  45. package/dist/index.cjs.map +0 -1
  46. package/dist/index.d.cts.map +0 -1
  47. package/dist/index.d.mts +0 -5
  48. package/dist/index.d.mts.map +0 -1
  49. package/dist/index.mjs +0 -3
  50. package/dist/index.mjs.map +0 -1
  51. package/dist/logger.cjs +0 -8
  52. package/dist/logger.cjs.map +0 -1
  53. package/dist/logger.d.cts +0 -5
  54. package/dist/logger.d.cts.map +0 -1
  55. package/dist/logger.d.mts +0 -5
  56. package/dist/logger.d.mts.map +0 -1
  57. package/dist/logger.mjs.map +0 -1
  58. package/dist/types.cjs +0 -5
  59. package/dist/types.cjs.map +0 -1
  60. package/dist/types.d.cts.map +0 -1
  61. package/dist/types.d.mts +0 -20
  62. package/dist/types.d.mts.map +0 -1
  63. package/dist/types.mjs.map +0 -1
  64. package/dist/typing.cjs +0 -3
  65. package/dist/typing.cjs.map +0 -1
  66. package/dist/typing.d.cts.map +0 -1
  67. package/dist/typing.d.mts +0 -31
  68. package/dist/typing.d.mts.map +0 -1
  69. package/dist/typing.mjs +0 -2
  70. package/dist/typing.mjs.map +0 -1
  71. package/dist/utils.cjs +0 -216
  72. package/dist/utils.cjs.map +0 -1
  73. package/dist/utils.d.cts +0 -117
  74. package/dist/utils.d.cts.map +0 -1
  75. package/dist/utils.d.mts.map +0 -1
  76. package/dist/utils.mjs.map +0 -1
@@ -1,771 +0,0 @@
1
- "use strict";
2
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
- 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");
5
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
- };
7
- var _AccountsController_instances, _AccountsController_getAccountExpect, _AccountsController_assertAccountCanBeRenamed, _AccountsController_getInternalAccountForNonSnapAccount, _AccountsController_getSnapKeyring, _AccountsController_getAccountFromSnapKeyringV1, _AccountsController_getAccountFromSnapKeyringV2, _AccountsController_handleOnSnapKeyringAccountEvent, _AccountsController_handleOnKeyringStateChange, _AccountsController_update, _AccountsController_getLastSelectedAccount, _AccountsController_getLastSelectedIndex, _AccountsController_getInternalAccountFromAddressAndType, _AccountsController_handleOnMultichainNetworkDidChange, _AccountsController_subscribeToMessageEvents;
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.AccountsController = exports.EMPTY_ACCOUNT = exports.getDefaultAccountsControllerState = void 0;
10
- const base_controller_1 = require("@metamask/base-controller");
11
- const eth_snap_keyring_1 = require("@metamask/eth-snap-keyring");
12
- const v2_1 = require("@metamask/eth-snap-keyring/v2");
13
- const keyring_api_1 = require("@metamask/keyring-api");
14
- const v2_2 = require("@metamask/keyring-api/v2");
15
- const v2_3 = require("@metamask/keyring-sdk/v2");
16
- const keyring_utils_1 = require("@metamask/keyring-utils");
17
- const utils_1 = require("@metamask/utils");
18
- const lodash_1 = require("lodash");
19
- const logger_js_1 = require("./logger.cjs");
20
- const utils_js_1 = require("./utils.cjs");
21
- const controllerName = 'AccountsController';
22
- const MESSENGER_EXPOSED_METHODS = [
23
- 'setSelectedAccount',
24
- 'setAccountName',
25
- 'setAccountNameAndSelectAccount',
26
- 'listAccounts',
27
- 'listMultichainAccounts',
28
- 'updateAccounts',
29
- 'getSelectedAccount',
30
- 'getSelectedMultichainAccount',
31
- 'getAccountByAddress',
32
- 'getAccount',
33
- 'getAccounts',
34
- 'updateAccountMetadata',
35
- 'loadBackup',
36
- 'clearState',
37
- ];
38
- const accountsControllerMetadata = {
39
- internalAccounts: {
40
- includeInStateLogs: true,
41
- persist: true,
42
- includeInDebugSnapshot: false,
43
- usedInUi: true,
44
- },
45
- accountIdByAddress: {
46
- includeInStateLogs: false,
47
- persist: false,
48
- includeInDebugSnapshot: false,
49
- usedInUi: true,
50
- },
51
- };
52
- /**
53
- * Returns the default state for the AccountsController.
54
- *
55
- * @deprecated This function is deprecated and will be removed in a future version.
56
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
57
- * @returns The default AccountsController state.
58
- */
59
- function getDefaultAccountsControllerState() {
60
- return {
61
- internalAccounts: {
62
- accounts: {},
63
- selectedAccount: '',
64
- },
65
- accountIdByAddress: {},
66
- };
67
- }
68
- exports.getDefaultAccountsControllerState = getDefaultAccountsControllerState;
69
- /**
70
- * @deprecated This constant is deprecated and will be removed in a future version.
71
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
72
- */
73
- exports.EMPTY_ACCOUNT = {
74
- id: '',
75
- address: '',
76
- options: {},
77
- methods: [],
78
- type: keyring_api_1.EthAccountType.Eoa,
79
- scopes: [keyring_api_1.EthScope.Eoa],
80
- metadata: {
81
- name: '',
82
- keyring: {
83
- type: '',
84
- },
85
- importTime: 0,
86
- },
87
- };
88
- /**
89
- * Controller that manages internal accounts.
90
- * The accounts controller is responsible for creating and managing internal accounts.
91
- * It also provides convenience methods for accessing and updating the internal accounts.
92
- * The accounts controller also listens for keyring state changes and updates the internal accounts accordingly.
93
- * The accounts controller also listens for snap state changes and updates the internal accounts accordingly.
94
- *
95
- * @deprecated This class is deprecated and will be removed in a future version.
96
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
97
- */
98
- class AccountsController extends base_controller_1.BaseController {
99
- /**
100
- * Constructor for AccountsController.
101
- *
102
- * @param options - The controller options.
103
- * @param options.messenger - The messenger object.
104
- * @param options.state - Initial state to set on this controller
105
- */
106
- constructor({ messenger, state, }) {
107
- const accountIdByAddress = (0, utils_js_1.constructAccountIdByAddress)(state?.internalAccounts?.accounts ?? {});
108
- super({
109
- messenger,
110
- name: controllerName,
111
- metadata: accountsControllerMetadata,
112
- state: {
113
- ...getDefaultAccountsControllerState(),
114
- ...state,
115
- accountIdByAddress,
116
- },
117
- });
118
- _AccountsController_instances.add(this);
119
- this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
120
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_subscribeToMessageEvents).call(this);
121
- }
122
- /**
123
- * Returns the internal account object for the given account ID, if it exists.
124
- *
125
- * @deprecated This method is deprecated and will be removed in a future version.
126
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
127
- * @param accountId - The ID of the account to retrieve.
128
- * @returns The internal account object, or undefined if the account does not exist.
129
- */
130
- getAccount(accountId) {
131
- return this.state.internalAccounts.accounts[accountId];
132
- }
133
- /**
134
- * Returns the internal account objects for the given account IDs, if they exist.
135
- *
136
- * @deprecated This method is deprecated and will be removed in a future version.
137
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
138
- * @param accountIds - The IDs of the accounts to retrieve.
139
- * @returns The internal account objects, or undefined if the account(s) do not exist.
140
- */
141
- getAccounts(accountIds) {
142
- return accountIds.map((accountId) => this.getAccount(accountId));
143
- }
144
- /**
145
- * Returns an array of all evm internal accounts.
146
- *
147
- * @deprecated This method is deprecated and will be removed in a future version.
148
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
149
- * @returns An array of InternalAccount objects.
150
- */
151
- listAccounts() {
152
- const accounts = Object.values(this.state.internalAccounts.accounts);
153
- return accounts.filter((account) => (0, keyring_api_1.isEvmAccountType)(account.type));
154
- }
155
- /**
156
- * Returns an array of all internal accounts.
157
- *
158
- * @deprecated This method is deprecated and will be removed in a future version.
159
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
160
- * @param chainId - The chain ID.
161
- * @returns An array of InternalAccount objects.
162
- */
163
- listMultichainAccounts(chainId) {
164
- const accounts = Object.values(this.state.internalAccounts.accounts);
165
- if (!chainId) {
166
- return accounts;
167
- }
168
- if (!(0, utils_1.isCaipChainId)(chainId)) {
169
- throw new Error(`Invalid CAIP-2 chain ID: ${String(chainId)}`);
170
- }
171
- return accounts.filter((account) => (0, keyring_utils_1.isScopeEqualToAny)(chainId, account.scopes));
172
- }
173
- /**
174
- * Returns the last selected EVM account.
175
- *
176
- * @deprecated This method is deprecated and will be removed in a future version.
177
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
178
- * @returns The selected internal account.
179
- */
180
- getSelectedAccount() {
181
- const { internalAccounts: { selectedAccount }, } = this.state;
182
- // Edge case where the extension is setup but the srp is not yet created
183
- // certain ui elements will query the selected address before any accounts are created.
184
- if (!selectedAccount) {
185
- return exports.EMPTY_ACCOUNT;
186
- }
187
- const account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountExpect).call(this, selectedAccount);
188
- if ((0, keyring_api_1.isEvmAccountType)(account.type)) {
189
- return account;
190
- }
191
- const accounts = this.listAccounts();
192
- if (!accounts.length) {
193
- // ! Should never reach this.
194
- throw new Error('No EVM accounts');
195
- }
196
- // This will never be undefined because we have already checked if accounts.length is > 0
197
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
198
- return __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedAccount).call(this, accounts);
199
- }
200
- /**
201
- * __WARNING The return value may be undefined if there isn't an account for that chain id.__
202
- *
203
- * Retrieves the last selected account by chain ID.
204
- *
205
- * @deprecated This method is deprecated and will be removed in a future version.
206
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
207
- * @param chainId - The chain ID to filter the accounts.
208
- * @returns The last selected account compatible with the specified chain ID or undefined.
209
- */
210
- getSelectedMultichainAccount(chainId) {
211
- const { internalAccounts: { selectedAccount }, } = this.state;
212
- // Edge case where the extension is setup but the srp is not yet created
213
- // certain ui elements will query the selected address before any accounts are created.
214
- if (!selectedAccount) {
215
- return exports.EMPTY_ACCOUNT;
216
- }
217
- if (!chainId) {
218
- return __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountExpect).call(this, selectedAccount);
219
- }
220
- const accounts = this.listMultichainAccounts(chainId);
221
- return __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedAccount).call(this, accounts);
222
- }
223
- /**
224
- * Returns the account with the specified address.
225
- * ! This method will only return the first account that matches the address
226
- *
227
- * @deprecated This method is deprecated and will be removed in a future version.
228
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
229
- * @param address - The address of the account to retrieve.
230
- * @returns The account with the specified address, or undefined if not found.
231
- */
232
- getAccountByAddress(address) {
233
- // We need to have a fallback as a cache miss might be attributed to a checksummed address being passed.
234
- let accountId = this.state.accountIdByAddress[address];
235
- if (!accountId) {
236
- // FIXME: We should not need lower-cased addresses, but some consumers might
237
- // still be using non-normalized addresses. For now we keep it
238
- // for convenience, but we will need to remove this fallback
239
- // at some point.
240
- // NOTE: We should only hit that branch for EVM accounts only.
241
- const lowercasedAddress = address.toLowerCase();
242
- accountId = this.state.accountIdByAddress[lowercasedAddress];
243
- if (accountId) {
244
- (0, logger_js_1.projectLogger)(`Cache missed for account ID: ${accountId}, received address: "${address}", matched address: "${lowercasedAddress}"`);
245
- }
246
- }
247
- return accountId ? this.getAccount(accountId) : undefined;
248
- }
249
- /**
250
- * Sets the selected account by its ID.
251
- *
252
- * @deprecated This method is deprecated and will be removed in a future version.
253
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
254
- * @param accountId - The ID of the account to be selected.
255
- */
256
- setSelectedAccount(accountId) {
257
- const account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountExpect).call(this, accountId);
258
- if (this.state.internalAccounts.selectedAccount === account.id) {
259
- return;
260
- }
261
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
262
- const { internalAccounts } = state;
263
- internalAccounts.accounts[account.id].metadata.lastSelected = Date.now();
264
- internalAccounts.selectedAccount = account.id;
265
- });
266
- }
267
- /**
268
- * Sets the name of the account with the given ID.
269
- *
270
- * @deprecated This method is deprecated and will be removed in a future version.
271
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
272
- * @param accountId - The ID of the account to set the name for.
273
- * @param accountName - The new name for the account.
274
- * @throws An error if an account with the same name already exists.
275
- */
276
- setAccountName(accountId, accountName) {
277
- // This will check for name uniqueness and fire the `accountRenamed` event
278
- // if the account has been renamed.
279
- this.updateAccountMetadata(accountId, {
280
- name: accountName,
281
- nameLastUpdatedAt: Date.now(),
282
- });
283
- }
284
- /**
285
- * Sets the name of the account with the given ID and select it.
286
- *
287
- * @deprecated This method is deprecated and will be removed in a future version.
288
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
289
- * @param accountId - The ID of the account to set the name for and select.
290
- * @param accountName - The new name for the account.
291
- * @throws An error if an account with the same name already exists.
292
- */
293
- setAccountNameAndSelectAccount(accountId, accountName) {
294
- const account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountExpect).call(this, accountId);
295
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_assertAccountCanBeRenamed).call(this, account, accountName);
296
- const internalAccount = {
297
- ...account,
298
- metadata: {
299
- ...account.metadata,
300
- name: accountName,
301
- nameLastUpdatedAt: Date.now(),
302
- lastSelected: __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this),
303
- },
304
- };
305
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
306
- state.internalAccounts.accounts[account.id] = internalAccount;
307
- state.internalAccounts.selectedAccount = account.id;
308
- });
309
- this.messenger.publish('AccountsController:accountRenamed', internalAccount);
310
- }
311
- /**
312
- * Updates the metadata of the account with the given ID.
313
- *
314
- * @deprecated This method is deprecated and will be removed in a future version.
315
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
316
- * @param accountId - The ID of the account for which the metadata will be updated.
317
- * @param metadata - The new metadata for the account.
318
- */
319
- updateAccountMetadata(accountId, metadata) {
320
- const account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountExpect).call(this, accountId);
321
- if (metadata.name) {
322
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_assertAccountCanBeRenamed).call(this, account, metadata.name);
323
- }
324
- const internalAccount = {
325
- ...account,
326
- metadata: { ...account.metadata, ...metadata },
327
- };
328
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
329
- state.internalAccounts.accounts[accountId] = internalAccount;
330
- });
331
- if (metadata.name) {
332
- this.messenger.publish('AccountsController:accountRenamed', internalAccount);
333
- }
334
- }
335
- /**
336
- * Updates the internal accounts list by retrieving normal and snap accounts,
337
- * removing duplicates, and updating the metadata of each account.
338
- *
339
- * @deprecated This method is deprecated and will be removed in a future version.
340
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
341
- * @returns A Promise that resolves when the accounts have been updated.
342
- */
343
- async updateAccounts() {
344
- (0, logger_js_1.projectLogger)('Synchronizing accounts with keyrings...');
345
- const keyringAccountIndexes = new Map();
346
- const existingInternalAccounts = this.state.internalAccounts.accounts;
347
- const internalAccounts = {};
348
- const { keyrings } = this.messenger.call('KeyringController:getState');
349
- for (const keyring of keyrings) {
350
- // Money accounts are not treated as real accounts, they are owned by the `MoneyAccountController`, so
351
- // we need to filter them out here.
352
- if ((0, utils_js_1.isMoneyKeyringType)(keyring.type)) {
353
- continue;
354
- }
355
- const keyringTypeName = (0, utils_js_1.keyringTypeToName)(keyring.type);
356
- for (const address of keyring.accounts) {
357
- const internalAccount = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getInternalAccountFromAddressAndType).call(this, address, keyring);
358
- // This should never really happen, but if for some reason we're not
359
- // able to get the Snap keyring reference, this would return an
360
- // undefined account.
361
- // So we just skip it, even though, this should not really happen.
362
- if (!internalAccount) {
363
- continue;
364
- }
365
- // Get current index for this keyring (we use human indexing, so start at 1).
366
- const keyringAccountIndex = keyringAccountIndexes.get(keyringTypeName) ?? 1;
367
- const existingAccount = existingInternalAccounts[internalAccount.id];
368
- internalAccounts[internalAccount.id] = {
369
- ...internalAccount,
370
- metadata: {
371
- ...internalAccount.metadata,
372
- // Re-use existing metadata if any.
373
- name: existingAccount?.metadata.name ??
374
- `${keyringTypeName} ${keyringAccountIndex}`,
375
- importTime: existingAccount?.metadata.importTime ?? Date.now(),
376
- lastSelected: existingAccount?.metadata.lastSelected ?? 0,
377
- },
378
- };
379
- // Increment the account index for this keyring.
380
- keyringAccountIndexes.set(keyringTypeName, keyringAccountIndex + 1);
381
- }
382
- }
383
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
384
- state.internalAccounts.accounts = internalAccounts;
385
- state.accountIdByAddress = (0, utils_js_1.constructAccountIdByAddress)(internalAccounts);
386
- });
387
- (0, logger_js_1.projectLogger)('Accounts synchronized!');
388
- }
389
- /**
390
- * Loads the backup state of the accounts controller.
391
- *
392
- * @deprecated This method is deprecated and will be removed in a future version.
393
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
394
- * @param backup - The backup state to load.
395
- */
396
- loadBackup(backup) {
397
- if (backup.internalAccounts) {
398
- const accountIdByAddress = (0, utils_js_1.constructAccountIdByAddress)(backup.internalAccounts.accounts);
399
- this.update((currentState) => {
400
- currentState.internalAccounts = backup.internalAccounts;
401
- currentState.accountIdByAddress = accountIdByAddress;
402
- });
403
- }
404
- }
405
- /**
406
- * Clears the controller state and resets to default values.
407
- *
408
- * @deprecated This method is deprecated and will be removed in a future version.
409
- * Use `AccountTreeController`, `MultichainAccountService`, or the Keyring API v2 instead.
410
- */
411
- clearState() {
412
- this.update(() => {
413
- return getDefaultAccountsControllerState();
414
- });
415
- }
416
- }
417
- exports.AccountsController = AccountsController;
418
- _AccountsController_instances = new WeakSet(), _AccountsController_getAccountExpect = function _AccountsController_getAccountExpect(accountId) {
419
- const account = this.getAccount(accountId);
420
- if (account === undefined) {
421
- throw new Error(`Account Id "${accountId}" not found`);
422
- }
423
- return account;
424
- }, _AccountsController_assertAccountCanBeRenamed = function _AccountsController_assertAccountCanBeRenamed(account, accountName) {
425
- if (this.listMultichainAccounts().find((internalAccount) => internalAccount.metadata.name === accountName &&
426
- internalAccount.id !== account.id)) {
427
- throw new Error('Account name already exists');
428
- }
429
- }, _AccountsController_getInternalAccountForNonSnapAccount = function _AccountsController_getInternalAccountForNonSnapAccount(address, keyring) {
430
- const id = (0, utils_js_1.getUUIDFromAddressOfNormalAccount)(address);
431
- // We might have an account for this ID already, so we'll just re-use
432
- // the same metadata
433
- const account = this.getAccount(id);
434
- const metadata = {
435
- name: account?.metadata.name ?? '',
436
- ...(account?.metadata.nameLastUpdatedAt
437
- ? {
438
- nameLastUpdatedAt: account?.metadata.nameLastUpdatedAt,
439
- }
440
- : {}),
441
- importTime: account?.metadata.importTime ?? Date.now(),
442
- lastSelected: account?.metadata.lastSelected ?? 0,
443
- keyring: {
444
- type: keyring.type,
445
- },
446
- };
447
- let options = {};
448
- if ((0, utils_js_1.isHdKeyringType)(keyring.type)) {
449
- // We need to find the account index from its HD keyring.
450
- const groupIndex = (0, utils_js_1.getEvmGroupIndexFromAddressIndex)(keyring, address);
451
- // If for some reason, we cannot find this address, then the caller made a mistake
452
- // and it did not use the proper keyring object. For now, we do not fail and just
453
- // consider this account as "simple account".
454
- if (groupIndex !== undefined) {
455
- // NOTE: We are not using the `hdPath` from the associated keyring here and
456
- // getting the keyring instance here feels a bit overkill.
457
- // This will be naturally fixed once every keyring start using `KeyringAccount` and implement the keyring API.
458
- const derivationPath = (0, utils_js_1.getEvmDerivationPathForIndex)(groupIndex);
459
- // Those are "legacy options" and they were used before `KeyringAccount` added
460
- // support for type options. We keep those temporarily until we update everything
461
- // to use the new typed options.
462
- const legacyOptions = {
463
- entropySource: keyring.metadata.id,
464
- derivationPath,
465
- groupIndex,
466
- };
467
- // New typed entropy options. This is required for multichain accounts.
468
- const entropyOptions = {
469
- entropy: {
470
- type: keyring_api_1.KeyringAccountEntropyTypeOption.Mnemonic,
471
- id: keyring.metadata.id,
472
- derivationPath,
473
- groupIndex,
474
- },
475
- };
476
- options = {
477
- ...legacyOptions,
478
- ...entropyOptions,
479
- };
480
- }
481
- }
482
- return {
483
- id,
484
- address,
485
- options,
486
- methods: [
487
- keyring_api_1.EthMethod.PersonalSign,
488
- keyring_api_1.EthMethod.Sign,
489
- keyring_api_1.EthMethod.SignTransaction,
490
- keyring_api_1.EthMethod.SignTypedDataV1,
491
- keyring_api_1.EthMethod.SignTypedDataV3,
492
- keyring_api_1.EthMethod.SignTypedDataV4,
493
- ],
494
- scopes: [keyring_api_1.EthScope.Eoa],
495
- type: keyring_api_1.EthAccountType.Eoa,
496
- metadata,
497
- };
498
- }, _AccountsController_getSnapKeyring = function _AccountsController_getSnapKeyring() {
499
- const [snapKeyring] = this.messenger.call('KeyringController:getKeyringsByType', eth_snap_keyring_1.SnapKeyring.type);
500
- // Snap keyring is not available until the first account is created in the keyring
501
- // controller, so this might be undefined.
502
- return snapKeyring;
503
- }, _AccountsController_getAccountFromSnapKeyringV1 = function _AccountsController_getAccountFromSnapKeyringV1(address) {
504
- const snapKeyring = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getSnapKeyring).call(this);
505
- // We need the Snap keyring to retrieve the account from its address.
506
- if (!snapKeyring) {
507
- return undefined;
508
- }
509
- // This might be undefined if the Snap deleted the account before
510
- // reaching that point.
511
- return snapKeyring.getAccountByAddress(address);
512
- }, _AccountsController_getAccountFromSnapKeyringV2 = function _AccountsController_getAccountFromSnapKeyringV2(address) {
513
- const keyrings = this.messenger.call('KeyringController:getKeyringsByType', v2_2.KeyringType.Snap);
514
- // Snap keyring v2 are "per-Snaps" (and can be accessed using their v1 adapter), so we need to
515
- // iterate over all of them to find the account.
516
- // NOTE: `:getKeyringsByType` will only return v1 instances, that's why we need to use their v1
517
- // adapter + `unwrap` method to get the reference to their v2 instance.
518
- for (const keyring of keyrings) {
519
- if (keyring instanceof v2_3.KeyringV1Adapter) {
520
- // NOTE: We already filtering by `KeyringType.Snap`, so we are sure that those adapters
521
- // are wrapping a Snap keyring v2.
522
- const adapter = keyring;
523
- const keyringV2 = adapter.unwrap();
524
- // We use the synchronous method here since this method is used during `:stateChange` that are
525
- // use synchronous handlers.
526
- const account = keyringV2.lookupByAddress(address);
527
- if (account) {
528
- return {
529
- ...account,
530
- // We still have to use internal account for now, so we inject some metadata.
531
- metadata: {
532
- name: '',
533
- importTime: Date.now(),
534
- lastSelected: 0,
535
- keyring: {
536
- type: v2_2.KeyringType.Snap,
537
- },
538
- snap: {
539
- id: keyringV2.snapId,
540
- },
541
- },
542
- };
543
- }
544
- }
545
- }
546
- return undefined;
547
- }, _AccountsController_handleOnSnapKeyringAccountEvent = function _AccountsController_handleOnSnapKeyringAccountEvent(event, ...payload) {
548
- this.messenger.publish(event, ...payload);
549
- }, _AccountsController_handleOnKeyringStateChange = function _AccountsController_handleOnKeyringStateChange({ isUnlocked, keyrings, }) {
550
- // TODO: Change when accountAdded event is added to the keyring controller.
551
- // We check for keyrings length to be greater than 0 because the extension client may try execute
552
- // submit password twice and clear the keyring state.
553
- // https://github.com/MetaMask/KeyringController/blob/2d73a4deed8d013913f6ef0c9f5c0bb7c614f7d3/src/KeyringController.ts#L910
554
- if (!isUnlocked || keyrings.length === 0) {
555
- return;
556
- }
557
- (0, logger_js_1.projectLogger)('Synchronizing accounts with keyrings (through :stateChange)...');
558
- // State patches.
559
- const patch = {
560
- previous: {},
561
- added: [],
562
- updated: [],
563
- removed: [],
564
- };
565
- // Create a map (with lower-cased addresses) of all existing accounts.
566
- for (const account of this.listMultichainAccounts()) {
567
- const address = account.address.toLowerCase();
568
- patch.previous[address] = account;
569
- }
570
- // Go over all keyring changes and create patches out of it.
571
- const addresses = new Set();
572
- for (const keyring of keyrings) {
573
- // Money accounts are not treated as real accounts, they are owned by the `MoneyAccountController`, so
574
- // we need to filter them out here.
575
- if ((0, utils_js_1.isMoneyKeyringType)(keyring.type)) {
576
- continue;
577
- }
578
- for (const accountAddress of keyring.accounts) {
579
- // Lower-case address to use it in the `previous` map.
580
- const address = accountAddress.toLowerCase();
581
- const account = patch.previous[address];
582
- if (account) {
583
- // If the account exists before, this might be an update.
584
- patch.updated.push(account);
585
- }
586
- else {
587
- // Otherwise, that's a new account.
588
- patch.added.push({
589
- address,
590
- keyring,
591
- });
592
- }
593
- // Keep track of those address to check for removed accounts later.
594
- addresses.add(address);
595
- }
596
- }
597
- // We might have accounts associated with removed keyrings, so we iterate
598
- // over all previous known accounts and check against the keyring addresses.
599
- for (const [address, account] of Object.entries(patch.previous)) {
600
- // If a previous address is not part of the new addesses, then it got removed.
601
- if (!addresses.has(address)) {
602
- patch.removed.push(account);
603
- }
604
- }
605
- // Diff that we will use to publish events afterward.
606
- const diff = {
607
- removed: [],
608
- added: [],
609
- };
610
- __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
611
- const { internalAccounts, accountIdByAddress } = state;
612
- for (const account of patch.removed) {
613
- delete internalAccounts.accounts[account.id];
614
- delete accountIdByAddress[account.address];
615
- diff.removed.push(account.id);
616
- }
617
- for (const added of patch.added) {
618
- const account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getInternalAccountFromAddressAndType).call(this, added.address, added.keyring);
619
- if (account) {
620
- const accounts = Object.values(internalAccounts.accounts);
621
- // If it's the first account, we need to select it.
622
- const lastSelected = accounts.length === 0 ? __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this) : 0;
623
- internalAccounts.accounts[account.id] = {
624
- ...account,
625
- metadata: {
626
- ...account.metadata,
627
- importTime: Date.now(),
628
- lastSelected,
629
- },
630
- };
631
- accountIdByAddress[account.address] = account.id;
632
- diff.added.push(internalAccounts.accounts[account.id]);
633
- }
634
- }
635
- },
636
- // Will get executed after the update, but before re-selecting an account in case
637
- // the current one is not valid anymore.
638
- () => {
639
- // Now publish events
640
- for (const id of diff.removed) {
641
- this.messenger.publish('AccountsController:accountRemoved', id);
642
- }
643
- if (diff.removed.length > 0) {
644
- this.messenger.publish('AccountsController:accountsRemoved', diff.removed);
645
- }
646
- for (const account of diff.added) {
647
- this.messenger.publish('AccountsController:accountAdded', account);
648
- }
649
- if (diff.added.length > 0) {
650
- this.messenger.publish('AccountsController:accountsAdded', diff.added);
651
- }
652
- });
653
- (0, logger_js_1.projectLogger)('Accounts synchronized (through :stateChange)!');
654
- // NOTE: Since we also track "updated" accounts with our patches, we could fire a new event
655
- // like `accountUpdated` (we would still need to check if anything really changed on the account).
656
- }, _AccountsController_update = function _AccountsController_update(callback, beforeAutoSelectAccount) {
657
- // The currently selected account might get deleted during the update, so keep track
658
- // of it before doing any change.
659
- const previouslySelectedAccount = this.state.internalAccounts.selectedAccount;
660
- this.update((state) => {
661
- callback(state);
662
- // If the account no longer exists (or none is selected), we need to re-select another one.
663
- const { internalAccounts } = state;
664
- if (!internalAccounts.accounts[previouslySelectedAccount]) {
665
- const accounts = Object.values(internalAccounts.accounts);
666
- // Get the lastly selected account (according to the current accounts).
667
- const lastSelectedAccount = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedAccount).call(this, accounts);
668
- if (lastSelectedAccount) {
669
- internalAccounts.selectedAccount = lastSelectedAccount.id;
670
- internalAccounts.accounts[lastSelectedAccount.id].metadata.lastSelected = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this);
671
- }
672
- else {
673
- // It will be undefined if there are no accounts.
674
- internalAccounts.selectedAccount = '';
675
- }
676
- }
677
- });
678
- // We might want to do some pre-work before selecting a new account.
679
- beforeAutoSelectAccount?.();
680
- // Now, we compare the newly selected account, and we send event if different.
681
- const { selectedAccount } = this.state.internalAccounts;
682
- if (selectedAccount && selectedAccount !== previouslySelectedAccount) {
683
- const account = this.getSelectedMultichainAccount();
684
- // The account should always be defined at this point, since we have already checked for
685
- // `selectedAccount` to be non-empty.
686
- if (account) {
687
- if ((0, keyring_api_1.isEvmAccountType)(account.type)) {
688
- this.messenger.publish('AccountsController:selectedEvmAccountChange', account);
689
- }
690
- this.messenger.publish('AccountsController:selectedAccountChange', account);
691
- }
692
- }
693
- }, _AccountsController_getLastSelectedAccount = function _AccountsController_getLastSelectedAccount(accounts) {
694
- const [accountToSelect] = accounts.sort((accountA, accountB) => {
695
- // sort by lastSelected descending
696
- return ((accountB.metadata.lastSelected ?? 0) -
697
- (accountA.metadata.lastSelected ?? 0));
698
- });
699
- return accountToSelect;
700
- }, _AccountsController_getLastSelectedIndex = function _AccountsController_getLastSelectedIndex() {
701
- // NOTE: For now we use the current date, since we know this value
702
- // will always be higher than any already selected account index.
703
- return Date.now();
704
- }, _AccountsController_getInternalAccountFromAddressAndType = function _AccountsController_getInternalAccountFromAddressAndType(address, keyring) {
705
- const isSnapKeyringV1 = (0, utils_js_1.isSnapKeyringType)(keyring.type);
706
- const isSnapKeyringV2 = (0, utils_js_1.isSnapKeyringV2Type)(keyring.type);
707
- if (isSnapKeyringV1 || isSnapKeyringV2) {
708
- let account;
709
- if (isSnapKeyringV1) {
710
- account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountFromSnapKeyringV1).call(this, address);
711
- }
712
- else {
713
- account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getAccountFromSnapKeyringV2).call(this, address);
714
- }
715
- if (account) {
716
- // We force the copy here, to avoid mutating the reference returned by the Snap keyring.
717
- account = (0, lodash_1.cloneDeep)(account);
718
- // MIGRATION: To avoid any existing Snap account migration, we are
719
- // just "adding" the new typed options that we need for multichain
720
- // accounts. Ultimately, we would need a real Snap account migrations
721
- // (being handled by each Snaps).
722
- if ((0, utils_js_1.isHdSnapKeyringAccount)(account)) {
723
- const options = {
724
- ...account.options,
725
- entropy: {
726
- type: keyring_api_1.KeyringAccountEntropyTypeOption.Mnemonic,
727
- id: account.options.entropySource,
728
- groupIndex: account.options.index,
729
- derivationPath: account.options.derivationPath,
730
- },
731
- };
732
- // Inject the new typed options to the internal account copy.
733
- account.options = options;
734
- }
735
- }
736
- return account;
737
- }
738
- return __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getInternalAccountForNonSnapAccount).call(this, address, keyring);
739
- }, _AccountsController_handleOnMultichainNetworkDidChange = function _AccountsController_handleOnMultichainNetworkDidChange(id) {
740
- let accountId;
741
- // We only support non-EVM Caip chain IDs at the moment. Ex Solana and Bitcoin
742
- // MultichainNetworkController will handle throwing an error if the Caip chain ID is not supported
743
- if ((0, utils_1.isCaipChainId)(id)) {
744
- // Update selected account to non evm account
745
- const lastSelectedNonEvmAccount = this.getSelectedMultichainAccount(id);
746
- // @ts-expect-error - This should never be undefined, otherwise it's a bug that should be handled
747
- accountId = lastSelectedNonEvmAccount.id;
748
- }
749
- else {
750
- // Update selected account to evm account
751
- const lastSelectedEvmAccount = this.getSelectedAccount();
752
- accountId = lastSelectedEvmAccount.id;
753
- }
754
- if (this.state.internalAccounts.selectedAccount === accountId) {
755
- return;
756
- }
757
- this.update((currentState) => {
758
- currentState.internalAccounts.accounts[accountId].metadata.lastSelected =
759
- Date.now();
760
- currentState.internalAccounts.selectedAccount = accountId;
761
- });
762
- // DO NOT publish AccountsController:setSelectedAccount to prevent circular listener loops
763
- }, _AccountsController_subscribeToMessageEvents = function _AccountsController_subscribeToMessageEvents() {
764
- this.messenger.subscribe('KeyringController:stateChange', (keyringState) => __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnKeyringStateChange).call(this, keyringState));
765
- this.messenger.subscribe('SnapAccountService:accountAssetListUpdated', (snapAccountEvent) => __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnSnapKeyringAccountEvent).call(this, 'AccountsController:accountAssetListUpdated', snapAccountEvent));
766
- this.messenger.subscribe('SnapAccountService:accountBalancesUpdated', (snapAccountEvent) => __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnSnapKeyringAccountEvent).call(this, 'AccountsController:accountBalancesUpdated', snapAccountEvent));
767
- this.messenger.subscribe('SnapAccountService:accountTransactionsUpdated', (snapAccountEvent) => __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnSnapKeyringAccountEvent).call(this, 'AccountsController:accountTransactionsUpdated', snapAccountEvent));
768
- // Handle account change when multichain network is changed
769
- this.messenger.subscribe('MultichainNetworkController:networkDidChange', (id) => __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleOnMultichainNetworkDidChange).call(this, id));
770
- };
771
- //# sourceMappingURL=AccountsController.cjs.map