@metamask-previews/multichain-account-service 5.0.0-preview-fa81dffb → 5.1.0-preview-903db2da

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/dist/MultichainAccountGroup.cjs +84 -45
  3. package/dist/MultichainAccountGroup.cjs.map +1 -1
  4. package/dist/MultichainAccountGroup.d.cts +17 -4
  5. package/dist/MultichainAccountGroup.d.cts.map +1 -1
  6. package/dist/MultichainAccountGroup.d.mts +17 -4
  7. package/dist/MultichainAccountGroup.d.mts.map +1 -1
  8. package/dist/MultichainAccountGroup.mjs +84 -45
  9. package/dist/MultichainAccountGroup.mjs.map +1 -1
  10. package/dist/MultichainAccountService.cjs +154 -113
  11. package/dist/MultichainAccountService.cjs.map +1 -1
  12. package/dist/MultichainAccountService.d.cts +48 -20
  13. package/dist/MultichainAccountService.d.cts.map +1 -1
  14. package/dist/MultichainAccountService.d.mts +48 -20
  15. package/dist/MultichainAccountService.d.mts.map +1 -1
  16. package/dist/MultichainAccountService.mjs +155 -114
  17. package/dist/MultichainAccountService.mjs.map +1 -1
  18. package/dist/MultichainAccountWallet.cjs +108 -123
  19. package/dist/MultichainAccountWallet.cjs.map +1 -1
  20. package/dist/MultichainAccountWallet.d.cts +5 -4
  21. package/dist/MultichainAccountWallet.d.cts.map +1 -1
  22. package/dist/MultichainAccountWallet.d.mts +5 -4
  23. package/dist/MultichainAccountWallet.d.mts.map +1 -1
  24. package/dist/MultichainAccountWallet.mjs +108 -123
  25. package/dist/MultichainAccountWallet.mjs.map +1 -1
  26. package/dist/providers/AccountProviderWrapper.cjs +18 -0
  27. package/dist/providers/AccountProviderWrapper.cjs.map +1 -1
  28. package/dist/providers/AccountProviderWrapper.d.cts +12 -0
  29. package/dist/providers/AccountProviderWrapper.d.cts.map +1 -1
  30. package/dist/providers/AccountProviderWrapper.d.mts +12 -0
  31. package/dist/providers/AccountProviderWrapper.d.mts.map +1 -1
  32. package/dist/providers/AccountProviderWrapper.mjs +18 -0
  33. package/dist/providers/AccountProviderWrapper.mjs.map +1 -1
  34. package/dist/providers/BaseBip44AccountProvider.cjs +45 -20
  35. package/dist/providers/BaseBip44AccountProvider.cjs.map +1 -1
  36. package/dist/providers/BaseBip44AccountProvider.d.cts +58 -6
  37. package/dist/providers/BaseBip44AccountProvider.d.cts.map +1 -1
  38. package/dist/providers/BaseBip44AccountProvider.d.mts +58 -6
  39. package/dist/providers/BaseBip44AccountProvider.d.mts.map +1 -1
  40. package/dist/providers/BaseBip44AccountProvider.mjs +45 -20
  41. package/dist/providers/BaseBip44AccountProvider.mjs.map +1 -1
  42. package/dist/providers/BtcAccountProvider.cjs +1 -0
  43. package/dist/providers/BtcAccountProvider.cjs.map +1 -1
  44. package/dist/providers/BtcAccountProvider.d.cts.map +1 -1
  45. package/dist/providers/BtcAccountProvider.d.mts.map +1 -1
  46. package/dist/providers/BtcAccountProvider.mjs +1 -0
  47. package/dist/providers/BtcAccountProvider.mjs.map +1 -1
  48. package/dist/providers/EvmAccountProvider.cjs +39 -5
  49. package/dist/providers/EvmAccountProvider.cjs.map +1 -1
  50. package/dist/providers/EvmAccountProvider.d.cts +8 -0
  51. package/dist/providers/EvmAccountProvider.d.cts.map +1 -1
  52. package/dist/providers/EvmAccountProvider.d.mts +8 -0
  53. package/dist/providers/EvmAccountProvider.d.mts.map +1 -1
  54. package/dist/providers/EvmAccountProvider.mjs +39 -5
  55. package/dist/providers/EvmAccountProvider.mjs.map +1 -1
  56. package/dist/providers/SnapAccountProvider.cjs +20 -8
  57. package/dist/providers/SnapAccountProvider.cjs.map +1 -1
  58. package/dist/providers/SnapAccountProvider.d.cts.map +1 -1
  59. package/dist/providers/SnapAccountProvider.d.mts.map +1 -1
  60. package/dist/providers/SnapAccountProvider.mjs +20 -8
  61. package/dist/providers/SnapAccountProvider.mjs.map +1 -1
  62. package/dist/providers/SolAccountProvider.cjs +4 -0
  63. package/dist/providers/SolAccountProvider.cjs.map +1 -1
  64. package/dist/providers/SolAccountProvider.d.cts.map +1 -1
  65. package/dist/providers/SolAccountProvider.d.mts.map +1 -1
  66. package/dist/providers/SolAccountProvider.mjs +4 -0
  67. package/dist/providers/SolAccountProvider.mjs.map +1 -1
  68. package/dist/providers/TrxAccountProvider.cjs +1 -0
  69. package/dist/providers/TrxAccountProvider.cjs.map +1 -1
  70. package/dist/providers/TrxAccountProvider.d.cts.map +1 -1
  71. package/dist/providers/TrxAccountProvider.d.mts.map +1 -1
  72. package/dist/providers/TrxAccountProvider.mjs +1 -0
  73. package/dist/providers/TrxAccountProvider.mjs.map +1 -1
  74. package/dist/tests/messenger.cjs +4 -0
  75. package/dist/tests/messenger.cjs.map +1 -1
  76. package/dist/tests/messenger.d.cts.map +1 -1
  77. package/dist/tests/messenger.d.mts.map +1 -1
  78. package/dist/tests/messenger.mjs +4 -0
  79. package/dist/tests/messenger.mjs.map +1 -1
  80. package/dist/tests/providers.cjs +62 -7
  81. package/dist/tests/providers.cjs.map +1 -1
  82. package/dist/tests/providers.d.cts +17 -3
  83. package/dist/tests/providers.d.cts.map +1 -1
  84. package/dist/tests/providers.d.mts +17 -3
  85. package/dist/tests/providers.d.mts.map +1 -1
  86. package/dist/tests/providers.mjs +60 -6
  87. package/dist/tests/providers.mjs.map +1 -1
  88. package/dist/types.cjs.map +1 -1
  89. package/dist/types.d.cts +8 -4
  90. package/dist/types.d.cts.map +1 -1
  91. package/dist/types.d.mts +8 -4
  92. package/dist/types.d.mts.map +1 -1
  93. package/dist/types.mjs.map +1 -1
  94. package/dist/utils.cjs +1 -11
  95. package/dist/utils.cjs.map +1 -1
  96. package/dist/utils.d.cts +0 -1
  97. package/dist/utils.d.cts.map +1 -1
  98. package/dist/utils.d.mts +0 -1
  99. package/dist/utils.d.mts.map +1 -1
  100. package/dist/utils.mjs +0 -9
  101. package/dist/utils.mjs.map +1 -1
  102. package/package.json +1 -1
@@ -9,16 +9,18 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _MultichainAccountGroup_id, _MultichainAccountGroup_wallet, _MultichainAccountGroup_groupIndex, _MultichainAccountGroup_providers, _MultichainAccountGroup_providerToAccounts, _MultichainAccountGroup_accountToProvider, _MultichainAccountGroup_messenger, _MultichainAccountGroup_log, _MultichainAccountGroup_initialized;
12
+ var _MultichainAccountGroup_instances, _MultichainAccountGroup_id, _MultichainAccountGroup_wallet, _MultichainAccountGroup_groupIndex, _MultichainAccountGroup_providers, _MultichainAccountGroup_providerToAccounts, _MultichainAccountGroup_accountToProvider, _MultichainAccountGroup_messenger, _MultichainAccountGroup_log, _MultichainAccountGroup_initialized, _MultichainAccountGroup_clearAccountToProviderState, _MultichainAccountGroup_setState;
13
13
  import { AccountGroupType, select, selectOne } from "@metamask/account-api";
14
14
  import { toMultichainAccountGroupId } from "@metamask/account-api";
15
15
  import { projectLogger as log, createModuleLogger, WARNING_PREFIX } from "./logger.mjs";
16
+ import { isAccountProviderWrapper } from "./providers/index.mjs";
16
17
  import { createSentryError } from "./utils.mjs";
17
18
  /**
18
19
  * A multichain account group that holds multiple accounts.
19
20
  */
20
21
  export class MultichainAccountGroup {
21
22
  constructor({ groupIndex, wallet, providers, messenger, }) {
23
+ _MultichainAccountGroup_instances.add(this);
22
24
  _MultichainAccountGroup_id.set(this, void 0);
23
25
  _MultichainAccountGroup_wallet.set(this, void 0);
24
26
  _MultichainAccountGroup_groupIndex.set(this, void 0);
@@ -27,7 +29,6 @@ export class MultichainAccountGroup {
27
29
  _MultichainAccountGroup_accountToProvider.set(this, void 0);
28
30
  _MultichainAccountGroup_messenger.set(this, void 0);
29
31
  _MultichainAccountGroup_log.set(this, void 0);
30
- // eslint-disable-next-line @typescript-eslint/prefer-readonly
31
32
  _MultichainAccountGroup_initialized.set(this, false);
32
33
  __classPrivateFieldSet(this, _MultichainAccountGroup_id, toMultichainAccountGroupId(wallet.id, groupIndex), "f");
33
34
  __classPrivateFieldSet(this, _MultichainAccountGroup_groupIndex, groupIndex, "f");
@@ -37,41 +38,26 @@ export class MultichainAccountGroup {
37
38
  __classPrivateFieldSet(this, _MultichainAccountGroup_providerToAccounts, new Map(), "f");
38
39
  __classPrivateFieldSet(this, _MultichainAccountGroup_accountToProvider, new Map(), "f");
39
40
  __classPrivateFieldSet(this, _MultichainAccountGroup_log, createModuleLogger(log, `[${__classPrivateFieldGet(this, _MultichainAccountGroup_id, "f")}]`), "f");
40
- this.sync();
41
- __classPrivateFieldSet(this, _MultichainAccountGroup_initialized, true, "f");
42
41
  }
43
42
  /**
44
- * Force multichain account synchronization.
43
+ * Initialize the multichain account group and construct the internal representation of accounts.
45
44
  *
46
- * This can be used if account providers got new accounts that the multichain
47
- * account doesn't know about.
45
+ * @param groupState - The group state.
48
46
  */
49
- sync() {
50
- __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Synchronizing with account providers...');
51
- // Clear reverse mapping and re-construct it entirely based on the refreshed
52
- // list of accounts from each providers.
53
- __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").clear();
54
- for (const provider of __classPrivateFieldGet(this, _MultichainAccountGroup_providers, "f")) {
55
- // Filter account only for that index.
56
- const accounts = [];
57
- for (const account of provider.getAccounts()) {
58
- if (account.options.entropy.id === this.wallet.entropySource &&
59
- account.options.entropy.groupIndex === this.groupIndex) {
60
- // We only use IDs to always fetch the latest version of accounts.
61
- accounts.push(account.id);
62
- }
63
- }
64
- __classPrivateFieldGet(this, _MultichainAccountGroup_providerToAccounts, "f").set(provider, accounts);
65
- // Reverse-mapping for fast indexing.
66
- for (const id of accounts) {
67
- __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").set(id, provider);
68
- }
69
- }
70
- // Emit update event when group is synced (only if initialized)
71
- if (__classPrivateFieldGet(this, _MultichainAccountGroup_initialized, "f")) {
72
- __classPrivateFieldGet(this, _MultichainAccountGroup_messenger, "f").publish('MultichainAccountService:multichainAccountGroupUpdated', this);
73
- }
74
- __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Synchronized');
47
+ init(groupState) {
48
+ __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Initializing group state...');
49
+ __classPrivateFieldGet(this, _MultichainAccountGroup_instances, "m", _MultichainAccountGroup_setState).call(this, groupState);
50
+ __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Finished initializing group state...');
51
+ }
52
+ /**
53
+ * Update the group state.
54
+ *
55
+ * @param groupState - The group state.
56
+ */
57
+ update(groupState) {
58
+ __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Updating group state...');
59
+ __classPrivateFieldGet(this, _MultichainAccountGroup_instances, "m", _MultichainAccountGroup_setState).call(this, groupState);
60
+ __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Finished updating group state...');
75
61
  }
76
62
  /**
77
63
  * Gets the multichain account group ID.
@@ -134,6 +120,14 @@ export class MultichainAccountGroup {
134
120
  }
135
121
  return allAccounts;
136
122
  }
123
+ /**
124
+ * Gets the account IDs for this multichain account.
125
+ *
126
+ * @returns The account IDs.
127
+ */
128
+ getAccountIds() {
129
+ return [...__classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").keys()];
130
+ }
137
131
  /**
138
132
  * Gets the account for a given account ID.
139
133
  *
@@ -175,19 +169,26 @@ export class MultichainAccountGroup {
175
169
  */
176
170
  async alignAccounts() {
177
171
  __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Aligning accounts...');
172
+ __classPrivateFieldGet(this, _MultichainAccountGroup_providerToAccounts, "f").clear();
173
+ __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").clear();
178
174
  const results = await Promise.allSettled(__classPrivateFieldGet(this, _MultichainAccountGroup_providers, "f").map(async (provider) => {
179
175
  try {
180
- const accounts = __classPrivateFieldGet(this, _MultichainAccountGroup_providerToAccounts, "f").get(provider);
181
- if (!accounts || accounts.length === 0) {
176
+ const accounts = await provider.alignAccounts({
177
+ entropySource: this.wallet.entropySource,
178
+ groupIndex: this.groupIndex,
179
+ });
180
+ const isDisabled = isAccountProviderWrapper(provider) && provider.isDisabled();
181
+ if (isDisabled) {
182
+ __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, `Account provider "${provider.getName()}" is disabled, skipping alignment...`);
183
+ }
184
+ else if (accounts.length > 0) {
182
185
  __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, `Found missing accounts for account provider "${provider.getName()}", creating them now...`);
183
- const created = await provider.createAccounts({
184
- entropySource: this.wallet.entropySource,
185
- groupIndex: this.groupIndex,
186
- });
187
- __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, `Created ${created.length} accounts`);
188
- return created;
186
+ __classPrivateFieldGet(this, _MultichainAccountGroup_providerToAccounts, "f").set(provider, accounts);
187
+ for (const accountId of accounts) {
188
+ __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").set(accountId, provider);
189
+ }
189
190
  }
190
- return Promise.resolve();
191
+ return accounts;
191
192
  }
192
193
  catch (error) {
193
194
  // istanbul ignore next
@@ -200,13 +201,51 @@ export class MultichainAccountGroup {
200
201
  throw error;
201
202
  }
202
203
  }));
203
- if (results.some((result) => result.status === 'rejected')) {
204
- const message = `Failed to fully align multichain account group for entropy ID: ${this.wallet.entropySource} and group index: ${this.groupIndex}, some accounts might be missing`;
204
+ let failureMessage = '';
205
+ let failureCount = 0;
206
+ const groupState = results.reduce((state, result, idx) => {
207
+ if (result.status === 'fulfilled' && result.value.length) {
208
+ state[__classPrivateFieldGet(this, _MultichainAccountGroup_providers, "f")[idx].getName()] = result.value;
209
+ }
210
+ else if (result.status === 'rejected') {
211
+ failureCount += 1;
212
+ failureMessage += `\n- ${__classPrivateFieldGet(this, _MultichainAccountGroup_providers, "f")[idx].getName()}: ${result.reason.message}`;
213
+ }
214
+ return state;
215
+ }, {});
216
+ // Update group state
217
+ this.update(groupState);
218
+ if (failureCount > 0) {
219
+ const hasMultipleFailures = failureCount > 1;
220
+ const message = `Failed to fully align multichain account group for entropy ID: ${this.wallet.entropySource} and group index: ${this.groupIndex}, some accounts might be missing. ${hasMultipleFailures ? 'Providers' : 'Provider'} threw the following ${hasMultipleFailures ? 'errors' : 'error'}:${failureMessage}`;
205
221
  __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, `${WARNING_PREFIX} ${message}`);
206
222
  console.warn(message);
207
223
  }
208
224
  __classPrivateFieldGet(this, _MultichainAccountGroup_log, "f").call(this, 'Aligned');
209
225
  }
210
226
  }
211
- _MultichainAccountGroup_id = new WeakMap(), _MultichainAccountGroup_wallet = new WeakMap(), _MultichainAccountGroup_groupIndex = new WeakMap(), _MultichainAccountGroup_providers = new WeakMap(), _MultichainAccountGroup_providerToAccounts = new WeakMap(), _MultichainAccountGroup_accountToProvider = new WeakMap(), _MultichainAccountGroup_messenger = new WeakMap(), _MultichainAccountGroup_log = new WeakMap(), _MultichainAccountGroup_initialized = new WeakMap();
227
+ _MultichainAccountGroup_id = new WeakMap(), _MultichainAccountGroup_wallet = new WeakMap(), _MultichainAccountGroup_groupIndex = new WeakMap(), _MultichainAccountGroup_providers = new WeakMap(), _MultichainAccountGroup_providerToAccounts = new WeakMap(), _MultichainAccountGroup_accountToProvider = new WeakMap(), _MultichainAccountGroup_messenger = new WeakMap(), _MultichainAccountGroup_log = new WeakMap(), _MultichainAccountGroup_initialized = new WeakMap(), _MultichainAccountGroup_instances = new WeakSet(), _MultichainAccountGroup_clearAccountToProviderState = function _MultichainAccountGroup_clearAccountToProviderState(provider) {
228
+ __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").forEach((accountProvider, id) => {
229
+ if (accountProvider === provider) {
230
+ __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").delete(id);
231
+ }
232
+ });
233
+ }, _MultichainAccountGroup_setState = function _MultichainAccountGroup_setState(groupState) {
234
+ for (const provider of __classPrivateFieldGet(this, _MultichainAccountGroup_providers, "f")) {
235
+ const accountIds = groupState[provider.getName()];
236
+ if (accountIds) {
237
+ __classPrivateFieldGet(this, _MultichainAccountGroup_instances, "m", _MultichainAccountGroup_clearAccountToProviderState).call(this, provider);
238
+ __classPrivateFieldGet(this, _MultichainAccountGroup_providerToAccounts, "f").set(provider, accountIds);
239
+ for (const accountId of accountIds) {
240
+ __classPrivateFieldGet(this, _MultichainAccountGroup_accountToProvider, "f").set(accountId, provider);
241
+ }
242
+ }
243
+ }
244
+ if (__classPrivateFieldGet(this, _MultichainAccountGroup_initialized, "f")) {
245
+ __classPrivateFieldGet(this, _MultichainAccountGroup_messenger, "f").publish('MultichainAccountService:multichainAccountGroupUpdated', this);
246
+ }
247
+ else {
248
+ __classPrivateFieldSet(this, _MultichainAccountGroup_initialized, true, "f");
249
+ }
250
+ };
212
251
  //# sourceMappingURL=MultichainAccountGroup.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainAccountGroup.mjs","sourceRoot":"","sources":["../src/MultichainAccountGroup.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupType, select, selectOne } from '@metamask/account-api';\nimport { toMultichainAccountGroupId } from '@metamask/account-api';\nimport type {\n MultichainAccountGroupId,\n MultichainAccountGroup as MultichainAccountGroupDefinition,\n} from '@metamask/account-api';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { AccountSelector } from '@metamask/account-api';\nimport type { KeyringAccount } from '@metamask/keyring-api';\n\nimport type { Logger } from './logger';\nimport {\n projectLogger as log,\n createModuleLogger,\n WARNING_PREFIX,\n} from './logger';\nimport type { MultichainAccountWallet } from './MultichainAccountWallet';\nimport type { Bip44AccountProvider } from './providers';\nimport type { MultichainAccountServiceMessenger } from './types';\nimport { createSentryError } from './utils';\n\n/**\n * A multichain account group that holds multiple accounts.\n */\nexport class MultichainAccountGroup<\n Account extends Bip44Account<KeyringAccount>,\n> implements MultichainAccountGroupDefinition<Account>\n{\n readonly #id: MultichainAccountGroupId;\n\n readonly #wallet: MultichainAccountWallet<Account>;\n\n readonly #groupIndex: number;\n\n readonly #providers: Bip44AccountProvider<Account>[];\n\n readonly #providerToAccounts: Map<\n Bip44AccountProvider<Account>,\n Account['id'][]\n >;\n\n readonly #accountToProvider: Map<\n Account['id'],\n Bip44AccountProvider<Account>\n >;\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 constructor({\n groupIndex,\n wallet,\n providers,\n messenger,\n }: {\n groupIndex: number;\n wallet: MultichainAccountWallet<Account>;\n providers: Bip44AccountProvider<Account>[];\n messenger: MultichainAccountServiceMessenger;\n }) {\n this.#id = toMultichainAccountGroupId(wallet.id, groupIndex);\n this.#groupIndex = groupIndex;\n this.#wallet = wallet;\n this.#providers = providers;\n this.#messenger = messenger;\n this.#providerToAccounts = new Map();\n this.#accountToProvider = new Map();\n\n this.#log = createModuleLogger(log, `[${this.#id}]`);\n\n this.sync();\n this.#initialized = true;\n }\n\n /**\n * Force multichain account synchronization.\n *\n * This can be used if account providers got new accounts that the multichain\n * account doesn't know about.\n */\n sync(): void {\n this.#log('Synchronizing with account providers...');\n // Clear reverse mapping and re-construct it entirely based on the refreshed\n // list of accounts from each providers.\n this.#accountToProvider.clear();\n\n for (const provider of this.#providers) {\n // Filter account only for that index.\n const accounts = [];\n for (const account of provider.getAccounts()) {\n if (\n account.options.entropy.id === this.wallet.entropySource &&\n account.options.entropy.groupIndex === this.groupIndex\n ) {\n // We only use IDs to always fetch the latest version of accounts.\n accounts.push(account.id);\n }\n }\n this.#providerToAccounts.set(provider, accounts);\n\n // Reverse-mapping for fast indexing.\n for (const id of accounts) {\n this.#accountToProvider.set(id, provider);\n }\n }\n\n // Emit update event when group is synced (only if initialized)\n if (this.#initialized) {\n this.#messenger.publish(\n 'MultichainAccountService:multichainAccountGroupUpdated',\n this,\n );\n }\n\n this.#log('Synchronized');\n }\n\n /**\n * Gets the multichain account group ID.\n *\n * @returns The multichain account group ID.\n */\n get id(): MultichainAccountGroupId {\n return this.#id;\n }\n\n /**\n * Gets the multichain account group type.\n *\n * @returns The multichain account type.\n */\n get type(): AccountGroupType.MultichainAccount {\n return AccountGroupType.MultichainAccount;\n }\n\n /**\n * Gets the multichain account's wallet reference (parent).\n *\n * @returns The multichain account's wallet.\n */\n get wallet(): MultichainAccountWallet<Account> {\n return this.#wallet;\n }\n\n /**\n * Gets the multichain account group index.\n *\n * @returns The multichain account group index.\n */\n get groupIndex(): number {\n return this.#groupIndex;\n }\n\n /**\n * Checks if there's any underlying accounts for this multichain accounts.\n *\n * @returns True if there's any underlying accounts, false otherwise.\n */\n hasAccounts(): boolean {\n // If there's anything in the reverse-map, it means we have some accounts.\n return this.#accountToProvider.size > 0;\n }\n\n /**\n * Gets the accounts for this multichain account.\n *\n * @returns The accounts.\n */\n getAccounts(): Account[] {\n const allAccounts: Account[] = [];\n\n for (const [provider, accounts] of this.#providerToAccounts.entries()) {\n for (const id of accounts) {\n const account = provider.getAccount(id);\n\n if (account) {\n // If for some reason we cannot get this account from the provider, it\n // might means it has been deleted or something, so we just filter it\n // out.\n allAccounts.push(account);\n }\n }\n }\n\n return allAccounts;\n }\n\n /**\n * Gets the account for a given account ID.\n *\n * @param id - Account ID.\n * @returns The account or undefined if not found.\n */\n getAccount(id: Account['id']): Account | undefined {\n const provider = this.#accountToProvider.get(id);\n\n // If there's nothing in the map, it means we tried to get an account\n // that does not belong to this multichain account.\n if (!provider) {\n return undefined;\n }\n return provider.getAccount(id);\n }\n\n /**\n * Query an account matching the selector.\n *\n * @param selector - Query selector.\n * @returns The account matching the selector or undefined if not matching.\n * @throws If multiple accounts match the selector.\n */\n get(selector: AccountSelector<Account>): Account | undefined {\n return selectOne(this.getAccounts(), selector);\n }\n\n /**\n * Query accounts matching the selector.\n *\n * @param selector - Query selector.\n * @returns The accounts matching the selector.\n */\n select(selector: AccountSelector<Account>): Account[] {\n return select(this.getAccounts(), selector);\n }\n\n /**\n * Align the multichain account group.\n *\n * This will create accounts for providers that don't have any accounts yet.\n */\n async alignAccounts(): Promise<void> {\n this.#log('Aligning accounts...');\n\n const results = await Promise.allSettled(\n this.#providers.map(async (provider) => {\n try {\n const accounts = this.#providerToAccounts.get(provider);\n if (!accounts || accounts.length === 0) {\n this.#log(\n `Found missing accounts for account provider \"${provider.getName()}\", creating them now...`,\n );\n const created = await provider.createAccounts({\n entropySource: this.wallet.entropySource,\n groupIndex: this.groupIndex,\n });\n this.#log(`Created ${created.length} accounts`);\n\n return created;\n }\n return Promise.resolve();\n } catch (error) {\n // istanbul ignore next\n this.#log(\n `${WARNING_PREFIX} ${error instanceof Error ? error.message : String(error)}`,\n );\n const sentryError = createSentryError(\n `Unable to align accounts with provider \"${provider.getName()}\"`,\n error as Error,\n {\n groupIndex: this.groupIndex,\n provider: provider.getName(),\n },\n );\n this.#messenger.captureException?.(sentryError);\n throw error;\n }\n }),\n );\n\n if (results.some((result) => result.status === 'rejected')) {\n const message = `Failed to fully align multichain account group for entropy ID: ${this.wallet.entropySource} and group index: ${this.groupIndex}, some accounts might be missing`;\n\n this.#log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\n }\n\n this.#log('Aligned');\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainAccountGroup.mjs","sourceRoot":"","sources":["../src/MultichainAccountGroup.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupType, select, selectOne } from '@metamask/account-api';\nimport { toMultichainAccountGroupId } from '@metamask/account-api';\nimport type {\n MultichainAccountGroupId,\n MultichainAccountGroup as MultichainAccountGroupDefinition,\n} from '@metamask/account-api';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { AccountSelector } from '@metamask/account-api';\nimport type { KeyringAccount } from '@metamask/keyring-api';\n\nimport type { Logger } from './logger';\nimport {\n projectLogger as log,\n createModuleLogger,\n WARNING_PREFIX,\n} from './logger';\nimport type { ServiceState, StateKeys } from './MultichainAccountService';\nimport type { MultichainAccountWallet } from './MultichainAccountWallet';\nimport type { Bip44AccountProvider } from './providers';\nimport { isAccountProviderWrapper } from './providers';\nimport type { MultichainAccountServiceMessenger } from './types';\nimport { createSentryError } from './utils';\n\nexport type GroupState =\n ServiceState[StateKeys['entropySource']][StateKeys['groupIndex']];\n\n/**\n * A multichain account group that holds multiple accounts.\n */\nexport class MultichainAccountGroup<\n Account extends Bip44Account<KeyringAccount>,\n> implements MultichainAccountGroupDefinition<Account>\n{\n readonly #id: MultichainAccountGroupId;\n\n readonly #wallet: MultichainAccountWallet<Account>;\n\n readonly #groupIndex: number;\n\n readonly #providers: Bip44AccountProvider<Account>[];\n\n readonly #providerToAccounts: Map<\n Bip44AccountProvider<Account>,\n Account['id'][]\n >;\n\n readonly #accountToProvider: Map<\n Account['id'],\n Bip44AccountProvider<Account>\n >;\n\n readonly #messenger: MultichainAccountServiceMessenger;\n\n readonly #log: Logger;\n\n #initialized = false;\n\n constructor({\n groupIndex,\n wallet,\n providers,\n messenger,\n }: {\n groupIndex: number;\n wallet: MultichainAccountWallet<Account>;\n providers: Bip44AccountProvider<Account>[];\n messenger: MultichainAccountServiceMessenger;\n }) {\n this.#id = toMultichainAccountGroupId(wallet.id, groupIndex);\n this.#groupIndex = groupIndex;\n this.#wallet = wallet;\n this.#providers = providers;\n this.#messenger = messenger;\n this.#providerToAccounts = new Map();\n this.#accountToProvider = new Map();\n\n this.#log = createModuleLogger(log, `[${this.#id}]`);\n }\n\n /**\n * Clear the account to provider state for a given provider.\n *\n * @param provider - The provider to clear the account to provider state for.\n */\n #clearAccountToProviderState(provider: Bip44AccountProvider<Account>): void {\n this.#accountToProvider.forEach((accountProvider, id) => {\n if (accountProvider === provider) {\n this.#accountToProvider.delete(id);\n }\n });\n }\n\n /**\n * Update the internal representation of accounts with the given group state.\n *\n * @param groupState - The group state.\n */\n #setState(groupState: GroupState): void {\n for (const provider of this.#providers) {\n const accountIds = groupState[provider.getName()];\n\n if (accountIds) {\n this.#clearAccountToProviderState(provider);\n this.#providerToAccounts.set(provider, accountIds);\n\n for (const accountId of accountIds) {\n this.#accountToProvider.set(accountId, provider);\n }\n }\n }\n\n if (this.#initialized) {\n this.#messenger.publish(\n 'MultichainAccountService:multichainAccountGroupUpdated',\n this,\n );\n } else {\n this.#initialized = true;\n }\n }\n\n /**\n * Initialize the multichain account group and construct the internal representation of accounts.\n *\n * @param groupState - The group state.\n */\n init(groupState: GroupState): void {\n this.#log('Initializing group state...');\n this.#setState(groupState);\n this.#log('Finished initializing group state...');\n }\n\n /**\n * Update the group state.\n *\n * @param groupState - The group state.\n */\n update(groupState: GroupState): void {\n this.#log('Updating group state...');\n this.#setState(groupState);\n this.#log('Finished updating group state...');\n }\n\n /**\n * Gets the multichain account group ID.\n *\n * @returns The multichain account group ID.\n */\n get id(): MultichainAccountGroupId {\n return this.#id;\n }\n\n /**\n * Gets the multichain account group type.\n *\n * @returns The multichain account type.\n */\n get type(): AccountGroupType.MultichainAccount {\n return AccountGroupType.MultichainAccount;\n }\n\n /**\n * Gets the multichain account's wallet reference (parent).\n *\n * @returns The multichain account's wallet.\n */\n get wallet(): MultichainAccountWallet<Account> {\n return this.#wallet;\n }\n\n /**\n * Gets the multichain account group index.\n *\n * @returns The multichain account group index.\n */\n get groupIndex(): number {\n return this.#groupIndex;\n }\n\n /**\n * Checks if there's any underlying accounts for this multichain accounts.\n *\n * @returns True if there's any underlying accounts, false otherwise.\n */\n hasAccounts(): boolean {\n // If there's anything in the reverse-map, it means we have some accounts.\n return this.#accountToProvider.size > 0;\n }\n\n /**\n * Gets the accounts for this multichain account.\n *\n * @returns The accounts.\n */\n getAccounts(): Account[] {\n const allAccounts: Account[] = [];\n\n for (const [provider, accounts] of this.#providerToAccounts.entries()) {\n for (const id of accounts) {\n const account = provider.getAccount(id);\n\n if (account) {\n // If for some reason we cannot get this account from the provider, it\n // might means it has been deleted or something, so we just filter it\n // out.\n allAccounts.push(account);\n }\n }\n }\n\n return allAccounts;\n }\n\n /**\n * Gets the account IDs for this multichain account.\n *\n * @returns The account IDs.\n */\n getAccountIds(): Account['id'][] {\n return [...this.#accountToProvider.keys()];\n }\n\n /**\n * Gets the account for a given account ID.\n *\n * @param id - Account ID.\n * @returns The account or undefined if not found.\n */\n getAccount(id: Account['id']): Account | undefined {\n const provider = this.#accountToProvider.get(id);\n\n // If there's nothing in the map, it means we tried to get an account\n // that does not belong to this multichain account.\n if (!provider) {\n return undefined;\n }\n\n return provider.getAccount(id);\n }\n\n /**\n * Query an account matching the selector.\n *\n * @param selector - Query selector.\n * @returns The account matching the selector or undefined if not matching.\n * @throws If multiple accounts match the selector.\n */\n get(selector: AccountSelector<Account>): Account | undefined {\n return selectOne(this.getAccounts(), selector);\n }\n\n /**\n * Query accounts matching the selector.\n *\n * @param selector - Query selector.\n * @returns The accounts matching the selector.\n */\n select(selector: AccountSelector<Account>): Account[] {\n return select(this.getAccounts(), selector);\n }\n\n /**\n * Align the multichain account group.\n *\n * This will create accounts for providers that don't have any accounts yet.\n */\n async alignAccounts(): Promise<void> {\n this.#log('Aligning accounts...');\n\n this.#providerToAccounts.clear();\n this.#accountToProvider.clear();\n\n const results = await Promise.allSettled(\n this.#providers.map(async (provider) => {\n try {\n const accounts = await provider.alignAccounts({\n entropySource: this.wallet.entropySource,\n groupIndex: this.groupIndex,\n });\n\n const isDisabled =\n isAccountProviderWrapper(provider) && provider.isDisabled();\n\n if (isDisabled) {\n this.#log(\n `Account provider \"${provider.getName()}\" is disabled, skipping alignment...`,\n );\n } else if (accounts.length > 0) {\n this.#log(\n `Found missing accounts for account provider \"${provider.getName()}\", creating them now...`,\n );\n this.#providerToAccounts.set(provider, accounts);\n for (const accountId of accounts) {\n this.#accountToProvider.set(accountId, provider);\n }\n }\n\n return accounts;\n } catch (error) {\n // istanbul ignore next\n this.#log(\n `${WARNING_PREFIX} ${error instanceof Error ? error.message : String(error)}`,\n );\n const sentryError = createSentryError(\n `Unable to align accounts with provider \"${provider.getName()}\"`,\n error as Error,\n {\n groupIndex: this.groupIndex,\n provider: provider.getName(),\n },\n );\n this.#messenger.captureException?.(sentryError);\n throw error;\n }\n }),\n );\n\n let failureMessage = '';\n let failureCount = 0;\n const groupState = results.reduce<GroupState>((state, result, idx) => {\n if (result.status === 'fulfilled' && result.value.length) {\n state[this.#providers[idx].getName()] = result.value;\n } else if (result.status === 'rejected') {\n failureCount += 1;\n failureMessage += `\\n- ${this.#providers[idx].getName()}: ${result.reason.message}`;\n }\n return state;\n }, {});\n\n // Update group state\n this.update(groupState);\n\n if (failureCount > 0) {\n const hasMultipleFailures = failureCount > 1;\n const message = `Failed to fully align multichain account group for entropy ID: ${this.wallet.entropySource} and group index: ${this.groupIndex}, some accounts might be missing. ${hasMultipleFailures ? 'Providers' : 'Provider'} threw the following ${hasMultipleFailures ? 'errors' : 'error'}:${failureMessage}`;\n\n this.#log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\n }\n\n this.#log('Aligned');\n }\n}\n"]}
@@ -10,11 +10,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _MultichainAccountService_instances, _MultichainAccountService_messenger, _MultichainAccountService_watcher, _MultichainAccountService_providers, _MultichainAccountService_wallets, _MultichainAccountService_accountIdToContext, _MultichainAccountService_handleOnAccountAdded, _MultichainAccountService_handleOnAccountRemoved, _MultichainAccountService_getWallet;
13
+ var _MultichainAccountService_instances, _MultichainAccountService_messenger, _MultichainAccountService_watcher, _MultichainAccountService_providers, _MultichainAccountService_wallets, _MultichainAccountService_getStateKeys, _MultichainAccountService_constructServiceState, _MultichainAccountService_getWallet, _MultichainAccountService_getPrimaryEntropySourceId, _MultichainAccountService_createWalletByImport, _MultichainAccountService_createWalletByNewVault, _MultichainAccountService_createWalletByRestore;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.MultichainAccountService = exports.serviceName = void 0;
16
16
  const account_api_1 = require("@metamask/account-api");
17
- const key_tree_1 = require("@metamask/key-tree");
18
17
  const keyring_controller_1 = require("@metamask/keyring-controller");
19
18
  const utils_1 = require("@metamask/utils");
20
19
  const analytics_1 = require("./analytics/index.cjs");
@@ -48,14 +47,12 @@ class MultichainAccountService {
48
47
  _MultichainAccountService_watcher.set(this, void 0);
49
48
  _MultichainAccountService_providers.set(this, void 0);
50
49
  _MultichainAccountService_wallets.set(this, void 0);
51
- _MultichainAccountService_accountIdToContext.set(this, void 0);
52
50
  /**
53
51
  * The name of the service.
54
52
  */
55
53
  this.name = exports.serviceName;
56
54
  __classPrivateFieldSet(this, _MultichainAccountService_messenger, messenger, "f");
57
55
  __classPrivateFieldSet(this, _MultichainAccountService_wallets, new Map(), "f");
58
- __classPrivateFieldSet(this, _MultichainAccountService_accountIdToContext, new Map(), "f");
59
56
  // Pass trace callback directly to preserve original 'this' context
60
57
  // This avoids binding the callback to the MultichainAccountService instance
61
58
  const traceCallback = config?.trace ?? analytics_1.traceFallback;
@@ -78,9 +75,8 @@ class MultichainAccountService {
78
75
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:alignWallet', (...args) => this.alignWallet(...args));
79
76
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:createMultichainAccountWallet', (...args) => this.createMultichainAccountWallet(...args));
80
77
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:resyncAccounts', (...args) => this.resyncAccounts(...args));
78
+ __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:removeMultichainAccountWallet', (...args) => this.removeMultichainAccountWallet(...args));
81
79
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:ensureCanUseSnapPlatform', (...args) => this.ensureCanUseSnapPlatform(...args));
82
- __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").subscribe('AccountsController:accountAdded', (account) => __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_handleOnAccountAdded).call(this, account));
83
- __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").subscribe('AccountsController:accountRemoved', (id) => __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_handleOnAccountRemoved).call(this, id));
84
80
  }
85
81
  /**
86
82
  * Initialize the service and constructs the internal reprensentation of
@@ -89,32 +85,22 @@ class MultichainAccountService {
89
85
  async init() {
90
86
  (0, logger_1.projectLogger)('Initializing...');
91
87
  __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").clear();
92
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").clear();
93
- // Create initial wallets.
94
- const { keyrings } = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getState');
95
- for (const keyring of keyrings) {
96
- if (keyring.type === keyring_controller_1.KeyringTypes.hd) {
97
- // Only HD keyrings have an entropy source/SRP.
98
- const entropySource = keyring.metadata.id;
99
- (0, logger_1.projectLogger)(`Adding new wallet for entropy: "${entropySource}"`);
100
- // This will automatically "associate" all multichain accounts for that wallet
101
- // (based on the accounts owned by each account providers).
102
- const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
103
- entropySource,
104
- providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
105
- messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
106
- });
107
- __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
108
- // Reverse mapping between account ID and their multichain wallet/account:
109
- for (const group of wallet.getMultichainAccountGroups()) {
110
- for (const account of group.getAccounts()) {
111
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").set(account.id, {
112
- wallet,
113
- group,
114
- });
115
- }
116
- }
117
- }
88
+ const { serviceState, providerState } = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_constructServiceState).call(this);
89
+ for (const provider of __classPrivateFieldGet(this, _MultichainAccountService_providers, "f")) {
90
+ const providerName = provider.getName();
91
+ // Initialize providers even if there are no accounts yet.
92
+ // Passing an empty array ensures providers start in a valid state.
93
+ const state = providerState[providerName] ?? [];
94
+ provider.init(state);
95
+ }
96
+ for (const entropySource of Object.keys(serviceState)) {
97
+ const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
98
+ entropySource,
99
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
100
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
101
+ });
102
+ wallet.init(serviceState[entropySource]);
103
+ __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
118
104
  }
119
105
  (0, logger_1.projectLogger)('Initialized');
120
106
  }
@@ -159,16 +145,6 @@ class MultichainAccountService {
159
145
  ensureCanUseSnapPlatform() {
160
146
  return __classPrivateFieldGet(this, _MultichainAccountService_watcher, "f").ensureCanUseSnapPlatform();
161
147
  }
162
- /**
163
- * Gets the account's context which contains its multichain wallet and
164
- * multichain account group references.
165
- *
166
- * @param id - Account ID.
167
- * @returns The account context if any, undefined otherwise.
168
- */
169
- getAccountContext(id) {
170
- return __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").get(id);
171
- }
172
148
  /**
173
149
  * Gets a reference to the multichain account wallet matching this entropy source.
174
150
  *
@@ -189,39 +165,51 @@ class MultichainAccountService {
189
165
  return Array.from(__classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").values());
190
166
  }
191
167
  /**
192
- * Creates a new multichain account wallet with the given mnemonic.
168
+ * Creates a new multichain account wallet by either importing an existing mnemonic,
169
+ * creating a new vault and keychain, or restoring a vault and keyring.
193
170
  *
194
171
  * NOTE: This method should only be called in client code where a mutex lock is acquired.
195
- * `discoverAndCreateAccounts` should be called after this method to discover and create accounts.
172
+ * `discoverAccounts` should be called after this method to discover and create accounts.
196
173
  *
197
- * @param options - Options.
198
- * @param options.mnemonic - The mnemonic to use to create the new wallet.
174
+ * @param params - The parameters to use to create the new wallet.
175
+ * @param params.mnemonic - The mnemonic to use to create the new wallet.
176
+ * @param params.password - The password to encrypt the vault with.
177
+ * @param params.type - The flow type to use to create the new wallet.
199
178
  * @throws If the mnemonic has already been imported.
200
179
  * @returns The new multichain account wallet.
201
180
  */
202
- async createMultichainAccountWallet({ mnemonic, }) {
203
- const existingKeyrings = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getKeyringsByType', keyring_controller_1.KeyringTypes.hd);
204
- const mnemonicAsBytes = (0, key_tree_1.mnemonicPhraseToBytes)(mnemonic);
205
- const alreadyHasImportedSrp = existingKeyrings.some((keyring) => {
206
- if (!keyring.mnemonic) {
207
- return false;
208
- }
209
- return (0, utils_1.areUint8ArraysEqual)(keyring.mnemonic, mnemonicAsBytes);
210
- });
211
- if (alreadyHasImportedSrp) {
212
- throw new Error('This Secret Recovery Phrase has already been imported.');
181
+ async createMultichainAccountWallet(params) {
182
+ let wallet;
183
+ if (params.type === 'import') {
184
+ wallet = await __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_createWalletByImport).call(this, params.mnemonic);
185
+ }
186
+ else if (params.type === 'create') {
187
+ wallet = await __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_createWalletByNewVault).call(this, params.password);
213
188
  }
214
- (0, logger_1.projectLogger)(`Creating new wallet...`);
215
- const result = await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:addNewKeyring', keyring_controller_1.KeyringTypes.hd, { mnemonic });
216
- const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
217
- providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
218
- entropySource: result.id,
219
- messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
220
- });
189
+ else if (params.type === 'restore') {
190
+ wallet = await __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_createWalletByRestore).call(this, params.password, params.mnemonic);
191
+ }
192
+ (0, utils_1.assert)(wallet, 'Failed to create wallet.');
221
193
  __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
222
194
  (0, logger_1.projectLogger)(`Wallet created: [${wallet.id}]`);
223
195
  return wallet;
224
196
  }
197
+ /**
198
+ * Removes a multichain account wallet.
199
+ *
200
+ * NOTE: This method should only be called in client code as a revert mechanism.
201
+ * At the point that this code is called, discovery shouldn't have been triggered.
202
+ * This is meant to be used in the scenario where a seed phrase backup is not successful.
203
+ *
204
+ * @param entropySource - The entropy source of the multichain account wallet.
205
+ * @param accountAddress - The address of the account to remove.
206
+ * @returns The removed multichain account wallet.
207
+ */
208
+ async removeMultichainAccountWallet(entropySource, accountAddress) {
209
+ const wallet = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource);
210
+ await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:removeAccount', accountAddress);
211
+ __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").delete(wallet.id);
212
+ }
225
213
  /**
226
214
  * Gets a reference to the multichain account group matching this entropy source
227
215
  * and a group index.
@@ -316,64 +304,117 @@ class MultichainAccountService {
316
304
  }
317
305
  }
318
306
  exports.MultichainAccountService = MultichainAccountService;
319
- _MultichainAccountService_messenger = new WeakMap(), _MultichainAccountService_watcher = new WeakMap(), _MultichainAccountService_providers = new WeakMap(), _MultichainAccountService_wallets = new WeakMap(), _MultichainAccountService_accountIdToContext = new WeakMap(), _MultichainAccountService_instances = new WeakSet(), _MultichainAccountService_handleOnAccountAdded = function _MultichainAccountService_handleOnAccountAdded(account) {
320
- // We completely omit non-BIP-44 accounts!
321
- if (!(0, account_api_1.isBip44Account)(account)) {
322
- return;
323
- }
324
- let sync = true;
325
- let wallet = __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").get((0, account_api_1.toMultichainAccountWalletId)(account.options.entropy.id));
326
- if (!wallet) {
327
- (0, logger_1.projectLogger)(`Adding new wallet for entropy: "${account.options.entropy.id}" (for account: "${account.id}")`);
328
- // That's a new wallet.
329
- wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
330
- entropySource: account.options.entropy.id,
331
- providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
332
- messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
333
- });
334
- __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
335
- // If that's a new wallet wallet. There's nothing to "force-sync".
336
- sync = false;
337
- }
338
- let group = wallet.getMultichainAccountGroup(account.options.entropy.groupIndex);
339
- if (!group) {
340
- // This new account is a new multichain account, let the wallet know
341
- // it has to re-sync with its providers.
342
- if (sync) {
343
- wallet.sync();
307
+ _MultichainAccountService_messenger = new WeakMap(), _MultichainAccountService_watcher = new WeakMap(), _MultichainAccountService_providers = new WeakMap(), _MultichainAccountService_wallets = new WeakMap(), _MultichainAccountService_instances = new WeakSet(), _MultichainAccountService_getStateKeys = function _MultichainAccountService_getStateKeys(account) {
308
+ for (const provider of __classPrivateFieldGet(this, _MultichainAccountService_providers, "f")) {
309
+ if ((0, account_api_1.isBip44Account)(account) && provider.isAccountCompatible(account)) {
310
+ return {
311
+ entropySource: account.options.entropy.id,
312
+ groupIndex: account.options.entropy.groupIndex,
313
+ providerName: provider.getName(),
314
+ };
344
315
  }
345
- group = wallet.getMultichainAccountGroup(account.options.entropy.groupIndex);
346
- // If that's a new multichain account. There's nothing to "force-sync".
347
- sync = false;
348
316
  }
349
- // We have to check against `undefined` in case `getMultichainAccount` is
350
- // not able to find this multichain account (which should not be possible...)
351
- if (group) {
352
- if (sync) {
353
- group.sync();
317
+ return null;
318
+ }, _MultichainAccountService_constructServiceState = function _MultichainAccountService_constructServiceState() {
319
+ var _a, _b;
320
+ const accounts = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('AccountsController:listMultichainAccounts');
321
+ const serviceState = {};
322
+ const providerState = {};
323
+ for (const account of accounts) {
324
+ const keys = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getStateKeys).call(this, account);
325
+ if (keys) {
326
+ const { entropySource, groupIndex, providerName } = keys;
327
+ serviceState[entropySource] ?? (serviceState[entropySource] = {});
328
+ (_a = serviceState[entropySource])[groupIndex] ?? (_a[groupIndex] = {});
329
+ (_b = serviceState[entropySource][groupIndex])[providerName] ?? (_b[providerName] = []);
330
+ serviceState[entropySource][groupIndex][providerName].push(account.id);
331
+ providerState[providerName] ?? (providerState[providerName] = []);
332
+ providerState[providerName].push(account.id);
354
333
  }
355
- // Same here, this account should have been already grouped in that
356
- // multichain account.
357
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").set(account.id, {
358
- wallet,
359
- group,
360
- });
361
334
  }
362
- }, _MultichainAccountService_handleOnAccountRemoved = function _MultichainAccountService_handleOnAccountRemoved(id) {
363
- // Force sync of the appropriate wallet if an account got removed.
364
- const found = __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").get(id);
365
- if (found) {
366
- const { wallet } = found;
367
- (0, logger_1.projectLogger)(`Re-synchronize wallet [${wallet.id}] since account "${id}" got removed`);
368
- wallet.sync();
369
- }
370
- // Safe to call delete even if the `id` was not referencing a BIP-44 account.
371
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").delete(id);
335
+ return { serviceState, providerState };
372
336
  }, _MultichainAccountService_getWallet = function _MultichainAccountService_getWallet(entropySource) {
373
337
  const wallet = __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").get((0, account_api_1.toMultichainAccountWalletId)(entropySource));
374
338
  if (!wallet) {
375
339
  throw new Error('Unknown wallet, no wallet matching this entropy source');
376
340
  }
377
341
  return wallet;
342
+ }, _MultichainAccountService_getPrimaryEntropySourceId = function _MultichainAccountService_getPrimaryEntropySourceId() {
343
+ const { keyrings } = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getState');
344
+ const primaryKeyring = keyrings.find((keyring) => keyring.type === 'HD Key Tree');
345
+ (0, utils_1.assert)(primaryKeyring, 'Primary keyring not found');
346
+ return primaryKeyring.metadata.id;
347
+ }, _MultichainAccountService_createWalletByImport =
348
+ /**
349
+ * Creates a new multichain account wallet by importing an existing mnemonic.
350
+ *
351
+ * @param mnemonic - The mnemonic to use to create the new wallet.
352
+ * @returns The new multichain account wallet.
353
+ */
354
+ async function _MultichainAccountService_createWalletByImport(mnemonic) {
355
+ (0, logger_1.projectLogger)(`Creating new wallet by importing an existing mnemonic...`);
356
+ const existingKeyrings = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getKeyringsByType', keyring_controller_1.KeyringTypes.hd);
357
+ const alreadyHasImportedSrp = existingKeyrings.some((keyring) => {
358
+ if (!keyring.mnemonic) {
359
+ return false;
360
+ }
361
+ return (0, utils_1.areUint8ArraysEqual)(keyring.mnemonic, mnemonic);
362
+ });
363
+ if (alreadyHasImportedSrp) {
364
+ throw new Error('This Secret Recovery Phrase has already been imported.');
365
+ }
366
+ const result = await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:addNewKeyring', keyring_controller_1.KeyringTypes.hd, { mnemonic, numberOfAccounts: 1 });
367
+ const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
368
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
369
+ entropySource: result.id,
370
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
371
+ });
372
+ wallet.init({});
373
+ await wallet.createNextMultichainAccountGroup();
374
+ // The wallet is ripe for discovery
375
+ return wallet;
376
+ }, _MultichainAccountService_createWalletByNewVault =
377
+ /**
378
+ * Creates a new multichain account wallet by creating a new vault and keychain.
379
+ *
380
+ * @param password - The password to encrypt the vault with.
381
+ * @returns The new multichain account wallet.
382
+ */
383
+ async function _MultichainAccountService_createWalletByNewVault(password) {
384
+ (0, logger_1.projectLogger)(`Creating new wallet by creating a new vault and keychain...`);
385
+ await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:createNewVaultAndKeychain', password);
386
+ const entropySourceId = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getPrimaryEntropySourceId).call(this);
387
+ const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
388
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
389
+ entropySource: entropySourceId,
390
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
391
+ });
392
+ wallet.init({});
393
+ await wallet.createMultichainAccountGroup(0, {
394
+ waitForAllProvidersToFinishCreatingAccounts: false,
395
+ });
396
+ // The wallet is ripe for discovery
397
+ return wallet;
398
+ }, _MultichainAccountService_createWalletByRestore =
399
+ /**
400
+ * Creates a new multichain account wallet by restoring a vault and keyring.
401
+ *
402
+ * @param password - The password to encrypt the vault with.
403
+ * @param mnemonic - The mnemonic to use to restore the new wallet.
404
+ * @returns The new multichain account wallet.
405
+ */
406
+ async function _MultichainAccountService_createWalletByRestore(password, mnemonic) {
407
+ (0, logger_1.projectLogger)(`Creating new wallet by restoring vault and keyring...`);
408
+ await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:createNewVaultAndRestore', password, mnemonic);
409
+ const entropySourceId = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getPrimaryEntropySourceId).call(this);
410
+ const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
411
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
412
+ entropySource: entropySourceId,
413
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
414
+ });
415
+ wallet.init({});
416
+ await wallet.createNextMultichainAccountGroup();
417
+ // The wallet is ripe for discovery
418
+ return wallet;
378
419
  };
379
420
  //# sourceMappingURL=MultichainAccountService.cjs.map