@metamask/accounts-controller 27.0.0 → 29.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.
- package/CHANGELOG.md +32 -1
- package/dist/AccountsController.cjs +249 -180
- package/dist/AccountsController.cjs.map +1 -1
- package/dist/AccountsController.d.cts +13 -1
- package/dist/AccountsController.d.cts.map +1 -1
- package/dist/AccountsController.d.mts +13 -1
- package/dist/AccountsController.d.mts.map +1 -1
- package/dist/AccountsController.mjs +250 -181
- package/dist/AccountsController.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/tests/mocks.cjs +13 -3
- package/dist/tests/mocks.cjs.map +1 -1
- package/dist/tests/mocks.d.cts +3 -1
- package/dist/tests/mocks.d.cts.map +1 -1
- package/dist/tests/mocks.d.mts +3 -1
- package/dist/tests/mocks.d.mts.map +1 -1
- package/dist/tests/mocks.mjs +11 -2
- package/dist/tests/mocks.mjs.map +1 -1
- package/dist/utils.cjs +21 -6
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +14 -0
- package/dist/utils.d.cts.map +1 -1
- package/dist/utils.d.mts +14 -0
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs +19 -6
- package/dist/utils.mjs.map +1 -1
- package/package.json +14 -14
@@ -3,14 +3,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
3
3
|
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");
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
5
5
|
};
|
6
|
-
var _AccountsController_instances, _AccountsController_generateInternalAccountForNonSnapAccount, _AccountsController_listSnapAccounts, _AccountsController_listNormalAccounts, _AccountsController_handleOnSnapKeyringAccountEvent, _AccountsController_handleOnKeyringStateChange, _AccountsController_handleOnSnapStateChange, _AccountsController_getAccountsByKeyringType, _AccountsController_getLastSelectedAccount, _AccountsController_getLastSelectedIndex,
|
6
|
+
var _AccountsController_instances, _AccountsController_assertAccountCanBeRenamed, _AccountsController_generateInternalAccountForNonSnapAccount, _AccountsController_getSnapKeyring, _AccountsController_listSnapAccounts, _AccountsController_listNormalAccounts, _AccountsController_handleOnSnapKeyringAccountEvent, _AccountsController_handleOnKeyringStateChange, _AccountsController_update, _AccountsController_handleOnSnapStateChange, _AccountsController_getAccountsByKeyringType, _AccountsController_getLastSelectedAccount, _AccountsController_getLastSelectedIndex, _AccountsController_getInternalAccountFromAddressAndType, _AccountsController_handleOnMultichainNetworkDidChange, _AccountsController_populateExistingMetadata, _AccountsController_subscribeToMessageEvents, _AccountsController_registerMessageHandlers;
|
7
7
|
import { BaseController } from "@metamask/base-controller";
|
8
8
|
import { SnapKeyring } from "@metamask/eth-snap-keyring";
|
9
9
|
import { EthAccountType, EthMethod, EthScope, isEvmAccountType } from "@metamask/keyring-api";
|
10
10
|
import { KeyringTypes } from "@metamask/keyring-controller";
|
11
11
|
import { isScopeEqualToAny } from "@metamask/keyring-utils";
|
12
12
|
import { isCaipChainId } from "@metamask/utils";
|
13
|
-
import { getUUIDFromAddressOfNormalAccount, isNormalKeyringType, keyringTypeToName } from "./utils.mjs";
|
13
|
+
import { getDerivationPathForIndex, getUUIDFromAddressOfNormalAccount, isHdKeyringType, isNormalKeyringType, keyringTypeToName } from "./utils.mjs";
|
14
14
|
const controllerName = 'AccountsController';
|
15
15
|
const accountsControllerMetadata = {
|
16
16
|
internalAccounts: {
|
@@ -123,14 +123,15 @@ export class AccountsController extends BaseController {
|
|
123
123
|
* @returns The selected internal account.
|
124
124
|
*/
|
125
125
|
getSelectedAccount() {
|
126
|
+
const { internalAccounts: { selectedAccount }, } = this.state;
|
126
127
|
// Edge case where the extension is setup but the srp is not yet created
|
127
128
|
// certain ui elements will query the selected address before any accounts are created.
|
128
|
-
if (
|
129
|
+
if (selectedAccount === '') {
|
129
130
|
return EMPTY_ACCOUNT;
|
130
131
|
}
|
131
|
-
const
|
132
|
-
if (isEvmAccountType(
|
133
|
-
return
|
132
|
+
const account = this.getAccountExpect(selectedAccount);
|
133
|
+
if (isEvmAccountType(account.type)) {
|
134
|
+
return account;
|
134
135
|
}
|
135
136
|
const accounts = this.listAccounts();
|
136
137
|
if (!accounts.length) {
|
@@ -150,13 +151,14 @@ export class AccountsController extends BaseController {
|
|
150
151
|
* @returns The last selected account compatible with the specified chain ID or undefined.
|
151
152
|
*/
|
152
153
|
getSelectedMultichainAccount(chainId) {
|
154
|
+
const { internalAccounts: { selectedAccount }, } = this.state;
|
153
155
|
// Edge case where the extension is setup but the srp is not yet created
|
154
156
|
// certain ui elements will query the selected address before any accounts are created.
|
155
|
-
if (
|
157
|
+
if (selectedAccount === '') {
|
156
158
|
return EMPTY_ACCOUNT;
|
157
159
|
}
|
158
160
|
if (!chainId) {
|
159
|
-
return this.getAccountExpect(
|
161
|
+
return this.getAccountExpect(selectedAccount);
|
160
162
|
}
|
161
163
|
const accounts = this.listMultichainAccounts(chainId);
|
162
164
|
return __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedAccount).call(this, accounts);
|
@@ -178,12 +180,11 @@ export class AccountsController extends BaseController {
|
|
178
180
|
*/
|
179
181
|
setSelectedAccount(accountId) {
|
180
182
|
const account = this.getAccountExpect(accountId);
|
181
|
-
this.
|
182
|
-
|
183
|
-
|
184
|
-
|
183
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
|
184
|
+
const { internalAccounts } = state;
|
185
|
+
internalAccounts.accounts[account.id].metadata.lastSelected = Date.now();
|
186
|
+
internalAccounts.selectedAccount = account.id;
|
185
187
|
});
|
186
|
-
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_publishAccountChangeEvent).call(this, account);
|
187
188
|
}
|
188
189
|
/**
|
189
190
|
* Sets the name of the account with the given ID.
|
@@ -200,6 +201,37 @@ export class AccountsController extends BaseController {
|
|
200
201
|
nameLastUpdatedAt: Date.now(),
|
201
202
|
});
|
202
203
|
}
|
204
|
+
/**
|
205
|
+
* Sets the name of the account with the given ID and select it.
|
206
|
+
*
|
207
|
+
* @param accountId - The ID of the account to set the name for and select.
|
208
|
+
* @param accountName - The new name for the account.
|
209
|
+
* @throws An error if an account with the same name already exists.
|
210
|
+
*/
|
211
|
+
setAccountNameAndSelectAccount(accountId, accountName) {
|
212
|
+
const account = this.getAccountExpect(accountId);
|
213
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_assertAccountCanBeRenamed).call(this, account, accountName);
|
214
|
+
const internalAccount = {
|
215
|
+
...account,
|
216
|
+
metadata: {
|
217
|
+
...account.metadata,
|
218
|
+
name: accountName,
|
219
|
+
nameLastUpdatedAt: Date.now(),
|
220
|
+
lastSelected: __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this),
|
221
|
+
},
|
222
|
+
};
|
223
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
|
224
|
+
// FIXME: Using the state as-is cause the following error: "Type instantiation is excessively
|
225
|
+
// deep and possibly infinite.ts(2589)" (https://github.com/MetaMask/utils/issues/168)
|
226
|
+
// Using a type-cast workaround this error and is slightly better than using a @ts-expect-error
|
227
|
+
// which sometimes fail when compiling locally.
|
228
|
+
state.internalAccounts.accounts[account.id] =
|
229
|
+
internalAccount;
|
230
|
+
state.internalAccounts.selectedAccount =
|
231
|
+
account.id;
|
232
|
+
});
|
233
|
+
this.messagingSystem.publish('AccountsController:accountRenamed', internalAccount);
|
234
|
+
}
|
203
235
|
/**
|
204
236
|
* Updates the metadata of the account with the given ID.
|
205
237
|
*
|
@@ -208,24 +240,24 @@ export class AccountsController extends BaseController {
|
|
208
240
|
*/
|
209
241
|
updateAccountMetadata(accountId, metadata) {
|
210
242
|
const account = this.getAccountExpect(accountId);
|
211
|
-
if (metadata.name
|
212
|
-
this
|
213
|
-
internalAccount.id !== accountId)) {
|
214
|
-
throw new Error('Account name already exists');
|
243
|
+
if (metadata.name) {
|
244
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_assertAccountCanBeRenamed).call(this, account, metadata.name);
|
215
245
|
}
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
//
|
222
|
-
//
|
223
|
-
//
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
}
|
246
|
+
const internalAccount = {
|
247
|
+
...account,
|
248
|
+
metadata: { ...account.metadata, ...metadata },
|
249
|
+
};
|
250
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
|
251
|
+
// FIXME: Using the state as-is cause the following error: "Type instantiation is excessively
|
252
|
+
// deep and possibly infinite.ts(2589)" (https://github.com/MetaMask/utils/issues/168)
|
253
|
+
// Using a type-cast workaround this error and is slightly better than using a @ts-expect-error
|
254
|
+
// which sometimes fail when compiling locally.
|
255
|
+
state.internalAccounts.accounts[accountId] =
|
256
|
+
internalAccount;
|
228
257
|
});
|
258
|
+
if (metadata.name) {
|
259
|
+
this.messagingSystem.publish('AccountsController:accountRenamed', internalAccount);
|
260
|
+
}
|
229
261
|
}
|
230
262
|
/**
|
231
263
|
* Updates the internal accounts list by retrieving normal and snap accounts,
|
@@ -264,21 +296,8 @@ export class AccountsController extends BaseController {
|
|
264
296
|
};
|
265
297
|
return internalAccountMap;
|
266
298
|
}, {});
|
267
|
-
this.
|
268
|
-
|
269
|
-
if (!currentState.internalAccounts.accounts[currentState.internalAccounts.selectedAccount]) {
|
270
|
-
const lastSelectedAccount = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedAccount).call(this, Object.values(accounts));
|
271
|
-
if (lastSelectedAccount) {
|
272
|
-
currentState.internalAccounts.selectedAccount =
|
273
|
-
lastSelectedAccount.id;
|
274
|
-
currentState.internalAccounts.accounts[lastSelectedAccount.id].metadata.lastSelected = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this);
|
275
|
-
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_publishAccountChangeEvent).call(this, lastSelectedAccount);
|
276
|
-
}
|
277
|
-
else {
|
278
|
-
// It will be undefined if there are no accounts
|
279
|
-
currentState.internalAccounts.selectedAccount = '';
|
280
|
-
}
|
281
|
-
}
|
299
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
|
300
|
+
state.internalAccounts.accounts = accounts;
|
282
301
|
});
|
283
302
|
}
|
284
303
|
/**
|
@@ -321,7 +340,12 @@ export class AccountsController extends BaseController {
|
|
321
340
|
return `${keyringName} ${index}`;
|
322
341
|
}
|
323
342
|
}
|
324
|
-
_AccountsController_instances = new WeakSet(),
|
343
|
+
_AccountsController_instances = new WeakSet(), _AccountsController_assertAccountCanBeRenamed = function _AccountsController_assertAccountCanBeRenamed(account, accountName) {
|
344
|
+
if (this.listMultichainAccounts().find((internalAccount) => internalAccount.metadata.name === accountName &&
|
345
|
+
internalAccount.id !== account.id)) {
|
346
|
+
throw new Error('Account name already exists');
|
347
|
+
}
|
348
|
+
}, _AccountsController_generateInternalAccountForNonSnapAccount = function _AccountsController_generateInternalAccountForNonSnapAccount(address, type) {
|
325
349
|
return {
|
326
350
|
id: getUUIDFromAddressOfNormalAccount(address),
|
327
351
|
address,
|
@@ -344,6 +368,11 @@ _AccountsController_instances = new WeakSet(), _AccountsController_generateInter
|
|
344
368
|
},
|
345
369
|
},
|
346
370
|
};
|
371
|
+
}, _AccountsController_getSnapKeyring = function _AccountsController_getSnapKeyring() {
|
372
|
+
const [snapKeyring] = this.messagingSystem.call('KeyringController:getKeyringsByType', SnapKeyring.type);
|
373
|
+
// Snap keyring is not available until the first account is created in the keyring
|
374
|
+
// controller, so this might be undefined.
|
375
|
+
return snapKeyring;
|
347
376
|
}, _AccountsController_listSnapAccounts =
|
348
377
|
/**
|
349
378
|
* Returns a list of internal accounts created using the SnapKeyring.
|
@@ -351,13 +380,11 @@ _AccountsController_instances = new WeakSet(), _AccountsController_generateInter
|
|
351
380
|
* @returns A promise that resolves to an array of InternalAccount objects.
|
352
381
|
*/
|
353
382
|
async function _AccountsController_listSnapAccounts() {
|
354
|
-
const
|
355
|
-
|
356
|
-
if (!snapKeyring) {
|
383
|
+
const keyring = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getSnapKeyring).call(this);
|
384
|
+
if (!keyring) {
|
357
385
|
return [];
|
358
386
|
}
|
359
|
-
|
360
|
-
return snapAccounts;
|
387
|
+
return keyring.listAccounts();
|
361
388
|
}, _AccountsController_listNormalAccounts =
|
362
389
|
/**
|
363
390
|
* Returns a list of normal accounts.
|
@@ -368,20 +395,30 @@ async function _AccountsController_listSnapAccounts() {
|
|
368
395
|
*/
|
369
396
|
async function _AccountsController_listNormalAccounts() {
|
370
397
|
const internalAccounts = [];
|
371
|
-
const { keyrings } =
|
398
|
+
const { keyrings } = this.messagingSystem.call('KeyringController:getState');
|
372
399
|
for (const keyring of keyrings) {
|
373
400
|
const keyringType = keyring.type;
|
374
401
|
if (!isNormalKeyringType(keyringType)) {
|
375
402
|
// We only consider "normal accounts" here, so keep looping
|
376
403
|
continue;
|
377
404
|
}
|
378
|
-
for (const address of keyring.accounts) {
|
405
|
+
for (const [accountIndex, address] of keyring.accounts.entries()) {
|
379
406
|
const id = getUUIDFromAddressOfNormalAccount(address);
|
407
|
+
let options = {};
|
408
|
+
if (isHdKeyringType(keyring.type)) {
|
409
|
+
options = {
|
410
|
+
entropySource: keyring.metadata.id,
|
411
|
+
// NOTE: We are not using the `hdPath` from the associated keyring here and
|
412
|
+
// getting the keyring instance here feels a bit overkill.
|
413
|
+
// This will be naturally fixed once every keyring start using `KeyringAccount` and implement the keyring API.
|
414
|
+
derivationPath: getDerivationPathForIndex(accountIndex),
|
415
|
+
};
|
416
|
+
}
|
380
417
|
const nameLastUpdatedAt = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_populateExistingMetadata).call(this, id, 'nameLastUpdatedAt');
|
381
418
|
internalAccounts.push({
|
382
419
|
id,
|
383
420
|
address,
|
384
|
-
options
|
421
|
+
options,
|
385
422
|
methods: [
|
386
423
|
EthMethod.PersonalSign,
|
387
424
|
EthMethod.Sign,
|
@@ -407,122 +444,178 @@ async function _AccountsController_listNormalAccounts() {
|
|
407
444
|
return internalAccounts;
|
408
445
|
}, _AccountsController_handleOnSnapKeyringAccountEvent = function _AccountsController_handleOnSnapKeyringAccountEvent(event, ...payload) {
|
409
446
|
this.messagingSystem.publish(event, ...payload);
|
410
|
-
}, _AccountsController_handleOnKeyringStateChange = function _AccountsController_handleOnKeyringStateChange(
|
411
|
-
//
|
412
|
-
// TODO: change when accountAdded event is added to the keyring controller
|
447
|
+
}, _AccountsController_handleOnKeyringStateChange = function _AccountsController_handleOnKeyringStateChange({ isUnlocked, keyrings, }) {
|
448
|
+
// TODO: Change when accountAdded event is added to the keyring controller.
|
413
449
|
// We check for keyrings length to be greater than 0 because the extension client may try execute
|
414
450
|
// submit password twice and clear the keyring state.
|
415
451
|
// https://github.com/MetaMask/KeyringController/blob/2d73a4deed8d013913f6ef0c9f5c0bb7c614f7d3/src/KeyringController.ts#L910
|
416
|
-
if (
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
452
|
+
if (!isUnlocked || keyrings.length === 0) {
|
453
|
+
return;
|
454
|
+
}
|
455
|
+
// State patches.
|
456
|
+
const generatePatch = () => {
|
457
|
+
return {
|
458
|
+
previous: {},
|
459
|
+
added: [],
|
460
|
+
updated: [],
|
461
|
+
removed: [],
|
462
|
+
};
|
463
|
+
};
|
464
|
+
const patches = {
|
465
|
+
snap: generatePatch(),
|
466
|
+
normal: generatePatch(),
|
467
|
+
};
|
468
|
+
// Gets the patch object based on the keyring type (since Snap accounts and other accounts
|
469
|
+
// are handled differently).
|
470
|
+
const patchOf = (type) => {
|
471
|
+
if (type === KeyringTypes.snap) {
|
472
|
+
return patches.snap;
|
436
473
|
}
|
437
|
-
|
438
|
-
|
439
|
-
|
474
|
+
return patches.normal;
|
475
|
+
};
|
476
|
+
// Create a map (with lower-cased addresses) of all existing accounts.
|
477
|
+
for (const account of this.listMultichainAccounts()) {
|
478
|
+
const address = account.address.toLowerCase();
|
479
|
+
const patch = patchOf(account.metadata.keyring.type);
|
480
|
+
patch.previous[address] = account;
|
481
|
+
}
|
482
|
+
// Go over all keyring changes and create patches out of it.
|
483
|
+
const addresses = new Set();
|
484
|
+
for (const keyring of keyrings) {
|
485
|
+
const patch = patchOf(keyring.type);
|
486
|
+
for (const accountAddress of keyring.accounts) {
|
487
|
+
// Lower-case address to use it in the `previous` map.
|
488
|
+
const address = accountAddress.toLowerCase();
|
489
|
+
const account = patch.previous[address];
|
490
|
+
if (account) {
|
491
|
+
// If the account exists before, this might be an update.
|
492
|
+
patch.updated.push(account);
|
440
493
|
}
|
441
494
|
else {
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
previousSnapInternalAccounts: [],
|
448
|
-
});
|
449
|
-
const addedAccounts = [];
|
450
|
-
const deletedAccounts = [];
|
451
|
-
// snap account ids are random uuid while normal accounts
|
452
|
-
// are determininistic based on the address
|
453
|
-
// ^NOTE: This will be removed when normal accounts also implement internal accounts
|
454
|
-
// finding all the normal accounts that were added
|
455
|
-
for (const account of updatedNormalKeyringAddresses) {
|
456
|
-
if (!this.state.internalAccounts.accounts[getUUIDFromAddressOfNormalAccount(account.address)]) {
|
457
|
-
addedAccounts.push(account);
|
495
|
+
// Otherwise, that's a new account.
|
496
|
+
patch.added.push({
|
497
|
+
address,
|
498
|
+
type: keyring.type,
|
499
|
+
});
|
458
500
|
}
|
501
|
+
// Keep track of those address to check for removed accounts later.
|
502
|
+
addresses.add(address);
|
459
503
|
}
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
504
|
+
}
|
505
|
+
// We might have accounts associated with removed keyrings, so we iterate
|
506
|
+
// over all previous known accounts and check against the keyring addresses.
|
507
|
+
for (const patch of [patches.snap, patches.normal]) {
|
508
|
+
for (const [address, account] of Object.entries(patch.previous)) {
|
509
|
+
// If a previous address is not part of the new addesses, then it got removed.
|
510
|
+
if (!addresses.has(address)) {
|
511
|
+
patch.removed.push(account);
|
465
512
|
}
|
466
513
|
}
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
514
|
+
}
|
515
|
+
// Diff that we will use to publish events afterward.
|
516
|
+
const diff = {
|
517
|
+
removed: [],
|
518
|
+
added: [],
|
519
|
+
};
|
520
|
+
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_update).call(this, (state) => {
|
521
|
+
const { internalAccounts } = state;
|
522
|
+
for (const patch of [patches.snap, patches.normal]) {
|
523
|
+
for (const account of patch.removed) {
|
524
|
+
delete internalAccounts.accounts[account.id];
|
525
|
+
diff.removed.push(account.id);
|
471
526
|
}
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
527
|
+
for (const added of patch.added) {
|
528
|
+
const account = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getInternalAccountFromAddressAndType).call(this, added.address, added.type);
|
529
|
+
if (account) {
|
530
|
+
// Re-compute the list of accounts everytime, so we can make sure new names
|
531
|
+
// are also considered.
|
532
|
+
const accounts = Object.values(internalAccounts.accounts);
|
533
|
+
// Get next account name available for this given keyring.
|
534
|
+
const name = this.getNextAvailableAccountName(account.metadata.keyring.type, accounts);
|
535
|
+
// If it's the first account, we need to select it.
|
536
|
+
const lastSelected = accounts.length === 0 ? __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this) : 0;
|
537
|
+
internalAccounts.accounts[account.id] = {
|
538
|
+
...account,
|
539
|
+
metadata: {
|
540
|
+
...account.metadata,
|
541
|
+
name,
|
542
|
+
importTime: Date.now(),
|
543
|
+
lastSelected,
|
544
|
+
},
|
545
|
+
};
|
546
|
+
diff.added.push(internalAccounts.accounts[account.id]);
|
547
|
+
}
|
477
548
|
}
|
478
549
|
}
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
550
|
+
});
|
551
|
+
// Now publish events
|
552
|
+
for (const id of diff.removed) {
|
553
|
+
this.messagingSystem.publish('AccountsController:accountRemoved', id);
|
554
|
+
}
|
555
|
+
for (const account of diff.added) {
|
556
|
+
this.messagingSystem.publish('AccountsController:accountAdded', account);
|
557
|
+
}
|
558
|
+
// NOTE: Since we also track "updated" accounts with our patches, we could fire a new event
|
559
|
+
// like `accountUpdated` (we would still need to check if anything really changed on the account).
|
560
|
+
}, _AccountsController_update = function _AccountsController_update(callback) {
|
561
|
+
// The currently selected account might get deleted during the update, so keep track
|
562
|
+
// of it before doing any change.
|
563
|
+
const previouslySelectedAccount = this.state.internalAccounts.selectedAccount;
|
564
|
+
this.update((state) => {
|
565
|
+
callback(state);
|
566
|
+
// If the account no longer exists (or none is selected), we need to re-select another one.
|
567
|
+
const { internalAccounts } = state;
|
568
|
+
if (!internalAccounts.accounts[previouslySelectedAccount]) {
|
569
|
+
const accounts = Object.values(internalAccounts.accounts);
|
570
|
+
// Get the lastly selected account (according to the current accounts).
|
571
|
+
const lastSelectedAccount = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedAccount).call(this, accounts);
|
572
|
+
if (lastSelectedAccount) {
|
573
|
+
internalAccounts.selectedAccount = lastSelectedAccount.id;
|
574
|
+
internalAccounts.accounts[lastSelectedAccount.id].metadata.lastSelected = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this);
|
484
575
|
}
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
__classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_handleNewAccountAdded).call(this, currentState.internalAccounts.accounts, account);
|
489
|
-
}
|
576
|
+
else {
|
577
|
+
// It will be undefined if there are no accounts.
|
578
|
+
internalAccounts.selectedAccount = '';
|
490
579
|
}
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
else {
|
503
|
-
// It will be undefined if there are no accounts
|
504
|
-
currentState.internalAccounts.selectedAccount = '';
|
505
|
-
}
|
580
|
+
}
|
581
|
+
});
|
582
|
+
// Now, we compare the newly selected account, and we send event if different.
|
583
|
+
const { selectedAccount } = this.state.internalAccounts;
|
584
|
+
if (selectedAccount && selectedAccount !== previouslySelectedAccount) {
|
585
|
+
const account = this.getSelectedMultichainAccount();
|
586
|
+
// The account should always be defined at this point, since we have already checked for
|
587
|
+
// `selectedAccount` to be non-empty.
|
588
|
+
if (account) {
|
589
|
+
if (isEvmAccountType(account.type)) {
|
590
|
+
this.messagingSystem.publish('AccountsController:selectedEvmAccountChange', account);
|
506
591
|
}
|
507
|
-
|
592
|
+
this.messagingSystem.publish('AccountsController:selectedAccountChange', account);
|
593
|
+
}
|
508
594
|
}
|
509
595
|
}, _AccountsController_handleOnSnapStateChange = function _AccountsController_handleOnSnapStateChange(snapState) {
|
510
596
|
// only check if snaps changed in status
|
511
597
|
const { snaps } = snapState;
|
512
|
-
const accounts =
|
513
|
-
this.
|
514
|
-
|
515
|
-
const
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
598
|
+
const accounts = [];
|
599
|
+
for (const account of this.listMultichainAccounts()) {
|
600
|
+
if (account.metadata.snap) {
|
601
|
+
const snap = snaps[account.metadata.snap.id];
|
602
|
+
const enabled = snap.enabled && !snap.blocked;
|
603
|
+
const metadata = account.metadata.snap;
|
604
|
+
if (metadata.enabled !== enabled) {
|
605
|
+
accounts.push({ id: account.id, enabled });
|
606
|
+
}
|
607
|
+
}
|
608
|
+
}
|
609
|
+
if (accounts.length > 0) {
|
610
|
+
this.update((state) => {
|
611
|
+
for (const { id, enabled } of accounts) {
|
612
|
+
const account = state.internalAccounts.accounts[id];
|
613
|
+
if (account.metadata.snap) {
|
614
|
+
account.metadata.snap.enabled = enabled;
|
522
615
|
}
|
523
616
|
}
|
524
617
|
});
|
525
|
-
}
|
618
|
+
}
|
526
619
|
}, _AccountsController_getAccountsByKeyringType = function _AccountsController_getAccountsByKeyringType(keyringType, accounts) {
|
527
620
|
return (accounts ?? this.listMultichainAccounts()).filter((internalAccount) => {
|
528
621
|
// We do consider `hd` and `simple` keyrings to be of same type. So we check those 2 types
|
@@ -545,43 +638,18 @@ async function _AccountsController_listNormalAccounts() {
|
|
545
638
|
// NOTE: For now we use the current date, since we know this value
|
546
639
|
// will always be higher than any already selected account index.
|
547
640
|
return Date.now();
|
548
|
-
},
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
const [snapKeyring] = this.messagingSystem.call('KeyringController:getKeyringsByType', SnapKeyring.type);
|
555
|
-
newAccount = snapKeyring.getAccountByAddress(account.address);
|
556
|
-
// The snap deleted the account before the keyring controller could add it
|
557
|
-
if (!newAccount) {
|
558
|
-
return accountsState;
|
641
|
+
}, _AccountsController_getInternalAccountFromAddressAndType = function _AccountsController_getInternalAccountFromAddressAndType(address, type) {
|
642
|
+
if (type === KeyringTypes.snap) {
|
643
|
+
const keyring = __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getSnapKeyring).call(this);
|
644
|
+
// We need the Snap keyring to retrieve the account from its address.
|
645
|
+
if (!keyring) {
|
646
|
+
return undefined;
|
559
647
|
}
|
648
|
+
// This might be undefined if the Snap deleted the account before
|
649
|
+
// reaching that point.
|
650
|
+
return keyring.getAccountByAddress(address);
|
560
651
|
}
|
561
|
-
|
562
|
-
// Get next account name available for this given keyring
|
563
|
-
const accountName = this.getNextAvailableAccountName(newAccount.metadata.keyring.type, Object.values(accountsState));
|
564
|
-
const newAccountWithUpdatedMetadata = {
|
565
|
-
...newAccount,
|
566
|
-
metadata: {
|
567
|
-
...newAccount.metadata,
|
568
|
-
name: accountName,
|
569
|
-
importTime: Date.now(),
|
570
|
-
lastSelected: isFirstAccount ? __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_getLastSelectedIndex).call(this) : 0,
|
571
|
-
},
|
572
|
-
};
|
573
|
-
accountsState[newAccount.id] = newAccountWithUpdatedMetadata;
|
574
|
-
this.messagingSystem.publish('AccountsController:accountAdded', newAccountWithUpdatedMetadata);
|
575
|
-
return accountsState;
|
576
|
-
}, _AccountsController_publishAccountChangeEvent = function _AccountsController_publishAccountChangeEvent(account) {
|
577
|
-
if (isEvmAccountType(account.type)) {
|
578
|
-
this.messagingSystem.publish('AccountsController:selectedEvmAccountChange', account);
|
579
|
-
}
|
580
|
-
this.messagingSystem.publish('AccountsController:selectedAccountChange', account);
|
581
|
-
}, _AccountsController_handleAccountRemoved = function _AccountsController_handleAccountRemoved(accountsState, accountId) {
|
582
|
-
delete accountsState[accountId];
|
583
|
-
this.messagingSystem.publish('AccountsController:accountRemoved', accountId);
|
584
|
-
return accountsState;
|
652
|
+
return __classPrivateFieldGet(this, _AccountsController_instances, "m", _AccountsController_generateInternalAccountForNonSnapAccount).call(this, address, type);
|
585
653
|
}, _AccountsController_handleOnMultichainNetworkDidChange = function _AccountsController_handleOnMultichainNetworkDidChange(id) {
|
586
654
|
let accountId;
|
587
655
|
// We only support non-EVM Caip chain IDs at the moment. Ex Solana and Bitcoin
|
@@ -619,6 +687,7 @@ async function _AccountsController_listNormalAccounts() {
|
|
619
687
|
this.messagingSystem.registerActionHandler(`${controllerName}:listAccounts`, this.listAccounts.bind(this));
|
620
688
|
this.messagingSystem.registerActionHandler(`${controllerName}:listMultichainAccounts`, this.listMultichainAccounts.bind(this));
|
621
689
|
this.messagingSystem.registerActionHandler(`${controllerName}:setAccountName`, this.setAccountName.bind(this));
|
690
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:setAccountNameAndSelectAccount`, this.setAccountNameAndSelectAccount.bind(this));
|
622
691
|
this.messagingSystem.registerActionHandler(`${controllerName}:updateAccounts`, this.updateAccounts.bind(this));
|
623
692
|
this.messagingSystem.registerActionHandler(`${controllerName}:getSelectedAccount`, this.getSelectedAccount.bind(this));
|
624
693
|
this.messagingSystem.registerActionHandler(`${controllerName}:getSelectedMultichainAccount`, this.getSelectedMultichainAccount.bind(this));
|