@metamask/multichain-account-service 11.1.0 → 13.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 +39 -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/analytics/traces.cjs +0 -1
- package/dist/analytics/traces.cjs.map +1 -1
- package/dist/analytics/traces.d.cts +0 -1
- package/dist/analytics/traces.d.cts.map +1 -1
- package/dist/analytics/traces.d.mts +0 -1
- package/dist/analytics/traces.d.mts.map +1 -1
- package/dist/analytics/traces.mjs +0 -1
- package/dist/analytics/traces.mjs.map +1 -1
- package/dist/providers/BtcAccountProvider.cjs +3 -45
- package/dist/providers/BtcAccountProvider.cjs.map +1 -1
- package/dist/providers/BtcAccountProvider.d.cts +3 -12
- package/dist/providers/BtcAccountProvider.d.cts.map +1 -1
- package/dist/providers/BtcAccountProvider.d.mts +3 -12
- package/dist/providers/BtcAccountProvider.d.mts.map +1 -1
- package/dist/providers/BtcAccountProvider.mjs +4 -46
- package/dist/providers/BtcAccountProvider.mjs.map +1 -1
- package/dist/providers/SnapAccountProvider.cjs +121 -82
- package/dist/providers/SnapAccountProvider.cjs.map +1 -1
- package/dist/providers/SnapAccountProvider.d.cts +59 -21
- package/dist/providers/SnapAccountProvider.d.cts.map +1 -1
- package/dist/providers/SnapAccountProvider.d.mts +59 -21
- package/dist/providers/SnapAccountProvider.d.mts.map +1 -1
- package/dist/providers/SnapAccountProvider.mjs +123 -84
- 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 +3 -45
- package/dist/providers/SolAccountProvider.cjs.map +1 -1
- package/dist/providers/SolAccountProvider.d.cts +3 -11
- package/dist/providers/SolAccountProvider.d.cts.map +1 -1
- package/dist/providers/SolAccountProvider.d.mts +3 -11
- package/dist/providers/SolAccountProvider.d.mts.map +1 -1
- package/dist/providers/SolAccountProvider.mjs +4 -46
- package/dist/providers/SolAccountProvider.mjs.map +1 -1
- package/dist/providers/TrxAccountProvider.cjs +3 -44
- package/dist/providers/TrxAccountProvider.cjs.map +1 -1
- package/dist/providers/TrxAccountProvider.d.cts +3 -12
- package/dist/providers/TrxAccountProvider.d.cts.map +1 -1
- package/dist/providers/TrxAccountProvider.d.mts +3 -12
- package/dist/providers/TrxAccountProvider.d.mts.map +1 -1
- package/dist/providers/TrxAccountProvider.mjs +4 -45
- package/dist/providers/TrxAccountProvider.mjs.map +1 -1
- package/dist/providers/XlmAccountProvider.cjs +3 -44
- package/dist/providers/XlmAccountProvider.cjs.map +1 -1
- package/dist/providers/XlmAccountProvider.d.cts +3 -12
- package/dist/providers/XlmAccountProvider.d.cts.map +1 -1
- package/dist/providers/XlmAccountProvider.d.mts +3 -12
- package/dist/providers/XlmAccountProvider.d.mts.map +1 -1
- package/dist/providers/XlmAccountProvider.mjs +4 -45
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BtcAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/BtcAccountProvider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BtcAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/BtcAccountProvider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,8BAA8B;AAKjE,OAAO,EAAE,aAAa,EAAE,+BAAqB;AAE7C,OAAO,EAAE,mBAAmB,EAAE,kCAA8B;AAK5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,SAAS,CAAC;AAEnD,MAAM,CAAC,MAAM,mCAAmC,GAA6B;IAC3E,cAAc,EAAE,CAAC;IACjB,cAAc,EAAE;QACd,SAAS,EAAE,IAAI;KAChB;IACD,SAAS,EAAE;QACT,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,IAAI;KAChB;IACD,cAAc,EAAE;QACd,2BAA2B,EAAE,IAAI;KAClC;CACF,CAAC;AAEF,MAAM,OAAO,kBAAmB,SAAQ,mBAAmB;IASzD,YACE,SAA4C,EAC5C,SAAmC,mCAAmC,EACtE,QAAuB,aAAa;QAEpC,KAAK,CAAC,kBAAkB,CAAC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QATlE,2EAA2E;QAC3E,wEAAwE;QACrD,sBAAiB,GAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAQzE,CAAC;IAED,OAAO;QACL,OAAO,kBAAkB,CAAC,IAAI,CAAC;IACjC,CAAC;IAED,mBAAmB,CAAC,OAAsC;QACxD,OAAO,CACL,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,MAAM;YACtC,MAAM,CAAC,MAAM,CAAS,cAAc,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAC7D,CAAC;IACJ,CAAC;;AAzBM,uBAAI,GAAG,yBAAyB,AAA5B,CAA6B;AAEjC,8BAAW,GAAG,mCAA6C,AAAhD,CAAiD","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport { BtcAccountType, BtcScope } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { SnapId } from '@metamask/snaps-sdk';\nimport type { CaipChainId } from '@metamask/utils';\n\nimport { traceFallback } from '../analytics';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport { SnapAccountProvider } from './SnapAccountProvider';\nimport type { SnapAccountProviderConfig } from './SnapAccountProvider';\n\nexport type BtcAccountProviderConfig = SnapAccountProviderConfig;\n\nexport const BTC_ACCOUNT_PROVIDER_NAME = 'Bitcoin';\n\nexport const BTC_ACCOUNT_PROVIDER_DEFAULT_CONFIG: BtcAccountProviderConfig = {\n maxConcurrency: 3,\n createAccounts: {\n timeoutMs: 3000,\n },\n discovery: {\n enabled: true,\n timeoutMs: 2000,\n maxAttempts: 3,\n backOffMs: 1000,\n },\n resyncAccounts: {\n autoRemoveExtraSnapAccounts: true,\n },\n};\n\nexport class BtcAccountProvider extends SnapAccountProvider {\n static NAME = BTC_ACCOUNT_PROVIDER_NAME;\n\n static BTC_SNAP_ID = 'npm:@metamask/bitcoin-wallet-snap' as SnapId;\n\n // TODO: Remove once the Snap is fully v2 — discovery is then driven by the\n // Snap's own supported scopes via `createAccounts({ bip44:discover })`.\n protected readonly v1DiscoveryScopes: CaipChainId[] = [BtcScope.Mainnet];\n\n constructor(\n messenger: MultichainAccountServiceMessenger,\n config: BtcAccountProviderConfig = BTC_ACCOUNT_PROVIDER_DEFAULT_CONFIG,\n trace: TraceCallback = traceFallback,\n ) {\n super(BtcAccountProvider.BTC_SNAP_ID, messenger, config, trace);\n }\n\n getName(): string {\n return BtcAccountProvider.NAME;\n }\n\n isAccountCompatible(account: Bip44Account<InternalAccount>): boolean {\n return (\n account.type === BtcAccountType.P2wpkh &&\n Object.values<string>(BtcAccountType).includes(account.type)\n );\n }\n}\n"]}
|
|
@@ -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,
|
|
13
|
+
var _SnapAccountProvider_instances, _SnapAccountProvider_client, _SnapAccountProvider_sender, _SnapAccountProvider_queue, _SnapAccountProvider_trace, _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,
|
|
@@ -53,6 +64,10 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
53
64
|
/**
|
|
54
65
|
* Ensures that the Snap is ready to be used.
|
|
55
66
|
*
|
|
67
|
+
* Once this resolves, a Snap keyring for {@link snapId} is guaranteed to
|
|
68
|
+
* exist in the `KeyringController`, so subsequent {@link #withSnapKeyring}
|
|
69
|
+
* calls will not fail with "No keyring matches the selector".
|
|
70
|
+
*
|
|
56
71
|
* @returns A promise that resolves when the Snap is ready.
|
|
57
72
|
* @throws An error if the Snap could not become ready.
|
|
58
73
|
*/
|
|
@@ -76,10 +91,19 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
76
91
|
async trace(request, fn) {
|
|
77
92
|
return __classPrivateFieldGet(this, _SnapAccountProvider_trace, "f").call(this, request, fn);
|
|
78
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Whether the Snap supports the v2 keyring protocol, inferred from its
|
|
96
|
+
* declared capabilities (a v2-capable Snap declares BIP-44 capabilities).
|
|
97
|
+
*
|
|
98
|
+
* @returns `true` if the Snap is v2-capable.
|
|
99
|
+
*/
|
|
100
|
+
isV2() {
|
|
101
|
+
return Boolean(this.capabilities.bip44);
|
|
102
|
+
}
|
|
79
103
|
async resyncAccounts(accounts) {
|
|
80
|
-
await this.withSnap(async ({ keyring }) => {
|
|
104
|
+
await this.withSnap(async ({ client, keyring }) => {
|
|
81
105
|
const localSnapAccounts = accounts.filter((account) => account.metadata.snap?.id === this.snapId);
|
|
82
|
-
const snapAccounts = new Set((await
|
|
106
|
+
const snapAccounts = new Set((await client.getAccounts()).map((account) => account.id));
|
|
83
107
|
// NOTE: This should never happen, but if it does, we recover by deleting the
|
|
84
108
|
// extra accounts from the Snap to bring it back in sync with MetaMask.
|
|
85
109
|
if (localSnapAccounts.length < snapAccounts.size) {
|
|
@@ -93,7 +117,7 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
93
117
|
if (!localAccountIds.has(snapAccountId)) {
|
|
94
118
|
// This account exists in the Snap but not in MetaMask, delete it from
|
|
95
119
|
// the Snap.
|
|
96
|
-
await
|
|
120
|
+
await client.deleteAccount(snapAccountId);
|
|
97
121
|
// Update the local Set so subsequent checks use the correct size
|
|
98
122
|
snapAccounts.delete(snapAccountId);
|
|
99
123
|
}
|
|
@@ -145,10 +169,12 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
145
169
|
}
|
|
146
170
|
async withSnap(operation) {
|
|
147
171
|
await this.ensureReady();
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
172
|
+
const client = await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_resolveClient).call(this);
|
|
173
|
+
const keyring = {
|
|
174
|
+
createAccounts: (options) => __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, ({ keyring: snapKeyring }) => snapKeyring.createAccounts(options)),
|
|
175
|
+
deleteAccount: (id) => __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, ({ keyring: snapKeyring }) => snapKeyring.deleteAccount(id)),
|
|
176
|
+
};
|
|
177
|
+
return await operation({ client, keyring });
|
|
152
178
|
}
|
|
153
179
|
toBip44Account(account, _options) {
|
|
154
180
|
(0, account_api_1.assertIsBip44Account)(account);
|
|
@@ -156,55 +182,17 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
156
182
|
}
|
|
157
183
|
async createBip44Accounts(keyring, options) {
|
|
158
184
|
return this.withMaxConcurrency(async () => {
|
|
159
|
-
let groupIndexOffset = 0;
|
|
160
|
-
let snapAccounts = [];
|
|
161
|
-
const batched = this.config.createAccounts.batched ?? false;
|
|
162
185
|
const { entropySource } = options;
|
|
163
|
-
const
|
|
164
|
-
name: analytics_1.TraceName.ProviderCreateAccountV1,
|
|
165
|
-
data: {
|
|
166
|
-
provider: this.getName(),
|
|
167
|
-
groupIndex,
|
|
168
|
-
},
|
|
169
|
-
}, () => this.createAccountV1(keyring, { entropySource, groupIndex })), this.config.createAccounts.timeoutMs);
|
|
170
|
-
const createAccountsV2 = async (optionsV2) => await (0, utils_1.withTimeout)(() => this.trace({
|
|
186
|
+
const snapAccounts = await (0, utils_1.withTimeout)(() => this.trace({
|
|
171
187
|
name: analytics_1.TraceName.ProviderCreateAccounts,
|
|
172
188
|
data: {
|
|
173
189
|
provider: this.getName(),
|
|
174
|
-
...(0, analytics_1.toCreateAccountsV2DataTraces)(
|
|
190
|
+
...(0, analytics_1.toCreateAccountsV2DataTraces)(options),
|
|
175
191
|
},
|
|
176
|
-
}, () => keyring.createAccounts(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
snapAccounts = await createAccountsV2(options);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
const { range } = options;
|
|
184
|
-
// Create accounts one by one.
|
|
185
|
-
for (let groupIndex = range.from; groupIndex <= range.to; groupIndex++) {
|
|
186
|
-
const snapAccount = await createAccountV1(groupIndex);
|
|
187
|
-
snapAccounts.push(snapAccount);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
// Group indices are sequential, so we just need the starting index.
|
|
191
|
-
groupIndexOffset = options.range.from;
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
if (batched) {
|
|
195
|
-
// Create account using new v2-like flow (no async flow + no Snap keyring events).
|
|
196
|
-
snapAccounts = await createAccountsV2(options);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
const { groupIndex } = options;
|
|
200
|
-
// Create account using the existing v1 flow.
|
|
201
|
-
const snapAccount = await createAccountV1(groupIndex);
|
|
202
|
-
snapAccounts = [snapAccount];
|
|
203
|
-
}
|
|
204
|
-
// For single account, there will only be 1 account, so we can use the
|
|
205
|
-
// provided group index directly.
|
|
206
|
-
groupIndexOffset = options.groupIndex;
|
|
207
|
-
}
|
|
192
|
+
}, () => keyring.createAccounts(options)), this.config.createAccounts.timeoutMs);
|
|
193
|
+
const groupIndexOffset = options.type === `${keyring_api_1.AccountCreationType.Bip44DeriveIndexRange}`
|
|
194
|
+
? options.range.from
|
|
195
|
+
: options.groupIndex;
|
|
208
196
|
return snapAccounts.map((snapAccount, index) => {
|
|
209
197
|
const groupIndex = groupIndexOffset + index;
|
|
210
198
|
const account = this.toBip44Account(snapAccount, {
|
|
@@ -240,36 +228,68 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
240
228
|
});
|
|
241
229
|
this.accounts.delete(id);
|
|
242
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Discovers accounts for the given entropy source and group index.
|
|
233
|
+
*
|
|
234
|
+
* v2 Snaps drive discovery through `createAccounts({ bip44:discover })`: the
|
|
235
|
+
* Snap checks for on-chain activity (using its own supported scopes) and
|
|
236
|
+
* returns the created account(s), or nothing once discovery is exhausted.
|
|
237
|
+
*
|
|
238
|
+
* v1 Snaps use the client's `discoverAccounts` to detect activity on
|
|
239
|
+
* {@link v1DiscoveryScopes}, then create the account for the group index.
|
|
240
|
+
*
|
|
241
|
+
* @param options - The discovery options.
|
|
242
|
+
* @param options.entropySource - The entropy source to discover accounts for.
|
|
243
|
+
* @param options.groupIndex - The group index to discover accounts for.
|
|
244
|
+
* @returns The discovered (and created) accounts, or an empty array when
|
|
245
|
+
* there is nothing to discover at this group index.
|
|
246
|
+
*/
|
|
247
|
+
async discoverAccounts({ entropySource, groupIndex, }) {
|
|
248
|
+
return this.withSnap(async ({ client, keyring }) => this.trace({
|
|
249
|
+
name: analytics_1.TraceName.SnapDiscoverAccounts,
|
|
250
|
+
data: {
|
|
251
|
+
provider: this.getName(),
|
|
252
|
+
},
|
|
253
|
+
}, async () => {
|
|
254
|
+
if (!this.config.discovery.enabled) {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
if (this.isV2()) {
|
|
258
|
+
// The v2 client has no `discoverAccounts`, so discovery is only
|
|
259
|
+
// possible when the Snap supports `bip44:discover`. Otherwise there
|
|
260
|
+
// is no way to discover and we report nothing.
|
|
261
|
+
if (!this.capabilities.bip44?.discover) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
// v2: the Snap detects on-chain activity and creates the account in
|
|
265
|
+
// a single `createAccounts({ bip44:discover })` call. An empty
|
|
266
|
+
// result means discovery is exhausted at this group index.
|
|
267
|
+
return this.createBip44Accounts(keyring, {
|
|
268
|
+
type: keyring_api_1.AccountCreationType.Bip44Discover,
|
|
269
|
+
entropySource,
|
|
270
|
+
groupIndex,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
// v1: detect activity via the client, then create the account for
|
|
274
|
+
// this group index.
|
|
275
|
+
const discoveredAccounts = await (0, utils_1.withRetry)(() => (0, utils_1.withTimeout)(() => client.discoverAccounts(this.v1DiscoveryScopes, entropySource, groupIndex), this.config.discovery.timeoutMs), {
|
|
276
|
+
maxAttempts: this.config.discovery.maxAttempts,
|
|
277
|
+
backOffMs: this.config.discovery.backOffMs,
|
|
278
|
+
});
|
|
279
|
+
if (!discoveredAccounts.length) {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
return this.createBip44Accounts(keyring, {
|
|
283
|
+
type: keyring_api_1.AccountCreationType.Bip44DeriveIndex,
|
|
284
|
+
entropySource,
|
|
285
|
+
groupIndex,
|
|
286
|
+
});
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
243
289
|
}
|
|
244
290
|
exports.SnapAccountProvider = SnapAccountProvider;
|
|
245
|
-
_SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_queue = new WeakMap(), _SnapAccountProvider_trace = new WeakMap(), _SnapAccountProvider_instances = new WeakSet(),
|
|
246
|
-
// NOTE: We're not supposed to make the keyring instance escape `withKeyringV2` but
|
|
247
|
-
// we have to use the `SnapKeyringV2` instance to be able to create Solana account
|
|
248
|
-
// without triggering UI confirmation.
|
|
249
|
-
// Also, creating account that way won't invalidate the Snap keyring state. The
|
|
250
|
-
// account will get created and persisted properly with the Snap account creation
|
|
251
|
-
// flow "asynchronously" (with `notify:accountCreated`).
|
|
252
|
-
const { createAccount, createAccounts } = await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => ({
|
|
253
|
-
createAccount: keyring.createAccount.bind(keyring),
|
|
254
|
-
createAccounts: keyring.createAccounts.bind(keyring),
|
|
255
|
-
}));
|
|
291
|
+
_SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_sender = new WeakMap(), _SnapAccountProvider_queue = new WeakMap(), _SnapAccountProvider_trace = new WeakMap(), _SnapAccountProvider_instances = new WeakSet(), _SnapAccountProvider_createSender = function _SnapAccountProvider_createSender(snapId) {
|
|
256
292
|
return {
|
|
257
|
-
createAccount: async (options) =>
|
|
258
|
-
// We use the "unguarded" account creation here (see explanation above).
|
|
259
|
-
await createAccount(options, {
|
|
260
|
-
displayAccountNameSuggestion: false,
|
|
261
|
-
displayConfirmation: false,
|
|
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 }) => {
|
|
268
|
-
await keyring.deleteAccount(id);
|
|
269
|
-
}),
|
|
270
|
-
};
|
|
271
|
-
}, _SnapAccountProvider_getKeyringClientFromSnapId = function _SnapAccountProvider_getKeyringClientFromSnapId(snapId) {
|
|
272
|
-
return new keyring_snap_client_1.KeyringClient({
|
|
273
293
|
send: async (request) => {
|
|
274
294
|
const response = await this.messenger.call('SnapController:handleRequest', {
|
|
275
295
|
snapId: snapId,
|
|
@@ -279,7 +299,26 @@ _SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_queue = new We
|
|
|
279
299
|
});
|
|
280
300
|
return response;
|
|
281
301
|
},
|
|
282
|
-
}
|
|
302
|
+
};
|
|
303
|
+
}, _SnapAccountProvider_resolveClient =
|
|
304
|
+
/**
|
|
305
|
+
* Resolves the version-agnostic keyring client, fetching the Snap's
|
|
306
|
+
* capabilities from `SnapAccountService` on first use and caching both the
|
|
307
|
+
* capabilities and the resulting client.
|
|
308
|
+
*
|
|
309
|
+
* Callers must ensure the Snap is ready (via
|
|
310
|
+
* {@link SnapAccountProvider.ensureReady}) beforehand so that the
|
|
311
|
+
* capabilities are reliably populated — {@link SnapAccountProvider.withSnap}
|
|
312
|
+
* guarantees this ordering.
|
|
313
|
+
*
|
|
314
|
+
* @returns The resolved {@link SnapKeyringClient}.
|
|
315
|
+
*/
|
|
316
|
+
async function _SnapAccountProvider_resolveClient() {
|
|
317
|
+
if (!__classPrivateFieldGet(this, _SnapAccountProvider_client, "f")) {
|
|
318
|
+
this.capabilities = await this.messenger.call('SnapAccountService:getCapabilities', this.snapId);
|
|
319
|
+
__classPrivateFieldSet(this, _SnapAccountProvider_client, (0, SnapKeyringClient_1.createSnapKeyringClient)(__classPrivateFieldGet(this, _SnapAccountProvider_sender, "f"), this.isV2()), "f");
|
|
320
|
+
}
|
|
321
|
+
return __classPrivateFieldGet(this, _SnapAccountProvider_client, "f");
|
|
283
322
|
}, _SnapAccountProvider_withSnapKeyring = async function _SnapAccountProvider_withSnapKeyring(operation) {
|
|
284
323
|
return this.withKeyringV2({
|
|
285
324
|
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":"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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 {\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\n/**\n * A proxy to the Snap's keyring operations that routes every call through the\n * `KeyringController` mutex (via {@link SnapAccountProvider.#withSnapKeyring}).\n * Callers receive this object from {@link SnapAccountProvider.withSnap} and\n * never interact with the raw keyring or the mutex directly.\n */\nexport type SnapKeyringProxy = {\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 * Once this resolves, a Snap keyring for {@link snapId} is guaranteed to\n * exist in the `KeyringController`, so subsequent {@link #withSnapKeyring}\n * calls will not fail with \"No keyring matches the selector\".\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 #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: SnapKeyringProxy;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n await this.ensureReady();\n const client = await this.#resolveClient();\n const keyring: SnapKeyringProxy = {\n createAccounts: (options) =>\n this.#withSnapKeyring(({ keyring: snapKeyring }) =>\n snapKeyring.createAccounts(options),\n ),\n deleteAccount: (id) =>\n this.#withSnapKeyring(({ keyring: snapKeyring }) =>\n snapKeyring.deleteAccount(id),\n ),\n };\n return await operation({ client, keyring });\n }\n\n abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;\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: SnapKeyringProxy,\n options:\n | CreateAccountBip44DeriveIndexOptions\n | CreateAccountBip44DeriveIndexRangeOptions\n | CreateAccountBip44DiscoverOptions,\n ): Promise<Bip44Account<KeyringAccount>[]> {\n return this.withMaxConcurrency(async () => {\n const { entropySource } = options;\n\n const snapAccounts = await withTimeout(\n () =>\n this.trace(\n {\n name: TraceName.ProviderCreateAccounts,\n data: {\n provider: this.getName(),\n ...toCreateAccountsV2DataTraces(options),\n },\n },\n () => keyring.createAccounts(options),\n ),\n this.config.createAccounts.timeoutMs,\n );\n\n const groupIndexOffset =\n options.type === `${AccountCreationType.Bip44DeriveIndexRange}`\n ? options.range.from\n : options.groupIndex;\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,21 @@
|
|
|
1
1
|
import type { Bip44Account } from "@metamask/account-api";
|
|
2
2
|
import type { TraceCallback, TraceRequest } from "@metamask/controller-utils";
|
|
3
3
|
import type { SnapKeyring as SnapKeyringV2 } from "@metamask/eth-snap-keyring/v2";
|
|
4
|
-
import type { CreateAccountBip44DeriveIndexOptions, CreateAccountBip44DeriveIndexRangeOptions, CreateAccountOptions, EntropySourceId, KeyringAccount } from "@metamask/keyring-api";
|
|
4
|
+
import type { CreateAccountBip44DeriveIndexOptions, CreateAccountBip44DeriveIndexRangeOptions, CreateAccountBip44DiscoverOptions, CreateAccountOptions, EntropySourceId, KeyringAccount } from "@metamask/keyring-api";
|
|
5
|
+
import type { KeyringCapabilities } from "@metamask/keyring-api/v2";
|
|
5
6
|
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
6
|
-
import { KeyringClient } from "@metamask/keyring-snap-client";
|
|
7
7
|
import type { SnapId } from "@metamask/snaps-sdk";
|
|
8
|
+
import type { CaipChainId } from "@metamask/utils";
|
|
8
9
|
import type { MultichainAccountServiceMessenger } from "../types.cjs";
|
|
9
10
|
import { BaseBip44AccountProvider } from "./BaseBip44AccountProvider.cjs";
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
import type { SnapKeyringClient } from "./SnapKeyringClient.cjs";
|
|
12
|
+
/**
|
|
13
|
+
* A proxy to the Snap's keyring operations that routes every call through the
|
|
14
|
+
* `KeyringController` mutex (via {@link SnapAccountProvider.#withSnapKeyring}).
|
|
15
|
+
* Callers receive this object from {@link SnapAccountProvider.withSnap} and
|
|
16
|
+
* never interact with the raw keyring or the mutex directly.
|
|
17
|
+
*/
|
|
18
|
+
export type SnapKeyringProxy = {
|
|
12
19
|
createAccounts: SnapKeyringV2['createAccounts'];
|
|
13
20
|
deleteAccount: SnapKeyringV2['deleteAccount'];
|
|
14
21
|
};
|
|
@@ -21,18 +28,12 @@ export type SnapAccountProviderConfig = {
|
|
|
21
28
|
backOffMs: number;
|
|
22
29
|
};
|
|
23
30
|
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
31
|
/**
|
|
33
32
|
* Timeout for account creation operations.
|
|
34
33
|
*
|
|
35
|
-
* NOTE:
|
|
34
|
+
* NOTE: Batching (and thus whether a single call may create multiple
|
|
35
|
+
* accounts) is driven by the Snap's declared capabilities, not this config.
|
|
36
|
+
* The value might have to be adapted when the Snap supports batching.
|
|
36
37
|
*/
|
|
37
38
|
timeoutMs: number;
|
|
38
39
|
};
|
|
@@ -49,10 +50,28 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
49
50
|
#private;
|
|
50
51
|
readonly snapId: SnapId;
|
|
51
52
|
protected readonly config: SnapAccountProviderConfig;
|
|
53
|
+
/**
|
|
54
|
+
* The Snap's keyring capabilities, sourced from `SnapAccountService` (which
|
|
55
|
+
* reads them from the Snap's manifest). Populated the first time the client
|
|
56
|
+
* is resolved; defaults to an empty capability set until then.
|
|
57
|
+
*/
|
|
58
|
+
capabilities: KeyringCapabilities;
|
|
59
|
+
/**
|
|
60
|
+
* Scopes passed to the v1 `discoverAccounts` client method. Only used on the
|
|
61
|
+
* v1 discovery path.
|
|
62
|
+
*
|
|
63
|
+
* TODO: Remove once all Snaps are fully v2 — discovery is then driven by the
|
|
64
|
+
* Snap's own supported scopes via `createAccounts({ bip44:discover })`.
|
|
65
|
+
*/
|
|
66
|
+
protected abstract readonly v1DiscoveryScopes: CaipChainId[];
|
|
52
67
|
constructor(snapId: SnapId, messenger: MultichainAccountServiceMessenger, config: SnapAccountProviderConfig, trace?: TraceCallback);
|
|
53
68
|
/**
|
|
54
69
|
* Ensures that the Snap is ready to be used.
|
|
55
70
|
*
|
|
71
|
+
* Once this resolves, a Snap keyring for {@link snapId} is guaranteed to
|
|
72
|
+
* exist in the `KeyringController`, so subsequent {@link #withSnapKeyring}
|
|
73
|
+
* calls will not fail with "No keyring matches the selector".
|
|
74
|
+
*
|
|
56
75
|
* @returns A promise that resolves when the Snap is ready.
|
|
57
76
|
* @throws An error if the Snap could not become ready.
|
|
58
77
|
*/
|
|
@@ -67,21 +86,24 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
67
86
|
*/
|
|
68
87
|
protected withMaxConcurrency<Result>(operation: () => Promise<Result>): Promise<Result>;
|
|
69
88
|
protected trace<ReturnType>(request: TraceRequest, fn: () => Promise<ReturnType>): Promise<ReturnType>;
|
|
89
|
+
/**
|
|
90
|
+
* Whether the Snap supports the v2 keyring protocol, inferred from its
|
|
91
|
+
* declared capabilities (a v2-capable Snap declares BIP-44 capabilities).
|
|
92
|
+
*
|
|
93
|
+
* @returns `true` if the Snap is v2-capable.
|
|
94
|
+
*/
|
|
95
|
+
protected isV2(): boolean;
|
|
70
96
|
resyncAccounts(accounts: Bip44Account<InternalAccount>[]): Promise<void>;
|
|
71
97
|
protected withSnap<CallbackResult = void>(operation: (snap: {
|
|
72
|
-
client:
|
|
73
|
-
keyring:
|
|
98
|
+
client: SnapKeyringClient;
|
|
99
|
+
keyring: SnapKeyringProxy;
|
|
74
100
|
}) => Promise<CallbackResult>): Promise<CallbackResult>;
|
|
75
101
|
abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;
|
|
76
|
-
protected abstract createAccountV1(keyring: RestrictedSnapKeyring, options: {
|
|
77
|
-
entropySource: EntropySourceId;
|
|
78
|
-
groupIndex: number;
|
|
79
|
-
}): Promise<KeyringAccount>;
|
|
80
102
|
protected toBip44Account(account: KeyringAccount, _options: {
|
|
81
103
|
entropySource: EntropySourceId;
|
|
82
104
|
groupIndex: number;
|
|
83
105
|
}): Bip44Account<KeyringAccount>;
|
|
84
|
-
protected createBip44Accounts(keyring:
|
|
106
|
+
protected createBip44Accounts(keyring: SnapKeyringProxy, options: CreateAccountBip44DeriveIndexOptions | CreateAccountBip44DeriveIndexRangeOptions | CreateAccountBip44DiscoverOptions): Promise<Bip44Account<KeyringAccount>[]>;
|
|
85
107
|
createAccounts(options: CreateAccountOptions): Promise<Bip44Account<KeyringAccount>[]>;
|
|
86
108
|
/**
|
|
87
109
|
* Delete a snap account by id.
|
|
@@ -94,7 +116,23 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
94
116
|
* @param id - The id of the account to delete.
|
|
95
117
|
*/
|
|
96
118
|
deleteAccount(id: Bip44Account<KeyringAccount>['id']): Promise<void>;
|
|
97
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Discovers accounts for the given entropy source and group index.
|
|
121
|
+
*
|
|
122
|
+
* v2 Snaps drive discovery through `createAccounts({ bip44:discover })`: the
|
|
123
|
+
* Snap checks for on-chain activity (using its own supported scopes) and
|
|
124
|
+
* returns the created account(s), or nothing once discovery is exhausted.
|
|
125
|
+
*
|
|
126
|
+
* v1 Snaps use the client's `discoverAccounts` to detect activity on
|
|
127
|
+
* {@link v1DiscoveryScopes}, then create the account for the group index.
|
|
128
|
+
*
|
|
129
|
+
* @param options - The discovery options.
|
|
130
|
+
* @param options.entropySource - The entropy source to discover accounts for.
|
|
131
|
+
* @param options.groupIndex - The group index to discover accounts for.
|
|
132
|
+
* @returns The discovered (and created) accounts, or an empty array when
|
|
133
|
+
* there is nothing to discover at this group index.
|
|
134
|
+
*/
|
|
135
|
+
discoverAccounts({ entropySource, groupIndex, }: {
|
|
98
136
|
entropySource: EntropySourceId;
|
|
99
137
|
groupIndex: number;
|
|
100
138
|
}): 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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"}
|