@metamask-previews/eth-snap-keyring 19.0.0-fd40efd → 20.0.0-5c366be

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/dist/SnapKeyring.cjs +169 -826
  3. package/dist/SnapKeyring.cjs.map +1 -1
  4. package/dist/SnapKeyring.d.cts +21 -11
  5. package/dist/SnapKeyring.d.cts.map +1 -1
  6. package/dist/SnapKeyring.d.mts +21 -11
  7. package/dist/SnapKeyring.d.mts.map +1 -1
  8. package/dist/SnapKeyring.mjs +169 -826
  9. package/dist/SnapKeyring.mjs.map +1 -1
  10. package/dist/SnapKeyringMessenger.cjs.map +1 -1
  11. package/dist/SnapKeyringMessenger.d.cts +2 -2
  12. package/dist/SnapKeyringMessenger.d.cts.map +1 -1
  13. package/dist/SnapKeyringMessenger.d.mts +2 -2
  14. package/dist/SnapKeyringMessenger.d.mts.map +1 -1
  15. package/dist/SnapKeyringMessenger.mjs.map +1 -1
  16. package/dist/SnapKeyringV1.cjs +736 -0
  17. package/dist/SnapKeyringV1.cjs.map +1 -0
  18. package/dist/SnapKeyringV1.d.cts +222 -0
  19. package/dist/SnapKeyringV1.d.cts.map +1 -0
  20. package/dist/SnapKeyringV1.d.mts +222 -0
  21. package/dist/SnapKeyringV1.d.mts.map +1 -0
  22. package/dist/SnapKeyringV1.mjs +732 -0
  23. package/dist/SnapKeyringV1.mjs.map +1 -0
  24. package/dist/SnapKeyringV2.cjs +375 -0
  25. package/dist/SnapKeyringV2.cjs.map +1 -0
  26. package/dist/SnapKeyringV2.d.cts +275 -0
  27. package/dist/SnapKeyringV2.d.cts.map +1 -0
  28. package/dist/SnapKeyringV2.d.mts +275 -0
  29. package/dist/SnapKeyringV2.d.mts.map +1 -0
  30. package/dist/SnapKeyringV2.mjs +371 -0
  31. package/dist/SnapKeyringV2.mjs.map +1 -0
  32. package/dist/events.d.cts +4 -4
  33. package/dist/events.d.mts +4 -4
  34. package/dist/index.cjs +2 -0
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +2 -0
  37. package/dist/index.d.cts.map +1 -1
  38. package/dist/index.d.mts +2 -0
  39. package/dist/index.d.mts.map +1 -1
  40. package/dist/index.mjs +2 -0
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/util.cjs +16 -0
  43. package/dist/util.cjs.map +1 -1
  44. package/dist/util.d.cts +11 -0
  45. package/dist/util.d.cts.map +1 -1
  46. package/dist/util.d.mts +11 -0
  47. package/dist/util.d.mts.map +1 -1
  48. package/dist/util.mjs +15 -0
  49. package/dist/util.mjs.map +1 -1
  50. package/package.json +11 -10
  51. package/dist/DeferredPromise.cjs +0 -30
  52. package/dist/DeferredPromise.cjs.map +0 -1
  53. package/dist/DeferredPromise.d.cts +0 -16
  54. package/dist/DeferredPromise.d.cts.map +0 -1
  55. package/dist/DeferredPromise.d.mts +0 -16
  56. package/dist/DeferredPromise.d.mts.map +0 -1
  57. package/dist/DeferredPromise.mjs +0 -26
  58. package/dist/DeferredPromise.mjs.map +0 -1
@@ -10,46 +10,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  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");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _SnapKeyring_instances, _SnapKeyring_messenger, _SnapKeyring_snapClient, _SnapKeyring_accounts, _SnapKeyring_selectedAccounts, _SnapKeyring_requests, _SnapKeyring_options, _SnapKeyring_callbacks, _SnapKeyring_isAnyAccountTypeAllowed, _SnapKeyring_lock, _SnapKeyring_withLock, _SnapKeyring_isMinimumPlatformVersion, _SnapKeyring_assertAccountCanBeUsed, _SnapKeyring_getExistingAccount, _SnapKeyring_getInternalOptions, _SnapKeyring_handleAccountCreated, _SnapKeyring_handleAccountUpdated, _SnapKeyring_handleAccountDeleted, _SnapKeyring_handleGetSelectedAccounts, _SnapKeyring_handleRequestApproved, _SnapKeyring_handleRequestRejected, _SnapKeyring_rePublishAccountEvent, _SnapKeyring_handleAccountBalancesUpdated, _SnapKeyring_handleAccountAssetListUpdated, _SnapKeyring_handleAccountTransactionsUpdated, _SnapKeyring_getAccount, _SnapKeyring_submitRequest, _SnapKeyring_submitSnapRequest, _SnapKeyring_hasMethod, _SnapKeyring_createRequestPromise, _SnapKeyring_clearRequestPromise, _SnapKeyring_handleSyncResponse, _SnapKeyring_handleAsyncResponse, _SnapKeyring_sanitizeRedirectUrl, _SnapKeyring_validateRedirectUrl, _SnapKeyring_deleteAccount, _SnapKeyring_resolveAddress, _SnapKeyring_updateSelectedAccountsMap, _SnapKeyring_getSnap, _SnapKeyring_getSnapMetadata, _SnapKeyring_getSnapAllowedOrigins, _SnapKeyring_transformToInternalAccount;
13
+ var _SnapKeyring_instances, _SnapKeyring_messenger, _SnapKeyring_snapKeyrings, _SnapKeyring_accountIndex, _SnapKeyring_callbacks, _SnapKeyring_isAnyAccountTypeAllowed, _SnapKeyring_getOrCreateKeyring, _SnapKeyring_removeSnapKeyringIfEmpty, _SnapKeyring_assertAccountCanBeUsed, _SnapKeyring_getAccount, _SnapKeyring_resolveAddress, _SnapKeyring_getSnap, _SnapKeyring_getSnapMetadata, _SnapKeyring_transformToInternalAccount;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.SnapKeyring = exports.SNAP_KEYRING_TYPE = void 0;
16
- const tx_1 = require("@ethereumjs/tx");
17
16
  const eth_sig_util_1 = require("@metamask/eth-sig-util");
18
17
  const keyring_api_1 = require("@metamask/keyring-api");
19
- const keyring_internal_api_1 = require("@metamask/keyring-internal-api");
20
- const keyring_internal_snap_client_1 = require("@metamask/keyring-internal-snap-client");
21
- const keyring_snap_sdk_1 = require("@metamask/keyring-snap-sdk");
22
- const keyring_utils_1 = require("@metamask/keyring-utils");
23
- const superstruct_1 = require("@metamask/superstruct");
24
- const utils_1 = require("@metamask/utils");
25
- const async_mutex_1 = require("async-mutex");
26
- const uuid_1 = require("uuid");
27
- const account_1 = require("./account.cjs");
28
- const DeferredPromise_1 = require("./DeferredPromise.cjs");
29
- const events_1 = require("./events.cjs");
30
- const logger_1 = require("./logger.cjs");
31
- const migrations_1 = require("./migrations/index.cjs");
32
- const options_1 = require("./options.cjs");
33
- const platform_versions_1 = require("./platform-versions.cjs");
34
- const SnapIdMap_1 = require("./SnapIdMap.cjs");
35
18
  const SnapKeyringMessenger_1 = require("./SnapKeyringMessenger.cjs");
36
- const types_1 = require("./types.cjs");
19
+ const SnapKeyringV2_1 = require("./SnapKeyringV2.cjs");
37
20
  const util_1 = require("./util.cjs");
38
21
  exports.SNAP_KEYRING_TYPE = 'Snap Keyring';
39
- /**
40
- * Normalize account's address.
41
- *
42
- * @param account - The account.
43
- * @returns The normalized account address.
44
- */
45
- function normalizeAccountAddress(account) {
46
- // FIXME: Is it required to lowercase the address here? For now we'll keep this behavior
47
- // only for Ethereum addresses and use the original address for other non-EVM accounts.
48
- // For example, Solana addresses are case-sensitives.
49
- return (0, keyring_api_1.isEvmAccountType)(account.type)
50
- ? account.address.toLowerCase()
51
- : account.address;
52
- }
53
22
  /**
54
23
  * Keyring bridge implementation to support Snaps.
55
24
  */
@@ -73,26 +42,19 @@ class SnapKeyring {
73
42
  */
74
43
  _SnapKeyring_messenger.set(this, void 0);
75
44
  /**
76
- * Client used to call the Snap keyring.
77
- */
78
- _SnapKeyring_snapClient.set(this, void 0);
79
- /**
80
- * Mapping between account IDs and an object that contains the associated
81
- * account object and Snap ID.
82
- */
83
- _SnapKeyring_accounts.set(this, void 0);
84
- /**
85
- * Mapping between Snap IDs and the selected accounts.
86
- */
87
- _SnapKeyring_selectedAccounts.set(this, void 0);
88
- /**
89
- * Mapping between request IDs and their deferred promises.
45
+ * Per-snap keyring instances. Each `SnapKeyringV2` (which extends
46
+ * `SnapKeyringV1`) owns a single `KeyringAccountRegistry` and handles
47
+ * both the event-driven v1 flow and the `KeyringV2` batch interface.
90
48
  */
91
- _SnapKeyring_requests.set(this, void 0);
49
+ _SnapKeyring_snapKeyrings.set(this, void 0);
92
50
  /**
93
- * Mapping between internal options, a correlation ID and a Snap ID.
51
+ * Reverse index from account ID to the owning Snap ID.
52
+ *
53
+ * Populated and kept in sync via the `onRegister` / `onUnregister`
54
+ * callbacks injected into each entry. Enables O(1) routing for
55
+ * any "which snap owns this account?" query.
94
56
  */
95
- _SnapKeyring_options.set(this, void 0);
57
+ _SnapKeyring_accountIndex.set(this, void 0);
96
58
  /**
97
59
  * Callbacks used to interact with other components.
98
60
  */
@@ -103,77 +65,49 @@ class SnapKeyring {
103
65
  * Account deletion is not affected by this flag and is always allowed.
104
66
  */
105
67
  _SnapKeyring_isAnyAccountTypeAllowed.set(this, void 0);
106
- /**
107
- * Mutex to ensure exclusive access to the inner keyring during
108
- * operations that mutate its state.
109
- */
110
- _SnapKeyring_lock.set(this, void 0);
111
68
  this.type = SnapKeyring.type;
112
69
  __classPrivateFieldSet(this, _SnapKeyring_messenger, messenger, "f");
113
- __classPrivateFieldSet(this, _SnapKeyring_snapClient, new keyring_internal_snap_client_1.KeyringInternalSnapClient({ messenger }), "f");
114
- __classPrivateFieldSet(this, _SnapKeyring_requests, new SnapIdMap_1.SnapIdMap(), "f");
115
- __classPrivateFieldSet(this, _SnapKeyring_accounts, new SnapIdMap_1.SnapIdMap(), "f");
116
- __classPrivateFieldSet(this, _SnapKeyring_options, new SnapIdMap_1.SnapIdMap(), "f");
70
+ __classPrivateFieldSet(this, _SnapKeyring_snapKeyrings, new Map(), "f");
71
+ __classPrivateFieldSet(this, _SnapKeyring_accountIndex, new Map(), "f");
117
72
  __classPrivateFieldSet(this, _SnapKeyring_callbacks, callbacks, "f");
118
73
  __classPrivateFieldSet(this, _SnapKeyring_isAnyAccountTypeAllowed, isAnyAccountTypeAllowed, "f");
119
- __classPrivateFieldSet(this, _SnapKeyring_selectedAccounts, new Map(), "f");
120
- __classPrivateFieldSet(this, _SnapKeyring_lock, new async_mutex_1.Mutex(), "f");
121
74
  }
122
75
  /**
123
76
  * Handle a message from a Snap.
124
77
  *
78
+ * Delegates to the per-snap SnapKeyringV1 handler.
79
+ *
125
80
  * @param snapId - ID of the Snap.
126
81
  * @param message - Message sent by the Snap.
127
82
  * @returns The execution result.
128
83
  */
129
84
  async handleKeyringSnapMessage(snapId, message) {
130
- (0, superstruct_1.assert)(message, types_1.SnapMessageStruct);
131
- switch (message.method) {
132
- case `${keyring_api_1.KeyringEvent.AccountCreated}`: {
133
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAccountCreated).call(this, snapId, message);
134
- }
135
- case `${keyring_api_1.KeyringEvent.AccountUpdated}`: {
136
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAccountUpdated).call(this, snapId, message);
137
- }
138
- case `${keyring_api_1.KeyringEvent.AccountDeleted}`: {
139
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAccountDeleted).call(this, snapId, message);
140
- }
141
- case `${keyring_api_1.KeyringEvent.RequestApproved}`: {
142
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleRequestApproved).call(this, snapId, message);
143
- }
144
- case `${keyring_api_1.KeyringEvent.RequestRejected}`: {
145
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleRequestRejected).call(this, snapId, message);
146
- }
147
- // Assets related events:
148
- case `${keyring_api_1.KeyringEvent.AccountBalancesUpdated}`: {
149
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAccountBalancesUpdated).call(this, snapId, message);
150
- }
151
- case `${keyring_api_1.KeyringEvent.AccountAssetListUpdated}`: {
152
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAccountAssetListUpdated).call(this, snapId, message);
153
- }
154
- case `${keyring_api_1.KeyringEvent.AccountTransactionsUpdated}`: {
155
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAccountTransactionsUpdated).call(this, snapId, message);
156
- }
157
- case `${keyring_snap_sdk_1.SnapManageAccountsMethod.GetSelectedAccounts}`: {
158
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleGetSelectedAccounts).call(this, snapId, message);
159
- }
160
- default:
161
- throw new Error(`Method not supported: ${message.method}`);
162
- }
85
+ return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getOrCreateKeyring).call(this, snapId).handleKeyringSnapMessage(message);
163
86
  }
164
87
  /**
165
88
  * Serialize the keyring state.
166
89
  *
90
+ * Delegates to each per-snap v2 keyring and flattens back into the original
91
+ * external format so that `KeyringController` sees no change.
92
+ *
167
93
  * @returns Serialized keyring state.
168
94
  */
169
95
  async serialize() {
170
- return {
171
- accounts: __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").toObject(),
172
- };
96
+ const accounts = {};
97
+ for (const keyring of __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").values()) {
98
+ for (const account of keyring.accounts()) {
99
+ accounts[account.id] = { account, snapId: keyring.snapId };
100
+ }
101
+ }
102
+ return { accounts };
173
103
  }
174
104
  /**
175
105
  * Deserialize the keyring state into this keyring.
176
106
  *
107
+ * Groups the flat persisted state by `snapId`, clears both indexes, then
108
+ * rebuilds each per-snap entry. The `onRegister` callbacks fired during
109
+ * `v2.deserialize()` automatically repopulate `#accountIndex`.
110
+ *
177
111
  * @param state - Serialized keyring state.
178
112
  */
179
113
  async deserialize(state) {
@@ -182,26 +116,25 @@ class SnapKeyring {
182
116
  if (state === undefined) {
183
117
  return;
184
118
  }
185
- // Running Snap keyring migrations. We might have some accounts that have a
186
- // different "version" than the one we expect.
187
- //
188
- // In this case, we "transform" then directly when deserializing to convert
189
- // them in the final account version.
190
- const accounts = {};
191
- for (const [snapId, entry] of Object.entries(state.accounts)) {
192
- // V1 accounts are missing the scopes.
193
- if ((0, migrations_1.isAccountV1)(entry.account)) {
194
- console.info(`SnapKeyring - Found a KeyringAccountV1, migrating to V2: ${entry.account.id}`);
195
- accounts[snapId] = {
196
- ...entry,
197
- account: (0, migrations_1.migrateAccountV1)(entry.account),
198
- };
199
- }
200
- else {
201
- accounts[snapId] = entry;
202
- }
119
+ // Group flat state by snapId. Migrations and migration logging are handled
120
+ // inside v2.deserialize().
121
+ const bySnap = new Map();
122
+ for (const entry of Object.values(state.accounts)) {
123
+ const snapAccounts = bySnap.get(entry.snapId) ?? {};
124
+ snapAccounts[entry.account.id] = entry.account;
125
+ bySnap.set(entry.snapId, snapAccounts);
126
+ }
127
+ // Clear both indexes before rebuilding — they must always be consistent.
128
+ __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").clear();
129
+ __classPrivateFieldGet(this, _SnapKeyring_accountIndex, "f").clear();
130
+ // Rebuild per-snap keyrings. Each keyrings handles its own validation
131
+ // and migration internally.
132
+ for (const [snapId, accounts] of bySnap) {
133
+ const keyring = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getOrCreateKeyring).call(this, snapId);
134
+ await keyring.deserialize({ snapId, accounts });
135
+ // onRegister callbacks fired above have repopulated #accountIndex.
136
+ __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_removeSnapKeyringIfEmpty).call(this, snapId);
203
137
  }
204
- __classPrivateFieldSet(this, _SnapKeyring_accounts, SnapIdMap_1.SnapIdMap.fromObject(accounts), "f");
205
138
  }
206
139
  /**
207
140
  * Get the addresses of the accounts in this keyring.
@@ -209,7 +142,13 @@ class SnapKeyring {
209
142
  * @returns The addresses of the accounts in this keyring.
210
143
  */
211
144
  async getAccounts() {
212
- return (0, util_1.unique)([...__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").values()].map(({ account }) => normalizeAccountAddress(account)));
145
+ const addresses = [];
146
+ for (const keyring of __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").values()) {
147
+ for (const account of keyring.accounts()) {
148
+ addresses.push((0, util_1.normalizeAccountAddress)(account));
149
+ }
150
+ }
151
+ return (0, util_1.unique)(addresses);
213
152
  }
214
153
  /**
215
154
  * Get the addresses of the accounts associated with a given Snap.
@@ -218,12 +157,12 @@ class SnapKeyring {
218
157
  * @returns The addresses of the accounts associated with the given Snap.
219
158
  */
220
159
  async getAccountsBySnapId(snapId) {
221
- return (0, util_1.unique)([...__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").values()]
222
- .filter(({ snapId: accountSnapId }) => accountSnapId === snapId)
223
- .map(({ account }) => normalizeAccountAddress(account)));
160
+ return (0, util_1.unique)((__classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").get(snapId)?.accounts() ?? []).map(util_1.normalizeAccountAddress));
224
161
  }
225
162
  /**
226
- * Create an account.
163
+ * Create an account (v1 event-driven flow).
164
+ *
165
+ * Delegates to the per-snap SnapKeyringV1 instance.
227
166
  *
228
167
  * @param snapId - Snap ID to create the account for.
229
168
  * @param options - Account creation options. Differs between keyrings.
@@ -231,119 +170,20 @@ class SnapKeyring {
231
170
  * @returns The account object.
232
171
  */
233
172
  async createAccount(snapId, options, internalOptions) {
234
- const client = new keyring_internal_snap_client_1.KeyringInternalSnapClient({
235
- messenger: __classPrivateFieldGet(this, _SnapKeyring_messenger, "f"),
236
- snapId,
237
- });
238
- // The 'metamask' field is reserved, so we have to prevent use of it on
239
- // the "normal options".
240
- const reserved = 'metamask';
241
- if ((0, utils_1.hasProperty)(options, reserved)) {
242
- throw new Error(`The '${reserved}' property is reserved for internal use`);
243
- }
244
- // Those internal options are optional. If not set, we avoid registering anything
245
- // to internal map (to avoid holding resources for nothing). In this case, it's
246
- // just a normal `keyring_createAccount`.
247
- if (!internalOptions) {
248
- return await client.createAccount(options);
249
- }
250
- // A unique ID to identify this execution flow which allows to associate the
251
- // internal options and the current `keyring_createAccount` flow for that Snap.
252
- const correlationId = (0, uuid_1.v4)();
253
- // Register those internal options to use them during the `keyring_createAccount`
254
- // flow.
255
- __classPrivateFieldGet(this, _SnapKeyring_options, "f").set(correlationId, {
256
- snapId,
257
- options: internalOptions,
258
- });
259
- return await client.createAccount({
260
- ...options,
261
- // Create internal options context.
262
- // NOTE: Those options HAVE TO be re-emitted during the `notify:accountCreated` event.
263
- ...{
264
- metamask: {
265
- correlationId,
266
- },
267
- },
268
- });
173
+ return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getOrCreateKeyring).call(this, snapId).createAccount(options, internalOptions);
269
174
  }
270
175
  /**
271
176
  * Creates one or more new accounts according to the provided options.
272
177
  *
273
- * Deterministic account creation MUST be idempotent, meaning that for
274
- * deterministic algorithms, like BIP-44, calling this method with the same
275
- * options should always return the same accounts, even if the accounts
276
- * already exist in the keyring.
277
- *
278
- * NOTE: If some accounts are not allowed (non-unique address, unsupported
279
- * generic account), this method will skip their creation and ask the Snap
280
- * to remove them from its state.
178
+ * Delegates to the per-snap SnapKeyringV2 instance which handles
179
+ * idempotency, validation, batch tracking, state persistence, and rollback.
281
180
  *
282
181
  * @param snapId - Snap ID to create the account(s) for.
283
182
  * @param options - Options describing how to create the account(s).
284
183
  * @returns An array of the created account objects.
285
184
  */
286
185
  async createAccounts(snapId, options) {
287
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_withLock).call(this, async () => {
288
- const client = new keyring_internal_snap_client_1.KeyringInternalSnapClient({
289
- messenger: __classPrivateFieldGet(this, _SnapKeyring_messenger, "f"),
290
- snapId,
291
- });
292
- // Keep track of address/account ID part of this batch, to avoid having duplicates.
293
- const accountAddresses = new Set();
294
- const accountIds = new Set();
295
- const accounts = [];
296
- const newAccounts = [];
297
- const snapAccounts = await client.createAccounts(options);
298
- try {
299
- for (const snapAccount of snapAccounts) {
300
- let account = (0, account_1.transformAccount)(snapAccount);
301
- const address = normalizeAccountAddress(account);
302
- // Check for idempotency.
303
- const existingAccount = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getExistingAccount).call(this, snapId, account);
304
- if (existingAccount) {
305
- // NOTE: We re-use the account from the internal state to avoid having the Snap
306
- // mutating the account object without updating the map.
307
- account = existingAccount;
308
- }
309
- else {
310
- await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_assertAccountCanBeUsed).call(this, snapId, account);
311
- // Also check for transient accounts that are not yet part of the keyring
312
- // state.
313
- if (accountAddresses.has(address) || accountIds.has(account.id)) {
314
- throw new Error(`Account '${account.id}' is already part of this batch (same address or account ID)`);
315
- }
316
- accountAddresses.add(address);
317
- accountIds.add(account.id);
318
- // NOTE: This method does not rely on the `AccountCreated` event to add
319
- // accounts to the keyring, so we have to add them to the state manually.
320
- newAccounts.push(account);
321
- }
322
- // New AND existing accounts are returned to the caller no matter what.
323
- accounts.push(account);
324
- }
325
- // We update the keyring state only if needed.
326
- if (newAccounts.length > 0) {
327
- for (const account of newAccounts) {
328
- __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").set(account.id, { account, snapId });
329
- }
330
- // NOTE: We assume this will never fail, thus, we don't need to rollback the
331
- // keyring state if anything goes wrong here.
332
- await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").saveState();
333
- }
334
- return accounts;
335
- }
336
- catch (error) {
337
- // Rollback Snap state.
338
- for (const account of snapAccounts) {
339
- // Make sure to only delete accounts that were not part of the keyring state.
340
- if (!__classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getExistingAccount).call(this, snapId, account)) {
341
- await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_deleteAccount).call(this, snapId, account);
342
- }
343
- }
344
- throw error;
345
- }
346
- });
186
+ return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getOrCreateKeyring).call(this, snapId).createAccounts(options);
347
187
  }
348
188
  /**
349
189
  * Checks if a Snap ID is known from the keyring.
@@ -352,7 +192,8 @@ class SnapKeyring {
352
192
  * @returns `true` if the Snap ID is known, `false` otherwise.
353
193
  */
354
194
  hasSnapId(snapId) {
355
- return __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").hasSnapId(snapId);
195
+ const keyring = __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").get(snapId);
196
+ return keyring !== undefined && keyring.accounts().length > 0;
356
197
  }
357
198
  /**
358
199
  * Resolve the Snap account's address associated from a signing request.
@@ -368,9 +209,7 @@ class SnapKeyring {
368
209
  if (!this.hasSnapId(snapId)) {
369
210
  throw new Error(`Unable to resolve account address: unknown Snap ID: ${snapId}`);
370
211
  }
371
- return await __classPrivateFieldGet(this, _SnapKeyring_snapClient, "f")
372
- .withSnapId(snapId)
373
- .resolveAccountAddress(scope, request);
212
+ return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getOrCreateKeyring).call(this, snapId).resolveAccountAddress(scope, request);
374
213
  }
375
214
  /**
376
215
  * Submit a request to a Snap from an account ID.
@@ -387,9 +226,11 @@ class SnapKeyring {
387
226
  */
388
227
  async submitRequest({ origin, account: accountId, method, params, scope, }) {
389
228
  const { account, snapId } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getAccount).call(this, accountId);
390
- return await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitSnapRequest).call(this, {
229
+ /* istanbul ignore next */
230
+ const keyring = __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").get(snapId) ??
231
+ (0, util_1.throwError)(`No keyring found for snap '${snapId}'`);
232
+ return await keyring.submitSnapRequest({
391
233
  origin,
392
- snapId,
393
234
  account,
394
235
  method: method,
395
236
  params,
@@ -408,33 +249,8 @@ class SnapKeyring {
408
249
  * @returns A promise that resolves to the signed transaction.
409
250
  */
410
251
  async signTransaction(address, transaction, _opts = {}) {
411
- const chainId = transaction.common.chainId();
412
- const tx = (0, util_1.toJson)({
413
- ...transaction.toJSON(),
414
- from: address,
415
- type: `0x${transaction.type.toString(16)}`,
416
- chainId: (0, utils_1.bigIntToHex)(chainId),
417
- });
418
- const signedTx = await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
419
- origin: 'metamask',
420
- address,
421
- method: keyring_api_1.EthMethod.SignTransaction,
422
- params: [tx],
423
- scope: (0, utils_1.toCaipChainId)(utils_1.KnownCaipNamespace.Eip155, `${chainId}`),
424
- });
425
- // ! It's *** CRITICAL *** that we mask the signature here, otherwise the
426
- // ! Snap could overwrite the transaction.
427
- const signature = (0, superstruct_1.mask)(signedTx, (0, superstruct_1.object)({
428
- r: (0, superstruct_1.string)(),
429
- s: (0, superstruct_1.string)(),
430
- v: (0, superstruct_1.string)(),
431
- }));
432
- return tx_1.TransactionFactory.fromTxData({
433
- ...tx,
434
- r: signature.r,
435
- s: signature.s,
436
- v: signature.v,
437
- });
252
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
253
+ return keyring.signTransaction(account, transaction, _opts);
438
254
  }
439
255
  /**
440
256
  * Sign a typed data message.
@@ -445,28 +261,8 @@ class SnapKeyring {
445
261
  * @returns The signature.
446
262
  */
447
263
  async signTypedData(address, data, opts = { version: eth_sig_util_1.SignTypedDataVersion.V1 }) {
448
- const methods = {
449
- [eth_sig_util_1.SignTypedDataVersion.V1]: keyring_api_1.EthMethod.SignTypedDataV1,
450
- [eth_sig_util_1.SignTypedDataVersion.V3]: keyring_api_1.EthMethod.SignTypedDataV3,
451
- [eth_sig_util_1.SignTypedDataVersion.V4]: keyring_api_1.EthMethod.SignTypedDataV4,
452
- };
453
- // Use 'V1' by default to match other keyring implementations. V1 will be
454
- // used if the version is not specified or not supported.
455
- const method = methods[opts.version] || keyring_api_1.EthMethod.SignTypedDataV1;
456
- // Extract chain ID as if it was a typed message (as defined by EIP-712), if
457
- // input is not a typed message, then chain ID will be undefined!
458
- const chainId = data.domain?.chainId;
459
- return (0, keyring_utils_1.strictMask)(await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
460
- origin: 'metamask',
461
- address,
462
- method,
463
- params: (0, util_1.toJson)([address, data]),
464
- ...(chainId === undefined
465
- ? {}
466
- : {
467
- scope: (0, utils_1.toCaipChainId)(utils_1.KnownCaipNamespace.Eip155, `${chainId}`),
468
- }),
469
- }), keyring_api_1.EthBytesStruct);
264
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
265
+ return keyring.signTypedData(account, data, opts);
470
266
  }
471
267
  /**
472
268
  * Sign a message.
@@ -476,12 +272,8 @@ class SnapKeyring {
476
272
  * @returns The signature.
477
273
  */
478
274
  async signMessage(address, hash) {
479
- return (0, keyring_utils_1.strictMask)(await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
480
- origin: 'metamask',
481
- address,
482
- method: keyring_api_1.EthMethod.Sign,
483
- params: (0, util_1.toJson)([address, hash]),
484
- }), keyring_api_1.EthBytesStruct);
275
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
276
+ return keyring.signMessage(account, hash);
485
277
  }
486
278
  /**
487
279
  * Sign a personal message.
@@ -494,12 +286,8 @@ class SnapKeyring {
494
286
  * @returns Promise of the signature.
495
287
  */
496
288
  async signPersonalMessage(address, data) {
497
- return (0, keyring_utils_1.strictMask)(await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
498
- origin: 'metamask',
499
- address,
500
- method: keyring_api_1.EthMethod.PersonalSign,
501
- params: (0, util_1.toJson)([data, address]),
502
- }), keyring_api_1.EthBytesStruct);
289
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
290
+ return keyring.signPersonalMessage(account, data);
503
291
  }
504
292
  /**
505
293
  * Convert a base transaction to a base UserOperation.
@@ -510,15 +298,8 @@ class SnapKeyring {
510
298
  * @returns A pseudo-UserOperation that can be used to construct a real.
511
299
  */
512
300
  async prepareUserOperation(address, transactions, context) {
513
- return (0, keyring_utils_1.strictMask)(await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
514
- origin: 'metamask',
515
- address,
516
- method: keyring_api_1.EthMethod.PrepareUserOperation,
517
- params: (0, util_1.toJson)(transactions),
518
- noPending: true,
519
- // We assume the chain ID is already well formatted
520
- scope: (0, utils_1.toCaipChainId)(utils_1.KnownCaipNamespace.Eip155, context.chainId),
521
- }), keyring_api_1.EthBaseUserOperationStruct);
301
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
302
+ return keyring.prepareUserOperation(account, transactions, context);
522
303
  }
523
304
  /**
524
305
  * Patches properties of a UserOperation. Currently, only the
@@ -530,33 +311,20 @@ class SnapKeyring {
530
311
  * @returns A patch to apply to the UserOperation.
531
312
  */
532
313
  async patchUserOperation(address, userOp, context) {
533
- return (0, keyring_utils_1.strictMask)(await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
534
- origin: 'metamask',
535
- address,
536
- method: keyring_api_1.EthMethod.PatchUserOperation,
537
- params: (0, util_1.toJson)([userOp]),
538
- noPending: true,
539
- // We assume the chain ID is already well formatted
540
- scope: (0, utils_1.toCaipChainId)(utils_1.KnownCaipNamespace.Eip155, context.chainId),
541
- }), keyring_api_1.EthUserOperationPatchStruct);
314
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
315
+ return keyring.patchUserOperation(account, userOp, context);
542
316
  }
543
317
  /**
544
- * Signs an UserOperation.
318
+ * Signs a UserOperation.
545
319
  *
546
320
  * @param address - Address of the sender.
547
321
  * @param userOp - UserOperation to sign.
548
- * @param context - Leyring execution context.
322
+ * @param context - Keyring execution context.
549
323
  * @returns The signature of the UserOperation.
550
324
  */
551
325
  async signUserOperation(address, userOp, context) {
552
- return (0, keyring_utils_1.strictMask)(await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitRequest).call(this, {
553
- origin: 'metamask',
554
- address,
555
- method: keyring_api_1.EthMethod.SignUserOperation,
556
- params: (0, util_1.toJson)([userOp]),
557
- // We assume the chain ID is already well formatted
558
- scope: (0, utils_1.toCaipChainId)(utils_1.KnownCaipNamespace.Eip155, context.chainId),
559
- }), keyring_api_1.EthBytesStruct);
326
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
327
+ return keyring.signUserOperation(account, userOp, context);
560
328
  }
561
329
  /**
562
330
  * Gets the private data associated with the given address so
@@ -575,30 +343,39 @@ class SnapKeyring {
575
343
  /**
576
344
  * Removes the account matching the given address.
577
345
  *
346
+ * Delegates to the per-snap SnapKeyringV2 keyring which handles
347
+ * registry removal, index cleanup, and snap communication.
348
+ *
578
349
  * @param address - Address of the account to remove.
579
350
  */
580
351
  async removeAccount(address) {
581
- const { account, snapId } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
582
- await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_deleteAccount).call(this, snapId, account);
352
+ const { account, keyring } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
353
+ await keyring.deleteAccount(account.id);
354
+ __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_removeSnapKeyringIfEmpty).call(this, keyring.snapId);
583
355
  }
584
356
  /**
585
357
  * Set the selected accounts.
586
358
  *
359
+ * Distributes the global list by snap and forwards to each v1 instance.
360
+ *
587
361
  * @param accounts - The accounts to set as selected.
588
362
  */
589
363
  async setSelectedAccounts(accounts) {
590
- __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_updateSelectedAccountsMap).call(this, accounts);
591
- const entries = [...__classPrivateFieldGet(this, _SnapKeyring_selectedAccounts, "f").entries()];
592
- await Promise.all(entries.map(async ([snapId, accountIds]) => {
593
- try {
594
- await __classPrivateFieldGet(this, _SnapKeyring_snapClient, "f")
595
- .withSnapId(snapId)
596
- .setSelectedAccounts(accountIds);
597
- }
598
- catch (error) {
599
- console.error(`Failed to set selected accounts for ${snapId} snap: '${error.message}'`);
364
+ // Build per-snap distribution using the account index.
365
+ const bySnap = new Map();
366
+ for (const accountId of accounts) {
367
+ const snapId = __classPrivateFieldGet(this, _SnapKeyring_accountIndex, "f").get(accountId);
368
+ if (!snapId) {
369
+ continue;
600
370
  }
601
- }));
371
+ const snapAccounts = bySnap.get(snapId) ?? [];
372
+ snapAccounts.push(accountId);
373
+ bySnap.set(snapId, snapAccounts);
374
+ }
375
+ await Promise.all([...__classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").entries()].map(async ([snapId, keyring]) => keyring.setSelectedAccounts(
376
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
377
+ /* istanbul ignore next */
378
+ bySnap.get(snapId) ?? [])));
602
379
  }
603
380
  /**
604
381
  * Return an internal account object for a given address.
@@ -607,11 +384,13 @@ class SnapKeyring {
607
384
  * @returns An internal account object for the given address.
608
385
  */
609
386
  getAccountByAddress(address) {
610
- const accounts = [...__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").values()];
611
- const account = accounts.find(({ account: { address: accountAddress } }) => (0, util_1.equalsIgnoreCase)(accountAddress, address));
612
- return account
613
- ? __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_transformToInternalAccount).call(this, account.account, account.snapId)
614
- : undefined;
387
+ for (const [snapId, keyring] of __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f")) {
388
+ const account = keyring.lookupByAddress(address);
389
+ if (account) {
390
+ return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_transformToInternalAccount).call(this, account, snapId);
391
+ }
392
+ }
393
+ return undefined;
615
394
  }
616
395
  /**
617
396
  * List all Snap keyring accounts.
@@ -621,32 +400,55 @@ class SnapKeyring {
621
400
  * @returns An array containing all Snap keyring accounts.
622
401
  */
623
402
  listAccounts() {
624
- return [...__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").values()].map(({ account, snapId }) => __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_transformToInternalAccount).call(this, account, snapId));
403
+ const accounts = [];
404
+ for (const [snapId, keyring] of __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f")) {
405
+ for (const account of keyring.accounts()) {
406
+ accounts.push(__classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_transformToInternalAccount).call(this, account, snapId));
407
+ }
408
+ }
409
+ return accounts;
625
410
  }
626
411
  }
627
412
  exports.SnapKeyring = SnapKeyring;
628
- _SnapKeyring_messenger = new WeakMap(), _SnapKeyring_snapClient = new WeakMap(), _SnapKeyring_accounts = new WeakMap(), _SnapKeyring_selectedAccounts = new WeakMap(), _SnapKeyring_requests = new WeakMap(), _SnapKeyring_options = new WeakMap(), _SnapKeyring_callbacks = new WeakMap(), _SnapKeyring_isAnyAccountTypeAllowed = new WeakMap(), _SnapKeyring_lock = new WeakMap(), _SnapKeyring_instances = new WeakSet(), _SnapKeyring_withLock =
629
- /**
630
- * Execute an operation behind a lock.
631
- *
632
- * @param callback - A function that performs the operation.
633
- * @returns The result of the callback.
634
- */
635
- async function _SnapKeyring_withLock(callback) {
636
- return __classPrivateFieldGet(this, _SnapKeyring_lock, "f").runExclusive(callback);
637
- }, _SnapKeyring_isMinimumPlatformVersion = function _SnapKeyring_isMinimumPlatformVersion(snapId, platformVersion) {
638
- return __classPrivateFieldGet(this, _SnapKeyring_messenger, "f").call('SnapController:isMinimumPlatformVersion', snapId, platformVersion);
413
+ _SnapKeyring_messenger = new WeakMap(), _SnapKeyring_snapKeyrings = new WeakMap(), _SnapKeyring_accountIndex = new WeakMap(), _SnapKeyring_callbacks = new WeakMap(), _SnapKeyring_isAnyAccountTypeAllowed = new WeakMap(), _SnapKeyring_instances = new WeakSet(), _SnapKeyring_getOrCreateKeyring = function _SnapKeyring_getOrCreateKeyring(snapId) {
414
+ let keyring = __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").get(snapId);
415
+ if (!keyring) {
416
+ keyring = new SnapKeyringV2_1.SnapKeyringV2({
417
+ snapId,
418
+ messenger: __classPrivateFieldGet(this, _SnapKeyring_messenger, "f"),
419
+ isAnyAccountTypeAllowed: __classPrivateFieldGet(this, _SnapKeyring_isAnyAccountTypeAllowed, "f"),
420
+ callbacks: {
421
+ onRegister: (id) => {
422
+ __classPrivateFieldGet(this, _SnapKeyring_accountIndex, "f").set(id, snapId);
423
+ },
424
+ onUnregister: (id) => {
425
+ __classPrivateFieldGet(this, _SnapKeyring_accountIndex, "f").delete(id);
426
+ },
427
+ addAccount: async (address, handleUserInput, onceSaved, accountNameSuggestion, internalOptions) => __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").addAccount(address, snapId, handleUserInput, onceSaved, accountNameSuggestion, internalOptions),
428
+ removeAccount: async (address, handleUserInput) => __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").removeAccount(address, snapId, handleUserInput),
429
+ saveState: async () => __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").saveState(),
430
+ redirectUser: async (url, message) => __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").redirectUser(snapId, url, message),
431
+ assertAccountCanBeUsed: async (account) => __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_assertAccountCanBeUsed).call(this, account),
432
+ },
433
+ });
434
+ __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").set(snapId, keyring);
435
+ }
436
+ return keyring;
437
+ }, _SnapKeyring_removeSnapKeyringIfEmpty = function _SnapKeyring_removeSnapKeyringIfEmpty(snapId) {
438
+ const keyring = __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").get(snapId);
439
+ if (keyring !== undefined && keyring.accounts().length === 0) {
440
+ __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").delete(snapId);
441
+ }
639
442
  }, _SnapKeyring_assertAccountCanBeUsed =
640
443
  /**
641
444
  * Asserts that an account can be used within the Snap keyring. (e.g. generic accounts, unique
642
445
  * addresses, etc...).
643
446
  *
644
- * @param snapId - The account's Snap ID.
645
447
  * @param account - The account to check.
646
448
  * @throws If the account cannot be used.
647
449
  */
648
- async function _SnapKeyring_assertAccountCanBeUsed(snapId, account) {
649
- const address = normalizeAccountAddress(account);
450
+ async function _SnapKeyring_assertAccountCanBeUsed(account) {
451
+ const address = (0, util_1.normalizeAccountAddress)(account);
650
452
  // The `AnyAccountType.Account` generic account type is allowed only during
651
453
  // development, so we check whether it's allowed before continuing.
652
454
  if (!__classPrivateFieldGet(this, _SnapKeyring_isAnyAccountTypeAllowed, "f") &&
@@ -655,7 +457,8 @@ async function _SnapKeyring_assertAccountCanBeUsed(snapId, account) {
655
457
  }
656
458
  // A Snap could try to create an account with a different address but with
657
459
  // an existing ID, so the above test only is not enough.
658
- if (__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").has(snapId, account.id)) {
460
+ // Account IDs are globally unique across all snaps.
461
+ if (__classPrivateFieldGet(this, _SnapKeyring_accountIndex, "f").has(account.id)) {
659
462
  throw new Error(`Account '${account.id}' already exists`);
660
463
  }
661
464
  // The UI still uses the account address to identify accounts, so we need
@@ -664,490 +467,30 @@ async function _SnapKeyring_assertAccountCanBeUsed(snapId, account) {
664
467
  if (await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").addressExists(address)) {
665
468
  throw new Error(`Account address '${address}' already exists`);
666
469
  }
667
- }, _SnapKeyring_getExistingAccount = function _SnapKeyring_getExistingAccount(snapId, account) {
668
- const address = normalizeAccountAddress(account);
669
- // Acount creation is idempotent, so we need to check whether the account already exists
670
- // and that the right Snap is trying to "create" it again.
671
- // NOTE: We are not checking account object equality here. If a Snap
672
- // re-send this event with different account data, we will ignore it.
673
- const accountEntry = __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").get(snapId, account.id);
674
- if (accountEntry !== undefined &&
675
- normalizeAccountAddress(accountEntry.account) === address) {
676
- return accountEntry.account;
677
- }
678
- return undefined; // Not a known account.
679
- }, _SnapKeyring_getInternalOptions = function _SnapKeyring_getInternalOptions(snapId, correlationId) {
680
- if (correlationId) {
681
- // We still need to check if the correlation ID is valid and associated to
682
- // some internal options.
683
- //
684
- // NOTE: `found` will be `undefined` if a Snap tried to use a correlation ID that
685
- // belongs to another Snap ID. However, if a Snap starts 2 parallel flow (which
686
- // will results in 2 different correlation IDs), we won't be able to prevent
687
- // the Snap from swapping/mixing up those correlation IDs he owns.
688
- const found = __classPrivateFieldGet(this, _SnapKeyring_options, "f").pop(snapId, correlationId);
689
- if (found) {
690
- return found.options;
691
- }
692
- console.warn(`SnapKeyring - Received unmapped correlation ID: "${correlationId}"`);
693
- }
694
- return undefined;
695
- }, _SnapKeyring_handleAccountCreated =
696
- /**
697
- * Handle an Account Created event from a Snap.
698
- *
699
- * @param snapId - Snap ID.
700
- * @param message - Event message.
701
- * @returns `null`.
702
- */
703
- async function _SnapKeyring_handleAccountCreated(snapId, message) {
704
- (0, superstruct_1.assert)(message, events_1.AccountCreatedEventStruct);
705
- const { metamask, // Used for internal options.
706
- account: newAccountFromEvent, accountNameSuggestion, displayAccountNameSuggestion, displayConfirmation, } = message.params;
707
- // READ THIS CAREFULLY:
708
- // ------------------------------------------------------------------------
709
- // The account creation flow is now asynchronous. We expect the Snap to
710
- // first create the account data and then fire the "AccountCreated" event.
711
- // Potentially migrate the account.
712
- const account = (0, account_1.transformAccount)(newAccountFromEvent);
713
- const address = normalizeAccountAddress(account);
714
- if (__classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getExistingAccount).call(this, snapId, account)) {
715
- // If the account already exists, we skip it.
716
- return null;
717
- }
718
- // Make sure this new account is valid.
719
- await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_assertAccountCanBeUsed).call(this, snapId, account);
720
- // A deferred promise that will be resolved once the Snap keyring has saved
721
- // its internal state.
722
- // This part of the flow is run asynchronously, so we have no other way of
723
- // letting the MetaMask client that this "save" has been run.
724
- // NOTE: Another way of fixing that could be to rely on events through the
725
- // messenger maybe?
726
- const onceSaved = new DeferredPromise_1.DeferredPromise();
727
- // Add the account to the keyring, but wait for the MetaMask client to
728
- // approve the account creation first.
729
- await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").addAccount(address, snapId,
730
- // This callback is passed to the MetaMask client, it will be called whenever
731
- // the end user will accept or not the account creation.
732
- async (accepted) => {
733
- if (accepted) {
734
- // We consider the account to be created on the Snap keyring only if
735
- // the user accepted it. Meaning that the Snap MIGHT HAVE created the
736
- // account on its own state, but the Snap keyring MIGHT NOT HAVE it yet.
737
- //
738
- // e.g The account creation dialog crashed on MetaMask, this callback
739
- // will never be called, but the Snap still has the account.
740
- __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").set(account.id, { account, snapId });
741
- // This is the "true async part". We do not `await` for this call, mainly
742
- // because this callback will persist the account on the client side
743
- // (through the `AccountsController`).
744
- //
745
- // Since this will happen after the Snap account creation and Snap
746
- // event, if anything goes wrong, we will delete the account by
747
- // calling `deleteAccount` on the Snap.
748
- // eslint-disable-next-line no-void
749
- void __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f")
750
- .saveState()
751
- .then(() => {
752
- // This allows the MetaMask client to be "notified" when then
753
- // Snap keyring has truly persisted its state. From there, we should
754
- // be able to use the account (e.g. to display account creation
755
- // confirmation dialogs).
756
- onceSaved.resolve(account.id);
757
- })
758
- .catch(async (error) => {
759
- // FIXME: There's a potential race condition here, if the Snap did
760
- // not persist the account yet (this should mostly be for older Snaps).
761
- await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_deleteAccount).call(this, snapId, account);
762
- // This allows the MetaMask client to be "notified" that something went
763
- // wrong with the Snap keyring. (e.g. useful to display account creation
764
- // error dialogs).
765
- onceSaved.reject(error);
766
- });
767
- }
768
- }, onceSaved.promise, accountNameSuggestion, (0, options_1.getInternalOptionsOf)([
769
- // 1. We use the internal options from the Snap keyring.
770
- __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getInternalOptions).call(this, snapId, metamask?.correlationId) ?? {},
771
- // 2. We use the ones coming from the Snap.
772
- {
773
- displayConfirmation,
774
- displayAccountNameSuggestion,
775
- },
776
- ]));
777
- return null;
778
- }, _SnapKeyring_handleAccountUpdated =
779
- /**
780
- * Handle an Account Updated event from a Snap.
781
- *
782
- * @param snapId - Snap ID.
783
- * @param message - Event message.
784
- * @returns `null`.
785
- */
786
- async function _SnapKeyring_handleAccountUpdated(snapId, message) {
787
- (0, superstruct_1.assert)(message, events_1.AccountUpdatedEventStruct);
788
- const { account: newAccountFromEvent } = message.params;
789
- const { account: oldAccount } = __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").get(snapId, newAccountFromEvent.id) ??
790
- (0, util_1.throwError)(`Account '${newAccountFromEvent.id}' not found`);
791
- // Potentially migrate the account.
792
- const newAccount = (0, account_1.transformAccount)(newAccountFromEvent);
793
- // The `AnyAccountType.Account` generic account type is allowed only during
794
- // development, so we check whether it's allowed before continuing.
795
- //
796
- // An account cannot be updated if the `isAnyAccountTypeAllowed` flag is
797
- // set to `false` and the new or old account is a generic account.
798
- const isGenericAccountInvolved = newAccount.type === keyring_api_1.AnyAccountType.Account ||
799
- oldAccount.type === keyring_api_1.AnyAccountType.Account;
800
- if (!__classPrivateFieldGet(this, _SnapKeyring_isAnyAccountTypeAllowed, "f") && isGenericAccountInvolved) {
801
- throw new Error(`Cannot update generic account '${newAccount.id}'`);
802
- }
803
- // The address of the account cannot be changed. In the future, we will
804
- // support changing the address of an account since it will be required to
805
- // support UTXO-based chains.
806
- if (!(0, util_1.equalsIgnoreCase)(oldAccount.address, newAccount.address)) {
807
- throw new Error(`Cannot change address of account '${newAccount.id}'`);
808
- }
809
- __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").set(newAccount.id, { account: newAccount, snapId });
810
- await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").saveState();
811
- return null;
812
- }, _SnapKeyring_handleAccountDeleted =
813
- /**
814
- * Handle an Account Deleted event from a Snap.
815
- *
816
- * @param snapId - Snap ID.
817
- * @param message - Event message.
818
- * @returns `null`.
819
- */
820
- async function _SnapKeyring_handleAccountDeleted(snapId, message) {
821
- (0, superstruct_1.assert)(message, events_1.AccountDeletedEventStruct);
822
- const { id } = message.params;
823
- const entry = __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").get(snapId, id);
824
- // We can ignore the case where the account was already removed from the
825
- // keyring, making the deletion idempotent.
826
- //
827
- // This happens when the keyring calls the Snap to delete an account, and
828
- // the Snap calls the keyring back with an `AccountDeleted` event.
829
- if (entry === undefined) {
830
- return null;
831
- }
832
- // At this point we know that the account exists, so we can safely
833
- // destructure it.
834
- const { account } = entry;
835
- await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").removeAccount(normalizeAccountAddress(account), snapId, async (accepted) => {
836
- if (accepted) {
837
- await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").saveState();
838
- }
839
- });
840
- return null;
841
- }, _SnapKeyring_handleGetSelectedAccounts =
842
- /**
843
- * Handle a Get Selected Accounts method call from a Snap.
844
- *
845
- * @param snapId - Snap ID.
846
- * @param message - Method call message.
847
- * @returns The selected accounts.
848
- */
849
- async function _SnapKeyring_handleGetSelectedAccounts(snapId, message) {
850
- (0, superstruct_1.assert)(message, keyring_snap_sdk_1.GetSelectedAccountsRequestStruct);
851
- return __classPrivateFieldGet(this, _SnapKeyring_selectedAccounts, "f").get(snapId) ?? [];
852
- }, _SnapKeyring_handleRequestApproved =
853
- /**
854
- * Handle an Request Approved event from a Snap.
855
- *
856
- * @param snapId - Snap ID.
857
- * @param message - Event message.
858
- * @returns `null`.
859
- */
860
- async function _SnapKeyring_handleRequestApproved(snapId, message) {
861
- (0, superstruct_1.assert)(message, events_1.RequestApprovedEventStruct);
862
- const { id, result } = message.params;
863
- const { promise } = __classPrivateFieldGet(this, _SnapKeyring_requests, "f").get(snapId, id) ?? (0, util_1.throwError)(`Request '${id}' not found`);
864
- __classPrivateFieldGet(this, _SnapKeyring_requests, "f").delete(snapId, id);
865
- promise.resolve(result);
866
- return null;
867
- }, _SnapKeyring_handleRequestRejected =
868
- /**
869
- * Handle an Request Rejected event from a Snap.
870
- *
871
- * @param snapId - Snap ID.
872
- * @param message - Event message.
873
- * @returns `null`.
874
- */
875
- async function _SnapKeyring_handleRequestRejected(snapId, message) {
876
- (0, superstruct_1.assert)(message, events_1.RequestRejectedEventStruct);
877
- const { id } = message.params;
878
- const { promise } = __classPrivateFieldGet(this, _SnapKeyring_requests, "f").get(snapId, id) ?? (0, util_1.throwError)(`Request '${id}' not found`);
879
- __classPrivateFieldGet(this, _SnapKeyring_requests, "f").delete(snapId, id);
880
- promise.reject(new Error(`Request rejected by user or snap.`));
881
- return null;
882
- }, _SnapKeyring_rePublishAccountEvent =
883
- /**
884
- * Re-publish an account event.
885
- *
886
- * @param snapId - Snap ID.
887
- * @param event - The event type. This is a unique identifier for this event.
888
- * @param filteredEventCallback - A callback that returns the event to re-publish. This callback takes a filtering
889
- * function as parameter that can be used to filter out account ID that do not belong to this Snap ID.
890
- * @template EventType - A Snap keyring event type.
891
- * @returns `null`.
892
- */
893
- async function _SnapKeyring_rePublishAccountEvent(snapId, event, filteredEventCallback) {
894
- // This callback can be used to filter out the accounts that no longer exists on the Snap (fail-safe) or to
895
- // prevent other Snaps from updating accounts they do not own.
896
- const filter = (accountMapping) => {
897
- return Object.entries(accountMapping).reduce((filtered, [accountId, entry]) => {
898
- if (__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").has(snapId, accountId)) {
899
- // If the Snap owns this account, we can use it.
900
- filtered[accountId] = entry;
901
- }
902
- else {
903
- // Otherwise, we just filter it out and log it (for debugging/tracking purposes).
904
- console.warn(`SnapKeyring - ${event} - Found an unknown account ID "${accountId}" for Snap ID "${snapId}". Skipping.`);
905
- }
906
- return filtered;
907
- }, {});
908
- };
909
- __classPrivateFieldGet(this, _SnapKeyring_messenger, "f").publish(event, ...filteredEventCallback(filter));
910
- return null;
911
- }, _SnapKeyring_handleAccountBalancesUpdated =
912
- /**
913
- * Handle a balances updated event from a Snap.
914
- *
915
- * @param snapId - ID of the Snap.
916
- * @param message - Event message.
917
- * @returns `null`.
918
- */
919
- async function _SnapKeyring_handleAccountBalancesUpdated(snapId, message) {
920
- (0, superstruct_1.assert)(message, keyring_api_1.AccountBalancesUpdatedEventStruct);
921
- const event = message.params;
922
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_rePublishAccountEvent).call(this, snapId, 'SnapKeyring:accountBalancesUpdated', (filter) => {
923
- event.balances = filter(event.balances);
924
- return [event];
925
- });
926
- }, _SnapKeyring_handleAccountAssetListUpdated =
927
- /**
928
- * Handle a asset list updated event from a Snap.
929
- *
930
- * @param snapId - ID of the Snap.
931
- * @param message - Event message.
932
- * @returns `null`.
933
- */
934
- async function _SnapKeyring_handleAccountAssetListUpdated(snapId, message) {
935
- (0, superstruct_1.assert)(message, keyring_api_1.AccountAssetListUpdatedEventStruct);
936
- const event = message.params;
937
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_rePublishAccountEvent).call(this, snapId, 'SnapKeyring:accountAssetListUpdated', (filter) => {
938
- event.assets = filter(event.assets);
939
- return [event];
940
- });
941
- }, _SnapKeyring_handleAccountTransactionsUpdated =
942
- /**
943
- * Handle a transactions updated event from a Snap.
944
- *
945
- * @param snapId - ID of the Snap.
946
- * @param message - Event message.
947
- * @returns `null`.
948
- */
949
- async function _SnapKeyring_handleAccountTransactionsUpdated(snapId, message) {
950
- (0, superstruct_1.assert)(message, keyring_api_1.AccountTransactionsUpdatedEventStruct);
951
- const event = message.params;
952
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_rePublishAccountEvent).call(this, snapId, 'SnapKeyring:accountTransactionsUpdated', (filter) => {
953
- event.transactions = filter(event.transactions);
954
- return [event];
955
- });
956
470
  }, _SnapKeyring_getAccount = function _SnapKeyring_getAccount(id) {
957
- const found = [...__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").values()].find((entry) => entry.account.id === id);
958
- if (!found) {
471
+ const snapId = __classPrivateFieldGet(this, _SnapKeyring_accountIndex, "f").get(id);
472
+ const account = snapId
473
+ ? __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").get(snapId)?.lookupAccount(id)
474
+ : undefined;
475
+ if (!snapId || !account) {
959
476
  throw new Error(`Unable to get account: unknown account ID: '${id}'`);
960
477
  }
961
- return found;
962
- }, _SnapKeyring_submitRequest =
963
- /**
964
- * Submit a request to a Snap from an account address.
965
- *
966
- * @param opts - Request options.
967
- * @param opts.origin - Sender origin.
968
- * @param opts.address - Account address.
969
- * @param opts.method - Method to call.
970
- * @param opts.params - Method parameters.
971
- * @param opts.scope - Selected chain ID (CAIP-2).
972
- * @param opts.noPending - Whether the response is allowed to be pending.
973
- * @returns Promise that resolves to the result of the method call.
974
- */
975
- async function _SnapKeyring_submitRequest({ origin, address, method, params, scope = '', noPending = false, }) {
976
- const { account, snapId } = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_resolveAddress).call(this, address);
977
- return await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_submitSnapRequest).call(this, {
978
- origin,
979
- snapId,
980
- account,
981
- method: method,
982
- params,
983
- scope,
984
- noPending,
985
- });
986
- }, _SnapKeyring_submitSnapRequest =
987
- /**
988
- * Submits a request to a Snap.
989
- *
990
- * @param options - The options for the Snap request.
991
- * @param options.origin - The sender origin.
992
- * @param options.snapId - The Snap ID to submit the request to.
993
- * @param options.account - The account to use for the request.
994
- * @param options.method - The Ethereum method to call.
995
- * @param options.params - The parameters to pass to the method, can be undefined.
996
- * @param options.scope - The chain ID to use for the request, can be an empty string.
997
- * @param options.noPending - Whether the response is allowed to be pending.
998
- * @returns A promise that resolves to the keyring response from the Snap.
999
- * @throws An error if the Snap fails to respond or if there's an issue with the request submission.
1000
- */
1001
- async function _SnapKeyring_submitSnapRequest({ origin, snapId, account, method, params, scope, noPending, }) {
1002
- if (!__classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_hasMethod).call(this, account, method)) {
1003
- throw new Error(`Method '${method}' not supported for account ${account.address}`);
1004
- }
1005
- // Will both catch `undefined` and "empty" origins.
1006
- if (!origin?.trim()) {
1007
- throw new Error('An `origin` is required');
1008
- }
1009
- // Generate a new random request ID to keep track of the request execution flow.
1010
- const requestId = (0, uuid_1.v4)();
1011
- // Create the promise before calling the Snap to prevent a race condition
1012
- // where the Snap responds before we have a chance to create it.
1013
- const requestPromise = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_createRequestPromise).call(this, requestId, snapId);
1014
- try {
1015
- // Snaps are expecting to receive the `origin` field after a specific
1016
- // platform version.
1017
- //
1018
- // We need to check the Snap platform version to know whether we can
1019
- // include it or not.
1020
- const useOrigin = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_isMinimumPlatformVersion).call(this, snapId, platform_versions_1.PLATFORM_VERSION_FOR_KEYRING_REQUEST_WITH_ORIGIN);
1021
- const request = {
1022
- id: requestId,
1023
- origin,
1024
- scope,
1025
- account: account.id,
1026
- request: {
1027
- method,
1028
- ...(params !== undefined && { params }),
1029
- },
1030
- };
1031
- (0, logger_1.projectLogger)('Submit Snap request: ', request);
1032
- // Get specific client for that Snap.
1033
- const client = __classPrivateFieldGet(this, _SnapKeyring_snapClient, "f").withSnapId(snapId);
1034
- let response;
1035
- if (useOrigin) {
1036
- response = await client.submitRequest(request);
1037
- }
1038
- else {
1039
- // Legacy keyring request did not support the `origin` field.
1040
- response = await client.submitRequestWithoutOrigin((0, keyring_internal_api_1.toKeyringRequestWithoutOrigin)(request));
1041
- }
1042
- // Some methods, like the ones used to prepare and patch user operations,
1043
- // require the Snap to answer synchronously in order to work with the
1044
- // confirmation flow. This check lets the caller enforce this behavior.
1045
- if (noPending && response.pending) {
1046
- throw new Error(`Request '${requestId}' to Snap '${snapId}' is pending and noPending is true.`);
1047
- }
1048
- // If the Snap answers synchronously, the promise must be removed from the
1049
- // map to prevent a leak.
1050
- if (!response.pending) {
1051
- return __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleSyncResponse).call(this, response, requestId, snapId);
1052
- }
1053
- // If the Snap answers asynchronously, we will inform the user with a redirect
1054
- if (response.redirect?.message || response.redirect?.url) {
1055
- await __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_handleAsyncResponse).call(this, response.redirect, snapId);
1056
- }
1057
- return requestPromise.promise;
1058
- }
1059
- catch (error) {
1060
- (0, logger_1.projectLogger)('Snap Request failed: ', { requestId });
1061
- // If the Snap failed to respond, delete the promise to prevent a leak.
1062
- __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_clearRequestPromise).call(this, requestId, snapId);
1063
- throw error;
1064
- }
1065
- }, _SnapKeyring_hasMethod = function _SnapKeyring_hasMethod(account, method) {
1066
- return account.methods.includes(method);
1067
- }, _SnapKeyring_createRequestPromise = function _SnapKeyring_createRequestPromise(requestId, snapId) {
1068
- const promise = new DeferredPromise_1.DeferredPromise();
1069
- __classPrivateFieldGet(this, _SnapKeyring_requests, "f").set(requestId, { promise, snapId });
1070
- return promise;
1071
- }, _SnapKeyring_clearRequestPromise = function _SnapKeyring_clearRequestPromise(requestId, snapId) {
1072
- __classPrivateFieldGet(this, _SnapKeyring_requests, "f").delete(snapId, requestId);
1073
- }, _SnapKeyring_handleSyncResponse = function _SnapKeyring_handleSyncResponse(response, requestId, snapId) {
1074
- __classPrivateFieldGet(this, _SnapKeyring_requests, "f").delete(snapId, requestId);
1075
- // We consider `Response` to be compatible with `result` here.
1076
- return response.result;
1077
- }, _SnapKeyring_handleAsyncResponse =
1078
- /**
1079
- * Handles the async redirect and response from a Snap. Validates the redirect URL and informs the user with a message and URL if provided.
1080
- *
1081
- * @param redirect - The redirect information including message and URL.
1082
- * @param redirect.message - The message to show to the user if provided.
1083
- * @param redirect.url - The URL to redirect the user to if provided.
1084
- * @param snapId - The Snap ID associated with the request.
1085
- * @throws An error if the redirect URL is not an allowed origin for the Snap.
1086
- */
1087
- async function _SnapKeyring_handleAsyncResponse(redirect, snapId) {
1088
- const { message = '', url: redirectUrl = '' } = redirect;
1089
- const url = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_sanitizeRedirectUrl).call(this, redirectUrl);
1090
- if (url) {
1091
- __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_validateRedirectUrl).call(this, url, snapId);
1092
- }
1093
- await __classPrivateFieldGet(this, _SnapKeyring_callbacks, "f").redirectUser(snapId, url, message);
1094
- }, _SnapKeyring_sanitizeRedirectUrl = function _SnapKeyring_sanitizeRedirectUrl(url) {
1095
- // We do check if the URL is empty or not since the Snap might not returns any URL at all.
1096
- return url ? (0, util_1.sanitizeUrl)(url) : url;
1097
- }, _SnapKeyring_validateRedirectUrl = function _SnapKeyring_validateRedirectUrl(url, snapId) {
1098
- const { origin } = new URL(url);
1099
- const snap = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getSnap).call(this, snapId);
1100
- if (!snap) {
1101
- throw new Error(`Snap '${snapId}' not found.`);
1102
- }
1103
- const allowedOrigins = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getSnapAllowedOrigins).call(this, snap);
1104
- if (!allowedOrigins.includes(origin)) {
1105
- throw new Error(`Redirect URL domain '${origin}' is not an allowed origin by snap '${snapId}'`);
1106
- }
1107
- }, _SnapKeyring_deleteAccount =
1108
- /**
1109
- * Removes an account.
1110
- *
1111
- * @param snapId - Snap ID.
1112
- * @param account - Account to delete.
1113
- */
1114
- async function _SnapKeyring_deleteAccount(snapId, account) {
1115
- // Always remove the account from the maps, even if the Snap is going to
1116
- // fail to delete it.
1117
- __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").delete(snapId, account.id);
1118
- try {
1119
- await __classPrivateFieldGet(this, _SnapKeyring_snapClient, "f").withSnapId(snapId).deleteAccount(account.id);
1120
- }
1121
- catch (error) {
1122
- // If the Snap failed to delete the account, log the error and continue
1123
- // with the account deletion, otherwise the account will be stuck in the
1124
- // keyring.
1125
- console.error(`Account '${account.address}' may not have been removed from snap '${snapId}':`, error);
1126
- }
478
+ return { account, snapId };
1127
479
  }, _SnapKeyring_resolveAddress = function _SnapKeyring_resolveAddress(address) {
1128
- return ([...__classPrivateFieldGet(this, _SnapKeyring_accounts, "f").values()].find(({ account }) => (0, util_1.equalsIgnoreCase)(account.address, address)) ?? (0, util_1.throwError)(`Account '${address}' not found`));
1129
- }, _SnapKeyring_updateSelectedAccountsMap = function _SnapKeyring_updateSelectedAccountsMap(accounts) {
1130
- const selectedAccounts = __classPrivateFieldGet(this, _SnapKeyring_selectedAccounts, "f");
1131
- selectedAccounts.clear();
1132
- for (const account of accounts) {
1133
- const snapId = __classPrivateFieldGet(this, _SnapKeyring_accounts, "f").getSnapId(account);
1134
- if (!snapId) {
1135
- continue;
480
+ for (const keyring of __classPrivateFieldGet(this, _SnapKeyring_snapKeyrings, "f").values()) {
481
+ const account = keyring.lookupByAddress(address);
482
+ if (account) {
483
+ return { account, keyring };
1136
484
  }
1137
- const snapAccounts = selectedAccounts.get(snapId) ?? [];
1138
- snapAccounts.push(account);
1139
- selectedAccounts.set(snapId, snapAccounts);
1140
485
  }
486
+ return (0, util_1.throwError)(`Account '${address}' not found`);
1141
487
  }, _SnapKeyring_getSnap = function _SnapKeyring_getSnap(snapId) {
1142
- return __classPrivateFieldGet(this, _SnapKeyring_messenger, "f").call('SnapController:get', snapId);
488
+ return __classPrivateFieldGet(this, _SnapKeyring_messenger, "f").call('SnapController:getSnap', snapId);
1143
489
  }, _SnapKeyring_getSnapMetadata = function _SnapKeyring_getSnapMetadata(snapId) {
1144
490
  const snap = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getSnap).call(this, snapId);
1145
491
  return snap
1146
492
  ? { id: snapId, name: snap.manifest.proposedName, enabled: snap.enabled }
1147
493
  : undefined;
1148
- }, _SnapKeyring_getSnapAllowedOrigins = function _SnapKeyring_getSnapAllowedOrigins(snap) {
1149
- return (snap.manifest.initialPermissions['endowment:keyring']?.allowedOrigins ??
1150
- []);
1151
494
  }, _SnapKeyring_transformToInternalAccount = function _SnapKeyring_transformToInternalAccount(account, snapId) {
1152
495
  const snap = __classPrivateFieldGet(this, _SnapKeyring_instances, "m", _SnapKeyring_getSnapMetadata).call(this, snapId);
1153
496
  return {
@@ -1161,7 +504,7 @@ async function _SnapKeyring_deleteAccount(snapId, account) {
1161
504
  //
1162
505
  // NOTE: We convert the address only for EVM accounts, see
1163
506
  // `normalizeAccountAddress`.
1164
- address: normalizeAccountAddress(account),
507
+ address: (0, util_1.normalizeAccountAddress)(account),
1165
508
  metadata: {
1166
509
  name: '',
1167
510
  importTime: 0,