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