@metamask-previews/multichain-account-service 1.2.0-preview-73b4d57 → 1.4.0-preview-683bbcb0
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 +13 -1
- package/dist/MultichainAccountWallet.cjs +35 -24
- package/dist/MultichainAccountWallet.cjs.map +1 -1
- package/dist/MultichainAccountWallet.d.cts +3 -4
- package/dist/MultichainAccountWallet.d.cts.map +1 -1
- package/dist/MultichainAccountWallet.d.mts +3 -4
- package/dist/MultichainAccountWallet.d.mts.map +1 -1
- package/dist/MultichainAccountWallet.mjs +35 -24
- package/dist/MultichainAccountWallet.mjs.map +1 -1
- package/dist/logger.cjs +2 -1
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.d.cts +1 -0
- package/dist/logger.d.cts.map +1 -1
- package/dist/logger.d.mts +1 -0
- package/dist/logger.d.mts.map +1 -1
- package/dist/logger.mjs +1 -0
- package/dist/logger.mjs.map +1 -1
- package/dist/tests/providers.cjs +7 -1
- package/dist/tests/providers.cjs.map +1 -1
- package/dist/tests/providers.d.cts +2 -1
- package/dist/tests/providers.d.cts.map +1 -1
- package/dist/tests/providers.d.mts +2 -1
- package/dist/tests/providers.d.mts.map +1 -1
- package/dist/tests/providers.mjs +7 -1
- package/dist/tests/providers.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.4.0]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Only await for EVM account creation in `MultichainAccountWallet.createMultichainAccountGroup()` instead of all types of providers ([#6755](https://github.com/MetaMask/core/pull/6755))
|
|
15
|
+
- Other type of providers will create accounts in the background and won't throw errors in case they fail to do so.
|
|
16
|
+
- Multichain account groups will now be "misaligned" for a short period of time, until each of the other providers finish creating their accounts.
|
|
17
|
+
|
|
18
|
+
## [1.3.0]
|
|
19
|
+
|
|
10
20
|
### Added
|
|
11
21
|
|
|
12
22
|
- Add `{Btc/Trx}AccountProvider` account providers ([#6662](https://github.com/MetaMask/core/pull/6662))
|
|
@@ -198,7 +208,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
198
208
|
- Add `MultichainAccountService` ([#6141](https://github.com/MetaMask/core/pull/6141)), ([#6165](https://github.com/MetaMask/core/pull/6165))
|
|
199
209
|
- This service manages multichain accounts/wallets.
|
|
200
210
|
|
|
201
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@1.
|
|
211
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@1.4.0...HEAD
|
|
212
|
+
[1.4.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@1.3.0...@metamask/multichain-account-service@1.4.0
|
|
213
|
+
[1.3.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@1.2.0...@metamask/multichain-account-service@1.3.0
|
|
202
214
|
[1.2.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@1.1.0...@metamask/multichain-account-service@1.2.0
|
|
203
215
|
[1.1.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@1.0.0...@metamask/multichain-account-service@1.1.0
|
|
204
216
|
[1.0.0]: https://github.com/MetaMask/core/compare/@metamask/multichain-account-service@0.11.0...@metamask/multichain-account-service@1.0.0
|
|
@@ -14,11 +14,11 @@ var _MultichainAccountWallet_instances, _MultichainAccountWallet_lock, _Multicha
|
|
|
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
|
-
const
|
|
18
|
-
const account_api_3 = require("@metamask/account-api");
|
|
17
|
+
const utils_1 = require("@metamask/utils");
|
|
19
18
|
const async_mutex_1 = require("async-mutex");
|
|
20
19
|
const logger_1 = require("./logger.cjs");
|
|
21
20
|
const MultichainAccountGroup_1 = require("./MultichainAccountGroup.cjs");
|
|
21
|
+
const providers_1 = require("./providers/index.cjs");
|
|
22
22
|
/**
|
|
23
23
|
* A multichain account wallet that holds multiple multichain accounts (one multichain account per
|
|
24
24
|
* group index).
|
|
@@ -111,7 +111,7 @@ class MultichainAccountWallet {
|
|
|
111
111
|
* @returns The multichain account wallet type.
|
|
112
112
|
*/
|
|
113
113
|
get type() {
|
|
114
|
-
return
|
|
114
|
+
return account_api_1.AccountWalletType.Entropy;
|
|
115
115
|
}
|
|
116
116
|
/**
|
|
117
117
|
* Gets the multichain account wallet entropy source.
|
|
@@ -138,7 +138,7 @@ class MultichainAccountWallet {
|
|
|
138
138
|
*/
|
|
139
139
|
getAccountGroup(id) {
|
|
140
140
|
// We consider the "default case" to be mapped to index 0.
|
|
141
|
-
if (id === (0,
|
|
141
|
+
if (id === (0, account_api_1.toDefaultAccountGroupId)(this.id)) {
|
|
142
142
|
return __classPrivateFieldGet(this, _MultichainAccountWallet_accountGroups, "f").get(0);
|
|
143
143
|
}
|
|
144
144
|
// If it is not a valid ID, we cannot extract the group index
|
|
@@ -208,10 +208,37 @@ class MultichainAccountWallet {
|
|
|
208
208
|
return group;
|
|
209
209
|
}
|
|
210
210
|
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `Creating new group for index ${groupIndex}...`);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
// Extract the EVM provider from the list of providers.
|
|
212
|
+
// We will only await the EVM provider to create its accounts, while
|
|
213
|
+
// all other providers will be started in the background.
|
|
214
|
+
const [evmProvider, ...otherProviders] = __classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f");
|
|
215
|
+
(0, utils_1.assert)(evmProvider instanceof providers_1.EvmAccountProvider, 'EVM account provider must be first');
|
|
216
|
+
// Create account with the EVM provider first and await it.
|
|
217
|
+
// If it fails, we don't start creating accounts with other providers.
|
|
218
|
+
try {
|
|
219
|
+
await evmProvider.createAccounts({
|
|
220
|
+
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
221
|
+
groupIndex,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
const errorMessage = `Unable to create multichain account group for index: ${groupIndex} with provider "${evmProvider.getName()}". Error: ${error.message}`;
|
|
226
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `${logger_1.ERROR_PREFIX} ${errorMessage}:`, error);
|
|
227
|
+
throw new Error(errorMessage);
|
|
228
|
+
}
|
|
229
|
+
// Create account with other providers in the background
|
|
230
|
+
otherProviders.forEach((provider) => {
|
|
231
|
+
provider
|
|
232
|
+
.createAccounts({
|
|
233
|
+
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
234
|
+
groupIndex,
|
|
235
|
+
})
|
|
236
|
+
.catch((error) => {
|
|
237
|
+
// Log errors from background providers but don't fail the operation
|
|
238
|
+
const errorMessage = `Could not to create account with provider "${provider.getName()}" for multichain account group index: ${groupIndex}`;
|
|
239
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `${logger_1.WARNING_PREFIX} ${errorMessage}:`, error);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
215
242
|
// --------------------------------------------------------------------------------
|
|
216
243
|
// READ THIS CAREFULLY:
|
|
217
244
|
//
|
|
@@ -233,22 +260,6 @@ class MultichainAccountWallet {
|
|
|
233
260
|
// "aligned" (missing "blockchain account" on this group).
|
|
234
261
|
//
|
|
235
262
|
// --------------------------------------------------------------------------------
|
|
236
|
-
// If any of the provider failed to create their accounts, then we consider the
|
|
237
|
-
// multichain account group to have failed too.
|
|
238
|
-
if (results.some((result) => result.status === 'rejected')) {
|
|
239
|
-
// NOTE: Some accounts might still have been created on other account providers. We
|
|
240
|
-
// don't rollback them.
|
|
241
|
-
const error = `Unable to create multichain account group for index: ${groupIndex}`;
|
|
242
|
-
let message = `${error}:`;
|
|
243
|
-
for (const result of results) {
|
|
244
|
-
if (result.status === 'rejected') {
|
|
245
|
-
message += `\n- ${result.reason}`;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `${logger_1.WARNING_PREFIX} ${message}`);
|
|
249
|
-
console.warn(message);
|
|
250
|
-
throw new Error(error);
|
|
251
|
-
}
|
|
252
263
|
// Because of the :accountAdded automatic sync, we might already have created the
|
|
253
264
|
// group, so we first try to get it.
|
|
254
265
|
group = this.getMultichainAccountGroup(groupIndex);
|
|
@@ -1 +1 @@
|
|
|
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 { Mutex } from 'async-mutex';\n\nimport type { Logger } from './logger';\nimport {\n createModuleLogger,\n projectLogger as log,\n WARNING_PREFIX,\n} from './logger';\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\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 readonly #log: Logger;\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 this.#log = createModuleLogger(log, `[${this.#id}]`);\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 this.#log('Synchronizing with account providers...');\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.#log(`Found a new group: [${multichainAccount.id}]`);\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.#log(`Deleting group: [${multichainAccount.id}]`);\n this.#accountGroups.delete(groupIndex);\n }\n }\n\n this.#log('Synchronized');\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.#log(`Locking wallet with status \"${status}\"...`);\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 this.#log(`Releasing wallet lock (was \"${status}\")`);\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 this.#log(\n `Trying to re-create existing group: [${group.id}] (idempotent)`,\n );\n return group;\n }\n\n this.#log(`Creating new group for index ${groupIndex}...`);\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 message = `${error}:`;\n for (const result of results) {\n if (result.status === 'rejected') {\n message += `\\n- ${result.reason}`;\n }\n }\n this.#log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\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 this.#log(`New group created: [${group.id}]`);\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.alignAccounts()));\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 alignAccountsOf(groupIndex: number): Promise<void> {\n await this.#withLock('in-progress:alignment', async () => {\n const group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n await group.alignAccounts();\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 providerName = context.provider.getName();\n const message = (stepName: string, groupIndex: number) =>\n `[${providerName}] Discovery ${stepName} for group index: ${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(\n message(\n `failed (with: \"${(error as Error).message}\")`,\n targetGroupIndex,\n ),\n error,\n );\n break;\n }\n\n if (!accounts.length) {\n log(\n message('stopped (no accounts got discovered)', targetGroupIndex),\n );\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
|
+
{"version":3,"file":"MultichainAccountWallet.cjs","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountGroupId,\n Bip44Account,\n MultichainAccountWalletId,\n MultichainAccountWallet as MultichainAccountWalletDefinition,\n MultichainAccountWalletStatus,\n} from '@metamask/account-api';\nimport {\n AccountWalletType,\n getGroupIndexFromMultichainAccountGroupId,\n isMultichainAccountGroupId,\n toDefaultAccountGroupId,\n toMultichainAccountWalletId,\n} from '@metamask/account-api';\nimport type { EntropySourceId, KeyringAccount } from '@metamask/keyring-api';\nimport { assert } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { Logger } from './logger';\nimport {\n createModuleLogger,\n ERROR_PREFIX,\n projectLogger as log,\n WARNING_PREFIX,\n} from './logger';\nimport { MultichainAccountGroup } from './MultichainAccountGroup';\nimport { EvmAccountProvider, 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\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 readonly #log: Logger;\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 this.#log = createModuleLogger(log, `[${this.#id}]`);\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 this.#log('Synchronizing with account providers...');\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.#log(`Found a new group: [${multichainAccount.id}]`);\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.#log(`Deleting group: [${multichainAccount.id}]`);\n this.#accountGroups.delete(groupIndex);\n }\n }\n\n this.#log('Synchronized');\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.#log(`Locking wallet with status \"${status}\"...`);\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 this.#log(`Releasing wallet lock (was \"${status}\")`);\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 this.#log(\n `Trying to re-create existing group: [${group.id}] (idempotent)`,\n );\n return group;\n }\n\n this.#log(`Creating new group for index ${groupIndex}...`);\n\n // Extract the EVM provider from the list of providers.\n // We will only await the EVM provider to create its accounts, while\n // all other providers will be started in the background.\n const [evmProvider, ...otherProviders] = this.#providers;\n assert(\n evmProvider instanceof EvmAccountProvider,\n 'EVM account provider must be first',\n );\n\n // Create account with the EVM provider first and await it.\n // If it fails, we don't start creating accounts with other providers.\n try {\n await evmProvider.createAccounts({\n entropySource: this.#entropySource,\n groupIndex,\n });\n } catch (error) {\n const errorMessage = `Unable to create multichain account group for index: ${groupIndex} with provider \"${evmProvider.getName()}\". Error: ${(error as Error).message}`;\n this.#log(`${ERROR_PREFIX} ${errorMessage}:`, error);\n throw new Error(errorMessage);\n }\n\n // Create account with other providers in the background\n otherProviders.forEach((provider) => {\n provider\n .createAccounts({\n entropySource: this.#entropySource,\n groupIndex,\n })\n .catch((error) => {\n // Log errors from background providers but don't fail the operation\n const errorMessage = `Could not to create account with provider \"${provider.getName()}\" for multichain account group index: ${groupIndex}`;\n this.#log(`${WARNING_PREFIX} ${errorMessage}:`, error);\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 // 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 this.#log(`New group created: [${group.id}]`);\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.alignAccounts()));\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 alignAccountsOf(groupIndex: number): Promise<void> {\n await this.#withLock('in-progress:alignment', async () => {\n const group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n await group.alignAccounts();\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 providerName = context.provider.getName();\n const message = (stepName: string, groupIndex: number) =>\n `[${providerName}] Discovery ${stepName} for group index: ${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(\n message(\n `failed (with: \"${(error as Error).message}\")`,\n targetGroupIndex,\n ),\n error,\n );\n break;\n }\n\n if (!accounts.length) {\n log(\n message('stopped (no accounts got discovered)', targetGroupIndex),\n );\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,9 +1,8 @@
|
|
|
1
|
+
import type { AccountGroupId, Bip44Account, MultichainAccountWalletId, MultichainAccountWallet as MultichainAccountWalletDefinition, MultichainAccountWalletStatus } from "@metamask/account-api";
|
|
1
2
|
import { AccountWalletType } from "@metamask/account-api";
|
|
2
|
-
import type {
|
|
3
|
-
import type { AccountGroupId } from "@metamask/account-api";
|
|
4
|
-
import { type EntropySourceId, type KeyringAccount } from "@metamask/keyring-api";
|
|
3
|
+
import type { EntropySourceId, KeyringAccount } from "@metamask/keyring-api";
|
|
5
4
|
import { MultichainAccountGroup } from "./MultichainAccountGroup.cjs";
|
|
6
|
-
import type
|
|
5
|
+
import { type NamedAccountProvider } from "./providers/index.cjs";
|
|
7
6
|
import type { MultichainAccountServiceMessenger } from "./types.cjs";
|
|
8
7
|
/**
|
|
9
8
|
* A multichain account wallet that holds multiple multichain accounts (one multichain account per
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAccountWallet.d.cts","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MultichainAccountWallet.d.cts","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,yBAAyB,EACzB,uBAAuB,IAAI,iCAAiC,EAC5D,6BAA6B,EAC9B,8BAA8B;AAC/B,OAAO,EACL,iBAAiB,EAKlB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,8BAA8B;AAW7E,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAClE,OAAO,EAAsB,KAAK,oBAAoB,EAAE,8BAAoB;AAC5E,OAAO,KAAK,EAAE,iCAAiC,EAAE,oBAAgB;AAcjE;;;GAGG;AACH,qBAAa,uBAAuB,CAClC,OAAO,SAAS,YAAY,CAAC,cAAc,CAAC,CAC5C,YAAW,iCAAiC,CAAC,OAAO,CAAC;;gBAqBzC,EACV,SAAS,EACT,aAAa,EACb,SAAS,GACV,EAAE;QACD,SAAS,EAAE,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,aAAa,EAAE,eAAe,CAAC;QAC/B,SAAS,EAAE,iCAAiC,CAAC;KAC9C;IAgBD;;;;;OAKG;IACH,IAAI,IAAI,IAAI;IAsDZ;;;;OAIG;IACH,IAAI,EAAE,IAAI,yBAAyB,CAElC;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,iBAAiB,CAAC,OAAO,CAEpC;IAED;;;;OAIG;IACH,IAAI,aAAa,IAAI,eAAe,CAEnC;IAED;;;;OAIG;IACH,IAAI,MAAM,IAAI,6BAA6B,CAE1C;IAoCD;;;;;;OAMG;IACH,eAAe,CACb,EAAE,EAAE,cAAc,GACjB,sBAAsB,CAAC,OAAO,CAAC,GAAG,SAAS;IAgB9C;;;;OAIG;IACH,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAIrD;;;;;OAKG;IACH,yBAAyB,CACvB,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAAC,OAAO,CAAC,GAAG,SAAS;IAI9C;;;;OAIG;IACH,0BAA0B,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAI/D;;;;OAIG;IACH,iBAAiB,IAAI,MAAM;IAU3B;;;;;;;;OAQG;IACG,4BAA4B,CAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IA6G3C;;;;;OAKG;IACG,gCAAgC,IAAI,OAAO,CAC/C,sBAAsB,CAAC,OAAO,CAAC,CAChC;IAcD;;;;OAIG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAMpC;;;;;;OAMG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxD;;;;;;OAMG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAkF7C"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import type { AccountGroupId, Bip44Account, MultichainAccountWalletId, MultichainAccountWallet as MultichainAccountWalletDefinition, MultichainAccountWalletStatus } from "@metamask/account-api";
|
|
1
2
|
import { AccountWalletType } from "@metamask/account-api";
|
|
2
|
-
import type {
|
|
3
|
-
import type { AccountGroupId } from "@metamask/account-api";
|
|
4
|
-
import { type EntropySourceId, type KeyringAccount } from "@metamask/keyring-api";
|
|
3
|
+
import type { EntropySourceId, KeyringAccount } from "@metamask/keyring-api";
|
|
5
4
|
import { MultichainAccountGroup } from "./MultichainAccountGroup.mjs";
|
|
6
|
-
import type
|
|
5
|
+
import { type NamedAccountProvider } from "./providers/index.mjs";
|
|
7
6
|
import type { MultichainAccountServiceMessenger } from "./types.mjs";
|
|
8
7
|
/**
|
|
9
8
|
* A multichain account wallet that holds multiple multichain accounts (one multichain account per
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAccountWallet.d.mts","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MultichainAccountWallet.d.mts","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,yBAAyB,EACzB,uBAAuB,IAAI,iCAAiC,EAC5D,6BAA6B,EAC9B,8BAA8B;AAC/B,OAAO,EACL,iBAAiB,EAKlB,8BAA8B;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,8BAA8B;AAW7E,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAClE,OAAO,EAAsB,KAAK,oBAAoB,EAAE,8BAAoB;AAC5E,OAAO,KAAK,EAAE,iCAAiC,EAAE,oBAAgB;AAcjE;;;GAGG;AACH,qBAAa,uBAAuB,CAClC,OAAO,SAAS,YAAY,CAAC,cAAc,CAAC,CAC5C,YAAW,iCAAiC,CAAC,OAAO,CAAC;;gBAqBzC,EACV,SAAS,EACT,aAAa,EACb,SAAS,GACV,EAAE;QACD,SAAS,EAAE,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,aAAa,EAAE,eAAe,CAAC;QAC/B,SAAS,EAAE,iCAAiC,CAAC;KAC9C;IAgBD;;;;;OAKG;IACH,IAAI,IAAI,IAAI;IAsDZ;;;;OAIG;IACH,IAAI,EAAE,IAAI,yBAAyB,CAElC;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,iBAAiB,CAAC,OAAO,CAEpC;IAED;;;;OAIG;IACH,IAAI,aAAa,IAAI,eAAe,CAEnC;IAED;;;;OAIG;IACH,IAAI,MAAM,IAAI,6BAA6B,CAE1C;IAoCD;;;;;;OAMG;IACH,eAAe,CACb,EAAE,EAAE,cAAc,GACjB,sBAAsB,CAAC,OAAO,CAAC,GAAG,SAAS;IAgB9C;;;;OAIG;IACH,gBAAgB,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAIrD;;;;;OAKG;IACH,yBAAyB,CACvB,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAAC,OAAO,CAAC,GAAG,SAAS;IAI9C;;;;OAIG;IACH,0BAA0B,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAI/D;;;;OAIG;IACH,iBAAiB,IAAI,MAAM;IAU3B;;;;;;;;OAQG;IACG,4BAA4B,CAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IA6G3C;;;;;OAKG;IACG,gCAAgC,IAAI,OAAO,CAC/C,sBAAsB,CAAC,OAAO,CAAC,CAChC;IAcD;;;;OAIG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAMpC;;;;;;OAMG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxD;;;;;;OAMG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAkF7C"}
|
|
@@ -10,12 +10,12 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
12
|
var _MultichainAccountWallet_instances, _MultichainAccountWallet_lock, _MultichainAccountWallet_id, _MultichainAccountWallet_providers, _MultichainAccountWallet_entropySource, _MultichainAccountWallet_accountGroups, _MultichainAccountWallet_messenger, _MultichainAccountWallet_log, _MultichainAccountWallet_initialized, _MultichainAccountWallet_status, _MultichainAccountWallet_withLock, _MultichainAccountWallet_alignAccounts;
|
|
13
|
-
import { getGroupIndexFromMultichainAccountGroupId, isMultichainAccountGroupId, toMultichainAccountWalletId } from "@metamask/account-api";
|
|
14
|
-
import {
|
|
15
|
-
import { AccountWalletType } from "@metamask/account-api";
|
|
13
|
+
import { AccountWalletType, getGroupIndexFromMultichainAccountGroupId, isMultichainAccountGroupId, toDefaultAccountGroupId, toMultichainAccountWalletId } from "@metamask/account-api";
|
|
14
|
+
import { assert } from "@metamask/utils";
|
|
16
15
|
import { Mutex } from "async-mutex";
|
|
17
|
-
import { createModuleLogger, projectLogger as log, WARNING_PREFIX } from "./logger.mjs";
|
|
16
|
+
import { createModuleLogger, ERROR_PREFIX, projectLogger as log, WARNING_PREFIX } from "./logger.mjs";
|
|
18
17
|
import { MultichainAccountGroup } from "./MultichainAccountGroup.mjs";
|
|
18
|
+
import { EvmAccountProvider } from "./providers/index.mjs";
|
|
19
19
|
/**
|
|
20
20
|
* A multichain account wallet that holds multiple multichain accounts (one multichain account per
|
|
21
21
|
* group index).
|
|
@@ -205,10 +205,37 @@ export class MultichainAccountWallet {
|
|
|
205
205
|
return group;
|
|
206
206
|
}
|
|
207
207
|
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `Creating new group for index ${groupIndex}...`);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
208
|
+
// Extract the EVM provider from the list of providers.
|
|
209
|
+
// We will only await the EVM provider to create its accounts, while
|
|
210
|
+
// all other providers will be started in the background.
|
|
211
|
+
const [evmProvider, ...otherProviders] = __classPrivateFieldGet(this, _MultichainAccountWallet_providers, "f");
|
|
212
|
+
assert(evmProvider instanceof EvmAccountProvider, 'EVM account provider must be first');
|
|
213
|
+
// Create account with the EVM provider first and await it.
|
|
214
|
+
// If it fails, we don't start creating accounts with other providers.
|
|
215
|
+
try {
|
|
216
|
+
await evmProvider.createAccounts({
|
|
217
|
+
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
218
|
+
groupIndex,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
const errorMessage = `Unable to create multichain account group for index: ${groupIndex} with provider "${evmProvider.getName()}". Error: ${error.message}`;
|
|
223
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `${ERROR_PREFIX} ${errorMessage}:`, error);
|
|
224
|
+
throw new Error(errorMessage);
|
|
225
|
+
}
|
|
226
|
+
// Create account with other providers in the background
|
|
227
|
+
otherProviders.forEach((provider) => {
|
|
228
|
+
provider
|
|
229
|
+
.createAccounts({
|
|
230
|
+
entropySource: __classPrivateFieldGet(this, _MultichainAccountWallet_entropySource, "f"),
|
|
231
|
+
groupIndex,
|
|
232
|
+
})
|
|
233
|
+
.catch((error) => {
|
|
234
|
+
// Log errors from background providers but don't fail the operation
|
|
235
|
+
const errorMessage = `Could not to create account with provider "${provider.getName()}" for multichain account group index: ${groupIndex}`;
|
|
236
|
+
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `${WARNING_PREFIX} ${errorMessage}:`, error);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
212
239
|
// --------------------------------------------------------------------------------
|
|
213
240
|
// READ THIS CAREFULLY:
|
|
214
241
|
//
|
|
@@ -230,22 +257,6 @@ export class MultichainAccountWallet {
|
|
|
230
257
|
// "aligned" (missing "blockchain account" on this group).
|
|
231
258
|
//
|
|
232
259
|
// --------------------------------------------------------------------------------
|
|
233
|
-
// If any of the provider failed to create their accounts, then we consider the
|
|
234
|
-
// multichain account group to have failed too.
|
|
235
|
-
if (results.some((result) => result.status === 'rejected')) {
|
|
236
|
-
// NOTE: Some accounts might still have been created on other account providers. We
|
|
237
|
-
// don't rollback them.
|
|
238
|
-
const error = `Unable to create multichain account group for index: ${groupIndex}`;
|
|
239
|
-
let message = `${error}:`;
|
|
240
|
-
for (const result of results) {
|
|
241
|
-
if (result.status === 'rejected') {
|
|
242
|
-
message += `\n- ${result.reason}`;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
__classPrivateFieldGet(this, _MultichainAccountWallet_log, "f").call(this, `${WARNING_PREFIX} ${message}`);
|
|
246
|
-
console.warn(message);
|
|
247
|
-
throw new Error(error);
|
|
248
|
-
}
|
|
249
260
|
// Because of the :accountAdded automatic sync, we might already have created the
|
|
250
261
|
// group, so we first try to get it.
|
|
251
262
|
group = this.getMultichainAccountGroup(groupIndex);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAccountWallet.mjs","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 { Mutex } from 'async-mutex';\n\nimport type { Logger } from './logger';\nimport {\n createModuleLogger,\n projectLogger as log,\n WARNING_PREFIX,\n} from './logger';\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\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 readonly #log: Logger;\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 this.#log = createModuleLogger(log, `[${this.#id}]`);\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 this.#log('Synchronizing with account providers...');\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.#log(`Found a new group: [${multichainAccount.id}]`);\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.#log(`Deleting group: [${multichainAccount.id}]`);\n this.#accountGroups.delete(groupIndex);\n }\n }\n\n this.#log('Synchronized');\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.#log(`Locking wallet with status \"${status}\"...`);\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 this.#log(`Releasing wallet lock (was \"${status}\")`);\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 this.#log(\n `Trying to re-create existing group: [${group.id}] (idempotent)`,\n );\n return group;\n }\n\n this.#log(`Creating new group for index ${groupIndex}...`);\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 message = `${error}:`;\n for (const result of results) {\n if (result.status === 'rejected') {\n message += `\\n- ${result.reason}`;\n }\n }\n this.#log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\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 this.#log(`New group created: [${group.id}]`);\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.alignAccounts()));\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 alignAccountsOf(groupIndex: number): Promise<void> {\n await this.#withLock('in-progress:alignment', async () => {\n const group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n await group.alignAccounts();\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 providerName = context.provider.getName();\n const message = (stepName: string, groupIndex: number) =>\n `[${providerName}] Discovery ${stepName} for group index: ${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(\n message(\n `failed (with: \"${(error as Error).message}\")`,\n targetGroupIndex,\n ),\n error,\n );\n break;\n }\n\n if (!accounts.length) {\n log(\n message('stopped (no accounts got discovered)', targetGroupIndex),\n );\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
|
+
{"version":3,"file":"MultichainAccountWallet.mjs","sourceRoot":"","sources":["../src/MultichainAccountWallet.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountGroupId,\n Bip44Account,\n MultichainAccountWalletId,\n MultichainAccountWallet as MultichainAccountWalletDefinition,\n MultichainAccountWalletStatus,\n} from '@metamask/account-api';\nimport {\n AccountWalletType,\n getGroupIndexFromMultichainAccountGroupId,\n isMultichainAccountGroupId,\n toDefaultAccountGroupId,\n toMultichainAccountWalletId,\n} from '@metamask/account-api';\nimport type { EntropySourceId, KeyringAccount } from '@metamask/keyring-api';\nimport { assert } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\n\nimport type { Logger } from './logger';\nimport {\n createModuleLogger,\n ERROR_PREFIX,\n projectLogger as log,\n WARNING_PREFIX,\n} from './logger';\nimport { MultichainAccountGroup } from './MultichainAccountGroup';\nimport { EvmAccountProvider, 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\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 readonly #log: Logger;\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 this.#log = createModuleLogger(log, `[${this.#id}]`);\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 this.#log('Synchronizing with account providers...');\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.#log(`Found a new group: [${multichainAccount.id}]`);\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.#log(`Deleting group: [${multichainAccount.id}]`);\n this.#accountGroups.delete(groupIndex);\n }\n }\n\n this.#log('Synchronized');\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.#log(`Locking wallet with status \"${status}\"...`);\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 this.#log(`Releasing wallet lock (was \"${status}\")`);\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 this.#log(\n `Trying to re-create existing group: [${group.id}] (idempotent)`,\n );\n return group;\n }\n\n this.#log(`Creating new group for index ${groupIndex}...`);\n\n // Extract the EVM provider from the list of providers.\n // We will only await the EVM provider to create its accounts, while\n // all other providers will be started in the background.\n const [evmProvider, ...otherProviders] = this.#providers;\n assert(\n evmProvider instanceof EvmAccountProvider,\n 'EVM account provider must be first',\n );\n\n // Create account with the EVM provider first and await it.\n // If it fails, we don't start creating accounts with other providers.\n try {\n await evmProvider.createAccounts({\n entropySource: this.#entropySource,\n groupIndex,\n });\n } catch (error) {\n const errorMessage = `Unable to create multichain account group for index: ${groupIndex} with provider \"${evmProvider.getName()}\". Error: ${(error as Error).message}`;\n this.#log(`${ERROR_PREFIX} ${errorMessage}:`, error);\n throw new Error(errorMessage);\n }\n\n // Create account with other providers in the background\n otherProviders.forEach((provider) => {\n provider\n .createAccounts({\n entropySource: this.#entropySource,\n groupIndex,\n })\n .catch((error) => {\n // Log errors from background providers but don't fail the operation\n const errorMessage = `Could not to create account with provider \"${provider.getName()}\" for multichain account group index: ${groupIndex}`;\n this.#log(`${WARNING_PREFIX} ${errorMessage}:`, error);\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 // 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 this.#log(`New group created: [${group.id}]`);\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.alignAccounts()));\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 alignAccountsOf(groupIndex: number): Promise<void> {\n await this.#withLock('in-progress:alignment', async () => {\n const group = this.getMultichainAccountGroup(groupIndex);\n if (group) {\n await group.alignAccounts();\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 providerName = context.provider.getName();\n const message = (stepName: string, groupIndex: number) =>\n `[${providerName}] Discovery ${stepName} for group index: ${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(\n message(\n `failed (with: \"${(error as Error).message}\")`,\n targetGroupIndex,\n ),\n error,\n );\n break;\n }\n\n if (!accounts.length) {\n log(\n message('stopped (no accounts got discovered)', targetGroupIndex),\n );\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"]}
|
package/dist/logger.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WARNING_PREFIX = exports.createModuleLogger = exports.projectLogger = void 0;
|
|
3
|
+
exports.ERROR_PREFIX = exports.WARNING_PREFIX = exports.createModuleLogger = exports.projectLogger = void 0;
|
|
4
4
|
const utils_1 = require("@metamask/utils");
|
|
5
5
|
Object.defineProperty(exports, "createModuleLogger", { enumerable: true, get: function () { return utils_1.createModuleLogger; } });
|
|
6
6
|
exports.projectLogger = (0, utils_1.createProjectLogger)('multichain-account-service');
|
|
7
7
|
exports.WARNING_PREFIX = 'WARNING --';
|
|
8
|
+
exports.ERROR_PREFIX = 'ERROR --';
|
|
8
9
|
//# sourceMappingURL=logger.cjs.map
|
package/dist/logger.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.cjs","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;AAAA,2CAA0E;AAIjE,mGAJqB,0BAAkB,OAIrB;AAFd,QAAA,aAAa,GAAG,IAAA,2BAAmB,EAAC,4BAA4B,CAAC,CAAC;AAIlE,QAAA,cAAc,GAAG,YAAY,CAAC","sourcesContent":["import { createProjectLogger, createModuleLogger } from '@metamask/utils';\n\nexport const projectLogger = createProjectLogger('multichain-account-service');\n\nexport { createModuleLogger };\n\nexport const WARNING_PREFIX = 'WARNING --';\n\nexport type Logger = typeof projectLogger;\n"]}
|
|
1
|
+
{"version":3,"file":"logger.cjs","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;AAAA,2CAA0E;AAIjE,mGAJqB,0BAAkB,OAIrB;AAFd,QAAA,aAAa,GAAG,IAAA,2BAAmB,EAAC,4BAA4B,CAAC,CAAC;AAIlE,QAAA,cAAc,GAAG,YAAY,CAAC;AAC9B,QAAA,YAAY,GAAG,UAAU,CAAC","sourcesContent":["import { createProjectLogger, createModuleLogger } from '@metamask/utils';\n\nexport const projectLogger = createProjectLogger('multichain-account-service');\n\nexport { createModuleLogger };\n\nexport const WARNING_PREFIX = 'WARNING --';\nexport const ERROR_PREFIX = 'ERROR --';\n\nexport type Logger = typeof projectLogger;\n"]}
|
package/dist/logger.d.cts
CHANGED
|
@@ -3,5 +3,6 @@ import { createModuleLogger } from "@metamask/utils";
|
|
|
3
3
|
export declare const projectLogger: import("debug").Debugger;
|
|
4
4
|
export { createModuleLogger };
|
|
5
5
|
export declare const WARNING_PREFIX = "WARNING --";
|
|
6
|
+
export declare const ERROR_PREFIX = "ERROR --";
|
|
6
7
|
export type Logger = typeof projectLogger;
|
|
7
8
|
//# sourceMappingURL=logger.d.cts.map
|
package/dist/logger.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.cts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,kBAAkB,EAAE,wBAAwB;AAE1E,eAAO,MAAM,aAAa,0BAAoD,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,eAAO,MAAM,cAAc,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.cts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,kBAAkB,EAAE,wBAAwB;AAE1E,eAAO,MAAM,aAAa,0BAAoD,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC,MAAM,MAAM,MAAM,GAAG,OAAO,aAAa,CAAC"}
|
package/dist/logger.d.mts
CHANGED
|
@@ -3,5 +3,6 @@ import { createModuleLogger } from "@metamask/utils";
|
|
|
3
3
|
export declare const projectLogger: import("debug").Debugger;
|
|
4
4
|
export { createModuleLogger };
|
|
5
5
|
export declare const WARNING_PREFIX = "WARNING --";
|
|
6
|
+
export declare const ERROR_PREFIX = "ERROR --";
|
|
6
7
|
export type Logger = typeof projectLogger;
|
|
7
8
|
//# sourceMappingURL=logger.d.mts.map
|
package/dist/logger.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.mts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,kBAAkB,EAAE,wBAAwB;AAE1E,eAAO,MAAM,aAAa,0BAAoD,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,eAAO,MAAM,cAAc,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.mts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,kBAAkB,EAAE,wBAAwB;AAE1E,eAAO,MAAM,aAAa,0BAAoD,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC,MAAM,MAAM,MAAM,GAAG,OAAO,aAAa,CAAC"}
|
package/dist/logger.mjs
CHANGED
|
@@ -2,4 +2,5 @@ import { createProjectLogger, createModuleLogger } from "@metamask/utils";
|
|
|
2
2
|
export const projectLogger = createProjectLogger('multichain-account-service');
|
|
3
3
|
export { createModuleLogger };
|
|
4
4
|
export const WARNING_PREFIX = 'WARNING --';
|
|
5
|
+
export const ERROR_PREFIX = 'ERROR --';
|
|
5
6
|
//# sourceMappingURL=logger.mjs.map
|
package/dist/logger.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.mjs","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,wBAAwB;AAE1E,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC,4BAA4B,CAAC,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC","sourcesContent":["import { createProjectLogger, createModuleLogger } from '@metamask/utils';\n\nexport const projectLogger = createProjectLogger('multichain-account-service');\n\nexport { createModuleLogger };\n\nexport const WARNING_PREFIX = 'WARNING --';\n\nexport type Logger = typeof projectLogger;\n"]}
|
|
1
|
+
{"version":3,"file":"logger.mjs","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,wBAAwB;AAE1E,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC,4BAA4B,CAAC,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC","sourcesContent":["import { createProjectLogger, createModuleLogger } from '@metamask/utils';\n\nexport const projectLogger = createProjectLogger('multichain-account-service');\n\nexport { createModuleLogger };\n\nexport const WARNING_PREFIX = 'WARNING --';\nexport const ERROR_PREFIX = 'ERROR --';\n\nexport type Logger = typeof projectLogger;\n"]}
|
package/dist/tests/providers.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.setupNamedAccountProvider = exports.makeMockAccountProvider = void 0;
|
|
5
5
|
const account_api_1 = require("@metamask/account-api");
|
|
6
|
+
const providers_1 = require("../providers/index.cjs");
|
|
6
7
|
function makeMockAccountProvider(accounts = []) {
|
|
7
8
|
return {
|
|
8
9
|
accounts,
|
|
@@ -16,7 +17,7 @@ function makeMockAccountProvider(accounts = []) {
|
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
exports.makeMockAccountProvider = makeMockAccountProvider;
|
|
19
|
-
function setupNamedAccountProvider({ name = 'Mocked Provider', accounts, mocks = makeMockAccountProvider(), filter = () => true, }) {
|
|
20
|
+
function setupNamedAccountProvider({ name = 'Mocked Provider', accounts, mocks = makeMockAccountProvider(), filter = () => true, index, }) {
|
|
20
21
|
// You can mock this and all other mocks will re-use that list
|
|
21
22
|
// of accounts.
|
|
22
23
|
mocks.accounts = accounts;
|
|
@@ -27,6 +28,11 @@ function setupNamedAccountProvider({ name = 'Mocked Provider', accounts, mocks =
|
|
|
27
28
|
// Assuming this never fails.
|
|
28
29
|
getAccounts().find((account) => account.id === id));
|
|
29
30
|
mocks.createAccounts.mockResolvedValue([]);
|
|
31
|
+
if (index === 0) {
|
|
32
|
+
// Make the first provider to always be an `EvmAccountProvider`, since we
|
|
33
|
+
// check for this pre-condition in some methods.
|
|
34
|
+
Object.setPrototypeOf(mocks, providers_1.EvmAccountProvider.prototype);
|
|
35
|
+
}
|
|
30
36
|
return mocks;
|
|
31
37
|
}
|
|
32
38
|
exports.setupNamedAccountProvider = setupNamedAccountProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.cjs","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":";AAAA,wCAAwC;;;AAGxC,uDAAuD;
|
|
1
|
+
{"version":3,"file":"providers.cjs","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":";AAAA,wCAAwC;;;AAGxC,uDAAuD;AAGvD,sDAAkD;AAalD,SAAgB,uBAAuB,CACrC,WAA6B,EAAE;IAE/B,OAAO;QACL,QAAQ;QACR,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE;QACrB,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC3B,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC9B,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;KACnB,CAAC;AACJ,CAAC;AAbD,0DAaC;AAED,SAAgB,yBAAyB,CAAC,EACxC,IAAI,GAAG,iBAAiB,EACxB,QAAQ,EACR,KAAK,GAAG,uBAAuB,EAAE,EACjC,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,EACnB,KAAK,GAON;IACC,8DAA8D;IAC9D,eAAe;IACf,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAE1B,MAAM,WAAW,GAAG,GAAG,EAAE,CACvB,KAAK,CAAC,QAAQ,CAAC,MAAM,CACnB,CAAC,OAAO,EAAE,EAAE,CAAC,IAAA,4BAAc,EAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CACxD,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAE7C,KAAK,CAAC,WAAW,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAClD,KAAK,CAAC,UAAU,CAAC,kBAAkB,CACjC,CAAC,EAAsC,EAAE,EAAE;IACzC,6BAA6B;IAC7B,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CACrD,CAAC;IACF,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAE3C,IAAI,KAAK,KAAK,CAAC,EAAE;QACf,yEAAyE;QACzE,gDAAgD;QAChD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,8BAAkB,CAAC,SAAS,CAAC,CAAC;KAC5D;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAvCD,8DAuCC","sourcesContent":["/* eslint-disable jsdoc/require-jsdoc */\n\nimport type { Bip44Account } from '@metamask/account-api';\nimport { isBip44Account } from '@metamask/account-api';\nimport type { KeyringAccount } from '@metamask/keyring-api';\n\nimport { EvmAccountProvider } from '../providers';\n\nexport type MockAccountProvider = {\n accounts: KeyringAccount[];\n constructor: jest.Mock;\n getAccount: jest.Mock;\n getAccounts: jest.Mock;\n createAccounts: jest.Mock;\n discoverAccounts: jest.Mock;\n isAccountCompatible?: jest.Mock;\n getName: jest.Mock;\n};\n\nexport function makeMockAccountProvider(\n accounts: KeyringAccount[] = [],\n): MockAccountProvider {\n return {\n accounts,\n constructor: jest.fn(),\n getAccount: jest.fn(),\n getAccounts: jest.fn(),\n createAccounts: jest.fn(),\n discoverAccounts: jest.fn(),\n isAccountCompatible: jest.fn(),\n getName: jest.fn(),\n };\n}\n\nexport function setupNamedAccountProvider({\n name = 'Mocked Provider',\n accounts,\n mocks = makeMockAccountProvider(),\n filter = () => true,\n index,\n}: {\n name?: string;\n mocks?: MockAccountProvider;\n accounts: KeyringAccount[];\n filter?: (account: KeyringAccount) => boolean;\n index?: number;\n}): MockAccountProvider {\n // You can mock this and all other mocks will re-use that list\n // of accounts.\n mocks.accounts = accounts;\n\n const getAccounts = () =>\n mocks.accounts.filter(\n (account) => isBip44Account(account) && filter(account),\n );\n\n mocks.getName.mockImplementation(() => name);\n\n mocks.getAccounts.mockImplementation(getAccounts);\n mocks.getAccount.mockImplementation(\n (id: Bip44Account<KeyringAccount>['id']) =>\n // Assuming this never fails.\n getAccounts().find((account) => account.id === id),\n );\n mocks.createAccounts.mockResolvedValue([]);\n\n if (index === 0) {\n // Make the first provider to always be an `EvmAccountProvider`, since we\n // check for this pre-condition in some methods.\n Object.setPrototypeOf(mocks, EvmAccountProvider.prototype);\n }\n\n return mocks;\n}\n"]}
|
|
@@ -11,10 +11,11 @@ export type MockAccountProvider = {
|
|
|
11
11
|
getName: jest.Mock;
|
|
12
12
|
};
|
|
13
13
|
export declare function makeMockAccountProvider(accounts?: KeyringAccount[]): MockAccountProvider;
|
|
14
|
-
export declare function setupNamedAccountProvider({ name, accounts, mocks, filter, }: {
|
|
14
|
+
export declare function setupNamedAccountProvider({ name, accounts, mocks, filter, index, }: {
|
|
15
15
|
name?: string;
|
|
16
16
|
mocks?: MockAccountProvider;
|
|
17
17
|
accounts: KeyringAccount[];
|
|
18
18
|
filter?: (account: KeyringAccount) => boolean;
|
|
19
|
+
index?: number;
|
|
19
20
|
}): MockAccountProvider;
|
|
20
21
|
//# sourceMappingURL=providers.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.cts","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":";AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,8BAA8B;
|
|
1
|
+
{"version":3,"file":"providers.d.cts","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":";AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,8BAA8B;AAI5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC;IACvB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC;IACtB,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC;IACvB,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC;IAC1B,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC;IAC5B,mBAAmB,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;IAChC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;CACpB,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,QAAQ,GAAE,cAAc,EAAO,GAC9B,mBAAmB,CAWrB;AAED,wBAAgB,yBAAyB,CAAC,EACxC,IAAwB,EACxB,QAAQ,EACR,KAAiC,EACjC,MAAmB,EACnB,KAAK,GACN,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA2BtB"}
|
|
@@ -11,10 +11,11 @@ export type MockAccountProvider = {
|
|
|
11
11
|
getName: jest.Mock;
|
|
12
12
|
};
|
|
13
13
|
export declare function makeMockAccountProvider(accounts?: KeyringAccount[]): MockAccountProvider;
|
|
14
|
-
export declare function setupNamedAccountProvider({ name, accounts, mocks, filter, }: {
|
|
14
|
+
export declare function setupNamedAccountProvider({ name, accounts, mocks, filter, index, }: {
|
|
15
15
|
name?: string;
|
|
16
16
|
mocks?: MockAccountProvider;
|
|
17
17
|
accounts: KeyringAccount[];
|
|
18
18
|
filter?: (account: KeyringAccount) => boolean;
|
|
19
|
+
index?: number;
|
|
19
20
|
}): MockAccountProvider;
|
|
20
21
|
//# sourceMappingURL=providers.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.mts","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":";AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,8BAA8B;
|
|
1
|
+
{"version":3,"file":"providers.d.mts","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":";AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,8BAA8B;AAI5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC;IACvB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC;IACtB,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC;IACvB,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC;IAC1B,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC;IAC5B,mBAAmB,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;IAChC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC;CACpB,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,QAAQ,GAAE,cAAc,EAAO,GAC9B,mBAAmB,CAWrB;AAED,wBAAgB,yBAAyB,CAAC,EACxC,IAAwB,EACxB,QAAQ,EACR,KAAiC,EACjC,MAAmB,EACnB,KAAK,GACN,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,mBAAmB,CA2BtB"}
|
package/dist/tests/providers.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable jsdoc/require-jsdoc */
|
|
2
2
|
import { isBip44Account } from "@metamask/account-api";
|
|
3
|
+
import { EvmAccountProvider } from "../providers/index.mjs";
|
|
3
4
|
export function makeMockAccountProvider(accounts = []) {
|
|
4
5
|
return {
|
|
5
6
|
accounts,
|
|
@@ -12,7 +13,7 @@ export function makeMockAccountProvider(accounts = []) {
|
|
|
12
13
|
getName: jest.fn(),
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
|
-
export function setupNamedAccountProvider({ name = 'Mocked Provider', accounts, mocks = makeMockAccountProvider(), filter = () => true, }) {
|
|
16
|
+
export function setupNamedAccountProvider({ name = 'Mocked Provider', accounts, mocks = makeMockAccountProvider(), filter = () => true, index, }) {
|
|
16
17
|
// You can mock this and all other mocks will re-use that list
|
|
17
18
|
// of accounts.
|
|
18
19
|
mocks.accounts = accounts;
|
|
@@ -23,6 +24,11 @@ export function setupNamedAccountProvider({ name = 'Mocked Provider', accounts,
|
|
|
23
24
|
// Assuming this never fails.
|
|
24
25
|
getAccounts().find((account) => account.id === id));
|
|
25
26
|
mocks.createAccounts.mockResolvedValue([]);
|
|
27
|
+
if (index === 0) {
|
|
28
|
+
// Make the first provider to always be an `EvmAccountProvider`, since we
|
|
29
|
+
// check for this pre-condition in some methods.
|
|
30
|
+
Object.setPrototypeOf(mocks, EvmAccountProvider.prototype);
|
|
31
|
+
}
|
|
26
32
|
return mocks;
|
|
27
33
|
}
|
|
28
34
|
//# sourceMappingURL=providers.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.mjs","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAGxC,OAAO,EAAE,cAAc,EAAE,8BAA8B;
|
|
1
|
+
{"version":3,"file":"providers.mjs","sourceRoot":"","sources":["../../src/tests/providers.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAGxC,OAAO,EAAE,cAAc,EAAE,8BAA8B;AAGvD,OAAO,EAAE,kBAAkB,EAAE,+BAAqB;AAalD,MAAM,UAAU,uBAAuB,CACrC,WAA6B,EAAE;IAE/B,OAAO;QACL,QAAQ;QACR,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE;QACrB,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC3B,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC9B,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,EACxC,IAAI,GAAG,iBAAiB,EACxB,QAAQ,EACR,KAAK,GAAG,uBAAuB,EAAE,EACjC,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,EACnB,KAAK,GAON;IACC,8DAA8D;IAC9D,eAAe;IACf,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAE1B,MAAM,WAAW,GAAG,GAAG,EAAE,CACvB,KAAK,CAAC,QAAQ,CAAC,MAAM,CACnB,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CACxD,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAE7C,KAAK,CAAC,WAAW,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAClD,KAAK,CAAC,UAAU,CAAC,kBAAkB,CACjC,CAAC,EAAsC,EAAE,EAAE;IACzC,6BAA6B;IAC7B,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CACrD,CAAC;IACF,KAAK,CAAC,cAAc,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAE3C,IAAI,KAAK,KAAK,CAAC,EAAE;QACf,yEAAyE;QACzE,gDAAgD;QAChD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;KAC5D;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/* eslint-disable jsdoc/require-jsdoc */\n\nimport type { Bip44Account } from '@metamask/account-api';\nimport { isBip44Account } from '@metamask/account-api';\nimport type { KeyringAccount } from '@metamask/keyring-api';\n\nimport { EvmAccountProvider } from '../providers';\n\nexport type MockAccountProvider = {\n accounts: KeyringAccount[];\n constructor: jest.Mock;\n getAccount: jest.Mock;\n getAccounts: jest.Mock;\n createAccounts: jest.Mock;\n discoverAccounts: jest.Mock;\n isAccountCompatible?: jest.Mock;\n getName: jest.Mock;\n};\n\nexport function makeMockAccountProvider(\n accounts: KeyringAccount[] = [],\n): MockAccountProvider {\n return {\n accounts,\n constructor: jest.fn(),\n getAccount: jest.fn(),\n getAccounts: jest.fn(),\n createAccounts: jest.fn(),\n discoverAccounts: jest.fn(),\n isAccountCompatible: jest.fn(),\n getName: jest.fn(),\n };\n}\n\nexport function setupNamedAccountProvider({\n name = 'Mocked Provider',\n accounts,\n mocks = makeMockAccountProvider(),\n filter = () => true,\n index,\n}: {\n name?: string;\n mocks?: MockAccountProvider;\n accounts: KeyringAccount[];\n filter?: (account: KeyringAccount) => boolean;\n index?: number;\n}): MockAccountProvider {\n // You can mock this and all other mocks will re-use that list\n // of accounts.\n mocks.accounts = accounts;\n\n const getAccounts = () =>\n mocks.accounts.filter(\n (account) => isBip44Account(account) && filter(account),\n );\n\n mocks.getName.mockImplementation(() => name);\n\n mocks.getAccounts.mockImplementation(getAccounts);\n mocks.getAccount.mockImplementation(\n (id: Bip44Account<KeyringAccount>['id']) =>\n // Assuming this never fails.\n getAccounts().find((account) => account.id === id),\n );\n mocks.createAccounts.mockResolvedValue([]);\n\n if (index === 0) {\n // Make the first provider to always be an `EvmAccountProvider`, since we\n // check for this pre-condition in some methods.\n Object.setPrototypeOf(mocks, EvmAccountProvider.prototype);\n }\n\n return mocks;\n}\n"]}
|