@metamask-previews/multichain-account-service 4.1.0-preview-a9886279 → 5.0.0-preview-6a568504

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 (118) hide show
  1. package/CHANGELOG.md +36 -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 +150 -112
  11. package/dist/MultichainAccountService.cjs.map +1 -1
  12. package/dist/MultichainAccountService.d.cts +49 -20
  13. package/dist/MultichainAccountService.d.cts.map +1 -1
  14. package/dist/MultichainAccountService.d.mts +49 -20
  15. package/dist/MultichainAccountService.d.mts.map +1 -1
  16. package/dist/MultichainAccountService.mjs +151 -113
  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 +47 -32
  43. package/dist/providers/BtcAccountProvider.cjs.map +1 -1
  44. package/dist/providers/BtcAccountProvider.d.cts +2 -1
  45. package/dist/providers/BtcAccountProvider.d.cts.map +1 -1
  46. package/dist/providers/BtcAccountProvider.d.mts +2 -1
  47. package/dist/providers/BtcAccountProvider.d.mts.map +1 -1
  48. package/dist/providers/BtcAccountProvider.mjs +47 -32
  49. package/dist/providers/BtcAccountProvider.mjs.map +1 -1
  50. package/dist/providers/EvmAccountProvider.cjs +39 -5
  51. package/dist/providers/EvmAccountProvider.cjs.map +1 -1
  52. package/dist/providers/EvmAccountProvider.d.cts +8 -0
  53. package/dist/providers/EvmAccountProvider.d.cts.map +1 -1
  54. package/dist/providers/EvmAccountProvider.d.mts +8 -0
  55. package/dist/providers/EvmAccountProvider.d.mts.map +1 -1
  56. package/dist/providers/EvmAccountProvider.mjs +39 -5
  57. package/dist/providers/EvmAccountProvider.mjs.map +1 -1
  58. package/dist/providers/SnapAccountProvider.cjs +81 -54
  59. package/dist/providers/SnapAccountProvider.cjs.map +1 -1
  60. package/dist/providers/SnapAccountProvider.d.cts +16 -4
  61. package/dist/providers/SnapAccountProvider.d.cts.map +1 -1
  62. package/dist/providers/SnapAccountProvider.d.mts +16 -4
  63. package/dist/providers/SnapAccountProvider.d.mts.map +1 -1
  64. package/dist/providers/SnapAccountProvider.mjs +81 -54
  65. package/dist/providers/SnapAccountProvider.mjs.map +1 -1
  66. package/dist/providers/SolAccountProvider.cjs +40 -31
  67. package/dist/providers/SolAccountProvider.cjs.map +1 -1
  68. package/dist/providers/SolAccountProvider.d.cts.map +1 -1
  69. package/dist/providers/SolAccountProvider.d.mts.map +1 -1
  70. package/dist/providers/SolAccountProvider.mjs +40 -31
  71. package/dist/providers/SolAccountProvider.mjs.map +1 -1
  72. package/dist/providers/TrxAccountProvider.cjs +48 -29
  73. package/dist/providers/TrxAccountProvider.cjs.map +1 -1
  74. package/dist/providers/TrxAccountProvider.d.cts +1 -0
  75. package/dist/providers/TrxAccountProvider.d.cts.map +1 -1
  76. package/dist/providers/TrxAccountProvider.d.mts +1 -0
  77. package/dist/providers/TrxAccountProvider.d.mts.map +1 -1
  78. package/dist/providers/TrxAccountProvider.mjs +48 -29
  79. package/dist/providers/TrxAccountProvider.mjs.map +1 -1
  80. package/dist/snaps/SnapPlatformWatcher.cjs +60 -0
  81. package/dist/snaps/SnapPlatformWatcher.cjs.map +1 -0
  82. package/dist/snaps/SnapPlatformWatcher.d.cts +8 -0
  83. package/dist/snaps/SnapPlatformWatcher.d.cts.map +1 -0
  84. package/dist/snaps/SnapPlatformWatcher.d.mts +8 -0
  85. package/dist/snaps/SnapPlatformWatcher.d.mts.map +1 -0
  86. package/dist/snaps/SnapPlatformWatcher.mjs +57 -0
  87. package/dist/snaps/SnapPlatformWatcher.mjs.map +1 -0
  88. package/dist/tests/messenger.cjs +12 -1
  89. package/dist/tests/messenger.cjs.map +1 -1
  90. package/dist/tests/messenger.d.cts +9 -4
  91. package/dist/tests/messenger.d.cts.map +1 -1
  92. package/dist/tests/messenger.d.mts +9 -4
  93. package/dist/tests/messenger.d.mts.map +1 -1
  94. package/dist/tests/messenger.mjs +12 -1
  95. package/dist/tests/messenger.mjs.map +1 -1
  96. package/dist/tests/providers.cjs +62 -7
  97. package/dist/tests/providers.cjs.map +1 -1
  98. package/dist/tests/providers.d.cts +17 -3
  99. package/dist/tests/providers.d.cts.map +1 -1
  100. package/dist/tests/providers.d.mts +17 -3
  101. package/dist/tests/providers.d.mts.map +1 -1
  102. package/dist/tests/providers.mjs +60 -6
  103. package/dist/tests/providers.mjs.map +1 -1
  104. package/dist/types.cjs.map +1 -1
  105. package/dist/types.d.cts +14 -6
  106. package/dist/types.d.cts.map +1 -1
  107. package/dist/types.d.mts +14 -6
  108. package/dist/types.d.mts.map +1 -1
  109. package/dist/types.mjs.map +1 -1
  110. package/dist/utils.cjs +1 -11
  111. package/dist/utils.cjs.map +1 -1
  112. package/dist/utils.d.cts +0 -1
  113. package/dist/utils.d.cts.map +1 -1
  114. package/dist/utils.d.mts +0 -1
  115. package/dist/utils.d.mts.map +1 -1
  116. package/dist/utils.mjs +0 -9
  117. package/dist/utils.mjs.map +1 -1
  118. package/package.json +3 -2
@@ -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_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");
@@ -25,6 +24,7 @@ const AccountProviderWrapper_1 = require("./providers/AccountProviderWrapper.cjs
25
24
  const EvmAccountProvider_1 = require("./providers/EvmAccountProvider.cjs");
26
25
  const SolAccountProvider_1 = require("./providers/SolAccountProvider.cjs");
27
26
  const SolAccountProvider_2 = require("./providers/SolAccountProvider.cjs");
27
+ const SnapPlatformWatcher_1 = require("./snaps/SnapPlatformWatcher.cjs");
28
28
  const utils_2 = require("./utils.cjs");
29
29
  exports.serviceName = 'MultichainAccountService';
30
30
  /**
@@ -44,16 +44,15 @@ class MultichainAccountService {
44
44
  constructor({ messenger, providers = [], providerConfigs, config, }) {
45
45
  _MultichainAccountService_instances.add(this);
46
46
  _MultichainAccountService_messenger.set(this, void 0);
47
+ _MultichainAccountService_watcher.set(this, void 0);
47
48
  _MultichainAccountService_providers.set(this, void 0);
48
49
  _MultichainAccountService_wallets.set(this, void 0);
49
- _MultichainAccountService_accountIdToContext.set(this, void 0);
50
50
  /**
51
51
  * The name of the service.
52
52
  */
53
53
  this.name = exports.serviceName;
54
54
  __classPrivateFieldSet(this, _MultichainAccountService_messenger, messenger, "f");
55
55
  __classPrivateFieldSet(this, _MultichainAccountService_wallets, new Map(), "f");
56
- __classPrivateFieldSet(this, _MultichainAccountService_accountIdToContext, new Map(), "f");
57
56
  // Pass trace callback directly to preserve original 'this' context
58
57
  // This avoids binding the callback to the MultichainAccountService instance
59
58
  const traceCallback = config?.trace ?? analytics_1.traceFallback;
@@ -64,6 +63,7 @@ class MultichainAccountService {
64
63
  // Custom account providers that can be provided by the MetaMask client.
65
64
  ...providers,
66
65
  ], "f");
66
+ __classPrivateFieldSet(this, _MultichainAccountService_watcher, new SnapPlatformWatcher_1.SnapPlatformWatcher(messenger), "f");
67
67
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountGroup', (...args) => this.getMultichainAccountGroup(...args));
68
68
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountGroups', (...args) => this.getMultichainAccountGroups(...args));
69
69
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountWallet', (...args) => this.getMultichainAccountWallet(...args));
@@ -75,8 +75,8 @@ class MultichainAccountService {
75
75
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:alignWallet', (...args) => this.alignWallet(...args));
76
76
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:createMultichainAccountWallet', (...args) => this.createMultichainAccountWallet(...args));
77
77
  __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:resyncAccounts', (...args) => this.resyncAccounts(...args));
78
- __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").subscribe('AccountsController:accountAdded', (account) => __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_handleOnAccountAdded).call(this, account));
79
- __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").subscribe('AccountsController:accountRemoved', (id) => __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_handleOnAccountRemoved).call(this, id));
78
+ __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:removeMultichainAccountWallet', (...args) => this.removeMultichainAccountWallet(...args));
79
+ __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:ensureCanUseSnapPlatform', (...args) => this.ensureCanUseSnapPlatform(...args));
80
80
  }
81
81
  /**
82
82
  * Initialize the service and constructs the internal reprensentation of
@@ -85,32 +85,22 @@ class MultichainAccountService {
85
85
  async init() {
86
86
  (0, logger_1.projectLogger)('Initializing...');
87
87
  __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").clear();
88
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").clear();
89
- // Create initial wallets.
90
- const { keyrings } = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getState');
91
- for (const keyring of keyrings) {
92
- if (keyring.type === keyring_controller_1.KeyringTypes.hd) {
93
- // Only HD keyrings have an entropy source/SRP.
94
- const entropySource = keyring.metadata.id;
95
- (0, logger_1.projectLogger)(`Adding new wallet for entropy: "${entropySource}"`);
96
- // This will automatically "associate" all multichain accounts for that wallet
97
- // (based on the accounts owned by each account providers).
98
- const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
99
- entropySource,
100
- providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
101
- messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
102
- });
103
- __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
104
- // Reverse mapping between account ID and their multichain wallet/account:
105
- for (const group of wallet.getMultichainAccountGroups()) {
106
- for (const account of group.getAccounts()) {
107
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").set(account.id, {
108
- wallet,
109
- group,
110
- });
111
- }
112
- }
113
- }
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);
114
104
  }
115
105
  (0, logger_1.projectLogger)('Initialized');
116
106
  }
@@ -152,15 +142,8 @@ class MultichainAccountService {
152
142
  }));
153
143
  (0, logger_1.projectLogger)('Providers got re-synced!');
154
144
  }
155
- /**
156
- * Gets the account's context which contains its multichain wallet and
157
- * multichain account group references.
158
- *
159
- * @param id - Account ID.
160
- * @returns The account context if any, undefined otherwise.
161
- */
162
- getAccountContext(id) {
163
- return __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").get(id);
145
+ ensureCanUseSnapPlatform() {
146
+ return __classPrivateFieldGet(this, _MultichainAccountService_watcher, "f").ensureCanUseSnapPlatform();
164
147
  }
165
148
  /**
166
149
  * Gets a reference to the multichain account wallet matching this entropy source.
@@ -182,39 +165,52 @@ class MultichainAccountService {
182
165
  return Array.from(__classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").values());
183
166
  }
184
167
  /**
185
- * 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.
186
170
  *
187
171
  * NOTE: This method should only be called in client code where a mutex lock is acquired.
188
- * `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.
189
173
  *
190
- * @param options - Options.
191
- * @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.
192
178
  * @throws If the mnemonic has already been imported.
193
179
  * @returns The new multichain account wallet.
194
180
  */
195
- async createMultichainAccountWallet({ mnemonic, }) {
196
- const existingKeyrings = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getKeyringsByType', keyring_controller_1.KeyringTypes.hd);
197
- const mnemonicAsBytes = (0, key_tree_1.mnemonicPhraseToBytes)(mnemonic);
198
- const alreadyHasImportedSrp = existingKeyrings.some((keyring) => {
199
- if (!keyring.mnemonic) {
200
- return false;
201
- }
202
- return (0, utils_1.areUint8ArraysEqual)(keyring.mnemonic, mnemonicAsBytes);
203
- });
204
- if (alreadyHasImportedSrp) {
205
- 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);
206
188
  }
207
- (0, logger_1.projectLogger)(`Creating new wallet...`);
208
- const result = await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:addNewKeyring', keyring_controller_1.KeyringTypes.hd, { mnemonic });
209
- const wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
210
- providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
211
- entropySource: result.id,
212
- messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
213
- });
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.');
193
+ wallet.init({});
214
194
  __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
215
195
  (0, logger_1.projectLogger)(`Wallet created: [${wallet.id}]`);
216
196
  return wallet;
217
197
  }
198
+ /**
199
+ * Removes a multichain account wallet.
200
+ *
201
+ * NOTE: This method should only be called in client code as a revert mechanism.
202
+ * At the point that this code is called, discovery shouldn't have been triggered.
203
+ * This is meant to be used in the scenario where a seed phrase backup is not successful.
204
+ *
205
+ * @param entropySource - The entropy source of the multichain account wallet.
206
+ * @param accountAddress - The address of the account to remove.
207
+ * @returns The removed multichain account wallet.
208
+ */
209
+ async removeMultichainAccountWallet(entropySource, accountAddress) {
210
+ const wallet = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource);
211
+ await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:removeAccount', accountAddress);
212
+ __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").delete(wallet.id);
213
+ }
218
214
  /**
219
215
  * Gets a reference to the multichain account group matching this entropy source
220
216
  * and a group index.
@@ -309,64 +305,106 @@ class MultichainAccountService {
309
305
  }
310
306
  }
311
307
  exports.MultichainAccountService = MultichainAccountService;
312
- _MultichainAccountService_messenger = new WeakMap(), _MultichainAccountService_providers = new WeakMap(), _MultichainAccountService_wallets = new WeakMap(), _MultichainAccountService_accountIdToContext = new WeakMap(), _MultichainAccountService_instances = new WeakSet(), _MultichainAccountService_handleOnAccountAdded = function _MultichainAccountService_handleOnAccountAdded(account) {
313
- // We completely omit non-BIP-44 accounts!
314
- if (!(0, account_api_1.isBip44Account)(account)) {
315
- return;
316
- }
317
- let sync = true;
318
- let wallet = __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").get((0, account_api_1.toMultichainAccountWalletId)(account.options.entropy.id));
319
- if (!wallet) {
320
- (0, logger_1.projectLogger)(`Adding new wallet for entropy: "${account.options.entropy.id}" (for account: "${account.id}")`);
321
- // That's a new wallet.
322
- wallet = new MultichainAccountWallet_1.MultichainAccountWallet({
323
- entropySource: account.options.entropy.id,
324
- providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
325
- messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
326
- });
327
- __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
328
- // If that's a new wallet wallet. There's nothing to "force-sync".
329
- sync = false;
330
- }
331
- let group = wallet.getMultichainAccountGroup(account.options.entropy.groupIndex);
332
- if (!group) {
333
- // This new account is a new multichain account, let the wallet know
334
- // it has to re-sync with its providers.
335
- if (sync) {
336
- wallet.sync();
308
+ _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) {
309
+ for (const provider of __classPrivateFieldGet(this, _MultichainAccountService_providers, "f")) {
310
+ if ((0, account_api_1.isBip44Account)(account) && provider.isAccountCompatible(account)) {
311
+ return {
312
+ entropySource: account.options.entropy.id,
313
+ groupIndex: account.options.entropy.groupIndex,
314
+ providerName: provider.getName(),
315
+ };
337
316
  }
338
- group = wallet.getMultichainAccountGroup(account.options.entropy.groupIndex);
339
- // If that's a new multichain account. There's nothing to "force-sync".
340
- sync = false;
341
317
  }
342
- // We have to check against `undefined` in case `getMultichainAccount` is
343
- // not able to find this multichain account (which should not be possible...)
344
- if (group) {
345
- if (sync) {
346
- group.sync();
318
+ return null;
319
+ }, _MultichainAccountService_constructServiceState = function _MultichainAccountService_constructServiceState() {
320
+ var _a, _b;
321
+ const accounts = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('AccountsController:listMultichainAccounts');
322
+ const serviceState = {};
323
+ const providerState = {};
324
+ for (const account of accounts) {
325
+ const keys = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getStateKeys).call(this, account);
326
+ if (keys) {
327
+ const { entropySource, groupIndex, providerName } = keys;
328
+ serviceState[entropySource] ?? (serviceState[entropySource] = {});
329
+ (_a = serviceState[entropySource])[groupIndex] ?? (_a[groupIndex] = {});
330
+ (_b = serviceState[entropySource][groupIndex])[providerName] ?? (_b[providerName] = []);
331
+ serviceState[entropySource][groupIndex][providerName].push(account.id);
332
+ providerState[providerName] ?? (providerState[providerName] = []);
333
+ providerState[providerName].push(account.id);
347
334
  }
348
- // Same here, this account should have been already grouped in that
349
- // multichain account.
350
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").set(account.id, {
351
- wallet,
352
- group,
353
- });
354
335
  }
355
- }, _MultichainAccountService_handleOnAccountRemoved = function _MultichainAccountService_handleOnAccountRemoved(id) {
356
- // Force sync of the appropriate wallet if an account got removed.
357
- const found = __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").get(id);
358
- if (found) {
359
- const { wallet } = found;
360
- (0, logger_1.projectLogger)(`Re-synchronize wallet [${wallet.id}] since account "${id}" got removed`);
361
- wallet.sync();
362
- }
363
- // Safe to call delete even if the `id` was not referencing a BIP-44 account.
364
- __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").delete(id);
336
+ return { serviceState, providerState };
365
337
  }, _MultichainAccountService_getWallet = function _MultichainAccountService_getWallet(entropySource) {
366
338
  const wallet = __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").get((0, account_api_1.toMultichainAccountWalletId)(entropySource));
367
339
  if (!wallet) {
368
340
  throw new Error('Unknown wallet, no wallet matching this entropy source');
369
341
  }
370
342
  return wallet;
343
+ }, _MultichainAccountService_getPrimaryEntropySourceId = function _MultichainAccountService_getPrimaryEntropySourceId() {
344
+ const { keyrings } = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getState');
345
+ const primaryKeyring = keyrings.find((keyring) => keyring.type === 'HD Key Tree');
346
+ (0, utils_1.assert)(primaryKeyring, 'Primary keyring not found');
347
+ return primaryKeyring.metadata.id;
348
+ }, _MultichainAccountService_createWalletByImport =
349
+ /**
350
+ * Creates a new multichain account wallet by importing an existing mnemonic.
351
+ *
352
+ * @param mnemonic - The mnemonic to use to create the new wallet.
353
+ * @returns The new multichain account wallet.
354
+ */
355
+ async function _MultichainAccountService_createWalletByImport(mnemonic) {
356
+ (0, logger_1.projectLogger)(`Creating new wallet by importing an existing mnemonic...`);
357
+ const existingKeyrings = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getKeyringsByType', keyring_controller_1.KeyringTypes.hd);
358
+ const alreadyHasImportedSrp = existingKeyrings.some((keyring) => {
359
+ if (!keyring.mnemonic) {
360
+ return false;
361
+ }
362
+ return (0, utils_1.areUint8ArraysEqual)(keyring.mnemonic, mnemonic);
363
+ });
364
+ if (alreadyHasImportedSrp) {
365
+ throw new Error('This Secret Recovery Phrase has already been imported.');
366
+ }
367
+ const result = await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:addNewKeyring', keyring_controller_1.KeyringTypes.hd, { mnemonic });
368
+ // The wallet is ripe for discovery
369
+ return new MultichainAccountWallet_1.MultichainAccountWallet({
370
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
371
+ entropySource: result.id,
372
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
373
+ });
374
+ }, _MultichainAccountService_createWalletByNewVault =
375
+ /**
376
+ * Creates a new multichain account wallet by creating a new vault and keychain.
377
+ *
378
+ * @param password - The password to encrypt the vault with.
379
+ * @returns The new multichain account wallet.
380
+ */
381
+ async function _MultichainAccountService_createWalletByNewVault(password) {
382
+ (0, logger_1.projectLogger)(`Creating new wallet by creating a new vault and keychain...`);
383
+ await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:createNewVaultAndKeychain', password);
384
+ const entropySourceId = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getPrimaryEntropySourceId).call(this);
385
+ // The wallet is ripe for discovery
386
+ return new MultichainAccountWallet_1.MultichainAccountWallet({
387
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
388
+ entropySource: entropySourceId,
389
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
390
+ });
391
+ }, _MultichainAccountService_createWalletByRestore =
392
+ /**
393
+ * Creates a new multichain account wallet by restoring a vault and keyring.
394
+ *
395
+ * @param password - The password to encrypt the vault with.
396
+ * @param mnemonic - The mnemonic to use to restore the new wallet.
397
+ * @returns The new multichain account wallet.
398
+ */
399
+ async function _MultichainAccountService_createWalletByRestore(password, mnemonic) {
400
+ (0, logger_1.projectLogger)(`Creating new wallet by restoring vault and keyring...`);
401
+ await __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:createNewVaultAndRestore', password, mnemonic);
402
+ const entropySourceId = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getPrimaryEntropySourceId).call(this);
403
+ // The wallet is ripe for discovery
404
+ return new MultichainAccountWallet_1.MultichainAccountWallet({
405
+ providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
406
+ entropySource: entropySourceId,
407
+ messenger: __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f"),
408
+ });
371
409
  };
372
410
  //# sourceMappingURL=MultichainAccountService.cjs.map