@metamask-previews/keyring-controller 15.0.0-preview-2036edd1 → 15.0.0-preview-61ace68c

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.
@@ -3,7 +3,7 @@ import {
3
3
  __privateGet,
4
4
  __privateMethod,
5
5
  __privateSet
6
- } from "./chunk-XPARO3LL.mjs";
6
+ } from "./chunk-HT7WOORD.mjs";
7
7
 
8
8
  // src/KeyringController.ts
9
9
  import { isValidPrivate, toBuffer, getBinarySize } from "@ethereumjs/util";
@@ -86,7 +86,7 @@ async function displayForKeyring(keyring) {
86
86
  accounts: accounts.map(normalize)
87
87
  };
88
88
  }
89
- var _initVaultMutex, _vaultOperationMutex, _keyringBuilders, _keyrings, _unsupportedKeyrings, _password, _encryptor, _cacheEncryptionKey, _qrKeyringStateListener, _registerMessageHandlers, registerMessageHandlers_fn, _getKeyringBuilderForType, getKeyringBuilderForType_fn, _addQRKeyring, addQRKeyring_fn, _subscribeToQRKeyringEvents, subscribeToQRKeyringEvents_fn, _unsubscribeFromQRKeyringsEvents, unsubscribeFromQRKeyringsEvents_fn, _createNewVaultWithKeyring, createNewVaultWithKeyring_fn, _getUpdatedKeyrings, getUpdatedKeyrings_fn, _unlockKeyrings, unlockKeyrings_fn, _updateVault, updateVault_fn, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn, _createKeyringWithFirstAccount, createKeyringWithFirstAccount_fn, _newKeyring, newKeyring_fn, _clearKeyrings, clearKeyrings_fn, _restoreKeyring, restoreKeyring_fn, _destroyKeyring, destroyKeyring_fn, _removeEmptyKeyrings, removeEmptyKeyrings_fn, _checkForDuplicate, checkForDuplicate_fn, _setUnlocked, setUnlocked_fn, _getMemState, getMemState_fn, _withVaultLock, withVaultLock_fn;
89
+ var _controllerOperationMutex, _vaultOperationMutex, _keyringBuilders, _keyrings, _unsupportedKeyrings, _password, _encryptor, _cacheEncryptionKey, _qrKeyringStateListener, _registerMessageHandlers, registerMessageHandlers_fn, _getKeyringBuilderForType, getKeyringBuilderForType_fn, _addQRKeyring, addQRKeyring_fn, _subscribeToQRKeyringEvents, subscribeToQRKeyringEvents_fn, _unsubscribeFromQRKeyringsEvents, unsubscribeFromQRKeyringsEvents_fn, _createNewVaultWithKeyring, createNewVaultWithKeyring_fn, _getUpdatedKeyrings, getUpdatedKeyrings_fn, _unlockKeyrings, unlockKeyrings_fn, _updateVault, updateVault_fn, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn, _createKeyringWithFirstAccount, createKeyringWithFirstAccount_fn, _newKeyring, newKeyring_fn, _clearKeyrings, clearKeyrings_fn, _restoreKeyring, restoreKeyring_fn, _destroyKeyring, destroyKeyring_fn, _removeEmptyKeyrings, removeEmptyKeyrings_fn, _checkForDuplicate, checkForDuplicate_fn, _setUnlocked, setUnlocked_fn, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn, _withControllerLock, withControllerLock_fn, _withVaultLock, withVaultLock_fn;
90
90
  var KeyringController = class extends BaseController {
91
91
  /**
92
92
  * Creates a KeyringController instance.
@@ -266,7 +266,25 @@ var KeyringController = class extends BaseController {
266
266
  * @fires KeyringController:unlock
267
267
  */
268
268
  __privateAdd(this, _setUnlocked);
269
- __privateAdd(this, _getMemState);
269
+ /**
270
+ * Assert that the controller mutex is locked.
271
+ *
272
+ * @throws If the controller mutex is not locked.
273
+ */
274
+ __privateAdd(this, _assertControllerMutexIsLocked);
275
+ /**
276
+ * Lock the controller mutex before executing the given function,
277
+ * and release it after the function is resolved or after an
278
+ * error is thrown.
279
+ *
280
+ * This wrapper ensures that each mutable operation that interacts with the
281
+ * controller and that changes its state is executed in a mutually exclusive way,
282
+ * preventing unsafe concurrent access that could lead to unpredictable behavior.
283
+ *
284
+ * @param fn - The function to execute while the controller mutex is locked.
285
+ * @returns The result of the function.
286
+ */
287
+ __privateAdd(this, _withControllerLock);
270
288
  /**
271
289
  * Lock the vault mutex before executing the given function,
272
290
  * and release it after the function is resolved or after an
@@ -279,7 +297,7 @@ var KeyringController = class extends BaseController {
279
297
  * @returns The result of the function.
280
298
  */
281
299
  __privateAdd(this, _withVaultLock);
282
- __privateAdd(this, _initVaultMutex, new Mutex());
300
+ __privateAdd(this, _controllerOperationMutex, new Mutex());
283
301
  __privateAdd(this, _vaultOperationMutex, new Mutex());
284
302
  __privateAdd(this, _keyringBuilders, void 0);
285
303
  __privateAdd(this, _keyrings, void 0);
@@ -303,75 +321,74 @@ var KeyringController = class extends BaseController {
303
321
  *
304
322
  * @param accountCount - Number of accounts before adding a new one, used to
305
323
  * make the method idempotent.
306
- * @returns Promise resolving to keyring current state and added account
307
- * address.
324
+ * @returns Promise resolving to the added account address.
308
325
  */
309
326
  async addNewAccount(accountCount) {
310
- const primaryKeyring = this.getKeyringsByType("HD Key Tree")[0];
311
- if (!primaryKeyring) {
312
- throw new Error("No HD keyring found");
313
- }
314
- const oldAccounts = await primaryKeyring.getAccounts();
315
- if (accountCount && oldAccounts.length !== accountCount) {
316
- if (accountCount > oldAccounts.length) {
317
- throw new Error("Account out of sequence");
327
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
328
+ const primaryKeyring = this.getKeyringsByType("HD Key Tree")[0];
329
+ if (!primaryKeyring) {
330
+ throw new Error("No HD keyring found");
318
331
  }
319
- const existingAccount = oldAccounts[accountCount];
320
- if (!existingAccount) {
321
- throw new Error(`Can't find account at index ${accountCount}`);
332
+ const oldAccounts = await primaryKeyring.getAccounts();
333
+ if (accountCount && oldAccounts.length !== accountCount) {
334
+ if (accountCount > oldAccounts.length) {
335
+ throw new Error("Account out of sequence");
336
+ }
337
+ const existingAccount = oldAccounts[accountCount];
338
+ if (!existingAccount) {
339
+ throw new Error(`Can't find account at index ${accountCount}`);
340
+ }
341
+ return existingAccount;
322
342
  }
323
- return {
324
- keyringState: __privateMethod(this, _getMemState, getMemState_fn).call(this),
325
- addedAccountAddress: existingAccount
326
- };
327
- }
328
- const [addedAccountAddress] = await primaryKeyring.addAccounts(1);
329
- await this.verifySeedPhrase();
330
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
331
- return {
332
- keyringState: __privateMethod(this, _getMemState, getMemState_fn).call(this),
333
- addedAccountAddress
334
- };
343
+ const [addedAccountAddress] = await primaryKeyring.addAccounts(1);
344
+ await this.verifySeedPhrase();
345
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
346
+ return addedAccountAddress;
347
+ });
335
348
  }
336
349
  /**
337
350
  * Adds a new account to the specified keyring.
338
351
  *
339
352
  * @param keyring - Keyring to add the account to.
340
353
  * @param accountCount - Number of accounts before adding a new one, used to make the method idempotent.
341
- * @returns Promise resolving to keyring current state and added account
354
+ * @returns Promise resolving to the added account address
342
355
  */
343
356
  async addNewAccountForKeyring(keyring, accountCount) {
344
- const oldAccounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
345
- if (accountCount && oldAccounts.length !== accountCount) {
346
- if (accountCount > oldAccounts.length) {
347
- throw new Error("Account out of sequence");
357
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
358
+ const oldAccounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
359
+ if (accountCount && oldAccounts.length !== accountCount) {
360
+ if (accountCount > oldAccounts.length) {
361
+ throw new Error("Account out of sequence");
362
+ }
363
+ const existingAccount = oldAccounts[accountCount];
364
+ assertIsStrictHexString(existingAccount);
365
+ return existingAccount;
348
366
  }
349
- const existingAccount = oldAccounts[accountCount];
350
- assertIsStrictHexString(existingAccount);
351
- return existingAccount;
352
- }
353
- await keyring.addAccounts(1);
354
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
355
- const addedAccountAddress = (await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this)).find(
356
- (selectedAddress) => !oldAccounts.includes(selectedAddress)
357
- );
358
- assertIsStrictHexString(addedAccountAddress);
359
- return addedAccountAddress;
367
+ await keyring.addAccounts(1);
368
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
369
+ const addedAccountAddress = (await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this)).find(
370
+ (selectedAddress) => !oldAccounts.includes(selectedAddress)
371
+ );
372
+ assertIsStrictHexString(addedAccountAddress);
373
+ return addedAccountAddress;
374
+ });
360
375
  }
361
376
  /**
362
377
  * Adds a new account to the default (first) HD seed phrase keyring without updating identities in preferences.
363
378
  *
364
- * @returns Promise resolving to current state when the account is added.
379
+ * @returns Promise resolving to the added account address.
365
380
  */
366
381
  async addNewAccountWithoutUpdate() {
367
- const primaryKeyring = this.getKeyringsByType("HD Key Tree")[0];
368
- if (!primaryKeyring) {
369
- throw new Error("No HD keyring found");
370
- }
371
- await primaryKeyring.addAccounts(1);
372
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
373
- await this.verifySeedPhrase();
374
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
382
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
383
+ const primaryKeyring = this.getKeyringsByType("HD Key Tree")[0];
384
+ if (!primaryKeyring) {
385
+ throw new Error("No HD keyring found");
386
+ }
387
+ const [addedAccountAddress] = await primaryKeyring.addAccounts(1);
388
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
389
+ await this.verifySeedPhrase();
390
+ return addedAccountAddress;
391
+ });
375
392
  }
376
393
  /**
377
394
  * Effectively the same as creating a new keychain then populating it
@@ -380,14 +397,13 @@ var KeyringController = class extends BaseController {
380
397
  * @param password - Password to unlock keychain.
381
398
  * @param seed - A BIP39-compliant seed phrase as Uint8Array,
382
399
  * either as a string or an array of UTF-8 bytes that represent the string.
383
- * @returns Promise resolving to the restored keychain object.
400
+ * @returns Promise resolving when the operation ends successfully.
384
401
  */
385
402
  async createNewVaultAndRestore(password, seed) {
386
- const releaseLock = await __privateGet(this, _initVaultMutex).acquire();
387
- if (!password || !password.length) {
388
- throw new Error("Invalid password");
389
- }
390
- try {
403
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
404
+ if (!password || !password.length) {
405
+ throw new Error("Invalid password");
406
+ }
391
407
  await __privateMethod(this, _createNewVaultWithKeyring, createNewVaultWithKeyring_fn).call(this, password, {
392
408
  type: "HD Key Tree" /* hd */,
393
409
  opts: {
@@ -395,30 +411,23 @@ var KeyringController = class extends BaseController {
395
411
  numberOfAccounts: 1
396
412
  }
397
413
  });
398
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
399
- } finally {
400
- releaseLock();
401
- }
414
+ });
402
415
  }
403
416
  /**
404
417
  * Create a new primary keychain and wipe any previous keychains.
405
418
  *
406
419
  * @param password - Password to unlock the new vault.
407
- * @returns Newly-created keychain object.
420
+ * @returns Promise resolving when the operation ends successfully.
408
421
  */
409
422
  async createNewVaultAndKeychain(password) {
410
- const releaseLock = await __privateGet(this, _initVaultMutex).acquire();
411
- try {
423
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
412
424
  const accounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
413
425
  if (!accounts.length) {
414
426
  await __privateMethod(this, _createNewVaultWithKeyring, createNewVaultWithKeyring_fn).call(this, password, {
415
427
  type: "HD Key Tree" /* hd */
416
428
  });
417
429
  }
418
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
419
- } finally {
420
- releaseLock();
421
- }
430
+ });
422
431
  }
423
432
  /**
424
433
  * Adds a new keyring of the given `type`.
@@ -432,7 +441,7 @@ var KeyringController = class extends BaseController {
432
441
  if (type === "QR Hardware Wallet Device" /* qr */) {
433
442
  return this.getOrAddQRKeyring();
434
443
  }
435
- return __privateMethod(this, _newKeyring, newKeyring_fn).call(this, type, opts, true);
444
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => __privateMethod(this, _newKeyring, newKeyring_fn).call(this, type, opts, true));
436
445
  }
437
446
  /**
438
447
  * Method to verify a given password validity. Throws an
@@ -488,7 +497,10 @@ var KeyringController = class extends BaseController {
488
497
  * @returns A promise resolving to an array of addresses.
489
498
  */
490
499
  async getAccounts() {
491
- return __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
500
+ return this.state.keyrings.reduce(
501
+ (accounts, keyring) => accounts.concat(keyring.accounts),
502
+ []
503
+ );
492
504
  }
493
505
  /**
494
506
  * Get encryption public key.
@@ -581,7 +593,7 @@ var KeyringController = class extends BaseController {
581
593
  * operation completes.
582
594
  */
583
595
  async persistAllKeyrings() {
584
- return __privateMethod(this, _updateVault, updateVault_fn).call(this);
596
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => __privateMethod(this, _updateVault, updateVault_fn).call(this));
585
597
  }
586
598
  /**
587
599
  * Imports an account with the specified import strategy.
@@ -589,88 +601,88 @@ var KeyringController = class extends BaseController {
589
601
  * @param strategy - Import strategy name.
590
602
  * @param args - Array of arguments to pass to the underlying stategy.
591
603
  * @throws Will throw when passed an unrecognized strategy.
592
- * @returns Promise resolving to keyring current state and imported account
593
- * address.
604
+ * @returns Promise resolving to the imported account address.
594
605
  */
595
606
  async importAccountWithStrategy(strategy, args) {
596
- let privateKey;
597
- switch (strategy) {
598
- case "privateKey":
599
- const [importedKey] = args;
600
- if (!importedKey) {
601
- throw new Error("Cannot import an empty key.");
602
- }
603
- const prefixed = add0x(importedKey);
604
- let bufferedPrivateKey;
605
- try {
606
- bufferedPrivateKey = toBuffer(prefixed);
607
- } catch {
608
- throw new Error("Cannot import invalid private key.");
609
- }
610
- if (!isValidPrivate(bufferedPrivateKey) || // ensures that the key is 64 bytes long
611
- getBinarySize(prefixed) !== 64 + "0x".length) {
612
- throw new Error("Cannot import invalid private key.");
613
- }
614
- privateKey = remove0x(prefixed);
615
- break;
616
- case "json":
617
- let wallet;
618
- const [input, password] = args;
619
- try {
620
- wallet = importers.fromEtherWallet(input, password);
621
- } catch (e) {
622
- wallet = wallet || await Wallet.fromV3(input, password, true);
623
- }
624
- privateKey = bytesToHex(wallet.getPrivateKey());
625
- break;
626
- default:
627
- throw new Error(`Unexpected import strategy: '${strategy}'`);
628
- }
629
- const newKeyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, "Simple Key Pair" /* simple */, [privateKey], true);
630
- const accounts = await newKeyring.getAccounts();
631
- return {
632
- keyringState: __privateMethod(this, _getMemState, getMemState_fn).call(this),
633
- importedAccountAddress: accounts[0]
634
- };
607
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
608
+ let privateKey;
609
+ switch (strategy) {
610
+ case "privateKey":
611
+ const [importedKey] = args;
612
+ if (!importedKey) {
613
+ throw new Error("Cannot import an empty key.");
614
+ }
615
+ const prefixed = add0x(importedKey);
616
+ let bufferedPrivateKey;
617
+ try {
618
+ bufferedPrivateKey = toBuffer(prefixed);
619
+ } catch {
620
+ throw new Error("Cannot import invalid private key.");
621
+ }
622
+ if (!isValidPrivate(bufferedPrivateKey) || // ensures that the key is 64 bytes long
623
+ getBinarySize(prefixed) !== 64 + "0x".length) {
624
+ throw new Error("Cannot import invalid private key.");
625
+ }
626
+ privateKey = remove0x(prefixed);
627
+ break;
628
+ case "json":
629
+ let wallet;
630
+ const [input, password] = args;
631
+ try {
632
+ wallet = importers.fromEtherWallet(input, password);
633
+ } catch (e) {
634
+ wallet = wallet || await Wallet.fromV3(input, password, true);
635
+ }
636
+ privateKey = bytesToHex(wallet.getPrivateKey());
637
+ break;
638
+ default:
639
+ throw new Error(`Unexpected import strategy: '${strategy}'`);
640
+ }
641
+ const newKeyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, "Simple Key Pair" /* simple */, [privateKey], true);
642
+ const accounts = await newKeyring.getAccounts();
643
+ return accounts[0];
644
+ });
635
645
  }
636
646
  /**
637
647
  * Removes an account from keyring state.
638
648
  *
639
649
  * @param address - Address of the account to remove.
640
650
  * @fires KeyringController:accountRemoved
641
- * @returns Promise resolving current state when this account removal completes.
651
+ * @returns Promise resolving when the account is removed.
642
652
  */
643
653
  async removeAccount(address) {
644
- const keyring = await this.getKeyringForAccount(
645
- address
646
- );
647
- if (!keyring.removeAccount) {
648
- throw new Error("`KeyringController - The keyring for the current address does not support the method removeAccount" /* UnsupportedRemoveAccount */);
649
- }
650
- await keyring.removeAccount(address);
651
- const accounts = await keyring.getAccounts();
652
- if (accounts.length === 0) {
653
- await __privateMethod(this, _removeEmptyKeyrings, removeEmptyKeyrings_fn).call(this);
654
- }
655
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
654
+ await __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
655
+ const keyring = await this.getKeyringForAccount(
656
+ address
657
+ );
658
+ if (!keyring.removeAccount) {
659
+ throw new Error("`KeyringController - The keyring for the current address does not support the method removeAccount" /* UnsupportedRemoveAccount */);
660
+ }
661
+ await keyring.removeAccount(address);
662
+ const accounts = await keyring.getAccounts();
663
+ if (accounts.length === 0) {
664
+ await __privateMethod(this, _removeEmptyKeyrings, removeEmptyKeyrings_fn).call(this);
665
+ }
666
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
667
+ });
656
668
  this.messagingSystem.publish(`${name}:accountRemoved`, address);
657
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
658
669
  }
659
670
  /**
660
671
  * Deallocates all secrets and locks the wallet.
661
672
  *
662
- * @returns Promise resolving to current state.
673
+ * @returns Promise resolving when the operation completes.
663
674
  */
664
675
  async setLocked() {
665
- __privateMethod(this, _unsubscribeFromQRKeyringsEvents, unsubscribeFromQRKeyringsEvents_fn).call(this);
666
- __privateSet(this, _password, void 0);
667
- this.update((state) => {
668
- state.isUnlocked = false;
669
- state.keyrings = [];
676
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
677
+ __privateMethod(this, _unsubscribeFromQRKeyringsEvents, unsubscribeFromQRKeyringsEvents_fn).call(this);
678
+ __privateSet(this, _password, void 0);
679
+ this.update((state) => {
680
+ state.isUnlocked = false;
681
+ state.keyrings = [];
682
+ });
683
+ await __privateMethod(this, _clearKeyrings, clearKeyrings_fn).call(this);
684
+ this.messagingSystem.publish(`${name}:lock`);
670
685
  });
671
- await __privateMethod(this, _clearKeyrings, clearKeyrings_fn).call(this);
672
- this.messagingSystem.publish(`${name}:lock`);
673
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
674
686
  }
675
687
  /**
676
688
  * Signs message by calling down into a specific keyring.
@@ -824,32 +836,34 @@ var KeyringController = class extends BaseController {
824
836
  *
825
837
  * @param encryptionKey - Key to unlock the keychain.
826
838
  * @param encryptionSalt - Salt to unlock the keychain.
827
- * @returns Promise resolving to the current state.
839
+ * @returns Promise resolving when the operation completes.
828
840
  */
829
841
  async submitEncryptionKey(encryptionKey, encryptionSalt) {
830
- __privateSet(this, _keyrings, await __privateMethod(this, _unlockKeyrings, unlockKeyrings_fn).call(this, void 0, encryptionKey, encryptionSalt));
831
- __privateMethod(this, _setUnlocked, setUnlocked_fn).call(this);
832
- const qrKeyring = this.getQRKeyring();
833
- if (qrKeyring) {
834
- __privateMethod(this, _subscribeToQRKeyringEvents, subscribeToQRKeyringEvents_fn).call(this, qrKeyring);
835
- }
836
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
842
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
843
+ __privateSet(this, _keyrings, await __privateMethod(this, _unlockKeyrings, unlockKeyrings_fn).call(this, void 0, encryptionKey, encryptionSalt));
844
+ __privateMethod(this, _setUnlocked, setUnlocked_fn).call(this);
845
+ const qrKeyring = this.getQRKeyring();
846
+ if (qrKeyring) {
847
+ __privateMethod(this, _subscribeToQRKeyringEvents, subscribeToQRKeyringEvents_fn).call(this, qrKeyring);
848
+ }
849
+ });
837
850
  }
838
851
  /**
839
852
  * Attempts to decrypt the current vault and load its keyrings,
840
853
  * using the given password.
841
854
  *
842
855
  * @param password - Password to unlock the keychain.
843
- * @returns Promise resolving to the current state.
856
+ * @returns Promise resolving when the operation completes.
844
857
  */
845
858
  async submitPassword(password) {
846
- __privateSet(this, _keyrings, await __privateMethod(this, _unlockKeyrings, unlockKeyrings_fn).call(this, password));
847
- __privateMethod(this, _setUnlocked, setUnlocked_fn).call(this);
848
- const qrKeyring = this.getQRKeyring();
849
- if (qrKeyring) {
850
- __privateMethod(this, _subscribeToQRKeyringEvents, subscribeToQRKeyringEvents_fn).call(this, qrKeyring);
851
- }
852
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
859
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
860
+ __privateSet(this, _keyrings, await __privateMethod(this, _unlockKeyrings, unlockKeyrings_fn).call(this, password));
861
+ __privateMethod(this, _setUnlocked, setUnlocked_fn).call(this);
862
+ const qrKeyring = this.getQRKeyring();
863
+ if (qrKeyring) {
864
+ __privateMethod(this, _subscribeToQRKeyringEvents, subscribeToQRKeyringEvents_fn).call(this, qrKeyring);
865
+ }
866
+ });
853
867
  }
854
868
  /**
855
869
  * Verifies the that the seed phrase restores the current keychain's accounts.
@@ -899,14 +913,16 @@ var KeyringController = class extends BaseController {
899
913
  * @returns The added keyring
900
914
  */
901
915
  async getOrAddQRKeyring() {
902
- return this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
916
+ return this.getQRKeyring() || await __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this));
903
917
  }
904
918
  // TODO: Replace `any` with type
905
919
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
906
920
  async restoreQRKeyring(serialized) {
907
- const keyring = this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
908
- keyring.deserialize(serialized);
909
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
921
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
922
+ const keyring = this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
923
+ keyring.deserialize(serialized);
924
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
925
+ });
910
926
  }
911
927
  async resetQRKeyringState() {
912
928
  (await this.getOrAddQRKeyring()).resetStore();
@@ -933,34 +949,38 @@ var KeyringController = class extends BaseController {
933
949
  (await this.getOrAddQRKeyring()).cancelSync();
934
950
  }
935
951
  async connectQRHardware(page) {
936
- try {
937
- const keyring = this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
938
- let accounts;
939
- switch (page) {
940
- case -1:
941
- accounts = await keyring.getPreviousPage();
942
- break;
943
- case 1:
944
- accounts = await keyring.getNextPage();
945
- break;
946
- default:
947
- accounts = await keyring.getFirstPage();
952
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
953
+ try {
954
+ const keyring = this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
955
+ let accounts;
956
+ switch (page) {
957
+ case -1:
958
+ accounts = await keyring.getPreviousPage();
959
+ break;
960
+ case 1:
961
+ accounts = await keyring.getNextPage();
962
+ break;
963
+ default:
964
+ accounts = await keyring.getFirstPage();
965
+ }
966
+ return accounts.map((account) => {
967
+ return {
968
+ ...account,
969
+ balance: "0x0"
970
+ };
971
+ });
972
+ } catch (e) {
973
+ throw new Error(`Unspecified error when connect QR Hardware, ${e}`);
948
974
  }
949
- return accounts.map((account) => {
950
- return {
951
- ...account,
952
- balance: "0x0"
953
- };
954
- });
955
- } catch (e) {
956
- throw new Error(`Unspecified error when connect QR Hardware, ${e}`);
957
- }
975
+ });
958
976
  }
959
977
  async unlockQRHardwareWalletAccount(index) {
960
- const keyring = this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
961
- keyring.setAccountToUnlock(index);
962
- await keyring.addAccounts(1);
963
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
978
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
979
+ const keyring = this.getQRKeyring() || await __privateMethod(this, _addQRKeyring, addQRKeyring_fn).call(this);
980
+ keyring.setAccountToUnlock(index);
981
+ await keyring.addAccounts(1);
982
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
983
+ });
964
984
  }
965
985
  async getAccountKeyringType(account) {
966
986
  const keyring = await this.getKeyringForAccount(
@@ -969,21 +989,23 @@ var KeyringController = class extends BaseController {
969
989
  return keyring.type;
970
990
  }
971
991
  async forgetQRDevice() {
972
- const keyring = this.getQRKeyring();
973
- if (!keyring) {
974
- return { removedAccounts: [], remainingAccounts: [] };
975
- }
976
- const allAccounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
977
- keyring.forgetDevice();
978
- const remainingAccounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
979
- const removedAccounts = allAccounts.filter(
980
- (address) => !remainingAccounts.includes(address)
981
- );
982
- await __privateMethod(this, _updateVault, updateVault_fn).call(this);
983
- return { removedAccounts, remainingAccounts };
992
+ return __privateMethod(this, _withControllerLock, withControllerLock_fn).call(this, async () => {
993
+ const keyring = this.getQRKeyring();
994
+ if (!keyring) {
995
+ return { removedAccounts: [], remainingAccounts: [] };
996
+ }
997
+ const allAccounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
998
+ keyring.forgetDevice();
999
+ const remainingAccounts = await __privateMethod(this, _getAccountsFromKeyrings, getAccountsFromKeyrings_fn).call(this);
1000
+ const removedAccounts = allAccounts.filter(
1001
+ (address) => !remainingAccounts.includes(address)
1002
+ );
1003
+ await __privateMethod(this, _updateVault, updateVault_fn).call(this);
1004
+ return { removedAccounts, remainingAccounts };
1005
+ });
984
1006
  }
985
1007
  };
986
- _initVaultMutex = new WeakMap();
1008
+ _controllerOperationMutex = new WeakMap();
987
1009
  _vaultOperationMutex = new WeakMap();
988
1010
  _keyringBuilders = new WeakMap();
989
1011
  _keyrings = new WeakMap();
@@ -1051,6 +1073,7 @@ getKeyringBuilderForType_fn = function(type) {
1051
1073
  };
1052
1074
  _addQRKeyring = new WeakSet();
1053
1075
  addQRKeyring_fn = async function() {
1076
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1054
1077
  const qrKeyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, "QR Hardware Wallet Device" /* qr */, {
1055
1078
  accounts: []
1056
1079
  });
@@ -1081,6 +1104,7 @@ unsubscribeFromQRKeyringsEvents_fn = function() {
1081
1104
  };
1082
1105
  _createNewVaultWithKeyring = new WeakSet();
1083
1106
  createNewVaultWithKeyring_fn = async function(password, keyring) {
1107
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1084
1108
  if (typeof password !== "string") {
1085
1109
  throw new TypeError("KeyringController - Password must be of type string." /* WrongPasswordType */);
1086
1110
  }
@@ -1088,7 +1112,6 @@ createNewVaultWithKeyring_fn = async function(password, keyring) {
1088
1112
  await __privateMethod(this, _clearKeyrings, clearKeyrings_fn).call(this);
1089
1113
  await __privateMethod(this, _createKeyringWithFirstAccount, createKeyringWithFirstAccount_fn).call(this, keyring.type, keyring.opts);
1090
1114
  __privateMethod(this, _setUnlocked, setUnlocked_fn).call(this);
1091
- return __privateMethod(this, _getMemState, getMemState_fn).call(this);
1092
1115
  };
1093
1116
  _getUpdatedKeyrings = new WeakSet();
1094
1117
  getUpdatedKeyrings_fn = async function() {
@@ -1233,6 +1256,7 @@ getAccountsFromKeyrings_fn = async function() {
1233
1256
  };
1234
1257
  _createKeyringWithFirstAccount = new WeakSet();
1235
1258
  createKeyringWithFirstAccount_fn = async function(type, opts) {
1259
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1236
1260
  const keyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, type, opts, true);
1237
1261
  const [firstAccount] = await keyring.getAccounts();
1238
1262
  if (!firstAccount) {
@@ -1241,6 +1265,7 @@ createKeyringWithFirstAccount_fn = async function(type, opts) {
1241
1265
  };
1242
1266
  _newKeyring = new WeakSet();
1243
1267
  newKeyring_fn = async function(type, data, persist = false) {
1268
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1244
1269
  const keyringBuilder = __privateMethod(this, _getKeyringBuilderForType, getKeyringBuilderForType_fn).call(this, type);
1245
1270
  if (!keyringBuilder) {
1246
1271
  throw new Error(
@@ -1270,6 +1295,7 @@ newKeyring_fn = async function(type, data, persist = false) {
1270
1295
  };
1271
1296
  _clearKeyrings = new WeakSet();
1272
1297
  clearKeyrings_fn = async function(options = { skipStateUpdate: false }) {
1298
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1273
1299
  for (const keyring of __privateGet(this, _keyrings)) {
1274
1300
  await __privateMethod(this, _destroyKeyring, destroyKeyring_fn).call(this, keyring);
1275
1301
  }
@@ -1282,6 +1308,7 @@ clearKeyrings_fn = async function(options = { skipStateUpdate: false }) {
1282
1308
  };
1283
1309
  _restoreKeyring = new WeakSet();
1284
1310
  restoreKeyring_fn = async function(serialized) {
1311
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1285
1312
  try {
1286
1313
  const { type, data } = serialized;
1287
1314
  const keyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, type, data);
@@ -1299,6 +1326,7 @@ destroyKeyring_fn = async function(keyring) {
1299
1326
  };
1300
1327
  _removeEmptyKeyrings = new WeakSet();
1301
1328
  removeEmptyKeyrings_fn = async function() {
1329
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1302
1330
  const validKeyrings = [];
1303
1331
  await Promise.all(
1304
1332
  __privateGet(this, _keyrings).map(async (keyring) => {
@@ -1334,27 +1362,35 @@ checkForDuplicate_fn = async function(type, newAccountArray) {
1334
1362
  };
1335
1363
  _setUnlocked = new WeakSet();
1336
1364
  setUnlocked_fn = function() {
1365
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1337
1366
  this.update((state) => {
1338
1367
  state.isUnlocked = true;
1339
1368
  });
1340
1369
  this.messagingSystem.publish(`${name}:unlock`);
1341
1370
  };
1342
- _getMemState = new WeakSet();
1343
- getMemState_fn = function() {
1344
- return {
1345
- isUnlocked: this.state.isUnlocked,
1346
- keyrings: this.state.keyrings
1347
- };
1371
+ _assertControllerMutexIsLocked = new WeakSet();
1372
+ assertControllerMutexIsLocked_fn = function() {
1373
+ if (!__privateGet(this, _controllerOperationMutex).isLocked()) {
1374
+ throw new Error("KeyringController - attempt to update vault during a non mutually exclusive operation" /* ControllerLockRequired */);
1375
+ }
1376
+ };
1377
+ _withControllerLock = new WeakSet();
1378
+ withControllerLock_fn = async function(fn) {
1379
+ return withLock(__privateGet(this, _controllerOperationMutex), fn);
1348
1380
  };
1349
1381
  _withVaultLock = new WeakSet();
1350
1382
  withVaultLock_fn = async function(fn) {
1351
- const releaseLock = await __privateGet(this, _vaultOperationMutex).acquire();
1383
+ __privateMethod(this, _assertControllerMutexIsLocked, assertControllerMutexIsLocked_fn).call(this);
1384
+ return withLock(__privateGet(this, _vaultOperationMutex), fn);
1385
+ };
1386
+ async function withLock(mutex, fn) {
1387
+ const releaseLock = await mutex.acquire();
1352
1388
  try {
1353
1389
  return await fn({ releaseLock });
1354
1390
  } finally {
1355
1391
  releaseLock();
1356
1392
  }
1357
- };
1393
+ }
1358
1394
  var KeyringController_default = KeyringController;
1359
1395
 
1360
1396
  export {
@@ -1367,4 +1403,4 @@ export {
1367
1403
  KeyringController,
1368
1404
  KeyringController_default
1369
1405
  };
1370
- //# sourceMappingURL=chunk-5QTEIEPG.mjs.map
1406
+ //# sourceMappingURL=chunk-RVCG63UG.mjs.map