@metamask-previews/keyring-controller 19.1.0-preview-52c28555 → 19.2.0-preview-e2b3b183

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 CHANGED
@@ -7,10 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Changed
11
+
12
+ - Bump `@metamask/keyring-internal-api` from `^4.0.1` to `^4.0.2` ([#5356](https://github.com/MetaMask/core/pull/5356))
13
+
14
+ ## [19.2.0]
15
+
10
16
  ### Added
11
17
 
18
+ - Add `signEip7702Authorization` to `KeyringController` ([#5301](https://github.com/MetaMask/core/pull/5301))
12
19
  - Add `KeyringController:withKeyring` action ([#5332](https://github.com/MetaMask/core/pull/5332))
13
20
  - The action can be used to consume the `withKeyring` method of the `KeyringController` class
21
+ - Support keyring metadata in KeyringController ([#5112](https://github.com/MetaMask/core/pull/5112))
14
22
 
15
23
  ## [19.1.0]
16
24
 
@@ -675,7 +683,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
675
683
 
676
684
  All changes listed after this point were applied to this package following the monorepo conversion.
677
685
 
678
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/keyring-controller@19.1.0...HEAD
686
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/keyring-controller@19.2.0...HEAD
687
+ [19.2.0]: https://github.com/MetaMask/core/compare/@metamask/keyring-controller@19.1.0...@metamask/keyring-controller@19.2.0
679
688
  [19.1.0]: https://github.com/MetaMask/core/compare/@metamask/keyring-controller@19.0.7...@metamask/keyring-controller@19.1.0
680
689
  [19.0.7]: https://github.com/MetaMask/core/compare/@metamask/keyring-controller@19.0.6...@metamask/keyring-controller@19.0.7
681
690
  [19.0.6]: https://github.com/MetaMask/core/compare/@metamask/keyring-controller@19.0.5...@metamask/keyring-controller@19.0.6
@@ -36,7 +36,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
36
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
- var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_unsupportedKeyrings, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_password, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_checkForDuplicate, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
39
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_unsupportedKeyrings, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_keyringsMetadata, _KeyringController_password, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_checkForDuplicate, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.KeyringController = exports.getDefaultKeyringState = exports.keyringBuilderFactory = exports.SignTypedDataVersion = exports.AccountImportStrategy = exports.isCustodyKeyring = exports.KeyringTypes = void 0;
42
42
  const util_1 = require("@ethereumjs/util");
@@ -48,6 +48,8 @@ const eth_simple_keyring_1 = __importDefault(require("@metamask/eth-simple-keyri
48
48
  const utils_1 = require("@metamask/utils");
49
49
  const async_mutex_1 = require("async-mutex");
50
50
  const ethereumjs_wallet_1 = __importStar(require("ethereumjs-wallet"));
51
+ // When generating a ULID within the same millisecond, monotonicFactory provides some guarantees regarding sort order.
52
+ const ulid_1 = require("ulid");
51
53
  const constants_1 = require("./constants.cjs");
52
54
  const name = 'KeyringController';
53
55
  /**
@@ -109,13 +111,17 @@ function keyringBuilderFactory(KeyringConstructor) {
109
111
  }
110
112
  exports.keyringBuilderFactory = keyringBuilderFactory;
111
113
  const defaultKeyringBuilders = [
114
+ // todo: keyring types are mismatched, this should be fixed in they keyrings themselves
115
+ // @ts-expect-error keyring types are mismatched
112
116
  keyringBuilderFactory(eth_simple_keyring_1.default),
117
+ // @ts-expect-error keyring types are mismatched
113
118
  keyringBuilderFactory(eth_hd_keyring_1.default),
114
119
  ];
115
120
  const getDefaultKeyringState = () => {
116
121
  return {
117
122
  isUnlocked: false,
118
123
  keyrings: [],
124
+ keyringsMetadata: [],
119
125
  };
120
126
  };
121
127
  exports.getDefaultKeyringState = getDefaultKeyringState;
@@ -247,6 +253,7 @@ class KeyringController extends base_controller_1.BaseController {
247
253
  vault: { persist: true, anonymous: false },
248
254
  isUnlocked: { persist: false, anonymous: true },
249
255
  keyrings: { persist: false, anonymous: false },
256
+ keyringsMetadata: { persist: true, anonymous: false },
250
257
  encryptionKey: { persist: false, anonymous: false },
251
258
  encryptionSalt: { persist: false, anonymous: false },
252
259
  },
@@ -264,6 +271,7 @@ class KeyringController extends base_controller_1.BaseController {
264
271
  _KeyringController_encryptor.set(this, void 0);
265
272
  _KeyringController_cacheEncryptionKey.set(this, void 0);
266
273
  _KeyringController_keyrings.set(this, void 0);
274
+ _KeyringController_keyringsMetadata.set(this, void 0);
267
275
  _KeyringController_password.set(this, void 0);
268
276
  _KeyringController_qrKeyringStateListener.set(this, void 0);
269
277
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
@@ -271,6 +279,7 @@ class KeyringController extends base_controller_1.BaseController {
271
279
  : defaultKeyringBuilders, "f");
272
280
  __classPrivateFieldSet(this, _KeyringController_encryptor, encryptor, "f");
273
281
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
282
+ __classPrivateFieldSet(this, _KeyringController_keyringsMetadata, state?.keyringsMetadata ?? [], "f");
274
283
  __classPrivateFieldSet(this, _KeyringController_unsupportedKeyrings, [], "f");
275
284
  // This option allows the controller to cache an exported key
276
285
  // for use in decrypting and encrypting data without password
@@ -419,13 +428,18 @@ class KeyringController extends base_controller_1.BaseController {
419
428
  * Gets the seed phrase of the HD keyring.
420
429
  *
421
430
  * @param password - Password of the keyring.
431
+ * @param keyringId - The id of the keyring.
422
432
  * @returns Promise resolving to the seed phrase.
423
433
  */
424
- async exportSeedPhrase(password) {
434
+ async exportSeedPhrase(password, keyringId) {
425
435
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
426
436
  await this.verifyPassword(password);
427
- assertHasUint8ArrayMnemonic(__classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0]);
428
- return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0].mnemonic;
437
+ const selectedKeyring = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringByIdOrDefault).call(this, keyringId);
438
+ if (!selectedKeyring) {
439
+ throw new Error('Keyring not found');
440
+ }
441
+ assertHasUint8ArrayMnemonic(selectedKeyring);
442
+ return selectedKeyring.mnemonic;
429
443
  }
430
444
  /**
431
445
  * Gets the private key from the keyring controlling an address.
@@ -610,6 +624,13 @@ class KeyringController extends base_controller_1.BaseController {
610
624
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
611
625
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
612
626
  const keyring = (await this.getKeyringForAccount(address));
627
+ const keyringIndex = this.state.keyrings.findIndex((kr) => kr.accounts.includes(address));
628
+ const isPrimaryKeyring = keyringIndex === 0;
629
+ const shouldRemoveKeyring = (await keyring.getAccounts()).length === 1;
630
+ // Primary keyring should never be removed, so we need to keep at least one account in it
631
+ if (isPrimaryKeyring && shouldRemoveKeyring) {
632
+ throw new Error(constants_1.KeyringControllerError.LastAccountInPrimaryKeyring);
633
+ }
613
634
  // Not all the keyrings support this, so we have to check
614
635
  if (!keyring.removeAccount) {
615
636
  throw new Error(constants_1.KeyringControllerError.UnsupportedRemoveAccount);
@@ -620,9 +641,7 @@ class KeyringController extends base_controller_1.BaseController {
620
641
  // because `Keyring<State>.removeAccount` requires address to be `Hex`. Those
621
642
  // type would need to be updated for a full non-EVM support.
622
643
  keyring.removeAccount(address);
623
- const accounts = await keyring.getAccounts();
624
- // Check if this was the last/only account
625
- if (accounts.length === 0) {
644
+ if (shouldRemoveKeyring) {
626
645
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_removeEmptyKeyrings).call(this);
627
646
  }
628
647
  });
@@ -666,6 +685,27 @@ class KeyringController extends base_controller_1.BaseController {
666
685
  }
667
686
  return await keyring.signMessage(address, messageParams.data);
668
687
  }
688
+ /**
689
+ * Signs EIP-7702 Authorization message by calling down into a specific keyring.
690
+ *
691
+ * @param params - EIP7702AuthorizationParams object to sign.
692
+ * @returns Promise resolving to an EIP-7702 Authorization signature.
693
+ * @throws Will throw UnsupportedSignEIP7702Authorization if the keyring does not support signing EIP-7702 Authorization messages.
694
+ */
695
+ async signEip7702Authorization(params) {
696
+ const from = (0, eth_sig_util_1.normalize)(params.from);
697
+ const keyring = (await this.getKeyringForAccount(from));
698
+ if (!keyring.signEip7702Authorization) {
699
+ throw new Error(constants_1.KeyringControllerError.UnsupportedSignEip7702Authorization);
700
+ }
701
+ const { chainId, nonce } = params;
702
+ const contractAddress = (0, eth_sig_util_1.normalize)(params.contractAddress);
703
+ return await keyring.signEip7702Authorization(from, [
704
+ chainId,
705
+ contractAddress,
706
+ nonce,
707
+ ]);
708
+ }
669
709
  /**
670
710
  * Signs personal message by calling down into a specific keyring.
671
711
  *
@@ -839,11 +879,12 @@ class KeyringController extends base_controller_1.BaseController {
839
879
  /**
840
880
  * Verifies the that the seed phrase restores the current keychain's accounts.
841
881
  *
882
+ * @param keyringId - The id of the keyring to verify.
842
883
  * @returns Promise resolving to the seed phrase as Uint8Array.
843
884
  */
844
- async verifySeedPhrase() {
885
+ async verifySeedPhrase(keyringId) {
845
886
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
846
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_verifySeedPhrase).call(this));
887
+ return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_verifySeedPhrase).call(this, keyringId));
847
888
  }
848
889
  async withKeyring(selector, operation, options = {
849
890
  createIfMissing: false,
@@ -854,12 +895,15 @@ class KeyringController extends base_controller_1.BaseController {
854
895
  if ('address' in selector) {
855
896
  keyring = (await this.getKeyringForAccount(selector.address));
856
897
  }
857
- else {
898
+ else if ('type' in selector) {
858
899
  keyring = this.getKeyringsByType(selector.type)[selector.index || 0];
859
900
  if (!keyring && options.createIfMissing) {
860
901
  keyring = (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, selector.type, options.createWithData));
861
902
  }
862
903
  }
904
+ else if ('id' in selector) {
905
+ keyring = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringById).call(this, selector.id);
906
+ }
863
907
  if (!keyring) {
864
908
  throw new Error(constants_1.KeyringControllerError.KeyringNotFound);
865
909
  }
@@ -1073,8 +1117,9 @@ class KeyringController extends base_controller_1.BaseController {
1073
1117
  }
1074
1118
  }
1075
1119
  exports.KeyringController = KeyringController;
1076
- _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_cacheEncryptionKey = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_password = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1120
+ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_cacheEncryptionKey = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_keyringsMetadata = new WeakMap(), _KeyringController_password = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1077
1121
  this.messagingSystem.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
1122
+ this.messagingSystem.registerActionHandler(`${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this));
1078
1123
  this.messagingSystem.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
1079
1124
  this.messagingSystem.registerActionHandler(`${name}:signTypedMessage`, this.signTypedMessage.bind(this));
1080
1125
  this.messagingSystem.registerActionHandler(`${name}:decryptMessage`, this.decryptMessage.bind(this));
@@ -1088,6 +1133,14 @@ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_
1088
1133
  this.messagingSystem.registerActionHandler(`${name}:signUserOperation`, this.signUserOperation.bind(this));
1089
1134
  this.messagingSystem.registerActionHandler(`${name}:addNewAccount`, this.addNewAccount.bind(this));
1090
1135
  this.messagingSystem.registerActionHandler(`${name}:withKeyring`, this.withKeyring.bind(this));
1136
+ }, _KeyringController_getKeyringById = function _KeyringController_getKeyringById(keyringId) {
1137
+ const index = this.state.keyringsMetadata.findIndex((metadata) => metadata.id === keyringId);
1138
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[index];
1139
+ }, _KeyringController_getKeyringByIdOrDefault = function _KeyringController_getKeyringByIdOrDefault(keyringId) {
1140
+ if (!keyringId) {
1141
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0];
1142
+ }
1143
+ return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringById).call(this, keyringId);
1091
1144
  }, _KeyringController_getKeyringBuilderForType = function _KeyringController_getKeyringBuilderForType(type) {
1092
1145
  return __classPrivateFieldGet(this, _KeyringController_keyringBuilders, "f").find((keyringBuilder) => keyringBuilder.type === type);
1093
1146
  }, _KeyringController_addQRKeyring =
@@ -1140,23 +1193,29 @@ async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1140
1193
  });
1141
1194
  __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1142
1195
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
1196
+ __classPrivateFieldSet(this, _KeyringController_keyringsMetadata, [], "f");
1143
1197
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyringWithFirstAccount).call(this, keyring.type, keyring.opts);
1144
1198
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
1145
1199
  }, _KeyringController_verifySeedPhrase =
1146
1200
  /**
1147
1201
  * Internal non-exclusive method to verify the seed phrase.
1148
1202
  *
1203
+ * @param keyringId - The id of the keyring to verify the seed phrase for.
1149
1204
  * @returns A promise resolving to the seed phrase as Uint8Array.
1150
1205
  */
1151
- async function _KeyringController_verifySeedPhrase() {
1206
+ async function _KeyringController_verifySeedPhrase(keyringId) {
1152
1207
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1153
- const primaryKeyring = this.getKeyringsByType(KeyringTypes.hd)[0];
1154
- if (!primaryKeyring) {
1155
- throw new Error('No HD keyring found.');
1208
+ const keyring = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringByIdOrDefault).call(this, keyringId);
1209
+ if (!keyring) {
1210
+ throw new Error(constants_1.KeyringControllerError.KeyringNotFound);
1156
1211
  }
1157
- assertHasUint8ArrayMnemonic(primaryKeyring);
1158
- const seedWords = primaryKeyring.mnemonic;
1159
- const accounts = await primaryKeyring.getAccounts();
1212
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
1213
+ if (keyring.type !== KeyringTypes.hd) {
1214
+ throw new Error(constants_1.KeyringControllerError.UnsupportedVerifySeedPhrase);
1215
+ }
1216
+ assertHasUint8ArrayMnemonic(keyring);
1217
+ const seedWords = keyring.mnemonic;
1218
+ const accounts = await keyring.getAccounts();
1160
1219
  /* istanbul ignore if */
1161
1220
  if (accounts.length === 0) {
1162
1221
  throw new Error('Cannot verify an empty keyring.');
@@ -1336,9 +1395,13 @@ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryp
1336
1395
  throw new Error(constants_1.KeyringControllerError.MissingVaultData);
1337
1396
  }
1338
1397
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1398
+ if (updatedKeyrings.length !== __classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").length) {
1399
+ throw new Error(constants_1.KeyringControllerError.KeyringMetadataLengthMismatch);
1400
+ }
1339
1401
  this.update((state) => {
1340
1402
  state.vault = updatedState.vault;
1341
1403
  state.keyrings = updatedKeyrings;
1404
+ state.keyringsMetadata = __classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").slice();
1342
1405
  if (updatedState.encryptionKey) {
1343
1406
  state.encryptionKey = updatedState.encryptionKey;
1344
1407
  state.encryptionSalt = JSON.parse(updatedState.vault).salt;
@@ -1378,19 +1441,48 @@ async function _KeyringController_createKeyringWithFirstAccount(type, opts) {
1378
1441
  if (!firstAccount) {
1379
1442
  throw new Error(constants_1.KeyringControllerError.NoFirstAccount);
1380
1443
  }
1444
+ return firstAccount;
1381
1445
  }, _KeyringController_newKeyring =
1382
1446
  /**
1383
1447
  * Instantiate, initialize and return a new keyring of the given `type`,
1384
1448
  * using the given `opts`. The keyring is built using the keyring builder
1385
1449
  * registered for the given `type`.
1386
1450
  *
1451
+ * The internal keyring and keyring metadata arrays are updated with the new
1452
+ * keyring as well.
1387
1453
  *
1388
1454
  * @param type - The type of keyring to add.
1389
- * @param data - The data to restore a previously serialized keyring.
1455
+ * @param data - Keyring initialization options.
1390
1456
  * @returns The new keyring.
1391
1457
  * @throws If the keyring includes duplicated accounts.
1392
1458
  */
1393
1459
  async function _KeyringController_newKeyring(type, data) {
1460
+ const keyring = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyring).call(this, type, data);
1461
+ if (__classPrivateFieldGet(this, _KeyringController_keyrings, "f").length !== __classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").length) {
1462
+ throw new Error('Keyring metadata missing');
1463
+ }
1464
+ __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push(keyring);
1465
+ __classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").push(getDefaultKeyringMetadata());
1466
+ return keyring;
1467
+ }, _KeyringController_createKeyring =
1468
+ /**
1469
+ * Instantiate, initialize and return a keyring of the given `type` using the
1470
+ * given `opts`. The keyring is built using the keyring builder registered
1471
+ * for the given `type`.
1472
+ *
1473
+ * The keyring might be new, or it might be restored from the vault. This
1474
+ * function should only be called from `#newKeyring` or `#restoreKeyring`,
1475
+ * for the "new" and "restore" cases respectively.
1476
+ *
1477
+ * The internal keyring and keyring metadata arrays are *not* updated, the
1478
+ * caller is expected to update them.
1479
+ *
1480
+ * @param type - The type of keyring to add.
1481
+ * @param data - Keyring initialization options.
1482
+ * @returns The new keyring.
1483
+ * @throws If the keyring includes duplicated accounts.
1484
+ */
1485
+ async function _KeyringController_createKeyring(type, data) {
1394
1486
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1395
1487
  const keyringBuilder = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringBuilderForType).call(this, type);
1396
1488
  if (!keyringBuilder) {
@@ -1418,7 +1510,6 @@ async function _KeyringController_newKeyring(type, data) {
1418
1510
  // to its events after creating it
1419
1511
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_subscribeToQRKeyringEvents).call(this, keyring);
1420
1512
  }
1421
- __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push(keyring);
1422
1513
  return keyring;
1423
1514
  }, _KeyringController_clearKeyrings =
1424
1515
  /**
@@ -1443,7 +1534,15 @@ async function _KeyringController_restoreKeyring(serialized) {
1443
1534
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1444
1535
  try {
1445
1536
  const { type, data } = serialized;
1446
- return await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, type, data);
1537
+ const keyring = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyring).call(this, type, data);
1538
+ __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push(keyring);
1539
+ // If metadata is missing, assume the data is from an installation before
1540
+ // we had keyring metadata.
1541
+ if (__classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").length < __classPrivateFieldGet(this, _KeyringController_keyrings, "f").length) {
1542
+ console.log(`Adding missing metadata for '${type}' keyring`);
1543
+ __classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").push(getDefaultKeyringMetadata());
1544
+ }
1545
+ return keyring;
1447
1546
  }
1448
1547
  catch (_) {
1449
1548
  __classPrivateFieldGet(this, _KeyringController_unsupportedKeyrings, "f").push(serialized);
@@ -1471,19 +1570,22 @@ async function _KeyringController_destroyKeyring(keyring) {
1471
1570
  async function _KeyringController_removeEmptyKeyrings() {
1472
1571
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1473
1572
  const validKeyrings = [];
1573
+ const validKeyringMetadata = [];
1474
1574
  // Since getAccounts returns a Promise
1475
1575
  // We need to wait to hear back form each keyring
1476
1576
  // in order to decide which ones are now valid (accounts.length > 0)
1477
- await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(async (keyring) => {
1577
+ await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(async (keyring, index) => {
1478
1578
  const accounts = await keyring.getAccounts();
1479
1579
  if (accounts.length > 0) {
1480
1580
  validKeyrings.push(keyring);
1581
+ validKeyringMetadata.push(__classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f")[index]);
1481
1582
  }
1482
1583
  else {
1483
1584
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring);
1484
1585
  }
1485
1586
  }));
1486
1587
  __classPrivateFieldSet(this, _KeyringController_keyrings, validKeyrings, "f");
1588
+ __classPrivateFieldSet(this, _KeyringController_keyringsMetadata, validKeyringMetadata, "f");
1487
1589
  }, _KeyringController_checkForDuplicate =
1488
1590
  /**
1489
1591
  * Checks for duplicate keypairs, using the the first account in the given
@@ -1549,6 +1651,7 @@ async function _KeyringController_withRollback(callback) {
1549
1651
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async ({ releaseLock }) => {
1550
1652
  const currentSerializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1551
1653
  const currentPassword = __classPrivateFieldGet(this, _KeyringController_password, "f");
1654
+ const currentKeyringsMetadata = __classPrivateFieldGet(this, _KeyringController_keyringsMetadata, "f").slice();
1552
1655
  try {
1553
1656
  return await callback({ releaseLock });
1554
1657
  }
@@ -1556,6 +1659,7 @@ async function _KeyringController_withRollback(callback) {
1556
1659
  // Keyrings and password are restored to their previous state
1557
1660
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, currentSerializedKeyrings);
1558
1661
  __classPrivateFieldSet(this, _KeyringController_password, currentPassword, "f");
1662
+ __classPrivateFieldSet(this, _KeyringController_keyringsMetadata, currentKeyringsMetadata, "f");
1559
1663
  throw e;
1560
1664
  }
1561
1665
  });
@@ -1612,5 +1716,13 @@ async function withLock(mutex, callback) {
1612
1716
  releaseLock();
1613
1717
  }
1614
1718
  }
1719
+ /**
1720
+ * Generate a new keyring metadata object.
1721
+ *
1722
+ * @returns Keyring metadata.
1723
+ */
1724
+ function getDefaultKeyringMetadata() {
1725
+ return { id: (0, ulid_1.ulid)(), name: '' };
1726
+ }
1615
1727
  exports.default = KeyringController;
1616
1728
  //# sourceMappingURL=KeyringController.cjs.map