@metamask-previews/multichain-account-service 0.7.0-preview-ea6406b3 → 0.7.0-preview-9a5f096
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 +20 -0
- package/dist/MultichainAccountService.cjs +2 -11
- package/dist/MultichainAccountService.cjs.map +1 -1
- package/dist/MultichainAccountService.d.cts +0 -6
- package/dist/MultichainAccountService.d.cts.map +1 -1
- package/dist/MultichainAccountService.d.mts +0 -6
- package/dist/MultichainAccountService.d.mts.map +1 -1
- package/dist/MultichainAccountService.mjs +2 -11
- package/dist/MultichainAccountService.mjs.map +1 -1
- package/dist/MultichainAccountWallet.cjs +183 -156
- package/dist/MultichainAccountWallet.cjs.map +1 -1
- package/dist/MultichainAccountWallet.d.cts +17 -15
- package/dist/MultichainAccountWallet.d.cts.map +1 -1
- package/dist/MultichainAccountWallet.d.mts +17 -15
- package/dist/MultichainAccountWallet.d.mts.map +1 -1
- package/dist/MultichainAccountWallet.mjs +183 -156
- package/dist/MultichainAccountWallet.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/providers/AccountProviderWrapper.cjs +2 -2
- package/dist/providers/AccountProviderWrapper.cjs.map +1 -1
- package/dist/providers/AccountProviderWrapper.d.cts +1 -1
- package/dist/providers/AccountProviderWrapper.d.cts.map +1 -1
- package/dist/providers/AccountProviderWrapper.d.mts +1 -1
- package/dist/providers/AccountProviderWrapper.d.mts.map +1 -1
- package/dist/providers/AccountProviderWrapper.mjs +2 -2
- package/dist/providers/AccountProviderWrapper.mjs.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.cjs.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.d.cts +1 -1
- package/dist/providers/BaseBip44AccountProvider.d.cts.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.d.mts +1 -1
- package/dist/providers/BaseBip44AccountProvider.d.mts.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.mjs.map +1 -1
- package/dist/providers/EvmAccountProvider.cjs +1 -1
- package/dist/providers/EvmAccountProvider.cjs.map +1 -1
- package/dist/providers/EvmAccountProvider.d.cts +1 -1
- package/dist/providers/EvmAccountProvider.d.cts.map +1 -1
- package/dist/providers/EvmAccountProvider.d.mts +1 -1
- package/dist/providers/EvmAccountProvider.d.mts.map +1 -1
- package/dist/providers/EvmAccountProvider.mjs +1 -1
- package/dist/providers/EvmAccountProvider.mjs.map +1 -1
- package/dist/providers/SnapAccountProvider.cjs.map +1 -1
- package/dist/providers/SnapAccountProvider.d.cts +1 -1
- package/dist/providers/SnapAccountProvider.d.cts.map +1 -1
- package/dist/providers/SnapAccountProvider.d.mts +1 -1
- package/dist/providers/SnapAccountProvider.d.mts.map +1 -1
- package/dist/providers/SnapAccountProvider.mjs.map +1 -1
- package/dist/providers/SolAccountProvider.cjs +1 -1
- package/dist/providers/SolAccountProvider.cjs.map +1 -1
- package/dist/providers/SolAccountProvider.d.cts +1 -1
- package/dist/providers/SolAccountProvider.d.cts.map +1 -1
- package/dist/providers/SolAccountProvider.d.mts +1 -1
- package/dist/providers/SolAccountProvider.d.mts.map +1 -1
- package/dist/providers/SolAccountProvider.mjs +1 -1
- package/dist/providers/SolAccountProvider.mjs.map +1 -1
- package/dist/tests/accounts.cjs +2 -2
- package/dist/tests/accounts.cjs.map +1 -1
- package/dist/tests/accounts.mjs +2 -2
- package/dist/tests/accounts.mjs.map +1 -1
- package/dist/tests/providers.cjs +5 -4
- package/dist/tests/providers.cjs.map +1 -1
- package/dist/tests/providers.d.cts +3 -2
- package/dist/tests/providers.d.cts.map +1 -1
- package/dist/tests/providers.d.mts +3 -2
- package/dist/tests/providers.d.mts.map +1 -1
- package/dist/tests/providers.mjs +3 -2
- package/dist/tests/providers.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +7 -7
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +7 -7
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +9 -8
|
@@ -10,13 +10,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _MultichainAccountWallet_id, _MultichainAccountWallet_providers, _MultichainAccountWallet_entropySource, _MultichainAccountWallet_accountGroups, _MultichainAccountWallet_messenger, _MultichainAccountWallet_initialized,
|
|
13
|
+
var _MultichainAccountWallet_instances, _MultichainAccountWallet_lock, _MultichainAccountWallet_id, _MultichainAccountWallet_providers, _MultichainAccountWallet_entropySource, _MultichainAccountWallet_accountGroups, _MultichainAccountWallet_messenger, _MultichainAccountWallet_initialized, _MultichainAccountWallet_status, _MultichainAccountWallet_withLock, _MultichainAccountWallet_alignAccounts;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.MultichainAccountWallet = void 0;
|
|
16
16
|
const account_api_1 = require("@metamask/account-api");
|
|
17
17
|
const account_api_2 = require("@metamask/account-api");
|
|
18
18
|
const account_api_3 = require("@metamask/account-api");
|
|
19
19
|
const utils_1 = require("@metamask/utils");
|
|
20
|
+
const async_mutex_1 = require("async-mutex");
|
|
20
21
|
const MultichainAccountGroup_1 = require("./MultichainAccountGroup.cjs");
|
|
21
22
|
const log = (0, utils_1.createProjectLogger)('multichain-account-service');
|
|
22
23
|
/**
|
|
@@ -25,6 +26,8 @@ const log = (0, utils_1.createProjectLogger)('multichain-account-service');
|
|
|
25
26
|
*/
|
|
26
27
|
class MultichainAccountWallet {
|
|
27
28
|
constructor({ providers, entropySource, messenger, }) {
|
|
29
|
+
_MultichainAccountWallet_instances.add(this);
|
|
30
|
+
_MultichainAccountWallet_lock.set(this, new async_mutex_1.Mutex());
|
|
28
31
|
_MultichainAccountWallet_id.set(this, void 0);
|
|
29
32
|
_MultichainAccountWallet_providers.set(this, void 0);
|
|
30
33
|
_MultichainAccountWallet_entropySource.set(this, void 0);
|
|
@@ -32,15 +35,17 @@ class MultichainAccountWallet {
|
|
|
32
35
|
_MultichainAccountWallet_messenger.set(this, void 0);
|
|
33
36
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly
|
|
34
37
|
_MultichainAccountWallet_initialized.set(this, false);
|
|
35
|
-
|
|
38
|
+
_MultichainAccountWallet_status.set(this, void 0);
|
|
36
39
|
__classPrivateFieldSet(this, _MultichainAccountWallet_id, (0, account_api_1.toMultichainAccountWalletId)(entropySource), "f");
|
|
37
40
|
__classPrivateFieldSet(this, _MultichainAccountWallet_providers, providers, "f");
|
|
38
41
|
__classPrivateFieldSet(this, _MultichainAccountWallet_entropySource, entropySource, "f");
|
|
39
42
|
__classPrivateFieldSet(this, _MultichainAccountWallet_messenger, messenger, "f");
|
|
40
43
|
__classPrivateFieldSet(this, _MultichainAccountWallet_accountGroups, new Map(), "f");
|
|
41
44
|
// Initial synchronization (don't emit events during initialization).
|
|
45
|
+
__classPrivateFieldSet(this, _MultichainAccountWallet_status, 'uninitialized', "f");
|
|
42
46
|
this.sync();
|
|
43
47
|
__classPrivateFieldSet(this, _MultichainAccountWallet_initialized, true, "f");
|
|
48
|
+
__classPrivateFieldSet(this, _MultichainAccountWallet_status, 'ready', "f");
|
|
44
49
|
}
|
|
45
50
|
/**
|
|
46
51
|
* Force wallet synchronization.
|
|
@@ -111,6 +116,14 @@ class MultichainAccountWallet {
|
|
|
111
116
|
get entropySource() {
|
|
112
117
|
return __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f");
|
|
113
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Gets the multichain account wallet current status.
|
|
121
|
+
*
|
|
122
|
+
* @returns The multichain account wallet current status.
|
|
123
|
+
*/
|
|
124
|
+
get status() {
|
|
125
|
+
return __classPrivateFieldGet(this, _MultichainAccountWallet_status, "f");
|
|
126
|
+
}
|
|
114
127
|
/**
|
|
115
128
|
* Gets multichain account for a given ID.
|
|
116
129
|
* The default group ID will default to the multichain account with index 0.
|
|
@@ -169,80 +182,84 @@ class MultichainAccountWallet {
|
|
|
169
182
|
/**
|
|
170
183
|
* Creates a multichain account group for a given group index.
|
|
171
184
|
*
|
|
185
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
186
|
+
*
|
|
172
187
|
* @param groupIndex - The group index to use.
|
|
173
188
|
* @throws If any of the account providers fails to create their accounts.
|
|
174
189
|
* @returns The multichain account group for this group index.
|
|
175
190
|
*/
|
|
176
191
|
async createMultichainAccountGroup(groupIndex) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
let group = this.getMultichainAccountGroup(groupIndex);
|
|
182
|
-
if (group) {
|
|
183
|
-
// If the group already exists, we just `sync` it and returns the same
|
|
184
|
-
// reference.
|
|
185
|
-
group.sync();
|
|
186
|
-
return group;
|
|
187
|
-
}
|
|
188
|
-
const results = await Promise.allSettled(__classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f").map((provider) => provider.createAccounts({
|
|
189
|
-
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
190
|
-
groupIndex,
|
|
191
|
-
})));
|
|
192
|
-
// --------------------------------------------------------------------------------
|
|
193
|
-
// READ THIS CAREFULLY:
|
|
194
|
-
//
|
|
195
|
-
// Since we're not "fully supporting multichain" for now, we still rely on single
|
|
196
|
-
// :accountCreated events to sync multichain account groups and wallets. Which means
|
|
197
|
-
// that even if of the provider fails, some accounts will still be created on some
|
|
198
|
-
// other providers and will become "available" on the `AccountsController`, like:
|
|
199
|
-
//
|
|
200
|
-
// 1. Creating a multichain account group for index 1
|
|
201
|
-
// 2. EvmAccountProvider.createAccounts returns the EVM account for index 1
|
|
202
|
-
// * AccountsController WILL fire :accountCreated for this account
|
|
203
|
-
// * This account WILL BE "available" on the AccountsController state
|
|
204
|
-
// 3. SolAccountProvider.createAccounts fails to create a Solana account for index 1
|
|
205
|
-
// * AccountsController WON't fire :accountCreated for this account
|
|
206
|
-
// * This account WON'T be "available" on the Account
|
|
207
|
-
// 4. MultichainAccountService will receive a :accountCreated for the EVM account from
|
|
208
|
-
// step 2 and will create a new multichain account group for index 1, but it won't
|
|
209
|
-
// receive any event for the Solana account of this group. Thus, this group won't be
|
|
210
|
-
// "aligned" (missing "blockchain account" on this group).
|
|
211
|
-
//
|
|
212
|
-
// --------------------------------------------------------------------------------
|
|
213
|
-
// If any of the provider failed to create their accounts, then we consider the
|
|
214
|
-
// multichain account group to have failed too.
|
|
215
|
-
if (results.some((result) => result.status === 'rejected')) {
|
|
216
|
-
// NOTE: Some accounts might still have been created on other account providers. We
|
|
217
|
-
// don't rollback them.
|
|
218
|
-
const error = `Unable to create multichain account group for index: ${groupIndex}`;
|
|
219
|
-
let warn = `${error}:`;
|
|
220
|
-
for (const result of results) {
|
|
221
|
-
if (result.status === 'rejected') {
|
|
222
|
-
warn += `\n- ${result.reason}`;
|
|
223
|
-
}
|
|
192
|
+
return await __classPrivateFieldGet(this, _MultichainAccountWallet_instances, "m", _MultichainAccountWallet_withLock).call(this, 'in-progress:create-accounts', async () => {
|
|
193
|
+
const nextGroupIndex = this.getNextGroupIndex();
|
|
194
|
+
if (groupIndex > nextGroupIndex) {
|
|
195
|
+
throw new Error(`You cannot use a group index that is higher than the next available one: expected <=${nextGroupIndex}, got ${groupIndex}`);
|
|
224
196
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
wallet: this,
|
|
235
|
-
providers: __classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f"),
|
|
197
|
+
let group = this.getMultichainAccountGroup(groupIndex);
|
|
198
|
+
if (group) {
|
|
199
|
+
// If the group already exists, we just `sync` it and returns the same
|
|
200
|
+
// reference.
|
|
201
|
+
group.sync();
|
|
202
|
+
return group;
|
|
203
|
+
}
|
|
204
|
+
const results = await Promise.allSettled(__classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f").map((provider) => provider.createAccounts({
|
|
205
|
+
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
236
206
|
groupIndex,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
207
|
+
})));
|
|
208
|
+
// --------------------------------------------------------------------------------
|
|
209
|
+
// READ THIS CAREFULLY:
|
|
210
|
+
//
|
|
211
|
+
// Since we're not "fully supporting multichain" for now, we still rely on single
|
|
212
|
+
// :accountCreated events to sync multichain account groups and wallets. Which means
|
|
213
|
+
// that even if of the provider fails, some accounts will still be created on some
|
|
214
|
+
// other providers and will become "available" on the `AccountsController`, like:
|
|
215
|
+
//
|
|
216
|
+
// 1. Creating a multichain account group for index 1
|
|
217
|
+
// 2. EvmAccountProvider.createAccounts returns the EVM account for index 1
|
|
218
|
+
// * AccountsController WILL fire :accountCreated for this account
|
|
219
|
+
// * This account WILL BE "available" on the AccountsController state
|
|
220
|
+
// 3. SolAccountProvider.createAccounts fails to create a Solana account for index 1
|
|
221
|
+
// * AccountsController WON't fire :accountCreated for this account
|
|
222
|
+
// * This account WON'T be "available" on the Account
|
|
223
|
+
// 4. MultichainAccountService will receive a :accountCreated for the EVM account from
|
|
224
|
+
// step 2 and will create a new multichain account group for index 1, but it won't
|
|
225
|
+
// receive any event for the Solana account of this group. Thus, this group won't be
|
|
226
|
+
// "aligned" (missing "blockchain account" on this group).
|
|
227
|
+
//
|
|
228
|
+
// --------------------------------------------------------------------------------
|
|
229
|
+
// If any of the provider failed to create their accounts, then we consider the
|
|
230
|
+
// multichain account group to have failed too.
|
|
231
|
+
if (results.some((result) => result.status === 'rejected')) {
|
|
232
|
+
// NOTE: Some accounts might still have been created on other account providers. We
|
|
233
|
+
// don't rollback them.
|
|
234
|
+
const error = `Unable to create multichain account group for index: ${groupIndex}`;
|
|
235
|
+
let warn = `${error}:`;
|
|
236
|
+
for (const result of results) {
|
|
237
|
+
if (result.status === 'rejected') {
|
|
238
|
+
warn += `\n- ${result.reason}`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
console.warn(warn);
|
|
242
|
+
throw new Error(error);
|
|
243
|
+
}
|
|
244
|
+
// Because of the :accountAdded automatic sync, we might already have created the
|
|
245
|
+
// group, so we first try to get it.
|
|
246
|
+
group = this.getMultichainAccountGroup(groupIndex);
|
|
247
|
+
if (!group) {
|
|
248
|
+
// If for some reason it's still not created, we're creating it explicitly now:
|
|
249
|
+
group = new MultichainAccountGroup_1.MultichainAccountGroup({
|
|
250
|
+
wallet: this,
|
|
251
|
+
providers: __classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f"),
|
|
252
|
+
groupIndex,
|
|
253
|
+
messenger: __classPrivateFieldGet(this, _MultichainAccountWallet_messenger, "f"),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// Register the account to our internal map.
|
|
257
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_accountGroups, "f").set(groupIndex, group); // `group` cannot be undefined here.
|
|
258
|
+
if (__classPrivateFieldGet(this, _MultichainAccountWallet_initialized, "f")) {
|
|
259
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_messenger, "f").publish('MultichainAccountService:multichainAccountGroupCreated', group);
|
|
260
|
+
}
|
|
261
|
+
return group;
|
|
262
|
+
});
|
|
246
263
|
}
|
|
247
264
|
/**
|
|
248
265
|
* Creates the next multichain account group.
|
|
@@ -254,114 +271,124 @@ class MultichainAccountWallet {
|
|
|
254
271
|
return this.createMultichainAccountGroup(this.getNextGroupIndex());
|
|
255
272
|
}
|
|
256
273
|
/**
|
|
257
|
-
*
|
|
274
|
+
* Align all accounts from each existing multichain account groups.
|
|
258
275
|
*
|
|
259
|
-
*
|
|
260
|
-
*/
|
|
261
|
-
getIsAlignmentInProgress() {
|
|
262
|
-
return __classPrivateFieldGet(this, _MultichainAccountWallet_isAlignmentInProgress, "f");
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Align all multichain account groups.
|
|
276
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
266
277
|
*/
|
|
267
|
-
async
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
__classPrivateFieldSet(this, _MultichainAccountWallet_isAlignmentInProgress, true, "f");
|
|
272
|
-
try {
|
|
273
|
-
const groups = this.getMultichainAccountGroups();
|
|
274
|
-
await Promise.all(groups.map((g) => g.align()));
|
|
275
|
-
}
|
|
276
|
-
finally {
|
|
277
|
-
__classPrivateFieldSet(this, _MultichainAccountWallet_isAlignmentInProgress, false, "f");
|
|
278
|
-
}
|
|
278
|
+
async alignAccounts() {
|
|
279
|
+
await __classPrivateFieldGet(this, _MultichainAccountWallet_instances, "m", _MultichainAccountWallet_withLock).call(this, 'in-progress:alignment', async () => {
|
|
280
|
+
await __classPrivateFieldGet(this, _MultichainAccountWallet_instances, "m", _MultichainAccountWallet_alignAccounts).call(this);
|
|
281
|
+
});
|
|
279
282
|
}
|
|
280
283
|
/**
|
|
281
284
|
* Align a specific multichain account group.
|
|
282
285
|
*
|
|
286
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
287
|
+
*
|
|
283
288
|
* @param groupIndex - The group index to align.
|
|
284
289
|
*/
|
|
285
290
|
async alignGroup(groupIndex) {
|
|
286
|
-
|
|
287
|
-
return; // Prevent concurrent alignments
|
|
288
|
-
}
|
|
289
|
-
__classPrivateFieldSet(this, _MultichainAccountWallet_isAlignmentInProgress, true, "f");
|
|
290
|
-
try {
|
|
291
|
+
await __classPrivateFieldGet(this, _MultichainAccountWallet_instances, "m", _MultichainAccountWallet_withLock).call(this, 'in-progress:alignment', async () => {
|
|
291
292
|
const group = this.getMultichainAccountGroup(groupIndex);
|
|
292
293
|
if (group) {
|
|
293
294
|
await group.align();
|
|
294
295
|
}
|
|
295
|
-
}
|
|
296
|
-
finally {
|
|
297
|
-
__classPrivateFieldSet(this, _MultichainAccountWallet_isAlignmentInProgress, false, "f");
|
|
298
|
-
}
|
|
296
|
+
});
|
|
299
297
|
}
|
|
300
298
|
/**
|
|
301
299
|
* Discover and create accounts for all providers.
|
|
302
300
|
*
|
|
301
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
302
|
+
*
|
|
303
303
|
* @returns The discovered accounts for each provider.
|
|
304
304
|
*/
|
|
305
|
-
async
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
305
|
+
async discoverAccounts() {
|
|
306
|
+
return __classPrivateFieldGet(this, _MultichainAccountWallet_instances, "m", _MultichainAccountWallet_withLock).call(this, 'in-progress:discovery', async () => {
|
|
307
|
+
// Start with the next available group index (so we can resume the discovery
|
|
308
|
+
// from there).
|
|
309
|
+
let maxGroupIndex = this.getNextGroupIndex();
|
|
310
|
+
// One serialized loop per provider; all run concurrently
|
|
311
|
+
const runProviderDiscovery = async (context) => {
|
|
312
|
+
const message = (stepName, groupIndex) => `[${context.provider.getName()}] Discovery ${stepName} (groupIndex=${groupIndex})`;
|
|
313
|
+
while (!context.stopped) {
|
|
314
|
+
// Fast‑forward to current high‑water mark
|
|
315
|
+
const targetGroupIndex = Math.max(context.groupIndex, maxGroupIndex);
|
|
316
|
+
log(message('STARTED', targetGroupIndex));
|
|
317
|
+
let accounts = [];
|
|
318
|
+
try {
|
|
319
|
+
accounts = await context.provider.discoverAccounts({
|
|
320
|
+
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
321
|
+
groupIndex: targetGroupIndex,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
context.stopped = true;
|
|
326
|
+
console.error(error);
|
|
327
|
+
log(message('FAILED', targetGroupIndex), error);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
if (!accounts.length) {
|
|
331
|
+
log(message('STOPPED', targetGroupIndex));
|
|
332
|
+
context.stopped = true;
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
log(message('SUCCEEDED', targetGroupIndex));
|
|
336
|
+
context.accounts = context.accounts.concat(accounts);
|
|
337
|
+
const nextGroupIndex = targetGroupIndex + 1;
|
|
338
|
+
context.groupIndex = nextGroupIndex;
|
|
339
|
+
if (nextGroupIndex > maxGroupIndex) {
|
|
340
|
+
maxGroupIndex = nextGroupIndex;
|
|
341
|
+
}
|
|
333
342
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// Sync the wallet after discovery to ensure that the newly added accounts are added into their groups.
|
|
352
|
-
// We can potentially remove this if we know that this race condition is not an issue in practice.
|
|
353
|
-
this.sync();
|
|
354
|
-
// Align missing accounts from group. This is required to create missing account from non-discovered
|
|
355
|
-
// indexes for some providers.
|
|
356
|
-
await this.alignGroups();
|
|
357
|
-
const discoveredAccounts = {};
|
|
358
|
-
for (const context of providerContexts) {
|
|
359
|
-
const providerName = context.provider.getName();
|
|
360
|
-
discoveredAccounts[providerName] = context.count;
|
|
361
|
-
}
|
|
362
|
-
return discoveredAccounts;
|
|
343
|
+
};
|
|
344
|
+
const providerContexts = __classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f").map((provider) => ({
|
|
345
|
+
provider,
|
|
346
|
+
stopped: false,
|
|
347
|
+
groupIndex: maxGroupIndex,
|
|
348
|
+
accounts: [],
|
|
349
|
+
}));
|
|
350
|
+
// Start discovery for each providers.
|
|
351
|
+
await Promise.all(providerContexts.map(runProviderDiscovery));
|
|
352
|
+
// Sync the wallet after discovery to ensure that the newly added accounts are added into their groups.
|
|
353
|
+
// We can potentially remove this if we know that this race condition is not an issue in practice.
|
|
354
|
+
this.sync();
|
|
355
|
+
// Align missing accounts from group. This is required to create missing account from non-discovered
|
|
356
|
+
// indexes for some providers.
|
|
357
|
+
await __classPrivateFieldGet(this, _MultichainAccountWallet_instances, "m", _MultichainAccountWallet_alignAccounts).call(this);
|
|
358
|
+
return providerContexts.flatMap((context) => context.accounts);
|
|
359
|
+
});
|
|
363
360
|
}
|
|
364
361
|
}
|
|
365
362
|
exports.MultichainAccountWallet = MultichainAccountWallet;
|
|
366
|
-
_MultichainAccountWallet_id = new WeakMap(), _MultichainAccountWallet_providers = new WeakMap(), _MultichainAccountWallet_entropySource = new WeakMap(), _MultichainAccountWallet_accountGroups = new WeakMap(), _MultichainAccountWallet_messenger = new WeakMap(), _MultichainAccountWallet_initialized = new WeakMap(),
|
|
363
|
+
_MultichainAccountWallet_lock = new WeakMap(), _MultichainAccountWallet_id = new WeakMap(), _MultichainAccountWallet_providers = new WeakMap(), _MultichainAccountWallet_entropySource = new WeakMap(), _MultichainAccountWallet_accountGroups = new WeakMap(), _MultichainAccountWallet_messenger = new WeakMap(), _MultichainAccountWallet_initialized = new WeakMap(), _MultichainAccountWallet_status = new WeakMap(), _MultichainAccountWallet_instances = new WeakSet(), _MultichainAccountWallet_withLock =
|
|
364
|
+
/**
|
|
365
|
+
* Set the wallet status and run the associated operation callback.
|
|
366
|
+
*
|
|
367
|
+
* @param status - Wallet status associated with this operation.
|
|
368
|
+
* @param operation - Operation to run.
|
|
369
|
+
* @returns The operation's result.
|
|
370
|
+
* @throws {Error} If the wallet is already running a mutable operation.
|
|
371
|
+
*/
|
|
372
|
+
async function _MultichainAccountWallet_withLock(status, operation) {
|
|
373
|
+
const release = await __classPrivateFieldGet(this, _MultichainAccountWallet_lock, "f").acquire();
|
|
374
|
+
try {
|
|
375
|
+
__classPrivateFieldSet(this, _MultichainAccountWallet_status, status, "f");
|
|
376
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_messenger, "f").publish('MultichainAccountService:walletStatusChange', this.id, __classPrivateFieldGet(this, _MultichainAccountWallet_status, "f"));
|
|
377
|
+
return await operation();
|
|
378
|
+
}
|
|
379
|
+
finally {
|
|
380
|
+
__classPrivateFieldSet(this, _MultichainAccountWallet_status, 'ready', "f");
|
|
381
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_messenger, "f").publish('MultichainAccountService:walletStatusChange', this.id, __classPrivateFieldGet(this, _MultichainAccountWallet_status, "f"));
|
|
382
|
+
release();
|
|
383
|
+
}
|
|
384
|
+
}, _MultichainAccountWallet_alignAccounts =
|
|
385
|
+
/**
|
|
386
|
+
* Align all multichain account groups.
|
|
387
|
+
*
|
|
388
|
+
* NOTE: This operation WILL NOT lock the wallet's mutex.
|
|
389
|
+
*/
|
|
390
|
+
async function _MultichainAccountWallet_alignAccounts() {
|
|
391
|
+
const groups = this.getMultichainAccountGroups();
|
|
392
|
+
await Promise.all(groups.map((group) => group.align()));
|
|
393
|
+
};
|
|
367
394
|
//# sourceMappingURL=MultichainAccountWallet.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAccountWallet.cjs","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,uDAI+B;AAC/B,uDAAgE;AAChE,uDAA0D;AAW1D,2CAAsD;AAEtD,yEAAkE;AAqBlE,MAAM,GAAG,GAAG,IAAA,2BAAmB,EAAC,4BAA4B,CAAC,CAAC;AAE9D;;;GAGG;AACH,MAAa,uBAAuB;IAmBlC,YAAY,EACV,SAAS,EACT,aAAa,EACb,SAAS,GAKV;QAvBQ,8CAA+B;QAE/B,qDAA4C;QAE5C,yDAAgC;QAEhC,yDAA6D;QAE7D,qDAA8C;QAEvD,8DAA8D;QAC9D,+CAAe,KAAK,EAAC;QAErB,yDAAkC,KAAK,EAAC;QAWtC,uBAAA,IAAI,+BAAO,IAAA,yCAA2B,EAAC,aAAa,CAAC,MAAA,CAAC;QACtD,uBAAA,IAAI,sCAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,0CAAkB,aAAa,MAAA,CAAC;QACpC,uBAAA,IAAI,sCAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,0CAAkB,IAAI,GAAG,EAAE,MAAA,CAAC;QAEhC,qEAAqE;QACrE,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,uBAAA,IAAI,wCAAgB,IAAI,MAAA,CAAC;IAC3B,CAAC;IAED;;;;;OAKG;IACH,IAAI;QACF,KAAK,MAAM,QAAQ,IAAI,uBAAA,IAAI,0CAAW,EAAE;YACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE;gBAC5C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;gBAEpC,+BAA+B;gBAC/B,IAAI,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC,aAAa,EAAE;oBACrC,SAAS;iBACV;gBAED,gDAAgD;gBAChD,IAAI,iBAAiB,GAAG,uBAAA,IAAI,8CAAe,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBACpE,IAAI,CAAC,iBAAiB,EAAE;oBACtB,iBAAiB,GAAG,IAAI,+CAAsB,CAAU;wBACtD,UAAU,EAAE,OAAO,CAAC,UAAU;wBAC9B,MAAM,EAAE,IAAI;wBACZ,SAAS,EAAE,uBAAA,IAAI,0CAAW;wBAC1B,SAAS,EAAE,uBAAA,IAAI,0CAAW;qBAC3B,CAAC,CAAC;oBAEH,+DAA+D;oBAC/D,+DAA+D;oBAC/D,iEAAiE;oBACjE,iEAAiE;oBACjE,8DAA8D;oBAC9D,EAAE;oBACF,kEAAkE;oBAClE,wBAAwB;oBACxB,gEAAgE;oBAEhE,uBAAA,IAAI,8CAAe,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;iBAChE;aACF;SACF;QAED,oDAAoD;QACpD,KAAK,MAAM,CACT,UAAU,EACV,iBAAiB,EAClB,IAAI,uBAAA,IAAI,8CAAe,CAAC,OAAO,EAAE,EAAE;YAClC,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAEzB,oCAAoC;YACpC,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,EAAE;gBACpC,uBAAA,IAAI,8CAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;aACxC;SACF;IACH,CAAC;IAED;;;;OAIG;IACH,IAAI,EAAE;QACJ,OAAO,uBAAA,IAAI,mCAAI,CAAC;IAClB,CAAC;IAED;;;;OAIG;IACH,IAAI,IAAI;QACN,OAAO,+BAAiB,CAAC,OAAO,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,IAAI,aAAa;QACf,OAAO,uBAAA,IAAI,8CAAe,CAAC;IAC7B,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CACb,EAAkB;QAElB,0DAA0D;QAC1D,IAAI,EAAE,KAAK,IAAA,qCAAuB,EAAC,IAAI,CAAC,EAAE,CAAC,EAAE;YAC3C,OAAO,uBAAA,IAAI,8CAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACnC;QAED,6DAA6D;QAC7D,4BAA4B;QAC5B,IAAI,CAAC,IAAA,wCAA0B,EAAC,EAAE,CAAC,EAAE;YACnC,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,UAAU,GAAG,IAAA,uDAAyC,EAAC,EAAE,CAAC,CAAC;QACjE,OAAO,uBAAA,IAAI,8CAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,0BAA0B,EAAE,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,yBAAyB,CACvB,UAAkB;QAElB,OAAO,uBAAA,IAAI,8CAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,0BAA0B;QACxB,OAAO,KAAK,CAAC,IAAI,CAAC,uBAAA,IAAI,8CAAe,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,2BAA2B;IAC9E,CAAC;IAED;;;;OAIG;IACH,iBAAiB;QACf,4BAA4B;QAC5B,OAAO,CACL,IAAI,CAAC,GAAG,CACN,CAAC,CAAC,EAAE,wCAAwC;QAC5C,GAAG,uBAAA,IAAI,8CAAe,CAAC,IAAI,EAAE,CAC9B,GAAG,CAAC,CACN,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,4BAA4B,CAChC,UAAkB;QAElB,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAChD,IAAI,UAAU,GAAG,cAAc,EAAE;YAC/B,MAAM,IAAI,KAAK,CACb,uFAAuF,cAAc,SAAS,UAAU,EAAE,CAC3H,CAAC;SACH;QAED,IAAI,KAAK,GAAG,IAAI,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,KAAK,EAAE;YACT,sEAAsE;YACtE,aAAa;YACb,KAAK,CAAC,IAAI,EAAE,CAAC;YAEb,OAAO,KAAK,CAAC;SACd;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,uBAAA,IAAI,0CAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC/B,QAAQ,CAAC,cAAc,CAAC;YACtB,aAAa,EAAE,uBAAA,IAAI,8CAAe;YAClC,UAAU;SACX,CAAC,CACH,CACF,CAAC;QAEF,mFAAmF;QACnF,uBAAuB;QACvB,EAAE;QACF,iFAAiF;QACjF,oFAAoF;QACpF,kFAAkF;QAClF,iFAAiF;QACjF,EAAE;QACF,qDAAqD;QACrD,2EAA2E;QAC3E,oEAAoE;QACpE,uEAAuE;QACvE,oFAAoF;QACpF,qEAAqE;QACrE,uDAAuD;QACvD,sFAAsF;QACtF,kFAAkF;QAClF,oFAAoF;QACpF,0DAA0D;QAC1D,EAAE;QACF,mFAAmF;QAEnF,+EAA+E;QAC/E,+CAA+C;QAC/C,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,EAAE;YAC1D,mFAAmF;YACnF,uBAAuB;YACvB,MAAM,KAAK,GAAG,wDAAwD,UAAU,EAAE,CAAC;YAEnF,IAAI,IAAI,GAAG,GAAG,KAAK,GAAG,CAAC;YACvB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;gBAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE;oBAChC,IAAI,IAAI,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC;iBAChC;aACF;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEnB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;SACxB;QAED,iFAAiF;QACjF,oCAAoC;QACpC,KAAK,GAAG,IAAI,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE;YACV,+EAA+E;YAC/E,KAAK,GAAG,IAAI,+CAAsB,CAAC;gBACjC,MAAM,EAAE,IAAI;gBACZ,SAAS,EAAE,uBAAA,IAAI,0CAAW;gBAC1B,UAAU;gBACV,SAAS,EAAE,uBAAA,IAAI,0CAAW;aAC3B,CAAC,CAAC;SACJ;QAED,4CAA4C;QAC5C,uBAAA,IAAI,8CAAe,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,oCAAoC;QAEhF,IAAI,uBAAA,IAAI,4CAAa,EAAE;YACrB,uBAAA,IAAI,0CAAW,CAAC,OAAO,CACrB,wDAAwD,EACxD,KAAK,CACN,CAAC;SACH;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,gCAAgC;QAGpC,OAAO,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACrE,CAAC;IAED;;;;OAIG;IACH,wBAAwB;QACtB,OAAO,uBAAA,IAAI,sDAAuB,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACf,IAAI,uBAAA,IAAI,sDAAuB,EAAE;YAC/B,OAAO,CAAC,gCAAgC;SACzC;QAED,uBAAA,IAAI,kDAA0B,IAAI,MAAA,CAAC;QACnC,IAAI;YACF,MAAM,MAAM,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;YACjD,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;SACjD;gBAAS;YACR,uBAAA,IAAI,kDAA0B,KAAK,MAAA,CAAC;SACrC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,UAAkB;QACjC,IAAI,uBAAA,IAAI,sDAAuB,EAAE;YAC/B,OAAO,CAAC,gCAAgC;SACzC;QAED,uBAAA,IAAI,kDAA0B,IAAI,MAAA,CAAC;QACnC,IAAI;YACF,MAAM,KAAK,GAAG,IAAI,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;YACzD,IAAI,KAAK,EAAE;gBACT,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;aACrB;SACF;gBAAS;YACR,uBAAA,IAAI,kDAA0B,KAAK,MAAA,CAAC;SACrC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,yBAAyB;QAC7B,4EAA4E;QAC5E,eAAe;QACf,IAAI,aAAa,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE7C,yDAAyD;QACzD,MAAM,oBAAoB,GAAG,KAAK,EAChC,OAAwC,EACxC,EAAE;YACF,MAAM,OAAO,GAAG,CAAC,QAAgB,EAAE,UAAkB,EAAE,EAAE,CACvD,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,QAAQ,gBAAgB,UAAU,GAAG,CAAC;YAErF,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE;gBACvB,0CAA0C;gBAC1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;gBAErE,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;gBAE1C,IAAI,QAAQ,GAAmC,EAAE,CAAC;gBAClD,IAAI;oBACF,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;wBAC1D,aAAa,EAAE,uBAAA,IAAI,8CAAe;wBAClC,UAAU,EAAE,gBAAgB;qBAC7B,CAAC,CAAC;iBACJ;gBAAC,OAAO,KAAK,EAAE;oBACd,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;oBACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBACrB,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,KAAK,CAAC,CAAC;oBAChD,MAAM;iBACP;gBAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;oBACpB,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;oBAC1C,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;oBACvB,MAAM;iBACP;gBAED,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC,CAAC;gBAE5C,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC;gBAEjC,MAAM,cAAc,GAAG,gBAAgB,GAAG,CAAC,CAAC;gBAC5C,OAAO,CAAC,UAAU,GAAG,cAAc,CAAC;gBAEpC,IAAI,cAAc,GAAG,aAAa,EAAE;oBAClC,aAAa,GAAG,cAAc,CAAC;iBAChC;aACF;QACH,CAAC,CAAC;QAEF,MAAM,gBAAgB,GACpB,uBAAA,IAAI,0CAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACjC,QAAQ;YACR,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,aAAa;YACzB,KAAK,EAAE,CAAC;SACT,CAAC,CAAC,CAAC;QAEN,sCAAsC;QACtC,MAAM,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAE9D,uGAAuG;QACvG,kGAAkG;QAClG,IAAI,CAAC,IAAI,EAAE,CAAC;QAEZ,oGAAoG;QACpG,8BAA8B;QAC9B,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAEzB,MAAM,kBAAkB,GAA2B,EAAE,CAAC;QACtD,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE;YACtC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YAChD,kBAAkB,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;SAClD;QAED,OAAO,kBAAkB,CAAC;IAC5B,CAAC;CACF;AAjbD,0DAibC","sourcesContent":["import {\n getGroupIndexFromMultichainAccountGroupId,\n isMultichainAccountGroupId,\n toMultichainAccountWalletId,\n} from '@metamask/account-api';\nimport { toDefaultAccountGroupId } from '@metamask/account-api';\nimport { AccountWalletType } from '@metamask/account-api';\nimport type {\n Bip44Account,\n MultichainAccountWalletId,\n MultichainAccountWallet as MultichainAccountWalletDefinition,\n} from '@metamask/account-api';\nimport type { AccountGroupId } from '@metamask/account-api';\nimport {\n type EntropySourceId,\n type KeyringAccount,\n} from '@metamask/keyring-api';\nimport { createProjectLogger } from '@metamask/utils';\n\nimport { MultichainAccountGroup } from './MultichainAccountGroup';\nimport type { NamedAccountProvider } from './providers';\nimport type { MultichainAccountServiceMessenger } from './types';\n\n/**\n * The context for a provider discovery.\n */\ntype AccountProviderDiscoveryContext = {\n provider: NamedAccountProvider;\n stopped: boolean;\n groupIndex: number;\n count: number;\n};\n\n/**\n * The metrics resulting from account discovery.\n */\nexport type AccountDiscoveryMetrics = {\n [providerName: string]: number;\n};\n\nconst log = createProjectLogger('multichain-account-service');\n\n/**\n * A multichain account wallet that holds multiple multichain accounts (one multichain account per\n * group index).\n */\nexport class MultichainAccountWallet<\n Account extends Bip44Account<KeyringAccount>,\n> implements MultichainAccountWalletDefinition<Account>\n{\n readonly #id: MultichainAccountWalletId;\n\n readonly #providers: NamedAccountProvider<Account>[];\n\n readonly #entropySource: EntropySourceId;\n\n readonly #accountGroups: Map<number, MultichainAccountGroup<Account>>;\n\n readonly #messenger: MultichainAccountServiceMessenger;\n\n // eslint-disable-next-line @typescript-eslint/prefer-readonly\n #initialized = false;\n\n #isAlignmentInProgress: boolean = false;\n\n constructor({\n providers,\n entropySource,\n messenger,\n }: {\n providers: NamedAccountProvider<Account>[];\n entropySource: EntropySourceId;\n messenger: MultichainAccountServiceMessenger;\n }) {\n this.#id = toMultichainAccountWalletId(entropySource);\n this.#providers = providers;\n this.#entropySource = entropySource;\n this.#messenger = messenger;\n this.#accountGroups = new Map();\n\n // Initial synchronization (don't emit events during initialization).\n this.sync();\n this.#initialized = true;\n }\n\n /**\n * Force wallet synchronization.\n *\n * This can be used if account providers got new accounts that the wallet\n * doesn't know about.\n */\n sync(): void {\n for (const provider of this.#providers) {\n for (const account of provider.getAccounts()) {\n const { entropy } = account.options;\n\n // Filter for this wallet only.\n if (entropy.id !== this.entropySource) {\n continue;\n }\n\n // This multichain account might exists already.\n let multichainAccount = this.#accountGroups.get(entropy.groupIndex);\n if (!multichainAccount) {\n multichainAccount = new MultichainAccountGroup<Account>({\n groupIndex: entropy.groupIndex,\n wallet: this,\n providers: this.#providers,\n messenger: this.#messenger,\n });\n\n // This existing multichain account group might differ from the\n // `createMultichainAccountGroup` behavior. When creating a new\n // group, we expect the providers to all succeed. But here, we're\n // just fetching the account lists from them, so this group might\n // not be \"aligned\" yet (e.g having a missing Solana account).\n //\n // Since \"aligning\" is an async operation, it would have to be run\n // after the first-sync.\n // TODO: Implement align mechanism to create \"missing\" accounts.\n\n this.#accountGroups.set(entropy.groupIndex, multichainAccount);\n }\n }\n }\n\n // Now force-sync all remaining multichain accounts.\n for (const [\n groupIndex,\n multichainAccount,\n ] of this.#accountGroups.entries()) {\n multichainAccount.sync();\n\n // Clean up old multichain accounts.\n if (!multichainAccount.hasAccounts()) {\n this.#accountGroups.delete(groupIndex);\n }\n }\n }\n\n /**\n * Gets the multichain account wallet ID.\n *\n * @returns The multichain account wallet ID.\n */\n get id(): MultichainAccountWalletId {\n return this.#id;\n }\n\n /**\n * Gets the multichain account wallet type, which is always {@link AccountWalletType.Entropy}.\n *\n * @returns The multichain account wallet type.\n */\n get type(): AccountWalletType.Entropy {\n return AccountWalletType.Entropy;\n }\n\n /**\n * Gets the multichain account wallet entropy source.\n *\n * @returns The multichain account wallet entropy source.\n */\n get entropySource(): EntropySourceId {\n return this.#entropySource;\n }\n\n /**\n * Gets multichain account for a given ID.\n * The default group ID will default to the multichain account with index 0.\n *\n * @param id - Account group ID.\n * @returns Account group.\n */\n getAccountGroup(\n id: AccountGroupId,\n ): MultichainAccountGroup<Account> | undefined {\n // We consider the \"default case\" to be mapped to index 0.\n if (id === toDefaultAccountGroupId(this.id)) {\n return this.#accountGroups.get(0);\n }\n\n // If it is not a valid ID, we cannot extract the group index\n // from it, so we fail fast.\n if (!isMultichainAccountGroupId(id)) {\n return undefined;\n }\n\n const groupIndex = getGroupIndexFromMultichainAccountGroupId(id);\n return this.#accountGroups.get(groupIndex);\n }\n\n /**\n * Gets all multichain accounts. Similar to {@link MultichainAccountWallet.getMultichainAccountGroups}.\n *\n * @returns The multichain accounts.\n */\n getAccountGroups(): MultichainAccountGroup<Account>[] {\n return this.getMultichainAccountGroups();\n }\n\n /**\n * Gets multichain account group for a given index.\n *\n * @param groupIndex - Multichain account index.\n * @returns The multichain account associated with the given index.\n */\n getMultichainAccountGroup(\n groupIndex: number,\n ): MultichainAccountGroup<Account> | undefined {\n return this.#accountGroups.get(groupIndex);\n }\n\n /**\n * Gets all multichain account groups.\n *\n * @returns The multichain accounts.\n */\n getMultichainAccountGroups(): MultichainAccountGroup<Account>[] {\n return Array.from(this.#accountGroups.values()); // TODO: Prevent copy here.\n }\n\n /**\n * Gets next group index for this wallet.\n *\n * @returns The next group index of this wallet.\n */\n getNextGroupIndex(): number {\n // We do not check for gaps.\n return (\n Math.max(\n -1, // So it will default to 0 if no groups.\n ...this.#accountGroups.keys(),\n ) + 1\n );\n }\n\n /**\n * Creates a multichain account group for a given group index.\n *\n * @param groupIndex - The group index to use.\n * @throws If any of the account providers fails to create their accounts.\n * @returns The multichain account group for this group index.\n */\n async createMultichainAccountGroup(\n groupIndex: number,\n ): Promise<MultichainAccountGroup<Account>> {\n const nextGroupIndex = this.getNextGroupIndex();\n if (groupIndex > nextGroupIndex) {\n throw new Error(\n `You cannot use a group index that is higher than the next available one: expected <=${nextGroupIndex}, got ${groupIndex}`,\n );\n }\n\n let group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n // If the group already exists, we just `sync` it and returns the same\n // reference.\n group.sync();\n\n return group;\n }\n\n const results = await Promise.allSettled(\n this.#providers.map((provider) =>\n provider.createAccounts({\n entropySource: this.#entropySource,\n groupIndex,\n }),\n ),\n );\n\n // --------------------------------------------------------------------------------\n // READ THIS CAREFULLY:\n //\n // Since we're not \"fully supporting multichain\" for now, we still rely on single\n // :accountCreated events to sync multichain account groups and wallets. Which means\n // that even if of the provider fails, some accounts will still be created on some\n // other providers and will become \"available\" on the `AccountsController`, like:\n //\n // 1. Creating a multichain account group for index 1\n // 2. EvmAccountProvider.createAccounts returns the EVM account for index 1\n // * AccountsController WILL fire :accountCreated for this account\n // * This account WILL BE \"available\" on the AccountsController state\n // 3. SolAccountProvider.createAccounts fails to create a Solana account for index 1\n // * AccountsController WON't fire :accountCreated for this account\n // * This account WON'T be \"available\" on the Account\n // 4. MultichainAccountService will receive a :accountCreated for the EVM account from\n // step 2 and will create a new multichain account group for index 1, but it won't\n // receive any event for the Solana account of this group. Thus, this group won't be\n // \"aligned\" (missing \"blockchain account\" on this group).\n //\n // --------------------------------------------------------------------------------\n\n // If any of the provider failed to create their accounts, then we consider the\n // multichain account group to have failed too.\n if (results.some((result) => result.status === 'rejected')) {\n // NOTE: Some accounts might still have been created on other account providers. We\n // don't rollback them.\n const error = `Unable to create multichain account group for index: ${groupIndex}`;\n\n let warn = `${error}:`;\n for (const result of results) {\n if (result.status === 'rejected') {\n warn += `\\n- ${result.reason}`;\n }\n }\n console.warn(warn);\n\n throw new Error(error);\n }\n\n // Because of the :accountAdded automatic sync, we might already have created the\n // group, so we first try to get it.\n group = this.getMultichainAccountGroup(groupIndex);\n if (!group) {\n // If for some reason it's still not created, we're creating it explicitly now:\n group = new MultichainAccountGroup({\n wallet: this,\n providers: this.#providers,\n groupIndex,\n messenger: this.#messenger,\n });\n }\n\n // Register the account to our internal map.\n this.#accountGroups.set(groupIndex, group); // `group` cannot be undefined here.\n\n if (this.#initialized) {\n this.#messenger.publish(\n 'MultichainAccountService:multichainAccountGroupCreated',\n group,\n );\n }\n\n return group;\n }\n\n /**\n * Creates the next multichain account group.\n *\n * @throws If any of the account providers fails to create their accounts.\n * @returns The multichain account group for the next group index available.\n */\n async createNextMultichainAccountGroup(): Promise<\n MultichainAccountGroup<Account>\n > {\n return this.createMultichainAccountGroup(this.getNextGroupIndex());\n }\n\n /**\n * Gets whether alignment is currently in progress for this wallet.\n *\n * @returns True if alignment is in progress, false otherwise.\n */\n getIsAlignmentInProgress(): boolean {\n return this.#isAlignmentInProgress;\n }\n\n /**\n * Align all multichain account groups.\n */\n async alignGroups(): Promise<void> {\n if (this.#isAlignmentInProgress) {\n return; // Prevent concurrent alignments\n }\n\n this.#isAlignmentInProgress = true;\n try {\n const groups = this.getMultichainAccountGroups();\n await Promise.all(groups.map((g) => g.align()));\n } finally {\n this.#isAlignmentInProgress = false;\n }\n }\n\n /**\n * Align a specific multichain account group.\n *\n * @param groupIndex - The group index to align.\n */\n async alignGroup(groupIndex: number): Promise<void> {\n if (this.#isAlignmentInProgress) {\n return; // Prevent concurrent alignments\n }\n\n this.#isAlignmentInProgress = true;\n try {\n const group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n await group.align();\n }\n } finally {\n this.#isAlignmentInProgress = false;\n }\n }\n\n /**\n * Discover and create accounts for all providers.\n *\n * @returns The discovered accounts for each provider.\n */\n async discoverAndCreateAccounts(): Promise<AccountDiscoveryMetrics> {\n // Start with the next available group index (so we can resume the discovery\n // from there).\n let maxGroupIndex = this.getNextGroupIndex();\n\n // One serialized loop per provider; all run concurrently\n const runProviderDiscovery = async (\n context: AccountProviderDiscoveryContext,\n ) => {\n const message = (stepName: string, groupIndex: number) =>\n `[${context.provider.getName()}] Discovery ${stepName} (groupIndex=${groupIndex})`;\n\n while (!context.stopped) {\n // Fast‑forward to current high‑water mark\n const targetGroupIndex = Math.max(context.groupIndex, maxGroupIndex);\n\n log(message('STARTED', targetGroupIndex));\n\n let accounts: Bip44Account<KeyringAccount>[] = [];\n try {\n accounts = await context.provider.discoverAndCreateAccounts({\n entropySource: this.#entropySource,\n groupIndex: targetGroupIndex,\n });\n } catch (error) {\n context.stopped = true;\n console.error(error);\n log(message('FAILED', targetGroupIndex), error);\n break;\n }\n\n if (!accounts.length) {\n log(message('STOPPED', targetGroupIndex));\n context.stopped = true;\n break;\n }\n\n log(message('SUCCEEDED', targetGroupIndex));\n\n context.count += accounts.length;\n\n const nextGroupIndex = targetGroupIndex + 1;\n context.groupIndex = nextGroupIndex;\n\n if (nextGroupIndex > maxGroupIndex) {\n maxGroupIndex = nextGroupIndex;\n }\n }\n };\n\n const providerContexts: AccountProviderDiscoveryContext[] =\n this.#providers.map((provider) => ({\n provider,\n stopped: false,\n groupIndex: maxGroupIndex,\n count: 0,\n }));\n\n // Start discovery for each providers.\n await Promise.all(providerContexts.map(runProviderDiscovery));\n\n // Sync the wallet after discovery to ensure that the newly added accounts are added into their groups.\n // We can potentially remove this if we know that this race condition is not an issue in practice.\n this.sync();\n\n // Align missing accounts from group. This is required to create missing account from non-discovered\n // indexes for some providers.\n await this.alignGroups();\n\n const discoveredAccounts: Record<string, number> = {};\n for (const context of providerContexts) {\n const providerName = context.provider.getName();\n discoveredAccounts[providerName] = context.count;\n }\n\n return discoveredAccounts;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainAccountWallet.cjs","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getGroupIndexFromMultichainAccountGroupId,\n isMultichainAccountGroupId,\n toMultichainAccountWalletId,\n} from '@metamask/account-api';\nimport { toDefaultAccountGroupId } from '@metamask/account-api';\nimport { AccountWalletType } from '@metamask/account-api';\nimport type {\n Bip44Account,\n MultichainAccountWalletId,\n MultichainAccountWallet as MultichainAccountWalletDefinition,\n MultichainAccountWalletStatus,\n} from '@metamask/account-api';\nimport type { AccountGroupId } from '@metamask/account-api';\nimport {\n type EntropySourceId,\n type KeyringAccount,\n} from '@metamask/keyring-api';\nimport { createProjectLogger } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport { MultichainAccountGroup } from './MultichainAccountGroup';\nimport type { NamedAccountProvider } from './providers';\nimport type { MultichainAccountServiceMessenger } from './types';\n\n/**\n * The context for a provider discovery.\n */\ntype AccountProviderDiscoveryContext<\n Account extends Bip44Account<KeyringAccount>,\n> = {\n provider: NamedAccountProvider<Account>;\n stopped: boolean;\n groupIndex: number;\n accounts: Account[];\n};\n\nconst log = createProjectLogger('multichain-account-service');\n\n/**\n * A multichain account wallet that holds multiple multichain accounts (one multichain account per\n * group index).\n */\nexport class MultichainAccountWallet<\n Account extends Bip44Account<KeyringAccount>,\n> implements MultichainAccountWalletDefinition<Account>\n{\n readonly #lock = new Mutex();\n\n readonly #id: MultichainAccountWalletId;\n\n readonly #providers: NamedAccountProvider<Account>[];\n\n readonly #entropySource: EntropySourceId;\n\n readonly #accountGroups: Map<number, MultichainAccountGroup<Account>>;\n\n readonly #messenger: MultichainAccountServiceMessenger;\n\n // eslint-disable-next-line @typescript-eslint/prefer-readonly\n #initialized = false;\n\n #status: MultichainAccountWalletStatus;\n\n constructor({\n providers,\n entropySource,\n messenger,\n }: {\n providers: NamedAccountProvider<Account>[];\n entropySource: EntropySourceId;\n messenger: MultichainAccountServiceMessenger;\n }) {\n this.#id = toMultichainAccountWalletId(entropySource);\n this.#providers = providers;\n this.#entropySource = entropySource;\n this.#messenger = messenger;\n this.#accountGroups = new Map();\n\n // Initial synchronization (don't emit events during initialization).\n this.#status = 'uninitialized';\n this.sync();\n this.#initialized = true;\n this.#status = 'ready';\n }\n\n /**\n * Force wallet synchronization.\n *\n * This can be used if account providers got new accounts that the wallet\n * doesn't know about.\n */\n sync(): void {\n for (const provider of this.#providers) {\n for (const account of provider.getAccounts()) {\n const { entropy } = account.options;\n\n // Filter for this wallet only.\n if (entropy.id !== this.entropySource) {\n continue;\n }\n\n // This multichain account might exists already.\n let multichainAccount = this.#accountGroups.get(entropy.groupIndex);\n if (!multichainAccount) {\n multichainAccount = new MultichainAccountGroup<Account>({\n groupIndex: entropy.groupIndex,\n wallet: this,\n providers: this.#providers,\n messenger: this.#messenger,\n });\n\n // This existing multichain account group might differ from the\n // `createMultichainAccountGroup` behavior. When creating a new\n // group, we expect the providers to all succeed. But here, we're\n // just fetching the account lists from them, so this group might\n // not be \"aligned\" yet (e.g having a missing Solana account).\n //\n // Since \"aligning\" is an async operation, it would have to be run\n // after the first-sync.\n // TODO: Implement align mechanism to create \"missing\" accounts.\n\n this.#accountGroups.set(entropy.groupIndex, multichainAccount);\n }\n }\n }\n\n // Now force-sync all remaining multichain accounts.\n for (const [\n groupIndex,\n multichainAccount,\n ] of this.#accountGroups.entries()) {\n multichainAccount.sync();\n\n // Clean up old multichain accounts.\n if (!multichainAccount.hasAccounts()) {\n this.#accountGroups.delete(groupIndex);\n }\n }\n }\n\n /**\n * Gets the multichain account wallet ID.\n *\n * @returns The multichain account wallet ID.\n */\n get id(): MultichainAccountWalletId {\n return this.#id;\n }\n\n /**\n * Gets the multichain account wallet type, which is always {@link AccountWalletType.Entropy}.\n *\n * @returns The multichain account wallet type.\n */\n get type(): AccountWalletType.Entropy {\n return AccountWalletType.Entropy;\n }\n\n /**\n * Gets the multichain account wallet entropy source.\n *\n * @returns The multichain account wallet entropy source.\n */\n get entropySource(): EntropySourceId {\n return this.#entropySource;\n }\n\n /**\n * Gets the multichain account wallet current status.\n *\n * @returns The multichain account wallet current status.\n */\n get status(): MultichainAccountWalletStatus {\n return this.#status;\n }\n\n /**\n * Set the wallet status and run the associated operation callback.\n *\n * @param status - Wallet status associated with this operation.\n * @param operation - Operation to run.\n * @returns The operation's result.\n * @throws {Error} If the wallet is already running a mutable operation.\n */\n async #withLock<Return>(\n status: MultichainAccountWalletStatus,\n operation: () => Promise<Return>,\n ) {\n const release = await this.#lock.acquire();\n try {\n this.#status = status;\n this.#messenger.publish(\n 'MultichainAccountService:walletStatusChange',\n this.id,\n this.#status,\n );\n return await operation();\n } finally {\n this.#status = 'ready';\n this.#messenger.publish(\n 'MultichainAccountService:walletStatusChange',\n this.id,\n this.#status,\n );\n release();\n }\n }\n\n /**\n * Gets multichain account for a given ID.\n * The default group ID will default to the multichain account with index 0.\n *\n * @param id - Account group ID.\n * @returns Account group.\n */\n getAccountGroup(\n id: AccountGroupId,\n ): MultichainAccountGroup<Account> | undefined {\n // We consider the \"default case\" to be mapped to index 0.\n if (id === toDefaultAccountGroupId(this.id)) {\n return this.#accountGroups.get(0);\n }\n\n // If it is not a valid ID, we cannot extract the group index\n // from it, so we fail fast.\n if (!isMultichainAccountGroupId(id)) {\n return undefined;\n }\n\n const groupIndex = getGroupIndexFromMultichainAccountGroupId(id);\n return this.#accountGroups.get(groupIndex);\n }\n\n /**\n * Gets all multichain accounts. Similar to {@link MultichainAccountWallet.getMultichainAccountGroups}.\n *\n * @returns The multichain accounts.\n */\n getAccountGroups(): MultichainAccountGroup<Account>[] {\n return this.getMultichainAccountGroups();\n }\n\n /**\n * Gets multichain account group for a given index.\n *\n * @param groupIndex - Multichain account index.\n * @returns The multichain account associated with the given index.\n */\n getMultichainAccountGroup(\n groupIndex: number,\n ): MultichainAccountGroup<Account> | undefined {\n return this.#accountGroups.get(groupIndex);\n }\n\n /**\n * Gets all multichain account groups.\n *\n * @returns The multichain accounts.\n */\n getMultichainAccountGroups(): MultichainAccountGroup<Account>[] {\n return Array.from(this.#accountGroups.values()); // TODO: Prevent copy here.\n }\n\n /**\n * Gets next group index for this wallet.\n *\n * @returns The next group index of this wallet.\n */\n getNextGroupIndex(): number {\n // We do not check for gaps.\n return (\n Math.max(\n -1, // So it will default to 0 if no groups.\n ...this.#accountGroups.keys(),\n ) + 1\n );\n }\n\n /**\n * Creates a multichain account group for a given group index.\n *\n * NOTE: This operation WILL lock the wallet's mutex.\n *\n * @param groupIndex - The group index to use.\n * @throws If any of the account providers fails to create their accounts.\n * @returns The multichain account group for this group index.\n */\n async createMultichainAccountGroup(\n groupIndex: number,\n ): Promise<MultichainAccountGroup<Account>> {\n return await this.#withLock('in-progress:create-accounts', async () => {\n const nextGroupIndex = this.getNextGroupIndex();\n if (groupIndex > nextGroupIndex) {\n throw new Error(\n `You cannot use a group index that is higher than the next available one: expected <=${nextGroupIndex}, got ${groupIndex}`,\n );\n }\n\n let group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n // If the group already exists, we just `sync` it and returns the same\n // reference.\n group.sync();\n\n return group;\n }\n\n const results = await Promise.allSettled(\n this.#providers.map((provider) =>\n provider.createAccounts({\n entropySource: this.#entropySource,\n groupIndex,\n }),\n ),\n );\n\n // --------------------------------------------------------------------------------\n // READ THIS CAREFULLY:\n //\n // Since we're not \"fully supporting multichain\" for now, we still rely on single\n // :accountCreated events to sync multichain account groups and wallets. Which means\n // that even if of the provider fails, some accounts will still be created on some\n // other providers and will become \"available\" on the `AccountsController`, like:\n //\n // 1. Creating a multichain account group for index 1\n // 2. EvmAccountProvider.createAccounts returns the EVM account for index 1\n // * AccountsController WILL fire :accountCreated for this account\n // * This account WILL BE \"available\" on the AccountsController state\n // 3. SolAccountProvider.createAccounts fails to create a Solana account for index 1\n // * AccountsController WON't fire :accountCreated for this account\n // * This account WON'T be \"available\" on the Account\n // 4. MultichainAccountService will receive a :accountCreated for the EVM account from\n // step 2 and will create a new multichain account group for index 1, but it won't\n // receive any event for the Solana account of this group. Thus, this group won't be\n // \"aligned\" (missing \"blockchain account\" on this group).\n //\n // --------------------------------------------------------------------------------\n\n // If any of the provider failed to create their accounts, then we consider the\n // multichain account group to have failed too.\n if (results.some((result) => result.status === 'rejected')) {\n // NOTE: Some accounts might still have been created on other account providers. We\n // don't rollback them.\n const error = `Unable to create multichain account group for index: ${groupIndex}`;\n\n let warn = `${error}:`;\n for (const result of results) {\n if (result.status === 'rejected') {\n warn += `\\n- ${result.reason}`;\n }\n }\n console.warn(warn);\n\n throw new Error(error);\n }\n\n // Because of the :accountAdded automatic sync, we might already have created the\n // group, so we first try to get it.\n group = this.getMultichainAccountGroup(groupIndex);\n if (!group) {\n // If for some reason it's still not created, we're creating it explicitly now:\n group = new MultichainAccountGroup({\n wallet: this,\n providers: this.#providers,\n groupIndex,\n messenger: this.#messenger,\n });\n }\n\n // Register the account to our internal map.\n this.#accountGroups.set(groupIndex, group); // `group` cannot be undefined here.\n\n if (this.#initialized) {\n this.#messenger.publish(\n 'MultichainAccountService:multichainAccountGroupCreated',\n group,\n );\n }\n\n return group;\n });\n }\n\n /**\n * Creates the next multichain account group.\n *\n * @throws If any of the account providers fails to create their accounts.\n * @returns The multichain account group for the next group index available.\n */\n async createNextMultichainAccountGroup(): Promise<\n MultichainAccountGroup<Account>\n > {\n return this.createMultichainAccountGroup(this.getNextGroupIndex());\n }\n\n /**\n * Align all multichain account groups.\n *\n * NOTE: This operation WILL NOT lock the wallet's mutex.\n */\n async #alignAccounts(): Promise<void> {\n const groups = this.getMultichainAccountGroups();\n await Promise.all(groups.map((group) => group.align()));\n }\n\n /**\n * Align all accounts from each existing multichain account groups.\n *\n * NOTE: This operation WILL lock the wallet's mutex.\n */\n async alignAccounts(): Promise<void> {\n await this.#withLock('in-progress:alignment', async () => {\n await this.#alignAccounts();\n });\n }\n\n /**\n * Align a specific multichain account group.\n *\n * NOTE: This operation WILL lock the wallet's mutex.\n *\n * @param groupIndex - The group index to align.\n */\n async alignGroup(groupIndex: number): Promise<void> {\n await this.#withLock('in-progress:alignment', async () => {\n const group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n await group.align();\n }\n });\n }\n\n /**\n * Discover and create accounts for all providers.\n *\n * NOTE: This operation WILL lock the wallet's mutex.\n *\n * @returns The discovered accounts for each provider.\n */\n async discoverAccounts(): Promise<Account[]> {\n return this.#withLock('in-progress:discovery', async () => {\n // Start with the next available group index (so we can resume the discovery\n // from there).\n let maxGroupIndex = this.getNextGroupIndex();\n\n // One serialized loop per provider; all run concurrently\n const runProviderDiscovery = async (\n context: AccountProviderDiscoveryContext<Account>,\n ) => {\n const message = (stepName: string, groupIndex: number) =>\n `[${context.provider.getName()}] Discovery ${stepName} (groupIndex=${groupIndex})`;\n\n while (!context.stopped) {\n // Fast‑forward to current high‑water mark\n const targetGroupIndex = Math.max(context.groupIndex, maxGroupIndex);\n\n log(message('STARTED', targetGroupIndex));\n\n let accounts: Account[] = [];\n try {\n accounts = await context.provider.discoverAccounts({\n entropySource: this.#entropySource,\n groupIndex: targetGroupIndex,\n });\n } catch (error) {\n context.stopped = true;\n console.error(error);\n log(message('FAILED', targetGroupIndex), error);\n break;\n }\n\n if (!accounts.length) {\n log(message('STOPPED', targetGroupIndex));\n context.stopped = true;\n break;\n }\n\n log(message('SUCCEEDED', targetGroupIndex));\n\n context.accounts = context.accounts.concat(accounts);\n\n const nextGroupIndex = targetGroupIndex + 1;\n context.groupIndex = nextGroupIndex;\n\n if (nextGroupIndex > maxGroupIndex) {\n maxGroupIndex = nextGroupIndex;\n }\n }\n };\n\n const providerContexts: AccountProviderDiscoveryContext<Account>[] =\n this.#providers.map((provider) => ({\n provider,\n stopped: false,\n groupIndex: maxGroupIndex,\n accounts: [],\n }));\n\n // Start discovery for each providers.\n await Promise.all(providerContexts.map(runProviderDiscovery));\n\n // Sync the wallet after discovery to ensure that the newly added accounts are added into their groups.\n // We can potentially remove this if we know that this race condition is not an issue in practice.\n this.sync();\n\n // Align missing accounts from group. This is required to create missing account from non-discovered\n // indexes for some providers.\n await this.#alignAccounts();\n\n return providerContexts.flatMap((context) => context.accounts);\n });\n }\n}\n"]}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { AccountWalletType } from "@metamask/account-api";
|
|
2
|
-
import type { Bip44Account, MultichainAccountWalletId, MultichainAccountWallet as MultichainAccountWalletDefinition } from "@metamask/account-api";
|
|
2
|
+
import type { Bip44Account, MultichainAccountWalletId, MultichainAccountWallet as MultichainAccountWalletDefinition, MultichainAccountWalletStatus } from "@metamask/account-api";
|
|
3
3
|
import type { AccountGroupId } from "@metamask/account-api";
|
|
4
4
|
import { type EntropySourceId, type KeyringAccount } from "@metamask/keyring-api";
|
|
5
5
|
import { MultichainAccountGroup } from "./MultichainAccountGroup.cjs";
|
|
6
6
|
import type { NamedAccountProvider } from "./providers/index.cjs";
|
|
7
7
|
import type { MultichainAccountServiceMessenger } from "./types.cjs";
|
|
8
|
-
/**
|
|
9
|
-
* The metrics resulting from account discovery.
|
|
10
|
-
*/
|
|
11
|
-
export type AccountDiscoveryMetrics = {
|
|
12
|
-
[providerName: string]: number;
|
|
13
|
-
};
|
|
14
8
|
/**
|
|
15
9
|
* A multichain account wallet that holds multiple multichain accounts (one multichain account per
|
|
16
10
|
* group index).
|
|
@@ -47,6 +41,12 @@ export declare class MultichainAccountWallet<Account extends Bip44Account<Keyrin
|
|
|
47
41
|
* @returns The multichain account wallet entropy source.
|
|
48
42
|
*/
|
|
49
43
|
get entropySource(): EntropySourceId;
|
|
44
|
+
/**
|
|
45
|
+
* Gets the multichain account wallet current status.
|
|
46
|
+
*
|
|
47
|
+
* @returns The multichain account wallet current status.
|
|
48
|
+
*/
|
|
49
|
+
get status(): MultichainAccountWalletStatus;
|
|
50
50
|
/**
|
|
51
51
|
* Gets multichain account for a given ID.
|
|
52
52
|
* The default group ID will default to the multichain account with index 0.
|
|
@@ -83,6 +83,8 @@ export declare class MultichainAccountWallet<Account extends Bip44Account<Keyrin
|
|
|
83
83
|
/**
|
|
84
84
|
* Creates a multichain account group for a given group index.
|
|
85
85
|
*
|
|
86
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
87
|
+
*
|
|
86
88
|
* @param groupIndex - The group index to use.
|
|
87
89
|
* @throws If any of the account providers fails to create their accounts.
|
|
88
90
|
* @returns The multichain account group for this group index.
|
|
@@ -96,26 +98,26 @@ export declare class MultichainAccountWallet<Account extends Bip44Account<Keyrin
|
|
|
96
98
|
*/
|
|
97
99
|
createNextMultichainAccountGroup(): Promise<MultichainAccountGroup<Account>>;
|
|
98
100
|
/**
|
|
99
|
-
*
|
|
101
|
+
* Align all accounts from each existing multichain account groups.
|
|
100
102
|
*
|
|
101
|
-
*
|
|
102
|
-
*/
|
|
103
|
-
getIsAlignmentInProgress(): boolean;
|
|
104
|
-
/**
|
|
105
|
-
* Align all multichain account groups.
|
|
103
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
106
104
|
*/
|
|
107
|
-
|
|
105
|
+
alignAccounts(): Promise<void>;
|
|
108
106
|
/**
|
|
109
107
|
* Align a specific multichain account group.
|
|
110
108
|
*
|
|
109
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
110
|
+
*
|
|
111
111
|
* @param groupIndex - The group index to align.
|
|
112
112
|
*/
|
|
113
113
|
alignGroup(groupIndex: number): Promise<void>;
|
|
114
114
|
/**
|
|
115
115
|
* Discover and create accounts for all providers.
|
|
116
116
|
*
|
|
117
|
+
* NOTE: This operation WILL lock the wallet's mutex.
|
|
118
|
+
*
|
|
117
119
|
* @returns The discovered accounts for each provider.
|
|
118
120
|
*/
|
|
119
|
-
|
|
121
|
+
discoverAccounts(): Promise<Account[]>;
|
|
120
122
|
}
|
|
121
123
|
//# sourceMappingURL=MultichainAccountWallet.d.cts.map
|