@metamask-previews/keyring-controller 19.0.3-preview-2ba45577 → 19.0.3-preview-183f0b5a

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.
@@ -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_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _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_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
39
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _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_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");
@@ -49,6 +49,10 @@ 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
51
  const constants_1 = require("./constants.cjs");
52
+ // When generating a ULID within the same millisecond, monotonicFactory provides some guarantees regarding sort order.
53
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
54
+ const { monotonicFactory } = require("ulidx");
55
+ const ulid = monotonicFactory();
52
56
  const name = 'KeyringController';
53
57
  /**
54
58
  * Available keyring types
@@ -132,6 +136,7 @@ const getDefaultKeyringState = () => {
132
136
  return {
133
137
  isUnlocked: false,
134
138
  keyrings: [],
139
+ keyringsMetadata: [],
135
140
  };
136
141
  };
137
142
  exports.getDefaultKeyringState = getDefaultKeyringState;
@@ -263,6 +268,7 @@ class KeyringController extends base_controller_1.BaseController {
263
268
  vault: { persist: true, anonymous: false },
264
269
  isUnlocked: { persist: false, anonymous: true },
265
270
  keyrings: { persist: false, anonymous: false },
271
+ keyringsMetadata: { persist: true, anonymous: false },
266
272
  encryptionKey: { persist: false, anonymous: false },
267
273
  encryptionSalt: { persist: false, anonymous: false },
268
274
  },
@@ -305,11 +311,8 @@ class KeyringController extends base_controller_1.BaseController {
305
311
  */
306
312
  async addNewAccount(accountCount) {
307
313
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
308
- const primaryKeyring = this.getKeyringsByType('HD Key Tree')[0];
309
- if (!primaryKeyring) {
310
- throw new Error('No HD keyring found');
311
- }
312
- const oldAccounts = await primaryKeyring.getAccounts();
314
+ const selectedKeyring = this.getKeyringsByType('HD Key Tree')[0];
315
+ const oldAccounts = await selectedKeyring.getAccounts();
313
316
  if (accountCount && oldAccounts.length !== accountCount) {
314
317
  if (accountCount > oldAccounts.length) {
315
318
  throw new Error('Account out of sequence');
@@ -321,7 +324,7 @@ class KeyringController extends base_controller_1.BaseController {
321
324
  }
322
325
  return existingAccount;
323
326
  }
324
- const [addedAccountAddress] = await primaryKeyring.addAccounts(1);
327
+ const [addedAccountAddress] = await selectedKeyring.addAccounts(1);
325
328
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_verifySeedPhrase).call(this);
326
329
  return addedAccountAddress;
327
330
  });
@@ -431,12 +434,21 @@ class KeyringController extends base_controller_1.BaseController {
431
434
  * Gets the seed phrase of the HD keyring.
432
435
  *
433
436
  * @param password - Password of the keyring.
437
+ * @param keyringId - The id of the keyring.
434
438
  * @returns Promise resolving to the seed phrase.
435
439
  */
436
- async exportSeedPhrase(password) {
440
+ async exportSeedPhrase(password, keyringId) {
437
441
  await this.verifyPassword(password);
438
- assertHasUint8ArrayMnemonic(__classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0]);
439
- return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0].mnemonic;
442
+ if (!keyringId) {
443
+ assertHasUint8ArrayMnemonic(__classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0]);
444
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0].mnemonic;
445
+ }
446
+ const selectedKeyring = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringById).call(this, keyringId);
447
+ if (!selectedKeyring) {
448
+ throw new Error('Keyring not found');
449
+ }
450
+ assertHasUint8ArrayMnemonic(selectedKeyring);
451
+ return selectedKeyring.mnemonic;
440
452
  }
441
453
  /**
442
454
  * Gets the private key from the keyring controlling an address.
@@ -837,10 +849,16 @@ class KeyringController extends base_controller_1.BaseController {
837
849
  /**
838
850
  * Verifies the that the seed phrase restores the current keychain's accounts.
839
851
  *
852
+ * @param keyringId - The id of the keyring to verify.
840
853
  * @returns Promise resolving to the seed phrase as Uint8Array.
841
854
  */
842
- async verifySeedPhrase() {
843
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_verifySeedPhrase).call(this));
855
+ async verifySeedPhrase(keyringId) {
856
+ const keyringIndex = this.state.keyringsMetadata.findIndex((keyring) => keyring.id === keyringId);
857
+ const keyring = this.state.keyrings[keyringIndex];
858
+ if (keyring.type !== KeyringTypes.hd) {
859
+ throw new Error(constants_1.KeyringControllerError.UnsupportedVerifySeedPhrase);
860
+ }
861
+ return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_verifySeedPhrase).call(this, keyringId));
844
862
  }
845
863
  async withKeyring(selector, operation, options = {
846
864
  createIfMissing: false,
@@ -850,12 +868,15 @@ class KeyringController extends base_controller_1.BaseController {
850
868
  if ('address' in selector) {
851
869
  keyring = (await this.getKeyringForAccount(selector.address));
852
870
  }
853
- else {
871
+ else if ('type' in selector) {
854
872
  keyring = this.getKeyringsByType(selector.type)[selector.index || 0];
855
873
  if (!keyring && options.createIfMissing) {
856
874
  keyring = (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, selector.type, options.createWithData));
857
875
  }
858
876
  }
877
+ else if ('id' in selector) {
878
+ keyring = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringById).call(this, selector.id);
879
+ }
859
880
  if (!keyring) {
860
881
  throw new Error(constants_1.KeyringControllerError.KeyringNotFound);
861
882
  }
@@ -1069,6 +1090,9 @@ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_
1069
1090
  this.messagingSystem.registerActionHandler(`${name}:patchUserOperation`, this.patchUserOperation.bind(this));
1070
1091
  this.messagingSystem.registerActionHandler(`${name}:signUserOperation`, this.signUserOperation.bind(this));
1071
1092
  this.messagingSystem.registerActionHandler(`${name}:addNewAccount`, this.addNewAccount.bind(this));
1093
+ }, _KeyringController_getKeyringById = function _KeyringController_getKeyringById(keyringId) {
1094
+ const index = this.state.keyringsMetadata.findIndex((metadata) => metadata.id === keyringId);
1095
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[index];
1072
1096
  }, _KeyringController_getKeyringBuilderForType = function _KeyringController_getKeyringBuilderForType(type) {
1073
1097
  return __classPrivateFieldGet(this, _KeyringController_keyringBuilders, "f").find((keyringBuilder) => keyringBuilder.type === type);
1074
1098
  }, _KeyringController_addQRKeyring =
@@ -1082,7 +1106,7 @@ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_
1082
1106
  async function _KeyringController_addQRKeyring() {
1083
1107
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1084
1108
  // QRKeyring is not yet compatible with Keyring type from @metamask/utils
1085
- return (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, KeyringTypes.qr));
1109
+ return (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, KeyringTypes.qr, undefined));
1086
1110
  }, _KeyringController_subscribeToQRKeyringEvents = function _KeyringController_subscribeToQRKeyringEvents(qrKeyring) {
1087
1111
  __classPrivateFieldSet(this, _KeyringController_qrKeyringStateListener, (state) => {
1088
1112
  this.messagingSystem.publish(`${name}:qrKeyringStateChange`, state);
@@ -1127,17 +1151,23 @@ async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1127
1151
  /**
1128
1152
  * Internal non-exclusive method to verify the seed phrase.
1129
1153
  *
1154
+ * @param keyringId - The id of the keyring to verify the seed phrase for.
1130
1155
  * @returns A promise resolving to the seed phrase as Uint8Array.
1131
1156
  */
1132
- async function _KeyringController_verifySeedPhrase() {
1157
+ async function _KeyringController_verifySeedPhrase(keyringId) {
1133
1158
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1134
- const primaryKeyring = this.getKeyringsByType(KeyringTypes.hd)[0];
1135
- if (!primaryKeyring) {
1159
+ const keyring = keyringId
1160
+ ? __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringById).call(this, keyringId)
1161
+ : this.getKeyringsByType(KeyringTypes.hd)[0];
1162
+ if (!keyring) {
1136
1163
  throw new Error('No HD keyring found.');
1137
1164
  }
1138
- assertHasUint8ArrayMnemonic(primaryKeyring);
1139
- const seedWords = primaryKeyring.mnemonic;
1140
- const accounts = await primaryKeyring.getAccounts();
1165
+ if (keyring.type !== KeyringTypes.hd) {
1166
+ throw new Error(constants_1.KeyringControllerError.UnsupportedVerifySeedPhrase);
1167
+ }
1168
+ assertHasUint8ArrayMnemonic(keyring);
1169
+ const seedWords = keyring.mnemonic;
1170
+ const accounts = await keyring.getAccounts();
1141
1171
  /* istanbul ignore if */
1142
1172
  if (accounts.length === 0) {
1143
1173
  throw new Error('Cannot verify an empty keyring.');
@@ -1185,7 +1215,7 @@ async function _KeyringController_getUpdatedKeyrings() {
1185
1215
  async function _KeyringController_getSerializedKeyrings({ includeUnsupported } = {
1186
1216
  includeUnsupported: true,
1187
1217
  }) {
1188
- const serializedKeyrings = await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(async (keyring) => {
1218
+ const serializedKeyrings = await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(async (keyring, index) => {
1189
1219
  const [type, data] = await Promise.all([
1190
1220
  keyring.type,
1191
1221
  keyring.serialize(),
@@ -1207,6 +1237,12 @@ async function _KeyringController_restoreSerializedKeyrings(serializedKeyrings)
1207
1237
  for (const serializedKeyring of serializedKeyrings) {
1208
1238
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreKeyring).call(this, serializedKeyring);
1209
1239
  }
1240
+ if (this.state.keyringsMetadata.length > __classPrivateFieldGet(this, _KeyringController_keyrings, "f").length) {
1241
+ this.update((state) => {
1242
+ // remove metadata from the end of the array to have the same length as the keyrings array
1243
+ state.keyringsMetadata = state.keyringsMetadata.slice(0, -1 * (state.keyringsMetadata.length - __classPrivateFieldGet(this, _KeyringController_keyrings, "f").length));
1244
+ });
1245
+ }
1210
1246
  }, _KeyringController_unlockKeyrings =
1211
1247
  /**
1212
1248
  * Unlock Keyrings, decrypting the vault and deserializing all
@@ -1324,6 +1360,9 @@ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryp
1324
1360
  state.encryptionKey = updatedState.encryptionKey;
1325
1361
  state.encryptionSalt = JSON.parse(updatedState.vault).salt;
1326
1362
  }
1363
+ if (updatedKeyrings.length < state.keyringsMetadata.length) {
1364
+ state.keyringsMetadata = state.keyringsMetadata.slice(0, -1 * (state.keyringsMetadata.length - updatedKeyrings.length));
1365
+ }
1327
1366
  });
1328
1367
  return true;
1329
1368
  });
@@ -1359,13 +1398,13 @@ async function _KeyringController_createKeyringWithFirstAccount(type, opts) {
1359
1398
  if (!firstAccount) {
1360
1399
  throw new Error(constants_1.KeyringControllerError.NoFirstAccount);
1361
1400
  }
1401
+ return firstAccount;
1362
1402
  }, _KeyringController_newKeyring =
1363
1403
  /**
1364
1404
  * Instantiate, initialize and return a new keyring of the given `type`,
1365
1405
  * using the given `opts`. The keyring is built using the keyring builder
1366
1406
  * registered for the given `type`.
1367
1407
  *
1368
- *
1369
1408
  * @param type - The type of keyring to add.
1370
1409
  * @param data - The data to restore a previously serialized keyring.
1371
1410
  * @returns The new keyring.
@@ -1373,6 +1412,7 @@ async function _KeyringController_createKeyringWithFirstAccount(type, opts) {
1373
1412
  */
1374
1413
  async function _KeyringController_newKeyring(type, data) {
1375
1414
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1415
+ const newKeyringMetadata = { id: ulid(), name: '' };
1376
1416
  const keyringBuilder = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringBuilderForType).call(this, type);
1377
1417
  if (!keyringBuilder) {
1378
1418
  throw new Error(`${constants_1.KeyringControllerError.NoKeyringBuilder}. Keyring type: ${type}`);
@@ -1403,6 +1443,15 @@ async function _KeyringController_newKeyring(type, data) {
1403
1443
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_subscribeToQRKeyringEvents).call(this, keyring);
1404
1444
  }
1405
1445
  __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push(keyring);
1446
+ if (newKeyringMetadata &&
1447
+ this.state.keyringsMetadata.length < __classPrivateFieldGet(this, _KeyringController_keyrings, "f").length) {
1448
+ this.update((state) => {
1449
+ state.keyringsMetadata = [
1450
+ ...state.keyringsMetadata,
1451
+ newKeyringMetadata,
1452
+ ];
1453
+ });
1454
+ }
1406
1455
  return keyring;
1407
1456
  }, _KeyringController_clearKeyrings =
1408
1457
  /**
@@ -1415,6 +1464,9 @@ async function _KeyringController_clearKeyrings() {
1415
1464
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring);
1416
1465
  }
1417
1466
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
1467
+ this.update((state) => {
1468
+ state.keyringsMetadata = [];
1469
+ });
1418
1470
  }, _KeyringController_restoreKeyring =
1419
1471
  /**
1420
1472
  * Restore a Keyring from a provided serialized payload.
@@ -1455,19 +1507,24 @@ async function _KeyringController_destroyKeyring(keyring) {
1455
1507
  async function _KeyringController_removeEmptyKeyrings() {
1456
1508
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1457
1509
  const validKeyrings = [];
1510
+ const validKeyringMetadata = [];
1458
1511
  // Since getAccounts returns a Promise
1459
1512
  // We need to wait to hear back form each keyring
1460
1513
  // in order to decide which ones are now valid (accounts.length > 0)
1461
- await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(async (keyring) => {
1514
+ await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(async (keyring, index) => {
1462
1515
  const accounts = await keyring.getAccounts();
1463
1516
  if (accounts.length > 0) {
1464
1517
  validKeyrings.push(keyring);
1518
+ validKeyringMetadata.push(this.state.keyringsMetadata[index]);
1465
1519
  }
1466
1520
  else {
1467
1521
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring);
1468
1522
  }
1469
1523
  }));
1470
1524
  __classPrivateFieldSet(this, _KeyringController_keyrings, validKeyrings, "f");
1525
+ this.update((state) => {
1526
+ state.keyringsMetadata = validKeyringMetadata;
1527
+ });
1471
1528
  }, _KeyringController_checkForDuplicate =
1472
1529
  /**
1473
1530
  * Checks for duplicate keypairs, using the the first account in the given