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