@metamask-previews/keyring-controller 25.2.0-preview-dff83af4c → 25.2.0-preview-6b4f746

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.
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  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");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_encryptionKey, _KeyringController_getKeyringForAccount, _KeyringController_findKeyringIndexForAccount, _KeyringController_assertNoUnsafeDirectKeyringAccess, _KeyringController_registerMessageHandlers, _KeyringController_selectKeyring, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_createNewVaultWithKeyring, _KeyringController_deriveAndSetEncryptionKey, _KeyringController_setEncryptionKey, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_assertNoDuplicateAccounts, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
12
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_keyringV2Builders, _KeyringController_encryptor, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_encryptionKey, _KeyringController_getKeyringForAccount, _KeyringController_getKeyringEntryForAccount, _KeyringController_findKeyringIndexForAccount, _KeyringController_getKeyringEntriesByType, _KeyringController_assertNoUnsafeDirectKeyringAccess, _KeyringController_registerMessageHandlers, _KeyringController_selectKeyringEntry, _KeyringController_selectKeyring, _KeyringController_getKeyringById, _KeyringController_getKeyringEntryById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_getKeyringV2BuilderForType, _KeyringController_createNewVaultWithKeyring, _KeyringController_deriveAndSetEncryptionKey, _KeyringController_setEncryptionKey, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_assertNoDuplicateAccounts, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -18,16 +18,16 @@ function $importDefault(module) {
18
18
  }
19
19
  import { isValidPrivate, getBinarySize } from "@ethereumjs/util";
20
20
  import { BaseController } from "@metamask/base-controller";
21
- import { HdKeyring } from "@metamask/eth-hd-keyring";
21
+ import { HdKeyring, HdKeyringV2 } from "@metamask/eth-hd-keyring";
22
22
  import { normalize as ethNormalize } from "@metamask/eth-sig-util";
23
- import SimpleKeyring from "@metamask/eth-simple-keyring";
23
+ import SimpleKeyring, { SimpleKeyringV2 } from "@metamask/eth-simple-keyring";
24
24
  import { add0x, assertIsStrictHexString, bytesToHex, hasProperty, hexToBytes, isObject, isStrictHexString, isValidHexAddress, isValidJson, remove0x } from "@metamask/utils";
25
25
  import { Mutex } from "async-mutex";
26
26
  import $Wallet from "ethereumjs-wallet";
27
27
  const { thirdparty: importers } = $Wallet;
28
28
  const Wallet = $importDefault($Wallet);
29
29
  import $lodash from "lodash";
30
- const { cloneDeep, isEqual } = $lodash;
30
+ const { cloneDeep } = $lodash;
31
31
  // When generating a ULID within the same millisecond, monotonicFactory provides some guarantees regarding sort order.
32
32
  import { ulid } from "ulid";
33
33
  import { KeyringControllerErrorMessage } from "./constants.mjs";
@@ -51,6 +51,8 @@ const MESSENGER_EXPOSED_METHODS = [
51
51
  'addNewAccount',
52
52
  'withKeyring',
53
53
  'withKeyringUnsafe',
54
+ 'withKeyringV2',
55
+ 'withKeyringV2Unsafe',
54
56
  'addNewKeyring',
55
57
  'createNewVaultAndKeychain',
56
58
  'createNewVaultAndRestore',
@@ -127,6 +129,17 @@ const defaultKeyringBuilders = [
127
129
  keyringBuilderFactory(SimpleKeyring),
128
130
  keyringBuilderFactory(HdKeyring),
129
131
  ];
132
+ const hdKeyringV2Builder = Object.assign((keyring, metadata) => new HdKeyringV2({
133
+ legacyKeyring: keyring,
134
+ entropySource: metadata.id,
135
+ }), { type: KeyringTypes.hd });
136
+ const simpleKeyringV2Builder = Object.assign((keyring) => new SimpleKeyringV2({
137
+ legacyKeyring: keyring,
138
+ }), { type: KeyringTypes.simple });
139
+ const defaultKeyringV2Builders = [
140
+ simpleKeyringV2Builder,
141
+ hdKeyringV2Builder,
142
+ ];
130
143
  export const getDefaultKeyringState = () => {
131
144
  return {
132
145
  isUnlocked: false,
@@ -251,7 +264,7 @@ export class KeyringController extends BaseController {
251
264
  * @param options.state - Initial state to set on this controller.
252
265
  */
253
266
  constructor(options) {
254
- const { encryptor, keyringBuilders, messenger, state } = options;
267
+ const { encryptor, keyringBuilders, keyringV2Builders, messenger, state } = options;
255
268
  super({
256
269
  name,
257
270
  metadata: {
@@ -296,6 +309,7 @@ export class KeyringController extends BaseController {
296
309
  _KeyringController_controllerOperationMutex.set(this, new Mutex());
297
310
  _KeyringController_vaultOperationMutex.set(this, new Mutex());
298
311
  _KeyringController_keyringBuilders.set(this, void 0);
312
+ _KeyringController_keyringV2Builders.set(this, void 0);
299
313
  _KeyringController_encryptor.set(this, void 0);
300
314
  _KeyringController_keyrings.set(this, void 0);
301
315
  _KeyringController_unsupportedKeyrings.set(this, void 0);
@@ -303,6 +317,9 @@ export class KeyringController extends BaseController {
303
317
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
304
318
  ? keyringBuilders.concat(defaultKeyringBuilders)
305
319
  : defaultKeyringBuilders, "f");
320
+ __classPrivateFieldSet(this, _KeyringController_keyringV2Builders, keyringV2Builders
321
+ ? keyringV2Builders.concat(defaultKeyringV2Builders)
322
+ : defaultKeyringV2Builders, "f");
306
323
  __classPrivateFieldSet(this, _KeyringController_encryptor, encryptor, "f");
307
324
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
308
325
  __classPrivateFieldSet(this, _KeyringController_unsupportedKeyrings, [], "f");
@@ -547,9 +564,7 @@ export class KeyringController extends BaseController {
547
564
  */
548
565
  getKeyringsByType(type) {
549
566
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
550
- return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")
551
- .filter(({ keyring }) => keyring.type === type)
552
- .map(({ keyring }) => keyring);
567
+ return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringEntriesByType).call(this, type).map(({ keyring }) => keyring);
553
568
  }
554
569
  /**
555
570
  * Persist all serialized keyrings in the vault.
@@ -638,7 +653,7 @@ export class KeyringController extends BaseController {
638
653
  if (keyringIndex === -1) {
639
654
  throw new KeyringControllerError(KeyringControllerErrorMessage.NoKeyring);
640
655
  }
641
- const { keyring } = __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[keyringIndex];
656
+ const { keyring, keyringV2 } = __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[keyringIndex];
642
657
  const isPrimaryKeyring = keyringIndex === 0;
643
658
  const shouldRemoveKeyring = (await keyring.getAccounts()).length === 1;
644
659
  // Primary keyring should never be removed, so we need to keep at least one account in it
@@ -659,7 +674,7 @@ export class KeyringController extends BaseController {
659
674
  await keyring.removeAccount(address);
660
675
  if (shouldRemoveKeyring) {
661
676
  __classPrivateFieldGet(this, _KeyringController_keyrings, "f").splice(keyringIndex, 1);
662
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring);
677
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring, keyringV2);
663
678
  }
664
679
  });
665
680
  this.messenger.publish(`${name}:accountRemoved`, address);
@@ -872,7 +887,7 @@ export class KeyringController extends BaseController {
872
887
  * @returns Promise resolving when the operation completes.
873
888
  */
874
889
  async submitEncryptionKey(encryptionKey, encryptionSalt) {
875
- const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
890
+ const { hasChanged } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
876
891
  const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, {
877
892
  encryptionKey,
878
893
  encryptionSalt,
@@ -884,7 +899,7 @@ export class KeyringController extends BaseController {
884
899
  // if new metadata has been generated during login, we
885
900
  // can attempt to upgrade the vault.
886
901
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
887
- if (newMetadata) {
902
+ if (hasChanged) {
888
903
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
889
904
  }
890
905
  });
@@ -915,17 +930,17 @@ export class KeyringController extends BaseController {
915
930
  * @returns Promise resolving when the operation completes.
916
931
  */
917
932
  async submitPassword(password) {
918
- const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
933
+ const { hasChanged } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
919
934
  const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, { password });
920
935
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
921
936
  return result;
922
937
  });
923
938
  try {
924
939
  // If there are stronger encryption params available, or
925
- // if new metadata has been generated during login, we
940
+ // if the keyring state has changed during deserialization, we
926
941
  // can attempt to upgrade the vault.
927
942
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
928
- if (newMetadata || __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isNewEncryptionAvailable).call(this)) {
943
+ if (hasChanged || __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isNewEncryptionAvailable).call(this)) {
929
944
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveAndSetEncryptionKey).call(this, password, {
930
945
  // If the vault is being upgraded, we want to ignore the metadata
931
946
  // that is already in the vault, so we can effectively
@@ -1017,17 +1032,124 @@ export class KeyringController extends BaseController {
1017
1032
  metadata: __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringMetadata).call(this, keyring),
1018
1033
  }), keyring);
1019
1034
  }
1035
+ /**
1036
+ * Select a keyring, wrap it in a `KeyringV2` adapter, and execute
1037
+ * the given operation with the wrapped keyring as a mutually
1038
+ * exclusive atomic operation.
1039
+ *
1040
+ * We re-wrap the keyring in a `KeyringV2` adapter on each invocation,
1041
+ * since V2 wrappers are ephemeral adapters created on-the-fly, and cheap to create.
1042
+ *
1043
+ * The method automatically persists changes at the end of the
1044
+ * function execution, or rolls back the changes if an error
1045
+ * is thrown.
1046
+ *
1047
+ * A `KeyringV2Builder` for the selected keyring's type must exist
1048
+ * (either as a default or registered via the `keyringV2Builders`
1049
+ * constructor option); otherwise an error is thrown.
1050
+ *
1051
+ * Selection is performed against the V1 keyrings in `#keyrings`, since
1052
+ * V2 wrappers are ephemeral adapters created on-the-fly.
1053
+ *
1054
+ * @param selector - Keyring selector object.
1055
+ * @param operation - Function to execute with the wrapped V2 keyring.
1056
+ * @returns Promise resolving to the result of the function execution.
1057
+ * @template CallbackResult - The type of the value resolved by the callback function.
1058
+ */
1059
+ async withKeyringV2(selector, operation) {
1060
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1061
+ return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
1062
+ const entry = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_selectKeyringEntry).call(this, {
1063
+ v2: true,
1064
+ selector,
1065
+ });
1066
+ if (!entry) {
1067
+ throw new KeyringControllerError(KeyringControllerErrorMessage.KeyringNotFound);
1068
+ }
1069
+ if (!entry.keyringV2) {
1070
+ throw new KeyringControllerError(KeyringControllerErrorMessage.KeyringV2NotSupported);
1071
+ }
1072
+ const { metadata } = entry;
1073
+ const keyring = entry.keyringV2;
1074
+ const result = await operation({
1075
+ keyring,
1076
+ metadata,
1077
+ });
1078
+ if (Object.is(result, keyring)) {
1079
+ throw new KeyringControllerError(KeyringControllerErrorMessage.UnsafeDirectKeyringAccess);
1080
+ }
1081
+ return result;
1082
+ });
1083
+ }
1084
+ /**
1085
+ * Select a keyring, wrap it in a `KeyringV2` adapter, and execute
1086
+ * the given read-only operation **without** acquiring the controller's
1087
+ * mutual exclusion lock.
1088
+ *
1089
+ * ## When to use this method
1090
+ *
1091
+ * This method is an escape hatch for read-only access to keyring data that
1092
+ * is immutable once the keyring is initialized. A typical safe use case is
1093
+ * reading immutable fields from a `KeyringV2` adapter: data that is set
1094
+ * during initialization and never mutated afterwards.
1095
+ *
1096
+ * ## Why it is "unsafe"
1097
+ *
1098
+ * The "unsafe" designation mirrors the semantics of `unsafe { }` blocks in
1099
+ * Rust: the method itself does not enforce thread-safety guarantees. By
1100
+ * calling this method the **caller** explicitly takes responsibility for
1101
+ * ensuring that:
1102
+ *
1103
+ * - The operation is **read-only** — no state is mutated.
1104
+ * - The data being read is **immutable** after the keyring is initialized,
1105
+ * so concurrent locked operations cannot alter it while this callback
1106
+ * runs.
1107
+ *
1108
+ * Do **not** use this method to:
1109
+ * - Mutate keyring state (add accounts, sign, etc.) — use `withKeyringV2`.
1110
+ * - Read mutable fields that could change during concurrent operations.
1111
+ *
1112
+ * @param selector - Keyring selector object.
1113
+ * @param operation - Read-only function to execute with the wrapped V2 keyring.
1114
+ * @returns Promise resolving to the result of the function execution.
1115
+ * @template SelectedKeyring - The type of the selected V2 keyring.
1116
+ * @template CallbackResult - The type of the value resolved by the callback function.
1117
+ */
1118
+ async withKeyringV2Unsafe(selector, operation) {
1119
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1120
+ const entry = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_selectKeyringEntry).call(this, {
1121
+ v2: true,
1122
+ selector,
1123
+ });
1124
+ if (!entry) {
1125
+ throw new KeyringControllerError(KeyringControllerErrorMessage.KeyringNotFound);
1126
+ }
1127
+ if (!entry.keyringV2) {
1128
+ throw new KeyringControllerError(KeyringControllerErrorMessage.KeyringV2NotSupported);
1129
+ }
1130
+ const { metadata } = entry;
1131
+ const keyring = entry.keyringV2;
1132
+ const result = await operation({ keyring, metadata });
1133
+ if (Object.is(result, keyring)) {
1134
+ throw new KeyringControllerError(KeyringControllerErrorMessage.UnsafeDirectKeyringAccess);
1135
+ }
1136
+ return result;
1137
+ }
1020
1138
  async getAccountKeyringType(account) {
1021
1139
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1022
1140
  const keyring = (await this.getKeyringForAccount(account));
1023
1141
  return keyring.type;
1024
1142
  }
1025
1143
  }
1026
- _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_encryptionKey = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_getKeyringForAccount = async function _KeyringController_getKeyringForAccount(account) {
1144
+ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_keyringV2Builders = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_encryptionKey = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_getKeyringForAccount = async function _KeyringController_getKeyringForAccount(account) {
1145
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1146
+ const entry = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringEntryForAccount).call(this, account);
1147
+ return entry?.keyring;
1148
+ }, _KeyringController_getKeyringEntryForAccount = async function _KeyringController_getKeyringEntryForAccount(account) {
1027
1149
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1028
1150
  const keyringIndex = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_findKeyringIndexForAccount).call(this, account);
1029
1151
  if (keyringIndex > -1) {
1030
- return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[keyringIndex].keyring;
1152
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[keyringIndex];
1031
1153
  }
1032
1154
  return undefined;
1033
1155
  }, _KeyringController_findKeyringIndexForAccount = async function _KeyringController_findKeyringIndexForAccount(account) {
@@ -1035,6 +1157,9 @@ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_
1035
1157
  const address = account.toLowerCase();
1036
1158
  const accountsPerKeyring = await Promise.all(__classPrivateFieldGet(this, _KeyringController_keyrings, "f").map(({ keyring }) => keyring.getAccounts()));
1037
1159
  return accountsPerKeyring.findIndex((accounts) => accounts.map((a) => a.toLowerCase()).includes(address));
1160
+ }, _KeyringController_getKeyringEntriesByType = function _KeyringController_getKeyringEntriesByType(type) {
1161
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1162
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f").filter(({ keyring }) => keyring.type === type);
1038
1163
  }, _KeyringController_assertNoUnsafeDirectKeyringAccess = function _KeyringController_assertNoUnsafeDirectKeyringAccess(value, keyring) {
1039
1164
  if (Object.is(value, keyring)) {
1040
1165
  // Access to a keyring instance outside of controller safeguards
@@ -1046,32 +1171,60 @@ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_
1046
1171
  return value;
1047
1172
  }, _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1048
1173
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
1049
- }, _KeyringController_selectKeyring =
1174
+ }, _KeyringController_selectKeyringEntry =
1050
1175
  /**
1051
- * Select a keyring using a selector without acquiring the controller lock.
1176
+ * Select a keyring entry using a selector without acquiring the controller lock.
1052
1177
  *
1053
- * @param selector - Keyring selector object.
1054
- * @returns The selected keyring, or `undefined` if no match is found.
1178
+ * @param options - Selection options.
1179
+ * @param options.v2 - Tag to indicate whether the selector is for a V2 keyring.
1180
+ * @param options.selector - Keyring selector object.
1181
+ * @returns The selected keyring entry, or `undefined` if no match is found.
1055
1182
  * @template SelectedKeyring - The expected type of the selected keyring.
1183
+ * @template SelectedKeyringV2 - The expected type of the selected keyring (v2).
1056
1184
  */
1057
- async function _KeyringController_selectKeyring(selector) {
1058
- let keyring;
1185
+ async function _KeyringController_selectKeyringEntry({ v2, selector, }) {
1186
+ let entry;
1059
1187
  if ('address' in selector) {
1060
- keyring = (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringForAccount).call(this, selector.address));
1188
+ entry = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringEntryForAccount).call(this, selector.address);
1061
1189
  }
1062
1190
  else if ('type' in selector) {
1063
- keyring = this.getKeyringsByType(selector.type)[selector.index ?? 0];
1191
+ entry = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringEntriesByType).call(this, selector.type)[selector.index ?? 0];
1064
1192
  }
1065
1193
  else if ('id' in selector) {
1066
- keyring = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringById).call(this, selector.id);
1194
+ entry = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringEntryById).call(this, selector.id);
1067
1195
  }
1068
1196
  else if ('filter' in selector) {
1069
- keyring = __classPrivateFieldGet(this, _KeyringController_keyrings, "f").find(({ keyring: filteredKeyring, metadata }) => selector.filter(filteredKeyring, metadata))?.keyring;
1197
+ entry = __classPrivateFieldGet(this, _KeyringController_keyrings, "f").find(({ keyring, keyringV2, metadata }) => {
1198
+ // If v2, then we'll use the v2 selector which expects a `KeyringV2` instance.
1199
+ if (v2) {
1200
+ // However, some keyrings do not have a v2 wrapper, so we just skip them.
1201
+ if (!keyringV2) {
1202
+ return false;
1203
+ }
1204
+ return selector.filter(keyringV2, metadata);
1205
+ }
1206
+ return selector.filter(keyring, metadata);
1207
+ });
1070
1208
  }
1071
- return keyring;
1209
+ return entry;
1210
+ }, _KeyringController_selectKeyring =
1211
+ /**
1212
+ * Select a keyring using a selector without acquiring the controller lock.
1213
+ *
1214
+ * @param selector - Keyring selector object.
1215
+ * @returns The selected keyring, or `undefined` if no match is found.
1216
+ * @template SelectedKeyring - The expected type of the selected keyring.
1217
+ */
1218
+ async function _KeyringController_selectKeyring(selector) {
1219
+ const entry = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_selectKeyringEntry).call(this, {
1220
+ v2: false,
1221
+ selector,
1222
+ });
1223
+ return entry?.keyring;
1072
1224
  }, _KeyringController_getKeyringById = function _KeyringController_getKeyringById(keyringId) {
1073
- return __classPrivateFieldGet(this, _KeyringController_keyrings, "f").find(({ metadata }) => metadata.id === keyringId)
1074
- ?.keyring;
1225
+ return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringEntryById).call(this, keyringId)?.keyring;
1226
+ }, _KeyringController_getKeyringEntryById = function _KeyringController_getKeyringEntryById(keyringId) {
1227
+ return __classPrivateFieldGet(this, _KeyringController_keyrings, "f").find(({ metadata }) => metadata.id === keyringId);
1075
1228
  }, _KeyringController_getKeyringByIdOrDefault = function _KeyringController_getKeyringByIdOrDefault(keyringId) {
1076
1229
  if (!keyringId) {
1077
1230
  return __classPrivateFieldGet(this, _KeyringController_keyrings, "f")[0]?.keyring;
@@ -1085,6 +1238,8 @@ async function _KeyringController_selectKeyring(selector) {
1085
1238
  return keyringWithMetadata.metadata;
1086
1239
  }, _KeyringController_getKeyringBuilderForType = function _KeyringController_getKeyringBuilderForType(type) {
1087
1240
  return __classPrivateFieldGet(this, _KeyringController_keyringBuilders, "f").find((keyringBuilder) => keyringBuilder.type === type);
1241
+ }, _KeyringController_getKeyringV2BuilderForType = function _KeyringController_getKeyringV2BuilderForType(type) {
1242
+ return __classPrivateFieldGet(this, _KeyringController_keyringV2Builders, "f").find((builder) => builder.type === type);
1088
1243
  }, _KeyringController_createNewVaultWithKeyring =
1089
1244
  /**
1090
1245
  * Create new vault with an initial keyring
@@ -1272,18 +1427,18 @@ async function _KeyringController_getSessionState() {
1272
1427
  async function _KeyringController_restoreSerializedKeyrings(serializedKeyrings) {
1273
1428
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
1274
1429
  const keyrings = [];
1275
- let newMetadata = false;
1430
+ let hasChanged = false;
1276
1431
  for (const serializedKeyring of serializedKeyrings) {
1277
1432
  const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreKeyring).call(this, serializedKeyring);
1278
1433
  if (result) {
1279
1434
  const { keyring, metadata } = result;
1280
1435
  keyrings.push({ keyring, metadata });
1281
- if (result.newMetadata) {
1282
- newMetadata = true;
1436
+ if (result.hasChanged) {
1437
+ hasChanged = true;
1283
1438
  }
1284
1439
  }
1285
1440
  }
1286
- return { keyrings, newMetadata };
1441
+ return { keyrings, hasChanged };
1287
1442
  }, _KeyringController_unlockKeyrings =
1288
1443
  /**
1289
1444
  * Unlock Keyrings, decrypting the vault and deserializing all
@@ -1313,14 +1468,14 @@ async function _KeyringController_unlockKeyrings(credentials) {
1313
1468
  if (!isSerializedKeyringsArray(vault)) {
1314
1469
  throw new KeyringControllerError(KeyringControllerErrorMessage.VaultDataError);
1315
1470
  }
1316
- const { keyrings, newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, vault);
1471
+ const { keyrings, hasChanged } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, vault);
1317
1472
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1318
1473
  this.update((state) => {
1319
1474
  state.keyrings = updatedKeyrings;
1320
1475
  state.encryptionKey = encryptionKey;
1321
1476
  state.encryptionSalt = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.salt;
1322
1477
  });
1323
- return { keyrings, newMetadata };
1478
+ return { keyrings, hasChanged };
1324
1479
  });
1325
1480
  }, _KeyringController_updateVault = function _KeyringController_updateVault() {
1326
1481
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
@@ -1408,8 +1563,8 @@ async function _KeyringController_createKeyringWithFirstAccount(type, opts) {
1408
1563
  * @throws If the keyring includes duplicated accounts.
1409
1564
  */
1410
1565
  async function _KeyringController_newKeyring(type, data) {
1411
- const keyring = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyring).call(this, type, data);
1412
- __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push({ keyring, metadata: getDefaultKeyringMetadata() });
1566
+ const { keyring, keyringV2, metadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyring).call(this, type, data);
1567
+ __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push({ keyring, keyringV2, metadata });
1413
1568
  return keyring;
1414
1569
  }, _KeyringController_createKeyring =
1415
1570
  /**
@@ -1426,11 +1581,13 @@ async function _KeyringController_newKeyring(type, data) {
1426
1581
  *
1427
1582
  * @param type - The type of keyring to add.
1428
1583
  * @param data - Keyring initialization options.
1584
+ * @param metadata - Keyring metadata if available.
1429
1585
  * @returns The new keyring.
1430
1586
  * @throws If the keyring includes duplicated accounts.
1431
1587
  */
1432
- async function _KeyringController_createKeyring(type, data) {
1588
+ async function _KeyringController_createKeyring(type, data, metadata) {
1433
1589
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1590
+ const keyringMetadata = metadata ?? getDefaultKeyringMetadata();
1434
1591
  const keyringBuilder = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringBuilderForType).call(this, type);
1435
1592
  if (!keyringBuilder) {
1436
1593
  throw new KeyringControllerError(`${KeyringControllerErrorMessage.NoKeyringBuilder}. Keyring type: ${type}`);
@@ -1454,7 +1611,13 @@ async function _KeyringController_createKeyring(type, data) {
1454
1611
  await keyring.generateRandomMnemonic();
1455
1612
  await keyring.addAccounts(1);
1456
1613
  }
1457
- return keyring;
1614
+ // We now create the keyring V2 wrappers and store them in memory.
1615
+ const keyringBuilderV2 = __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringV2BuilderForType).call(this, type);
1616
+ let keyringV2;
1617
+ if (keyringBuilderV2) {
1618
+ keyringV2 = keyringBuilderV2(keyring, keyringMetadata);
1619
+ }
1620
+ return { keyring, keyringV2, metadata: keyringMetadata };
1458
1621
  }, _KeyringController_clearKeyrings =
1459
1622
  /**
1460
1623
  * Remove all managed keyrings, destroying all their
@@ -1462,8 +1625,8 @@ async function _KeyringController_createKeyring(type, data) {
1462
1625
  */
1463
1626
  async function _KeyringController_clearKeyrings() {
1464
1627
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1465
- for (const { keyring } of __classPrivateFieldGet(this, _KeyringController_keyrings, "f")) {
1466
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring);
1628
+ for (const { keyring, keyringV2 } of __classPrivateFieldGet(this, _KeyringController_keyrings, "f")) {
1629
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_destroyKeyring).call(this, keyring, keyringV2);
1467
1630
  }
1468
1631
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
1469
1632
  __classPrivateFieldSet(this, _KeyringController_unsupportedKeyrings, [], "f");
@@ -1479,23 +1642,28 @@ async function _KeyringController_restoreKeyring(serialized) {
1479
1642
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1480
1643
  try {
1481
1644
  const { type, data, metadata: serializedMetadata } = serialized;
1482
- let newMetadata = false;
1645
+ // Track if we need to trigger a vault update.
1646
+ let hasChanged = false;
1647
+ // If metadata is missing, assume the data is from an installation before we had
1648
+ // keyring metadata.
1483
1649
  let metadata = serializedMetadata;
1484
- const keyring = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyring).call(this, type, data);
1485
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertNoDuplicateAccounts).call(this, [keyring]);
1486
- // If metadata is missing, assume the data is from an installation before
1487
- // we had keyring metadata.
1488
1650
  if (!metadata) {
1489
- newMetadata = true;
1651
+ hasChanged = true;
1490
1652
  metadata = getDefaultKeyringMetadata();
1491
1653
  }
1654
+ const oldState = JSON.stringify(data);
1655
+ const { keyring, keyringV2 } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyring).call(this, type, data, metadata);
1656
+ const newState = JSON.stringify(await keyring.serialize());
1657
+ hasChanged || (hasChanged = oldState !== newState);
1658
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertNoDuplicateAccounts).call(this, [keyring]);
1492
1659
  // The keyring is added to the keyrings array only if it's successfully restored
1493
1660
  // and the metadata is successfully added to the controller
1494
1661
  __classPrivateFieldGet(this, _KeyringController_keyrings, "f").push({
1495
1662
  keyring,
1663
+ keyringV2,
1496
1664
  metadata,
1497
1665
  });
1498
- return { keyring, metadata, newMetadata };
1666
+ return { keyring, keyringV2, metadata, hasChanged };
1499
1667
  }
1500
1668
  catch (error) {
1501
1669
  console.error(error);
@@ -1511,9 +1679,13 @@ async function _KeyringController_restoreKeyring(serialized) {
1511
1679
  * clears the keyring bridge iframe from the DOM.
1512
1680
  *
1513
1681
  * @param keyring - The keyring to destroy.
1682
+ * @param keyringV2 - The keyring v2 to destroy (if any).
1514
1683
  */
1515
- async function _KeyringController_destroyKeyring(keyring) {
1684
+ async function _KeyringController_destroyKeyring(keyring, keyringV2) {
1516
1685
  await keyring.destroy?.();
1686
+ if (keyringV2) {
1687
+ await keyringV2.destroy?.();
1688
+ }
1517
1689
  }, _KeyringController_assertNoDuplicateAccounts =
1518
1690
  /**
1519
1691
  * Assert that there are no duplicate accounts in the keyrings.
@@ -1551,7 +1723,7 @@ async function _KeyringController_persistOrRollback(callback) {
1551
1723
  const callbackResult = await callback({ releaseLock });
1552
1724
  const newState = JSON.stringify(await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSessionState).call(this));
1553
1725
  // State is committed only if the operation is successful and need to trigger a vault update.
1554
- if (!isEqual(oldState, newState)) {
1726
+ if (oldState !== newState) {
1555
1727
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
1556
1728
  }
1557
1729
  return callbackResult;