@metamask/multichain-account-service 11.1.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -1
- package/dist/MultichainAccountGroup.cjs +15 -2
- package/dist/MultichainAccountGroup.cjs.map +1 -1
- package/dist/MultichainAccountGroup.d.cts +11 -0
- package/dist/MultichainAccountGroup.d.cts.map +1 -1
- package/dist/MultichainAccountGroup.d.mts +11 -0
- package/dist/MultichainAccountGroup.d.mts.map +1 -1
- package/dist/MultichainAccountGroup.mjs +15 -2
- package/dist/MultichainAccountGroup.mjs.map +1 -1
- package/dist/MultichainAccountWallet.cjs +45 -21
- package/dist/MultichainAccountWallet.cjs.map +1 -1
- package/dist/MultichainAccountWallet.d.cts.map +1 -1
- package/dist/MultichainAccountWallet.d.mts.map +1 -1
- package/dist/MultichainAccountWallet.mjs +45 -21
- package/dist/MultichainAccountWallet.mjs.map +1 -1
- package/dist/providers/BtcAccountProvider.cjs +7 -38
- package/dist/providers/BtcAccountProvider.cjs.map +1 -1
- package/dist/providers/BtcAccountProvider.d.cts +2 -6
- package/dist/providers/BtcAccountProvider.d.cts.map +1 -1
- package/dist/providers/BtcAccountProvider.d.mts +2 -6
- package/dist/providers/BtcAccountProvider.d.mts.map +1 -1
- package/dist/providers/BtcAccountProvider.mjs +8 -39
- package/dist/providers/BtcAccountProvider.mjs.map +1 -1
- package/dist/providers/SnapAccountProvider.cjs +125 -27
- package/dist/providers/SnapAccountProvider.cjs.map +1 -1
- package/dist/providers/SnapAccountProvider.d.cts +59 -15
- package/dist/providers/SnapAccountProvider.d.cts.map +1 -1
- package/dist/providers/SnapAccountProvider.d.mts +59 -15
- package/dist/providers/SnapAccountProvider.d.mts.map +1 -1
- package/dist/providers/SnapAccountProvider.mjs +127 -29
- package/dist/providers/SnapAccountProvider.mjs.map +1 -1
- package/dist/providers/SnapKeyringClient.cjs +35 -0
- package/dist/providers/SnapKeyringClient.cjs.map +1 -0
- package/dist/providers/SnapKeyringClient.d.cts +51 -0
- package/dist/providers/SnapKeyringClient.d.cts.map +1 -0
- package/dist/providers/SnapKeyringClient.d.mts +51 -0
- package/dist/providers/SnapKeyringClient.d.mts.map +1 -0
- package/dist/providers/SnapKeyringClient.mjs +31 -0
- package/dist/providers/SnapKeyringClient.mjs.map +1 -0
- package/dist/providers/SolAccountProvider.cjs +7 -40
- package/dist/providers/SolAccountProvider.cjs.map +1 -1
- package/dist/providers/SolAccountProvider.d.cts +2 -6
- package/dist/providers/SolAccountProvider.d.cts.map +1 -1
- package/dist/providers/SolAccountProvider.d.mts +2 -6
- package/dist/providers/SolAccountProvider.d.mts.map +1 -1
- package/dist/providers/SolAccountProvider.mjs +8 -41
- package/dist/providers/SolAccountProvider.mjs.map +1 -1
- package/dist/providers/TrxAccountProvider.cjs +7 -37
- package/dist/providers/TrxAccountProvider.cjs.map +1 -1
- package/dist/providers/TrxAccountProvider.d.cts +2 -6
- package/dist/providers/TrxAccountProvider.d.cts.map +1 -1
- package/dist/providers/TrxAccountProvider.d.mts +2 -6
- package/dist/providers/TrxAccountProvider.d.mts.map +1 -1
- package/dist/providers/TrxAccountProvider.mjs +8 -38
- package/dist/providers/TrxAccountProvider.mjs.map +1 -1
- package/dist/providers/XlmAccountProvider.cjs +7 -37
- package/dist/providers/XlmAccountProvider.cjs.map +1 -1
- package/dist/providers/XlmAccountProvider.d.cts +2 -6
- package/dist/providers/XlmAccountProvider.d.cts.map +1 -1
- package/dist/providers/XlmAccountProvider.d.mts +2 -6
- package/dist/providers/XlmAccountProvider.d.mts.map +1 -1
- package/dist/providers/XlmAccountProvider.mjs +8 -38
- package/dist/providers/XlmAccountProvider.mjs.map +1 -1
- package/dist/tests/messenger.cjs +1 -0
- package/dist/tests/messenger.cjs.map +1 -1
- package/dist/tests/messenger.d.cts.map +1 -1
- package/dist/tests/messenger.d.mts.map +1 -1
- package/dist/tests/messenger.mjs +1 -0
- package/dist/tests/messenger.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +2 -2
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +7 -7
|
@@ -10,19 +10,19 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
11
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
12
|
};
|
|
13
|
-
var _SnapAccountProvider_instances, _SnapAccountProvider_client, _SnapAccountProvider_queue, _SnapAccountProvider_trace, _SnapAccountProvider_getRestrictedSnapKeyring,
|
|
13
|
+
var _SnapAccountProvider_instances, _SnapAccountProvider_client, _SnapAccountProvider_sender, _SnapAccountProvider_queue, _SnapAccountProvider_trace, _SnapAccountProvider_getRestrictedSnapKeyring, _SnapAccountProvider_createSender, _SnapAccountProvider_resolveClient, _SnapAccountProvider_withSnapKeyring;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.isSnapAccountProvider = exports.SnapAccountProvider = void 0;
|
|
16
16
|
const account_api_1 = require("@metamask/account-api");
|
|
17
17
|
const v2_1 = require("@metamask/eth-snap-keyring/v2");
|
|
18
18
|
const keyring_api_1 = require("@metamask/keyring-api");
|
|
19
|
-
const keyring_snap_client_1 = require("@metamask/keyring-snap-client");
|
|
20
19
|
const snaps_utils_1 = require("@metamask/snaps-utils");
|
|
21
20
|
const async_mutex_1 = require("async-mutex");
|
|
22
21
|
const analytics_1 = require("../analytics/index.cjs");
|
|
23
22
|
const errors_1 = require("../errors.cjs");
|
|
24
23
|
const logger_1 = require("../logger.cjs");
|
|
25
24
|
const BaseBip44AccountProvider_1 = require("./BaseBip44AccountProvider.cjs");
|
|
25
|
+
const SnapKeyringClient_1 = require("./SnapKeyringClient.cjs");
|
|
26
26
|
const utils_1 = require("./utils.cjs");
|
|
27
27
|
class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountProvider {
|
|
28
28
|
constructor(snapId, messenger, config,
|
|
@@ -30,11 +30,22 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
30
30
|
trace = analytics_1.traceFallback) {
|
|
31
31
|
super(messenger);
|
|
32
32
|
_SnapAccountProvider_instances.add(this);
|
|
33
|
+
/**
|
|
34
|
+
* The Snap's keyring capabilities, sourced from `SnapAccountService` (which
|
|
35
|
+
* reads them from the Snap's manifest). Populated the first time the client
|
|
36
|
+
* is resolved; defaults to an empty capability set until then.
|
|
37
|
+
*/
|
|
38
|
+
this.capabilities = v2_1.EMPTY_CAPABILITIES;
|
|
39
|
+
/**
|
|
40
|
+
* Version-agnostic keyring client, resolved lazily once the Snap is ready and
|
|
41
|
+
* its capabilities are known — see {@link SnapAccountProvider.withSnap}.
|
|
42
|
+
*/
|
|
33
43
|
_SnapAccountProvider_client.set(this, void 0);
|
|
44
|
+
_SnapAccountProvider_sender.set(this, void 0);
|
|
34
45
|
_SnapAccountProvider_queue.set(this, void 0);
|
|
35
46
|
_SnapAccountProvider_trace.set(this, void 0);
|
|
36
47
|
this.snapId = snapId;
|
|
37
|
-
__classPrivateFieldSet(this,
|
|
48
|
+
__classPrivateFieldSet(this, _SnapAccountProvider_sender, __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_createSender).call(this, snapId), "f");
|
|
38
49
|
const maxConcurrency = config.maxConcurrency ?? Infinity;
|
|
39
50
|
this.config = {
|
|
40
51
|
...config,
|
|
@@ -76,10 +87,19 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
76
87
|
async trace(request, fn) {
|
|
77
88
|
return __classPrivateFieldGet(this, _SnapAccountProvider_trace, "f").call(this, request, fn);
|
|
78
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Whether the Snap supports the v2 keyring protocol, inferred from its
|
|
92
|
+
* declared capabilities (a v2-capable Snap declares BIP-44 capabilities).
|
|
93
|
+
*
|
|
94
|
+
* @returns `true` if the Snap is v2-capable.
|
|
95
|
+
*/
|
|
96
|
+
isV2() {
|
|
97
|
+
return Boolean(this.capabilities.bip44);
|
|
98
|
+
}
|
|
79
99
|
async resyncAccounts(accounts) {
|
|
80
|
-
await this.withSnap(async ({ keyring }) => {
|
|
100
|
+
await this.withSnap(async ({ client, keyring }) => {
|
|
81
101
|
const localSnapAccounts = accounts.filter((account) => account.metadata.snap?.id === this.snapId);
|
|
82
|
-
const snapAccounts = new Set((await
|
|
102
|
+
const snapAccounts = new Set((await client.getAccounts()).map((account) => account.id));
|
|
83
103
|
// NOTE: This should never happen, but if it does, we recover by deleting the
|
|
84
104
|
// extra accounts from the Snap to bring it back in sync with MetaMask.
|
|
85
105
|
if (localSnapAccounts.length < snapAccounts.size) {
|
|
@@ -93,7 +113,7 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
93
113
|
if (!localAccountIds.has(snapAccountId)) {
|
|
94
114
|
// This account exists in the Snap but not in MetaMask, delete it from
|
|
95
115
|
// the Snap.
|
|
96
|
-
await
|
|
116
|
+
await client.deleteAccount(snapAccountId);
|
|
97
117
|
// Update the local Set so subsequent checks use the correct size
|
|
98
118
|
snapAccounts.delete(snapAccountId);
|
|
99
119
|
}
|
|
@@ -145,8 +165,9 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
145
165
|
}
|
|
146
166
|
async withSnap(operation) {
|
|
147
167
|
await this.ensureReady();
|
|
168
|
+
const client = await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_resolveClient).call(this);
|
|
148
169
|
return await operation({
|
|
149
|
-
client
|
|
170
|
+
client,
|
|
150
171
|
keyring: await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_getRestrictedSnapKeyring).call(this),
|
|
151
172
|
});
|
|
152
173
|
}
|
|
@@ -158,7 +179,10 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
158
179
|
return this.withMaxConcurrency(async () => {
|
|
159
180
|
let groupIndexOffset = 0;
|
|
160
181
|
let snapAccounts = [];
|
|
161
|
-
|
|
182
|
+
// v2 Snaps expose `createAccounts` but no singular `createAccount`, so
|
|
183
|
+
// they must always go through the batched flow. v1 Snaps only have the
|
|
184
|
+
// singular `createAccount`.
|
|
185
|
+
const batched = this.isV2();
|
|
162
186
|
const { entropySource } = options;
|
|
163
187
|
const createAccountV1 = async (groupIndex) => await (0, utils_1.withTimeout)(() => this.trace({
|
|
164
188
|
name: analytics_1.TraceName.ProviderCreateAccountV1,
|
|
@@ -240,36 +264,91 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
240
264
|
});
|
|
241
265
|
this.accounts.delete(id);
|
|
242
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Discovers accounts for the given entropy source and group index.
|
|
269
|
+
*
|
|
270
|
+
* v2 Snaps drive discovery through `createAccounts({ bip44:discover })`: the
|
|
271
|
+
* Snap checks for on-chain activity (using its own supported scopes) and
|
|
272
|
+
* returns the created account(s), or nothing once discovery is exhausted.
|
|
273
|
+
*
|
|
274
|
+
* v1 Snaps use the client's `discoverAccounts` to detect activity on
|
|
275
|
+
* {@link v1DiscoveryScopes}, then create the account for the group index.
|
|
276
|
+
*
|
|
277
|
+
* @param options - The discovery options.
|
|
278
|
+
* @param options.entropySource - The entropy source to discover accounts for.
|
|
279
|
+
* @param options.groupIndex - The group index to discover accounts for.
|
|
280
|
+
* @returns The discovered (and created) accounts, or an empty array when
|
|
281
|
+
* there is nothing to discover at this group index.
|
|
282
|
+
*/
|
|
283
|
+
async discoverAccounts({ entropySource, groupIndex, }) {
|
|
284
|
+
return this.withSnap(async ({ client, keyring }) => this.trace({
|
|
285
|
+
name: analytics_1.TraceName.SnapDiscoverAccounts,
|
|
286
|
+
data: {
|
|
287
|
+
provider: this.getName(),
|
|
288
|
+
},
|
|
289
|
+
}, async () => {
|
|
290
|
+
if (!this.config.discovery.enabled) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
if (this.isV2()) {
|
|
294
|
+
// The v2 client has no `discoverAccounts`, so discovery is only
|
|
295
|
+
// possible when the Snap supports `bip44:discover`. Otherwise there
|
|
296
|
+
// is no way to discover and we report nothing.
|
|
297
|
+
if (!this.capabilities.bip44?.discover) {
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
300
|
+
// v2: the Snap detects on-chain activity and creates the account in
|
|
301
|
+
// a single `createAccounts({ bip44:discover })` call. An empty
|
|
302
|
+
// result means discovery is exhausted at this group index.
|
|
303
|
+
return this.createBip44Accounts(keyring, {
|
|
304
|
+
type: keyring_api_1.AccountCreationType.Bip44Discover,
|
|
305
|
+
entropySource,
|
|
306
|
+
groupIndex,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
// v1: detect activity via the client, then create the account for
|
|
310
|
+
// this group index.
|
|
311
|
+
const discoveredAccounts = await (0, utils_1.withRetry)(() => (0, utils_1.withTimeout)(() => client.discoverAccounts(this.v1DiscoveryScopes, entropySource, groupIndex), this.config.discovery.timeoutMs), {
|
|
312
|
+
maxAttempts: this.config.discovery.maxAttempts,
|
|
313
|
+
backOffMs: this.config.discovery.backOffMs,
|
|
314
|
+
});
|
|
315
|
+
if (!discoveredAccounts.length) {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
return this.createBip44Accounts(keyring, {
|
|
319
|
+
type: keyring_api_1.AccountCreationType.Bip44DeriveIndex,
|
|
320
|
+
entropySource,
|
|
321
|
+
groupIndex,
|
|
322
|
+
});
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
243
325
|
}
|
|
244
326
|
exports.SnapAccountProvider = SnapAccountProvider;
|
|
245
|
-
_SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_queue = new WeakMap(), _SnapAccountProvider_trace = new WeakMap(), _SnapAccountProvider_instances = new WeakSet(), _SnapAccountProvider_getRestrictedSnapKeyring = async function _SnapAccountProvider_getRestrictedSnapKeyring() {
|
|
327
|
+
_SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_sender = new WeakMap(), _SnapAccountProvider_queue = new WeakMap(), _SnapAccountProvider_trace = new WeakMap(), _SnapAccountProvider_instances = new WeakSet(), _SnapAccountProvider_getRestrictedSnapKeyring = async function _SnapAccountProvider_getRestrictedSnapKeyring() {
|
|
246
328
|
// NOTE: We're not supposed to make the keyring instance escape `withKeyringV2` but
|
|
247
329
|
// we have to use the `SnapKeyringV2` instance to be able to create Solana account
|
|
248
330
|
// without triggering UI confirmation.
|
|
249
331
|
// Also, creating account that way won't invalidate the Snap keyring state. The
|
|
250
332
|
// account will get created and persisted properly with the Snap account creation
|
|
251
333
|
// flow "asynchronously" (with `notify:accountCreated`).
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
334
|
+
const createAccount = await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => {
|
|
335
|
+
if (keyring.v1) {
|
|
336
|
+
return keyring.v1.createAccount.bind(keyring.v1);
|
|
337
|
+
}
|
|
338
|
+
// This method does not exist in v2.
|
|
339
|
+
return undefined;
|
|
340
|
+
});
|
|
256
341
|
return {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
setSelectedAccount: false,
|
|
263
|
-
}),
|
|
264
|
-
createAccounts: async (options) => await createAccounts(options),
|
|
265
|
-
deleteAccount: async (id) =>
|
|
266
|
-
// Though, when removing account, we can use the normal flow.
|
|
267
|
-
await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => {
|
|
342
|
+
// V1 interface is only present for v1 Snaps, otherwise it's `undefined`.
|
|
343
|
+
v1: createAccount ? { createAccount } : undefined,
|
|
344
|
+
// Every v2 operations must be done through the `#withSnapKeyring` transaction:
|
|
345
|
+
createAccounts: async (options) => await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => await keyring.createAccounts(options)),
|
|
346
|
+
deleteAccount: async (id) => await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => {
|
|
268
347
|
await keyring.deleteAccount(id);
|
|
269
348
|
}),
|
|
270
349
|
};
|
|
271
|
-
},
|
|
272
|
-
return
|
|
350
|
+
}, _SnapAccountProvider_createSender = function _SnapAccountProvider_createSender(snapId) {
|
|
351
|
+
return {
|
|
273
352
|
send: async (request) => {
|
|
274
353
|
const response = await this.messenger.call('SnapController:handleRequest', {
|
|
275
354
|
snapId: snapId,
|
|
@@ -279,7 +358,26 @@ _SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_queue = new We
|
|
|
279
358
|
});
|
|
280
359
|
return response;
|
|
281
360
|
},
|
|
282
|
-
}
|
|
361
|
+
};
|
|
362
|
+
}, _SnapAccountProvider_resolveClient =
|
|
363
|
+
/**
|
|
364
|
+
* Resolves the version-agnostic keyring client, fetching the Snap's
|
|
365
|
+
* capabilities from `SnapAccountService` on first use and caching both the
|
|
366
|
+
* capabilities and the resulting client.
|
|
367
|
+
*
|
|
368
|
+
* Callers must ensure the Snap is ready (via
|
|
369
|
+
* {@link SnapAccountProvider.ensureReady}) beforehand so that the
|
|
370
|
+
* capabilities are reliably populated — {@link SnapAccountProvider.withSnap}
|
|
371
|
+
* guarantees this ordering.
|
|
372
|
+
*
|
|
373
|
+
* @returns The resolved {@link SnapKeyringClient}.
|
|
374
|
+
*/
|
|
375
|
+
async function _SnapAccountProvider_resolveClient() {
|
|
376
|
+
if (!__classPrivateFieldGet(this, _SnapAccountProvider_client, "f")) {
|
|
377
|
+
this.capabilities = await this.messenger.call('SnapAccountService:getCapabilities', this.snapId);
|
|
378
|
+
__classPrivateFieldSet(this, _SnapAccountProvider_client, (0, SnapKeyringClient_1.createSnapKeyringClient)(__classPrivateFieldGet(this, _SnapAccountProvider_sender, "f"), this.isV2()), "f");
|
|
379
|
+
}
|
|
380
|
+
return __classPrivateFieldGet(this, _SnapAccountProvider_client, "f");
|
|
283
381
|
}, _SnapAccountProvider_withSnapKeyring = async function _SnapAccountProvider_withSnapKeyring(operation) {
|
|
284
382
|
return this.withKeyringV2({
|
|
285
383
|
filter: (keyring) => (0, v2_1.isSnapKeyring)(keyring) && keyring.snapId === this.snapId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { assertIsBip44Account } from '@metamask/account-api';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback, TraceRequest } from '@metamask/controller-utils';\nimport type { SnapKeyring as SnapKeyringV2 } from '@metamask/eth-snap-keyring/v2';\nimport { isSnapKeyring } from '@metamask/eth-snap-keyring/v2';\nimport {\n AccountCreationType,\n assertCreateAccountOptionIsSupported,\n} from '@metamask/keyring-api';\nimport type {\n CreateAccountBip44DeriveIndexOptions,\n CreateAccountBip44DeriveIndexRangeOptions,\n CreateAccountOptions,\n EntropySourceId,\n KeyringAccount,\n} from '@metamask/keyring-api';\nimport type { KeyringMetadata } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Semaphore } from 'async-mutex';\n\nimport {\n toCreateAccountsV2DataTraces,\n traceFallback,\n TraceName,\n} from '../analytics';\nimport { reportError } from '../errors';\nimport { projectLogger as log, WARNING_PREFIX } from '../logger';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport { BaseBip44AccountProvider } from './BaseBip44AccountProvider';\nimport { withTimeout } from './utils';\n\nexport type RestrictedSnapKeyring = {\n createAccount: SnapKeyringV2['createAccount'];\n createAccounts: SnapKeyringV2['createAccounts'];\n deleteAccount: SnapKeyringV2['deleteAccount'];\n};\n\nexport type SnapAccountProviderConfig = {\n maxConcurrency?: number;\n discovery: {\n enabled?: boolean;\n maxAttempts: number;\n timeoutMs: number;\n backOffMs: number;\n };\n createAccounts: {\n /**\n * Whether to enable account batching with `createAccounts` method. If `true`, accounts will\n * be created in batch.\n *\n * NOTE: The Snap has to implement this optional method for batching support.\n * Defaults to `false`.\n */\n batched: boolean;\n /**\n * Timeout for account creation operations.\n *\n * NOTE: The value might have to be adapted in case batching is enabled!\n */\n timeoutMs: number;\n };\n resyncAccounts?: {\n /**\n * Whether to automatically remove extra Snap accounts when the Snap has\n * more accounts than MetaMask. If `false`, a warning is logged instead.\n * Defaults to `true`.\n */\n autoRemoveExtraSnapAccounts?: boolean;\n };\n};\n\nexport abstract class SnapAccountProvider extends BaseBip44AccountProvider {\n readonly snapId: SnapId;\n\n protected readonly config: SnapAccountProviderConfig;\n\n readonly #client: KeyringClient;\n\n readonly #queue?: Semaphore;\n\n readonly #trace: TraceCallback;\n\n constructor(\n snapId: SnapId,\n messenger: MultichainAccountServiceMessenger,\n config: SnapAccountProviderConfig,\n /* istanbul ignore next */\n trace: TraceCallback = traceFallback,\n ) {\n super(messenger);\n\n this.snapId = snapId;\n this.#client = this.#getKeyringClientFromSnapId(snapId);\n\n const maxConcurrency = config.maxConcurrency ?? Infinity;\n this.config = {\n ...config,\n discovery: {\n ...config.discovery,\n enabled: config.discovery.enabled ?? true,\n },\n maxConcurrency,\n };\n\n // Create semaphore only if concurrency is limited\n if (isFinite(maxConcurrency)) {\n this.#queue = new Semaphore(maxConcurrency);\n }\n\n this.#trace = trace;\n }\n\n /**\n * Ensures that the Snap is ready to be used.\n *\n * @returns A promise that resolves when the Snap is ready.\n * @throws An error if the Snap could not become ready.\n */\n async ensureReady(): Promise<void> {\n return this.messenger.call('SnapAccountService:ensureReady', this.snapId);\n }\n\n /**\n * Wraps an async operation with concurrency limiting based on maxConcurrency config.\n * If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.\n * Otherwise, it's queued through the semaphore to respect the concurrency limit.\n *\n * @param operation - The async operation to execute.\n * @returns The result of the operation.\n */\n protected async withMaxConcurrency<Result>(\n operation: () => Promise<Result>,\n ): Promise<Result> {\n if (this.#queue) {\n return this.#queue.runExclusive(operation);\n }\n return operation();\n }\n\n protected async trace<ReturnType>(\n request: TraceRequest,\n fn: () => Promise<ReturnType>,\n ): Promise<ReturnType> {\n return this.#trace(request, fn);\n }\n\n async #getRestrictedSnapKeyring(): Promise<RestrictedSnapKeyring> {\n // NOTE: We're not supposed to make the keyring instance escape `withKeyringV2` but\n // we have to use the `SnapKeyringV2` instance to be able to create Solana account\n // without triggering UI confirmation.\n // Also, creating account that way won't invalidate the Snap keyring state. The\n // account will get created and persisted properly with the Snap account creation\n // flow \"asynchronously\" (with `notify:accountCreated`).\n const { createAccount, createAccounts } = await this.#withSnapKeyring<{\n createAccount: SnapKeyringV2['createAccount'];\n createAccounts: SnapKeyringV2['createAccounts'];\n }>(async ({ keyring }) => ({\n createAccount: keyring.createAccount.bind(keyring),\n createAccounts: keyring.createAccounts.bind(keyring),\n }));\n\n return {\n createAccount: async (options) =>\n // We use the \"unguarded\" account creation here (see explanation above).\n await createAccount(options, {\n displayAccountNameSuggestion: false,\n displayConfirmation: false,\n setSelectedAccount: false,\n }),\n createAccounts: async (options) => await createAccounts(options),\n deleteAccount: async (id: string) =>\n // Though, when removing account, we can use the normal flow.\n await this.#withSnapKeyring(async ({ keyring }) => {\n await keyring.deleteAccount(id);\n }),\n };\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest): Promise<Json> => {\n const response = await this.messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Json;\n },\n });\n }\n\n async resyncAccounts(\n accounts: Bip44Account<InternalAccount>[],\n ): Promise<void> {\n await this.withSnap(async ({ keyring }) => {\n const localSnapAccounts = accounts.filter(\n (account) => account.metadata.snap?.id === this.snapId,\n );\n const snapAccounts = new Set(\n (await this.#client.listAccounts()).map((account) => account.id),\n );\n\n // NOTE: This should never happen, but if it does, we recover by deleting the\n // extra accounts from the Snap to bring it back in sync with MetaMask.\n if (localSnapAccounts.length < snapAccounts.size) {\n const autoRemoveExtraSnapAccounts =\n this.config.resyncAccounts?.autoRemoveExtraSnapAccounts ?? true;\n\n if (autoRemoveExtraSnapAccounts) {\n // Build a set of local account IDs for quick lookup\n const localAccountIds = new Set(\n localSnapAccounts.map((account) => account.id),\n );\n\n // Find and delete accounts that exist in Snap but not in MetaMask\n await Promise.all(\n [...snapAccounts].map(async (snapAccountId) => {\n try {\n if (!localAccountIds.has(snapAccountId)) {\n // This account exists in the Snap but not in MetaMask, delete it from\n // the Snap.\n await this.#client.deleteAccount(snapAccountId);\n // Update the local Set so subsequent checks use the correct size\n snapAccounts.delete(snapAccountId);\n }\n } catch (error) {\n reportError(\n this.messenger,\n `Unable to delete de-synced Snap account: ${this.snapId}`,\n error,\n {\n provider: this.getName(),\n snapAccountId,\n },\n );\n }\n }),\n );\n } else {\n const message = `Snap \"${this.snapId}\" has de-synced accounts, Snap has more accounts than MetaMask! (${localSnapAccounts.length} < ${snapAccounts.size})`;\n log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\n return;\n }\n }\n\n // We want this part to be fast, so we only check for sizes, but we might need\n // to make a real \"diff\" between the 2 states to not miss any de-sync.\n if (localSnapAccounts.length > snapAccounts.size) {\n // We always use the MetaMask list as the main reference here.\n await Promise.all(\n localSnapAccounts.map(async (account) => {\n const { id: entropySource, groupIndex } = account.options.entropy;\n\n try {\n if (!snapAccounts.has(account.id)) {\n // We still need to remove the accounts from the Snap keyring since we're\n // about to create the same account again, which will use a new ID, but will\n // keep using the same address, and the Snap keyring does not allow this.\n await keyring.deleteAccount(account.id);\n // The Snap has no account in its state for this one, we re-create it.\n await this.createAccounts({\n type: AccountCreationType.Bip44DeriveIndex,\n entropySource,\n groupIndex,\n });\n }\n } catch (error) {\n reportError(this.messenger, 'Unable to re-sync accounts', error, {\n provider: this.getName(),\n groupIndex,\n });\n }\n }),\n );\n }\n });\n }\n\n async #withSnapKeyring<CallbackResult = void>(\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SnapKeyringV2;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n return this.withKeyringV2<SnapKeyringV2, CallbackResult>(\n {\n filter: (keyring) =>\n isSnapKeyring(keyring) && keyring.snapId === this.snapId,\n },\n (args) => operation(args),\n );\n }\n\n protected async withSnap<CallbackResult = void>(\n operation: (snap: {\n client: KeyringClient;\n keyring: RestrictedSnapKeyring;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n await this.ensureReady();\n\n return await operation({\n client: this.#client,\n keyring: await this.#getRestrictedSnapKeyring(),\n });\n }\n\n abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;\n\n protected abstract createAccountV1(\n keyring: RestrictedSnapKeyring,\n options: { entropySource: EntropySourceId; groupIndex: number },\n ): Promise<KeyringAccount>;\n\n protected toBip44Account(\n account: KeyringAccount,\n _options: { entropySource: EntropySourceId; groupIndex: number },\n ): Bip44Account<KeyringAccount> {\n assertIsBip44Account(account);\n return account;\n }\n\n protected async createBip44Accounts(\n keyring: RestrictedSnapKeyring,\n options:\n | CreateAccountBip44DeriveIndexOptions\n | CreateAccountBip44DeriveIndexRangeOptions,\n ): Promise<Bip44Account<KeyringAccount>[]> {\n return this.withMaxConcurrency(async () => {\n let groupIndexOffset = 0;\n let snapAccounts: KeyringAccount[] = [];\n\n const batched = this.config.createAccounts.batched ?? false;\n const { entropySource } = options;\n\n const createAccountV1 = async (\n groupIndex: number,\n ): Promise<KeyringAccount> =>\n await withTimeout(\n () =>\n this.trace(\n {\n name: TraceName.ProviderCreateAccountV1,\n data: {\n provider: this.getName(),\n groupIndex,\n },\n },\n () =>\n this.createAccountV1(keyring, { entropySource, groupIndex }),\n ),\n this.config.createAccounts.timeoutMs,\n );\n const createAccountsV2 = async (\n optionsV2:\n | CreateAccountBip44DeriveIndexOptions\n | CreateAccountBip44DeriveIndexRangeOptions,\n ): Promise<KeyringAccount[]> =>\n await withTimeout(\n () =>\n this.trace(\n {\n name: TraceName.ProviderCreateAccounts,\n data: {\n provider: this.getName(),\n ...toCreateAccountsV2DataTraces(optionsV2),\n },\n },\n () => keyring.createAccounts(optionsV2),\n ),\n this.config.createAccounts.timeoutMs,\n );\n\n if (options.type === `${AccountCreationType.Bip44DeriveIndexRange}`) {\n if (batched) {\n // Batch account creations.\n snapAccounts = await createAccountsV2(options);\n } else {\n const { range } = options;\n\n // Create accounts one by one.\n for (\n let groupIndex = range.from;\n groupIndex <= range.to;\n groupIndex++\n ) {\n const snapAccount = await createAccountV1(groupIndex);\n\n snapAccounts.push(snapAccount);\n }\n }\n\n // Group indices are sequential, so we just need the starting index.\n groupIndexOffset = options.range.from;\n } else {\n if (batched) {\n // Create account using new v2-like flow (no async flow + no Snap keyring events).\n snapAccounts = await createAccountsV2(options);\n } else {\n const { groupIndex } = options;\n\n // Create account using the existing v1 flow.\n const snapAccount = await createAccountV1(groupIndex);\n\n snapAccounts = [snapAccount];\n }\n\n // For single account, there will only be 1 account, so we can use the\n // provided group index directly.\n groupIndexOffset = options.groupIndex;\n }\n\n return snapAccounts.map((snapAccount, index) => {\n const groupIndex = groupIndexOffset + index;\n const account = this.toBip44Account(snapAccount, {\n entropySource,\n groupIndex,\n });\n\n this.accounts.add(snapAccount.id);\n return account;\n });\n });\n }\n\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<Bip44Account<KeyringAccount>[]> {\n assertCreateAccountOptionIsSupported(options, [\n `${AccountCreationType.Bip44DeriveIndex}`,\n `${AccountCreationType.Bip44DeriveIndexRange}`,\n ]);\n\n return this.withSnap(async ({ keyring }) =>\n this.createBip44Accounts(keyring, options),\n );\n }\n\n /**\n * Delete a snap account by id.\n *\n * Resolves the account's address from the tracked account, then forwards to\n * the legacy `SnapKeyring.removeAccount(address)`. The Snap keyring takes\n * care of notifying the snap to clean up its own state through the normal\n * account-removal flow (same path used by `resyncAccounts`).\n *\n * @param id - The id of the account to delete.\n */\n async deleteAccount(id: Bip44Account<KeyringAccount>['id']): Promise<void> {\n const account = this.getAccount(id);\n\n await this.#withSnapKeyring(async ({ keyring }) => {\n await keyring.deleteAccount(account.id);\n });\n\n this.accounts.delete(id);\n }\n\n abstract discoverAccounts(options: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]>;\n}\n\nexport const isSnapAccountProvider = (\n provider: unknown,\n): provider is SnapAccountProvider => {\n return provider instanceof SnapAccountProvider;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"SnapAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,uDAA6D;AAK7D,sDAGuC;AACvC,uDAG+B;AAa/B,uDAAoD;AAEpD,6CAAwC;AAExC,sDAIsB;AACtB,0CAAwC;AACxC,0CAAiE;AAEjE,6EAAsE;AACtE,+DAA8D;AAE9D,uCAAiD;AA4CjD,MAAsB,mBAAoB,SAAQ,mDAAwB;IAiCxE,YACE,MAAc,EACd,SAA4C,EAC5C,MAAiC;IACjC,0BAA0B;IAC1B,QAAuB,yBAAa;QAEpC,KAAK,CAAC,SAAS,CAAC,CAAC;;QAnCnB;;;;WAIG;QACH,iBAAY,GAAwB,uBAAkB,CAAC;QAEvD;;;WAGG;QACH,8CAA4B;QAEnB,8CAAgB;QAEhB,6CAAmB;QAEnB,6CAAsB;QAoB7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,uBAAA,IAAI,+BAAW,uBAAA,IAAI,yEAAc,MAAlB,IAAI,EAAe,MAAM,CAAC,MAAA,CAAC;QAE1C,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,QAAQ,CAAC;QACzD,IAAI,CAAC,MAAM,GAAG;YACZ,GAAG,MAAM;YACT,SAAS,EAAE;gBACT,GAAG,MAAM,CAAC,SAAS;gBACnB,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,IAAI,IAAI;aAC1C;YACD,cAAc;SACf,CAAC;QAEF,kDAAkD;QAClD,IAAI,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC7B,uBAAA,IAAI,8BAAU,IAAI,uBAAS,CAAC,cAAc,CAAC,MAAA,CAAC;QAC9C,CAAC;QAED,uBAAA,IAAI,8BAAU,KAAK,MAAA,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gCAAgC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC;IAED;;;;;;;OAOG;IACO,KAAK,CAAC,kBAAkB,CAChC,SAAgC;QAEhC,IAAI,uBAAA,IAAI,kCAAO,EAAE,CAAC;YAChB,OAAO,uBAAA,IAAI,kCAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,SAAS,EAAE,CAAC;IACrB,CAAC;IAES,KAAK,CAAC,KAAK,CACnB,OAAqB,EACrB,EAA6B;QAE7B,OAAO,uBAAA,IAAI,kCAAO,MAAX,IAAI,EAAQ,OAAO,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;IAkDD;;;;;OAKG;IACO,IAAI;QACZ,OAAO,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAyBD,KAAK,CAAC,cAAc,CAClB,QAAyC;QAEzC,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;YAChD,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CACvC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC,MAAM,CACvD,CAAC;YACF,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAC1D,CAAC;YAEF,6EAA6E;YAC7E,uEAAuE;YACvE,IAAI,iBAAiB,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;gBACjD,MAAM,2BAA2B,GAC/B,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,2BAA2B,IAAI,IAAI,CAAC;gBAElE,IAAI,2BAA2B,EAAE,CAAC;oBAChC,oDAAoD;oBACpD,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,iBAAiB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAC/C,CAAC;oBAEF,kEAAkE;oBAClE,MAAM,OAAO,CAAC,GAAG,CACf,CAAC,GAAG,YAAY,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;wBAC5C,IAAI,CAAC;4BACH,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;gCACxC,sEAAsE;gCACtE,YAAY;gCACZ,MAAM,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;gCAC1C,iEAAiE;gCACjE,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;4BACrC,CAAC;wBACH,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,IAAA,oBAAW,EACT,IAAI,CAAC,SAAS,EACd,4CAA4C,IAAI,CAAC,MAAM,EAAE,EACzD,KAAK,EACL;gCACE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;gCACxB,aAAa;6BACd,CACF,CAAC;wBACJ,CAAC;oBACH,CAAC,CAAC,CACH,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,MAAM,OAAO,GAAG,SAAS,IAAI,CAAC,MAAM,oEAAoE,iBAAiB,CAAC,MAAM,MAAM,YAAY,CAAC,IAAI,GAAG,CAAC;oBAC3J,IAAA,sBAAG,EAAC,GAAG,uBAAc,IAAI,OAAO,EAAE,CAAC,CAAC;oBACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO;gBACT,CAAC;YACH,CAAC;YAED,8EAA8E;YAC9E,sEAAsE;YACtE,IAAI,iBAAiB,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;gBACjD,8DAA8D;gBAC9D,MAAM,OAAO,CAAC,GAAG,CACf,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;oBACtC,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;oBAElE,IAAI,CAAC;wBACH,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;4BAClC,yEAAyE;4BACzE,4EAA4E;4BAC5E,yEAAyE;4BACzE,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;4BACxC,sEAAsE;4BACtE,MAAM,IAAI,CAAC,cAAc,CAAC;gCACxB,IAAI,EAAE,iCAAmB,CAAC,gBAAgB;gCAC1C,aAAa;gCACb,UAAU;6BACX,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,IAAA,oBAAW,EAAC,IAAI,CAAC,SAAS,EAAE,4BAA4B,EAAE,KAAK,EAAE;4BAC/D,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;4BACxB,UAAU;yBACX,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAoBS,KAAK,CAAC,QAAQ,CACtB,SAG6B;QAE7B,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,uBAAA,IAAI,0EAAe,MAAnB,IAAI,CAAiB,CAAC;QAE3C,OAAO,MAAM,SAAS,CAAC;YACrB,MAAM;YACN,OAAO,EAAE,MAAM,uBAAA,IAAI,qFAA0B,MAA9B,IAAI,CAA4B;SAChD,CAAC,CAAC;IACL,CAAC;IASS,cAAc,CACtB,OAAuB,EACvB,QAAgE;QAEhE,IAAA,kCAAoB,EAAC,OAAO,CAAC,CAAC;QAC9B,OAAO,OAAO,CAAC;IACjB,CAAC;IAES,KAAK,CAAC,mBAAmB,CACjC,OAA8B,EAC9B,OAGqC;QAErC,OAAO,IAAI,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;YACxC,IAAI,gBAAgB,GAAG,CAAC,CAAC;YACzB,IAAI,YAAY,GAAqB,EAAE,CAAC;YAExC,uEAAuE;YACvE,uEAAuE;YACvE,4BAA4B;YAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;YAElC,MAAM,eAAe,GAAG,KAAK,EAC3B,UAAkB,EACO,EAAE,CAC3B,MAAM,IAAA,mBAAW,EACf,GAAG,EAAE,CACH,IAAI,CAAC,KAAK,CACR;gBACE,IAAI,EAAE,qBAAS,CAAC,uBAAuB;gBACvC,IAAI,EAAE;oBACJ,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;oBACxB,UAAU;iBACX;aACF,EACD,GAAG,EAAE,CACH,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,CAC/D,EACH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CACrC,CAAC;YACJ,MAAM,gBAAgB,GAAG,KAAK,EAC5B,SAGqC,EACV,EAAE,CAC7B,MAAM,IAAA,mBAAW,EACf,GAAG,EAAE,CACH,IAAI,CAAC,KAAK,CACR;gBACE,IAAI,EAAE,qBAAS,CAAC,sBAAsB;gBACtC,IAAI,EAAE;oBACJ,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;oBACxB,GAAG,IAAA,wCAA4B,EAAC,SAAS,CAAC;iBAC3C;aACF,EACD,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CACxC,EACH,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CACrC,CAAC;YAEJ,IAAI,OAAO,CAAC,IAAI,KAAK,GAAG,iCAAmB,CAAC,qBAAqB,EAAE,EAAE,CAAC;gBACpE,IAAI,OAAO,EAAE,CAAC;oBACZ,2BAA2B;oBAC3B,YAAY,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;oBAE1B,8BAA8B;oBAC9B,KACE,IAAI,UAAU,GAAG,KAAK,CAAC,IAAI,EAC3B,UAAU,IAAI,KAAK,CAAC,EAAE,EACtB,UAAU,EAAE,EACZ,CAAC;wBACD,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;wBAEtD,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;gBAED,oEAAoE;gBACpE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,IAAI,OAAO,EAAE,CAAC;oBACZ,kFAAkF;oBAClF,YAAY,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;oBAE/B,6CAA6C;oBAC7C,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;oBAEtD,YAAY,GAAG,CAAC,WAAW,CAAC,CAAC;gBAC/B,CAAC;gBAED,sEAAsE;gBACtE,iCAAiC;gBACjC,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;YACxC,CAAC;YAED,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE;gBAC7C,MAAM,UAAU,GAAG,gBAAgB,GAAG,KAAK,CAAC;gBAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE;oBAC/C,aAAa;oBACb,UAAU;iBACX,CAAC,CAAC;gBAEH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;gBAClC,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,OAA6B;QAE7B,IAAA,kDAAoC,EAAC,OAAO,EAAE;YAC5C,GAAG,iCAAmB,CAAC,gBAAgB,EAAE;YACzC,GAAG,iCAAmB,CAAC,qBAAqB,EAAE;SAC/C,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CACzC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAC3C,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,aAAa,CAAC,EAAsC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAEpC,MAAM,uBAAA,IAAI,4EAAiB,MAArB,IAAI,EAAkB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YAChD,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,gBAAgB,CAAC,EACrB,aAAa,EACb,UAAU,GAIX;QACC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CACjD,IAAI,CAAC,KAAK,CACR;YACE,IAAI,EAAE,qBAAS,CAAC,oBAAoB;YACpC,IAAI,EAAE;gBACJ,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE;aACzB;SACF,EACD,KAAK,IAAI,EAAE;YACT,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBACnC,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBAChB,gEAAgE;gBAChE,oEAAoE;gBACpE,+CAA+C;gBAC/C,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;oBACvC,OAAO,EAAE,CAAC;gBACZ,CAAC;gBAED,oEAAoE;gBACpE,+DAA+D;gBAC/D,2DAA2D;gBAC3D,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;oBACvC,IAAI,EAAE,iCAAmB,CAAC,aAAa;oBACvC,aAAa;oBACb,UAAU;iBACX,CAAC,CAAC;YACL,CAAC;YAED,kEAAkE;YAClE,oBAAoB;YACpB,MAAM,kBAAkB,GAAG,MAAM,IAAA,iBAAS,EACxC,GAAG,EAAE,CACH,IAAA,mBAAW,EACT,GAAG,EAAE,CACH,MAAM,CAAC,gBAAgB,CACrB,IAAI,CAAC,iBAAiB,EACtB,aAAa,EACb,UAAU,CACX,EACH,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAChC,EACH;gBACE,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW;gBAC9C,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS;aAC3C,CACF,CAAC;YAEF,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC;gBAC/B,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;gBACvC,IAAI,EAAE,iCAAmB,CAAC,gBAAgB;gBAC1C,aAAa;gBACb,UAAU;aACX,CAAC,CAAC;QACL,CAAC,CACF,CACF,CAAC;IACJ,CAAC;CACF;AA7hBD,kDA6hBC;kRA5bC,KAAK;IACH,mFAAmF;IACnF,kFAAkF;IAClF,sCAAsC;IACtC,+EAA+E;IAC/E,iFAAiF;IACjF,wDAAwD;IACxD,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,4EAAiB,MAArB,IAAI,EAAkB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACtE,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,OAAO,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,oCAAoC;QACpC,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,yEAAyE;QACzE,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS;QACjD,+EAA+E;QAC/E,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAChC,MAAM,uBAAA,IAAI,4EAAiB,MAArB,IAAI,EACR,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAC7D;QACH,aAAa,EAAE,KAAK,EAAE,EAAU,EAAE,EAAE,CAClC,MAAM,uBAAA,IAAI,4EAAiB,MAArB,IAAI,EAAkB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YAChD,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC;KACL,CAAC;AACJ,CAAC,iFAEa,MAAc;IAC1B,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,OAAuB,EAAiB,EAAE;YACrD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACxC,8BAA8B,EAC9B;gBACE,MAAM,EAAE,MAAgB;gBACxB,MAAM,EAAE,UAAU;gBAClB,OAAO,EAAE,yBAAW,CAAC,gBAAgB;gBACrC,OAAO;aACR,CACF,CAAC;YACF,OAAO,QAAgB,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC;AAYD;;;;;;;;;;;GAWG;AACH,KAAK;IACH,IAAI,CAAC,uBAAA,IAAI,mCAAQ,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAC3C,oCAAoC,EACpC,IAAI,CAAC,MAAM,CACZ,CAAC;QACF,uBAAA,IAAI,+BAAW,IAAA,2CAAuB,EAAC,uBAAA,IAAI,mCAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,MAAA,CAAC;IACpE,CAAC;IACD,OAAO,uBAAA,IAAI,mCAAQ,CAAC;AACtB,CAAC,yCA0FD,KAAK,+CACH,SAM6B;IAE7B,OAAO,IAAI,CAAC,aAAa,CACvB;QACE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAClB,IAAA,kBAAa,EAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;KAC3D,EACD,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAC1B,CAAC;AACJ,CAAC;AAqQI,MAAM,qBAAqB,GAAG,CACnC,QAAiB,EACgB,EAAE;IACnC,OAAO,QAAQ,YAAY,mBAAmB,CAAC;AACjD,CAAC,CAAC;AAJW,QAAA,qBAAqB,yBAIhC","sourcesContent":["import { assertIsBip44Account } from '@metamask/account-api';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback, TraceRequest } from '@metamask/controller-utils';\nimport type { SnapKeyringV1 } from '@metamask/eth-snap-keyring';\nimport type { SnapKeyring as SnapKeyringV2 } from '@metamask/eth-snap-keyring/v2';\nimport {\n EMPTY_CAPABILITIES,\n isSnapKeyring,\n} from '@metamask/eth-snap-keyring/v2';\nimport {\n AccountCreationType,\n assertCreateAccountOptionIsSupported,\n} from '@metamask/keyring-api';\nimport type {\n CreateAccountBip44DeriveIndexOptions,\n CreateAccountBip44DeriveIndexRangeOptions,\n CreateAccountBip44DiscoverOptions,\n CreateAccountOptions,\n EntropySourceId,\n KeyringAccount,\n} from '@metamask/keyring-api';\nimport type { KeyringCapabilities } from '@metamask/keyring-api/v2';\nimport type { KeyringMetadata } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type { CaipChainId } from '@metamask/utils';\nimport { Semaphore } from 'async-mutex';\n\nimport {\n toCreateAccountsV2DataTraces,\n traceFallback,\n TraceName,\n} from '../analytics';\nimport { reportError } from '../errors';\nimport { projectLogger as log, WARNING_PREFIX } from '../logger';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport { BaseBip44AccountProvider } from './BaseBip44AccountProvider';\nimport { createSnapKeyringClient } from './SnapKeyringClient';\nimport type { Sender, SnapKeyringClient } from './SnapKeyringClient';\nimport { withRetry, withTimeout } from './utils';\n\nexport type RestrictedSnapKeyring = {\n /**\n * V1 interface, present only when the Snap does not declare v2 capabilities.\n * `undefined` for v2-only Snaps.\n *\n * Use this to make v1 calls explicit:\n * if (!keyring.v1) { throw new Error('Snap is v2-only'); }\n * keyring.v1.createAccount(options);\n */\n v1?: { createAccount: SnapKeyringV1['createAccount'] };\n createAccounts: SnapKeyringV2['createAccounts'];\n deleteAccount: SnapKeyringV2['deleteAccount'];\n};\n\nexport type SnapAccountProviderConfig = {\n maxConcurrency?: number;\n discovery: {\n enabled?: boolean;\n maxAttempts: number;\n timeoutMs: number;\n backOffMs: number;\n };\n createAccounts: {\n /**\n * Timeout for account creation operations.\n *\n * NOTE: Batching (and thus whether a single call may create multiple\n * accounts) is driven by the Snap's declared capabilities, not this config.\n * The value might have to be adapted when the Snap supports batching.\n */\n timeoutMs: number;\n };\n resyncAccounts?: {\n /**\n * Whether to automatically remove extra Snap accounts when the Snap has\n * more accounts than MetaMask. If `false`, a warning is logged instead.\n * Defaults to `true`.\n */\n autoRemoveExtraSnapAccounts?: boolean;\n };\n};\n\nexport abstract class SnapAccountProvider extends BaseBip44AccountProvider {\n readonly snapId: SnapId;\n\n protected readonly config: SnapAccountProviderConfig;\n\n /**\n * The Snap's keyring capabilities, sourced from `SnapAccountService` (which\n * reads them from the Snap's manifest). Populated the first time the client\n * is resolved; defaults to an empty capability set until then.\n */\n capabilities: KeyringCapabilities = EMPTY_CAPABILITIES;\n\n /**\n * Version-agnostic keyring client, resolved lazily once the Snap is ready and\n * its capabilities are known — see {@link SnapAccountProvider.withSnap}.\n */\n #client?: SnapKeyringClient;\n\n readonly #sender: Sender;\n\n readonly #queue?: Semaphore;\n\n readonly #trace: TraceCallback;\n\n /**\n * Scopes passed to the v1 `discoverAccounts` client method. Only used on the\n * v1 discovery path.\n *\n * TODO: Remove once all Snaps are fully v2 — discovery is then driven by the\n * Snap's own supported scopes via `createAccounts({ bip44:discover })`.\n */\n protected abstract readonly v1DiscoveryScopes: CaipChainId[];\n\n constructor(\n snapId: SnapId,\n messenger: MultichainAccountServiceMessenger,\n config: SnapAccountProviderConfig,\n /* istanbul ignore next */\n trace: TraceCallback = traceFallback,\n ) {\n super(messenger);\n\n this.snapId = snapId;\n this.#sender = this.#createSender(snapId);\n\n const maxConcurrency = config.maxConcurrency ?? Infinity;\n this.config = {\n ...config,\n discovery: {\n ...config.discovery,\n enabled: config.discovery.enabled ?? true,\n },\n maxConcurrency,\n };\n\n // Create semaphore only if concurrency is limited\n if (isFinite(maxConcurrency)) {\n this.#queue = new Semaphore(maxConcurrency);\n }\n\n this.#trace = trace;\n }\n\n /**\n * Ensures that the Snap is ready to be used.\n *\n * @returns A promise that resolves when the Snap is ready.\n * @throws An error if the Snap could not become ready.\n */\n async ensureReady(): Promise<void> {\n return this.messenger.call('SnapAccountService:ensureReady', this.snapId);\n }\n\n /**\n * Wraps an async operation with concurrency limiting based on maxConcurrency config.\n * If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.\n * Otherwise, it's queued through the semaphore to respect the concurrency limit.\n *\n * @param operation - The async operation to execute.\n * @returns The result of the operation.\n */\n protected async withMaxConcurrency<Result>(\n operation: () => Promise<Result>,\n ): Promise<Result> {\n if (this.#queue) {\n return this.#queue.runExclusive(operation);\n }\n return operation();\n }\n\n protected async trace<ReturnType>(\n request: TraceRequest,\n fn: () => Promise<ReturnType>,\n ): Promise<ReturnType> {\n return this.#trace(request, fn);\n }\n\n async #getRestrictedSnapKeyring(): Promise<RestrictedSnapKeyring> {\n // NOTE: We're not supposed to make the keyring instance escape `withKeyringV2` but\n // we have to use the `SnapKeyringV2` instance to be able to create Solana account\n // without triggering UI confirmation.\n // Also, creating account that way won't invalidate the Snap keyring state. The\n // account will get created and persisted properly with the Snap account creation\n // flow \"asynchronously\" (with `notify:accountCreated`).\n const createAccount = await this.#withSnapKeyring(async ({ keyring }) => {\n if (keyring.v1) {\n return keyring.v1.createAccount.bind(keyring.v1);\n }\n\n // This method does not exist in v2.\n return undefined;\n });\n\n return {\n // V1 interface is only present for v1 Snaps, otherwise it's `undefined`.\n v1: createAccount ? { createAccount } : undefined,\n // Every v2 operations must be done through the `#withSnapKeyring` transaction:\n createAccounts: async (options) =>\n await this.#withSnapKeyring(\n async ({ keyring }) => await keyring.createAccounts(options),\n ),\n deleteAccount: async (id: string) =>\n await this.#withSnapKeyring(async ({ keyring }) => {\n await keyring.deleteAccount(id);\n }),\n };\n }\n\n #createSender(snapId: string): Sender {\n return {\n send: async (request: JsonRpcRequest): Promise<Json> => {\n const response = await this.messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Json;\n },\n };\n }\n\n /**\n * Whether the Snap supports the v2 keyring protocol, inferred from its\n * declared capabilities (a v2-capable Snap declares BIP-44 capabilities).\n *\n * @returns `true` if the Snap is v2-capable.\n */\n protected isV2(): boolean {\n return Boolean(this.capabilities.bip44);\n }\n\n /**\n * Resolves the version-agnostic keyring client, fetching the Snap's\n * capabilities from `SnapAccountService` on first use and caching both the\n * capabilities and the resulting client.\n *\n * Callers must ensure the Snap is ready (via\n * {@link SnapAccountProvider.ensureReady}) beforehand so that the\n * capabilities are reliably populated — {@link SnapAccountProvider.withSnap}\n * guarantees this ordering.\n *\n * @returns The resolved {@link SnapKeyringClient}.\n */\n async #resolveClient(): Promise<SnapKeyringClient> {\n if (!this.#client) {\n this.capabilities = await this.messenger.call(\n 'SnapAccountService:getCapabilities',\n this.snapId,\n );\n this.#client = createSnapKeyringClient(this.#sender, this.isV2());\n }\n return this.#client;\n }\n\n async resyncAccounts(\n accounts: Bip44Account<InternalAccount>[],\n ): Promise<void> {\n await this.withSnap(async ({ client, keyring }) => {\n const localSnapAccounts = accounts.filter(\n (account) => account.metadata.snap?.id === this.snapId,\n );\n const snapAccounts = new Set(\n (await client.getAccounts()).map((account) => account.id),\n );\n\n // NOTE: This should never happen, but if it does, we recover by deleting the\n // extra accounts from the Snap to bring it back in sync with MetaMask.\n if (localSnapAccounts.length < snapAccounts.size) {\n const autoRemoveExtraSnapAccounts =\n this.config.resyncAccounts?.autoRemoveExtraSnapAccounts ?? true;\n\n if (autoRemoveExtraSnapAccounts) {\n // Build a set of local account IDs for quick lookup\n const localAccountIds = new Set(\n localSnapAccounts.map((account) => account.id),\n );\n\n // Find and delete accounts that exist in Snap but not in MetaMask\n await Promise.all(\n [...snapAccounts].map(async (snapAccountId) => {\n try {\n if (!localAccountIds.has(snapAccountId)) {\n // This account exists in the Snap but not in MetaMask, delete it from\n // the Snap.\n await client.deleteAccount(snapAccountId);\n // Update the local Set so subsequent checks use the correct size\n snapAccounts.delete(snapAccountId);\n }\n } catch (error) {\n reportError(\n this.messenger,\n `Unable to delete de-synced Snap account: ${this.snapId}`,\n error,\n {\n provider: this.getName(),\n snapAccountId,\n },\n );\n }\n }),\n );\n } else {\n const message = `Snap \"${this.snapId}\" has de-synced accounts, Snap has more accounts than MetaMask! (${localSnapAccounts.length} < ${snapAccounts.size})`;\n log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\n return;\n }\n }\n\n // We want this part to be fast, so we only check for sizes, but we might need\n // to make a real \"diff\" between the 2 states to not miss any de-sync.\n if (localSnapAccounts.length > snapAccounts.size) {\n // We always use the MetaMask list as the main reference here.\n await Promise.all(\n localSnapAccounts.map(async (account) => {\n const { id: entropySource, groupIndex } = account.options.entropy;\n\n try {\n if (!snapAccounts.has(account.id)) {\n // We still need to remove the accounts from the Snap keyring since we're\n // about to create the same account again, which will use a new ID, but will\n // keep using the same address, and the Snap keyring does not allow this.\n await keyring.deleteAccount(account.id);\n // The Snap has no account in its state for this one, we re-create it.\n await this.createAccounts({\n type: AccountCreationType.Bip44DeriveIndex,\n entropySource,\n groupIndex,\n });\n }\n } catch (error) {\n reportError(this.messenger, 'Unable to re-sync accounts', error, {\n provider: this.getName(),\n groupIndex,\n });\n }\n }),\n );\n }\n });\n }\n\n async #withSnapKeyring<CallbackResult = void>(\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SnapKeyringV2;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n return this.withKeyringV2<SnapKeyringV2, CallbackResult>(\n {\n filter: (keyring) =>\n isSnapKeyring(keyring) && keyring.snapId === this.snapId,\n },\n (args) => operation(args),\n );\n }\n\n protected async withSnap<CallbackResult = void>(\n operation: (snap: {\n client: SnapKeyringClient;\n keyring: RestrictedSnapKeyring;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n await this.ensureReady();\n const client = await this.#resolveClient();\n\n return await operation({\n client,\n keyring: await this.#getRestrictedSnapKeyring(),\n });\n }\n\n abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;\n\n protected abstract createAccountV1(\n keyring: RestrictedSnapKeyring,\n options: { entropySource: EntropySourceId; groupIndex: number },\n ): Promise<KeyringAccount>;\n\n protected toBip44Account(\n account: KeyringAccount,\n _options: { entropySource: EntropySourceId; groupIndex: number },\n ): Bip44Account<KeyringAccount> {\n assertIsBip44Account(account);\n return account;\n }\n\n protected async createBip44Accounts(\n keyring: RestrictedSnapKeyring,\n options:\n | CreateAccountBip44DeriveIndexOptions\n | CreateAccountBip44DeriveIndexRangeOptions\n | CreateAccountBip44DiscoverOptions,\n ): Promise<Bip44Account<KeyringAccount>[]> {\n return this.withMaxConcurrency(async () => {\n let groupIndexOffset = 0;\n let snapAccounts: KeyringAccount[] = [];\n\n // v2 Snaps expose `createAccounts` but no singular `createAccount`, so\n // they must always go through the batched flow. v1 Snaps only have the\n // singular `createAccount`.\n const batched = this.isV2();\n const { entropySource } = options;\n\n const createAccountV1 = async (\n groupIndex: number,\n ): Promise<KeyringAccount> =>\n await withTimeout(\n () =>\n this.trace(\n {\n name: TraceName.ProviderCreateAccountV1,\n data: {\n provider: this.getName(),\n groupIndex,\n },\n },\n () =>\n this.createAccountV1(keyring, { entropySource, groupIndex }),\n ),\n this.config.createAccounts.timeoutMs,\n );\n const createAccountsV2 = async (\n optionsV2:\n | CreateAccountBip44DeriveIndexOptions\n | CreateAccountBip44DeriveIndexRangeOptions\n | CreateAccountBip44DiscoverOptions,\n ): Promise<KeyringAccount[]> =>\n await withTimeout(\n () =>\n this.trace(\n {\n name: TraceName.ProviderCreateAccounts,\n data: {\n provider: this.getName(),\n ...toCreateAccountsV2DataTraces(optionsV2),\n },\n },\n () => keyring.createAccounts(optionsV2),\n ),\n this.config.createAccounts.timeoutMs,\n );\n\n if (options.type === `${AccountCreationType.Bip44DeriveIndexRange}`) {\n if (batched) {\n // Batch account creations.\n snapAccounts = await createAccountsV2(options);\n } else {\n const { range } = options;\n\n // Create accounts one by one.\n for (\n let groupIndex = range.from;\n groupIndex <= range.to;\n groupIndex++\n ) {\n const snapAccount = await createAccountV1(groupIndex);\n\n snapAccounts.push(snapAccount);\n }\n }\n\n // Group indices are sequential, so we just need the starting index.\n groupIndexOffset = options.range.from;\n } else {\n if (batched) {\n // Create account using new v2-like flow (no async flow + no Snap keyring events).\n snapAccounts = await createAccountsV2(options);\n } else {\n const { groupIndex } = options;\n\n // Create account using the existing v1 flow.\n const snapAccount = await createAccountV1(groupIndex);\n\n snapAccounts = [snapAccount];\n }\n\n // For single account, there will only be 1 account, so we can use the\n // provided group index directly.\n groupIndexOffset = options.groupIndex;\n }\n\n return snapAccounts.map((snapAccount, index) => {\n const groupIndex = groupIndexOffset + index;\n const account = this.toBip44Account(snapAccount, {\n entropySource,\n groupIndex,\n });\n\n this.accounts.add(snapAccount.id);\n return account;\n });\n });\n }\n\n async createAccounts(\n options: CreateAccountOptions,\n ): Promise<Bip44Account<KeyringAccount>[]> {\n assertCreateAccountOptionIsSupported(options, [\n `${AccountCreationType.Bip44DeriveIndex}`,\n `${AccountCreationType.Bip44DeriveIndexRange}`,\n ]);\n\n return this.withSnap(async ({ keyring }) =>\n this.createBip44Accounts(keyring, options),\n );\n }\n\n /**\n * Delete a snap account by id.\n *\n * Resolves the account's address from the tracked account, then forwards to\n * the legacy `SnapKeyring.removeAccount(address)`. The Snap keyring takes\n * care of notifying the snap to clean up its own state through the normal\n * account-removal flow (same path used by `resyncAccounts`).\n *\n * @param id - The id of the account to delete.\n */\n async deleteAccount(id: Bip44Account<KeyringAccount>['id']): Promise<void> {\n const account = this.getAccount(id);\n\n await this.#withSnapKeyring(async ({ keyring }) => {\n await keyring.deleteAccount(account.id);\n });\n\n this.accounts.delete(id);\n }\n\n /**\n * Discovers accounts for the given entropy source and group index.\n *\n * v2 Snaps drive discovery through `createAccounts({ bip44:discover })`: the\n * Snap checks for on-chain activity (using its own supported scopes) and\n * returns the created account(s), or nothing once discovery is exhausted.\n *\n * v1 Snaps use the client's `discoverAccounts` to detect activity on\n * {@link v1DiscoveryScopes}, then create the account for the group index.\n *\n * @param options - The discovery options.\n * @param options.entropySource - The entropy source to discover accounts for.\n * @param options.groupIndex - The group index to discover accounts for.\n * @returns The discovered (and created) accounts, or an empty array when\n * there is nothing to discover at this group index.\n */\n async discoverAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]> {\n return this.withSnap(async ({ client, keyring }) =>\n this.trace(\n {\n name: TraceName.SnapDiscoverAccounts,\n data: {\n provider: this.getName(),\n },\n },\n async () => {\n if (!this.config.discovery.enabled) {\n return [];\n }\n\n if (this.isV2()) {\n // The v2 client has no `discoverAccounts`, so discovery is only\n // possible when the Snap supports `bip44:discover`. Otherwise there\n // is no way to discover and we report nothing.\n if (!this.capabilities.bip44?.discover) {\n return [];\n }\n\n // v2: the Snap detects on-chain activity and creates the account in\n // a single `createAccounts({ bip44:discover })` call. An empty\n // result means discovery is exhausted at this group index.\n return this.createBip44Accounts(keyring, {\n type: AccountCreationType.Bip44Discover,\n entropySource,\n groupIndex,\n });\n }\n\n // v1: detect activity via the client, then create the account for\n // this group index.\n const discoveredAccounts = await withRetry(\n () =>\n withTimeout(\n () =>\n client.discoverAccounts(\n this.v1DiscoveryScopes,\n entropySource,\n groupIndex,\n ),\n this.config.discovery.timeoutMs,\n ),\n {\n maxAttempts: this.config.discovery.maxAttempts,\n backOffMs: this.config.discovery.backOffMs,\n },\n );\n\n if (!discoveredAccounts.length) {\n return [];\n }\n\n return this.createBip44Accounts(keyring, {\n type: AccountCreationType.Bip44DeriveIndex,\n entropySource,\n groupIndex,\n });\n },\n ),\n );\n }\n}\n\nexport const isSnapAccountProvider = (\n provider: unknown,\n): provider is SnapAccountProvider => {\n return provider instanceof SnapAccountProvider;\n};\n"]}
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import type { Bip44Account } from "@metamask/account-api";
|
|
2
2
|
import type { TraceCallback, TraceRequest } from "@metamask/controller-utils";
|
|
3
|
+
import type { SnapKeyringV1 } from "@metamask/eth-snap-keyring";
|
|
3
4
|
import type { SnapKeyring as SnapKeyringV2 } from "@metamask/eth-snap-keyring/v2";
|
|
4
|
-
import type { CreateAccountBip44DeriveIndexOptions, CreateAccountBip44DeriveIndexRangeOptions, CreateAccountOptions, EntropySourceId, KeyringAccount } from "@metamask/keyring-api";
|
|
5
|
+
import type { CreateAccountBip44DeriveIndexOptions, CreateAccountBip44DeriveIndexRangeOptions, CreateAccountBip44DiscoverOptions, CreateAccountOptions, EntropySourceId, KeyringAccount } from "@metamask/keyring-api";
|
|
6
|
+
import type { KeyringCapabilities } from "@metamask/keyring-api/v2";
|
|
5
7
|
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
6
|
-
import { KeyringClient } from "@metamask/keyring-snap-client";
|
|
7
8
|
import type { SnapId } from "@metamask/snaps-sdk";
|
|
9
|
+
import type { CaipChainId } from "@metamask/utils";
|
|
8
10
|
import type { MultichainAccountServiceMessenger } from "../types.cjs";
|
|
9
11
|
import { BaseBip44AccountProvider } from "./BaseBip44AccountProvider.cjs";
|
|
12
|
+
import type { SnapKeyringClient } from "./SnapKeyringClient.cjs";
|
|
10
13
|
export type RestrictedSnapKeyring = {
|
|
11
|
-
|
|
14
|
+
/**
|
|
15
|
+
* V1 interface, present only when the Snap does not declare v2 capabilities.
|
|
16
|
+
* `undefined` for v2-only Snaps.
|
|
17
|
+
*
|
|
18
|
+
* Use this to make v1 calls explicit:
|
|
19
|
+
* if (!keyring.v1) { throw new Error('Snap is v2-only'); }
|
|
20
|
+
* keyring.v1.createAccount(options);
|
|
21
|
+
*/
|
|
22
|
+
v1?: {
|
|
23
|
+
createAccount: SnapKeyringV1['createAccount'];
|
|
24
|
+
};
|
|
12
25
|
createAccounts: SnapKeyringV2['createAccounts'];
|
|
13
26
|
deleteAccount: SnapKeyringV2['deleteAccount'];
|
|
14
27
|
};
|
|
@@ -21,18 +34,12 @@ export type SnapAccountProviderConfig = {
|
|
|
21
34
|
backOffMs: number;
|
|
22
35
|
};
|
|
23
36
|
createAccounts: {
|
|
24
|
-
/**
|
|
25
|
-
* Whether to enable account batching with `createAccounts` method. If `true`, accounts will
|
|
26
|
-
* be created in batch.
|
|
27
|
-
*
|
|
28
|
-
* NOTE: The Snap has to implement this optional method for batching support.
|
|
29
|
-
* Defaults to `false`.
|
|
30
|
-
*/
|
|
31
|
-
batched: boolean;
|
|
32
37
|
/**
|
|
33
38
|
* Timeout for account creation operations.
|
|
34
39
|
*
|
|
35
|
-
* NOTE:
|
|
40
|
+
* NOTE: Batching (and thus whether a single call may create multiple
|
|
41
|
+
* accounts) is driven by the Snap's declared capabilities, not this config.
|
|
42
|
+
* The value might have to be adapted when the Snap supports batching.
|
|
36
43
|
*/
|
|
37
44
|
timeoutMs: number;
|
|
38
45
|
};
|
|
@@ -49,6 +56,20 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
49
56
|
#private;
|
|
50
57
|
readonly snapId: SnapId;
|
|
51
58
|
protected readonly config: SnapAccountProviderConfig;
|
|
59
|
+
/**
|
|
60
|
+
* The Snap's keyring capabilities, sourced from `SnapAccountService` (which
|
|
61
|
+
* reads them from the Snap's manifest). Populated the first time the client
|
|
62
|
+
* is resolved; defaults to an empty capability set until then.
|
|
63
|
+
*/
|
|
64
|
+
capabilities: KeyringCapabilities;
|
|
65
|
+
/**
|
|
66
|
+
* Scopes passed to the v1 `discoverAccounts` client method. Only used on the
|
|
67
|
+
* v1 discovery path.
|
|
68
|
+
*
|
|
69
|
+
* TODO: Remove once all Snaps are fully v2 — discovery is then driven by the
|
|
70
|
+
* Snap's own supported scopes via `createAccounts({ bip44:discover })`.
|
|
71
|
+
*/
|
|
72
|
+
protected abstract readonly v1DiscoveryScopes: CaipChainId[];
|
|
52
73
|
constructor(snapId: SnapId, messenger: MultichainAccountServiceMessenger, config: SnapAccountProviderConfig, trace?: TraceCallback);
|
|
53
74
|
/**
|
|
54
75
|
* Ensures that the Snap is ready to be used.
|
|
@@ -67,9 +88,16 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
67
88
|
*/
|
|
68
89
|
protected withMaxConcurrency<Result>(operation: () => Promise<Result>): Promise<Result>;
|
|
69
90
|
protected trace<ReturnType>(request: TraceRequest, fn: () => Promise<ReturnType>): Promise<ReturnType>;
|
|
91
|
+
/**
|
|
92
|
+
* Whether the Snap supports the v2 keyring protocol, inferred from its
|
|
93
|
+
* declared capabilities (a v2-capable Snap declares BIP-44 capabilities).
|
|
94
|
+
*
|
|
95
|
+
* @returns `true` if the Snap is v2-capable.
|
|
96
|
+
*/
|
|
97
|
+
protected isV2(): boolean;
|
|
70
98
|
resyncAccounts(accounts: Bip44Account<InternalAccount>[]): Promise<void>;
|
|
71
99
|
protected withSnap<CallbackResult = void>(operation: (snap: {
|
|
72
|
-
client:
|
|
100
|
+
client: SnapKeyringClient;
|
|
73
101
|
keyring: RestrictedSnapKeyring;
|
|
74
102
|
}) => Promise<CallbackResult>): Promise<CallbackResult>;
|
|
75
103
|
abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;
|
|
@@ -81,7 +109,7 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
81
109
|
entropySource: EntropySourceId;
|
|
82
110
|
groupIndex: number;
|
|
83
111
|
}): Bip44Account<KeyringAccount>;
|
|
84
|
-
protected createBip44Accounts(keyring: RestrictedSnapKeyring, options: CreateAccountBip44DeriveIndexOptions | CreateAccountBip44DeriveIndexRangeOptions): Promise<Bip44Account<KeyringAccount>[]>;
|
|
112
|
+
protected createBip44Accounts(keyring: RestrictedSnapKeyring, options: CreateAccountBip44DeriveIndexOptions | CreateAccountBip44DeriveIndexRangeOptions | CreateAccountBip44DiscoverOptions): Promise<Bip44Account<KeyringAccount>[]>;
|
|
85
113
|
createAccounts(options: CreateAccountOptions): Promise<Bip44Account<KeyringAccount>[]>;
|
|
86
114
|
/**
|
|
87
115
|
* Delete a snap account by id.
|
|
@@ -94,7 +122,23 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
94
122
|
* @param id - The id of the account to delete.
|
|
95
123
|
*/
|
|
96
124
|
deleteAccount(id: Bip44Account<KeyringAccount>['id']): Promise<void>;
|
|
97
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Discovers accounts for the given entropy source and group index.
|
|
127
|
+
*
|
|
128
|
+
* v2 Snaps drive discovery through `createAccounts({ bip44:discover })`: the
|
|
129
|
+
* Snap checks for on-chain activity (using its own supported scopes) and
|
|
130
|
+
* returns the created account(s), or nothing once discovery is exhausted.
|
|
131
|
+
*
|
|
132
|
+
* v1 Snaps use the client's `discoverAccounts` to detect activity on
|
|
133
|
+
* {@link v1DiscoveryScopes}, then create the account for the group index.
|
|
134
|
+
*
|
|
135
|
+
* @param options - The discovery options.
|
|
136
|
+
* @param options.entropySource - The entropy source to discover accounts for.
|
|
137
|
+
* @param options.groupIndex - The group index to discover accounts for.
|
|
138
|
+
* @returns The discovered (and created) accounts, or an empty array when
|
|
139
|
+
* there is nothing to discover at this group index.
|
|
140
|
+
*/
|
|
141
|
+
discoverAccounts({ entropySource, groupIndex, }: {
|
|
98
142
|
entropySource: EntropySourceId;
|
|
99
143
|
groupIndex: number;
|
|
100
144
|
}): Promise<Bip44Account<KeyringAccount>[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,mCAAmC;AAC9E,OAAO,KAAK,EAAE,WAAW,IAAI,aAAa,EAAE,sCAAsC;
|
|
1
|
+
{"version":3,"file":"SnapAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"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"}
|