@metamask-previews/assets-controller 2.0.2-preview-1e855a9f5 → 2.0.2-preview-702bd3940
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -1
- package/dist/AssetsController-method-action-types.cjs.map +1 -1
- package/dist/AssetsController-method-action-types.d.cts +5 -0
- package/dist/AssetsController-method-action-types.d.cts.map +1 -1
- package/dist/AssetsController-method-action-types.d.mts +5 -0
- package/dist/AssetsController-method-action-types.d.mts.map +1 -1
- package/dist/AssetsController-method-action-types.mjs.map +1 -1
- package/dist/AssetsController.cjs +214 -36
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +40 -6
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +40 -6
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +214 -36
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs +1 -0
- package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.mjs +1 -0
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.cjs +16 -4
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.mjs +13 -4
- package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
- package/dist/data-sources/PriceDataSource.cjs +20 -14
- package/dist/data-sources/PriceDataSource.cjs.map +1 -1
- package/dist/data-sources/PriceDataSource.d.cts +2 -2
- package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
- package/dist/data-sources/PriceDataSource.d.mts +2 -2
- package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
- package/dist/data-sources/PriceDataSource.mjs +20 -14
- package/dist/data-sources/PriceDataSource.mjs.map +1 -1
- package/dist/data-sources/RpcDataSource.cjs +2 -0
- package/dist/data-sources/RpcDataSource.cjs.map +1 -1
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
- package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
- package/dist/data-sources/RpcDataSource.mjs +2 -0
- package/dist/data-sources/RpcDataSource.mjs.map +1 -1
- package/dist/data-sources/SnapDataSource.cjs +3 -2
- package/dist/data-sources/SnapDataSource.cjs.map +1 -1
- package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
- package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
- package/dist/data-sources/SnapDataSource.mjs +3 -2
- package/dist/data-sources/SnapDataSource.mjs.map +1 -1
- package/dist/data-sources/TokenDataSource.cjs +1 -0
- package/dist/data-sources/TokenDataSource.cjs.map +1 -1
- package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
- package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
- package/dist/data-sources/TokenDataSource.mjs +1 -0
- package/dist/data-sources/TokenDataSource.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.cjs +44 -27
- package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.cts +15 -9
- package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.mts +15 -9
- package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.mjs +44 -27
- package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
- package/dist/middlewares/ParallelMiddleware.cjs +216 -0
- package/dist/middlewares/ParallelMiddleware.cjs.map +1 -0
- package/dist/middlewares/ParallelMiddleware.d.cts +45 -0
- package/dist/middlewares/ParallelMiddleware.d.cts.map +1 -0
- package/dist/middlewares/ParallelMiddleware.d.mts +45 -0
- package/dist/middlewares/ParallelMiddleware.d.mts.map +1 -0
- package/dist/middlewares/ParallelMiddleware.mjs +214 -0
- package/dist/middlewares/ParallelMiddleware.mjs.map +1 -0
- package/dist/middlewares/index.cjs +5 -1
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.d.cts +2 -0
- package/dist/middlewares/index.d.cts.map +1 -1
- package/dist/middlewares/index.d.mts +2 -0
- package/dist/middlewares/index.d.mts.map +1 -1
- package/dist/middlewares/index.mjs +1 -0
- package/dist/middlewares/index.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +16 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +16 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +6 -5
|
@@ -9,8 +9,9 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
|
-
var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trackMetaMetricsEvent, _AssetsController_firstInitFetchReported, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
|
|
12
|
+
var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trackMetaMetricsEvent, _AssetsController_firstInitFetchReported, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_updateActive, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
|
|
13
13
|
import { BaseController } from "@metamask/base-controller";
|
|
14
|
+
import { clientControllerSelectors } from "@metamask/client-controller";
|
|
14
15
|
import { isCaipChainId, isStrictHexString, parseCaipAssetType, parseCaipChainId } from "@metamask/utils";
|
|
15
16
|
import { Mutex } from "async-mutex";
|
|
16
17
|
import BigNumberJS from "bignumber.js";
|
|
@@ -25,6 +26,7 @@ import { StakedBalanceDataSource } from "./data-sources/StakedBalanceDataSource.
|
|
|
25
26
|
import { TokenDataSource } from "./data-sources/TokenDataSource.mjs";
|
|
26
27
|
import { projectLogger, createModuleLogger } from "./logger.mjs";
|
|
27
28
|
import { DetectionMiddleware } from "./middlewares/DetectionMiddleware.mjs";
|
|
29
|
+
import { createParallelBalanceMiddleware, createParallelMiddleware } from "./middlewares/ParallelMiddleware.mjs";
|
|
28
30
|
import { normalizeAssetId } from "./utils.mjs";
|
|
29
31
|
// ============================================================================
|
|
30
32
|
// CONTROLLER CONSTANTS
|
|
@@ -57,6 +59,7 @@ export function getDefaultAssetsControllerState() {
|
|
|
57
59
|
assetsPrice: {},
|
|
58
60
|
customAssets: {},
|
|
59
61
|
assetPreferences: {},
|
|
62
|
+
selectedCurrency: 'usd',
|
|
60
63
|
};
|
|
61
64
|
}
|
|
62
65
|
// ============================================================================
|
|
@@ -93,6 +96,12 @@ const stateMetadata = {
|
|
|
93
96
|
includeInDebugSnapshot: false,
|
|
94
97
|
usedInUi: true,
|
|
95
98
|
},
|
|
99
|
+
selectedCurrency: {
|
|
100
|
+
persist: true,
|
|
101
|
+
includeInStateLogs: false,
|
|
102
|
+
includeInDebugSnapshot: false,
|
|
103
|
+
usedInUi: true,
|
|
104
|
+
},
|
|
96
105
|
};
|
|
97
106
|
// ============================================================================
|
|
98
107
|
// HELPER FUNCTIONS
|
|
@@ -146,6 +155,9 @@ function normalizeResponse(response) {
|
|
|
146
155
|
if (response.errors) {
|
|
147
156
|
normalized.errors = { ...response.errors };
|
|
148
157
|
}
|
|
158
|
+
if (response.updateMode) {
|
|
159
|
+
normalized.updateMode = response.updateMode;
|
|
160
|
+
}
|
|
149
161
|
return normalized;
|
|
150
162
|
}
|
|
151
163
|
// ============================================================================
|
|
@@ -167,8 +179,10 @@ function normalizeResponse(response) {
|
|
|
167
179
|
* based on which chains they support. When active chains change, the controller
|
|
168
180
|
* dynamically adjusts subscriptions.
|
|
169
181
|
*
|
|
170
|
-
* 4. **Keyring Lifecycle**:
|
|
171
|
-
*
|
|
182
|
+
* 4. **Client + Keyring Lifecycle**: Starts subscriptions only when both the UI is
|
|
183
|
+
* open (ClientController) and the wallet is unlocked (KeyringController).
|
|
184
|
+
* Stops when either the UI closes or the keyring locks. See client-controller
|
|
185
|
+
* README for the combined pattern.
|
|
172
186
|
*
|
|
173
187
|
* ## Architecture
|
|
174
188
|
*
|
|
@@ -198,6 +212,10 @@ export class AssetsController extends BaseController {
|
|
|
198
212
|
_AssetsController_trackMetaMetricsEvent.set(this, void 0);
|
|
199
213
|
/** Whether we have already reported first init fetch for this session (reset on #stop). */
|
|
200
214
|
_AssetsController_firstInitFetchReported.set(this, false);
|
|
215
|
+
/** Whether the client (UI) is open. Combined with #keyringUnlocked for #updateActive. */
|
|
216
|
+
_AssetsController_uiOpen.set(this, false);
|
|
217
|
+
/** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
|
|
218
|
+
_AssetsController_keyringUnlocked.set(this, false);
|
|
201
219
|
_AssetsController_controllerMutex.set(this, new Mutex());
|
|
202
220
|
/**
|
|
203
221
|
* Active balance subscriptions keyed by account ID.
|
|
@@ -254,6 +272,7 @@ export class AssetsController extends BaseController {
|
|
|
254
272
|
}), "f");
|
|
255
273
|
__classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource({
|
|
256
274
|
queryApiClient,
|
|
275
|
+
getSelectedCurrency: () => this.state.selectedCurrency,
|
|
257
276
|
...priceDataSourceConfig,
|
|
258
277
|
}), "f");
|
|
259
278
|
__classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware(), "f");
|
|
@@ -267,7 +286,7 @@ export class AssetsController extends BaseController {
|
|
|
267
286
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
|
|
268
287
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
|
|
269
288
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
|
|
270
|
-
// Subscriptions start only
|
|
289
|
+
// Subscriptions start only when both UI is open and keyring unlocked -> #updateActive().
|
|
271
290
|
// Subscribe to basic-functionality changes after construction so a synchronous
|
|
272
291
|
// onChange during subscribe cannot run before data sources are initialized.
|
|
273
292
|
if (subscribeToBasicFunctionalityChange) {
|
|
@@ -318,6 +337,7 @@ export class AssetsController extends BaseController {
|
|
|
318
337
|
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
319
338
|
chainIds: addedEnabledChains,
|
|
320
339
|
forceUpdate: true,
|
|
340
|
+
updateMode: 'merge',
|
|
321
341
|
}).catch((error) => {
|
|
322
342
|
log('Failed to fetch balance for added chains', { error });
|
|
323
343
|
});
|
|
@@ -331,6 +351,9 @@ export class AssetsController extends BaseController {
|
|
|
331
351
|
const chainIds = options?.chainIds ?? [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")];
|
|
332
352
|
const assetTypes = options?.assetTypes ?? ['fungible'];
|
|
333
353
|
const dataTypes = options?.dataTypes ?? ['balance', 'metadata', 'price'];
|
|
354
|
+
if (accounts.length === 0 || chainIds.length === 0) {
|
|
355
|
+
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
|
|
356
|
+
}
|
|
334
357
|
// Collect custom assets for all requested accounts
|
|
335
358
|
const customAssets = [];
|
|
336
359
|
for (const account of accounts) {
|
|
@@ -344,16 +367,21 @@ export class AssetsController extends BaseController {
|
|
|
344
367
|
dataTypes,
|
|
345
368
|
customAssets: customAssets.length > 0 ? customAssets : undefined,
|
|
346
369
|
forceUpdate: true,
|
|
370
|
+
assetsForPriceUpdate: options?.assetsForPriceUpdate,
|
|
347
371
|
});
|
|
348
372
|
const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
|
|
349
373
|
? [
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
374
|
+
createParallelBalanceMiddleware([
|
|
375
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
|
|
376
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
|
|
377
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
|
|
378
|
+
__classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
|
|
379
|
+
]),
|
|
354
380
|
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
|
|
355
|
-
|
|
356
|
-
|
|
381
|
+
createParallelMiddleware([
|
|
382
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
|
|
383
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
|
|
384
|
+
]),
|
|
357
385
|
]
|
|
358
386
|
: [
|
|
359
387
|
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
|
|
@@ -361,7 +389,12 @@ export class AssetsController extends BaseController {
|
|
|
361
389
|
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
|
|
362
390
|
];
|
|
363
391
|
const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
|
|
364
|
-
|
|
392
|
+
// Default to 'merge' when fetching a subset of chains so we don't wipe
|
|
393
|
+
// balances from chains that weren't included in this fetch.
|
|
394
|
+
const isPartialChainFetch = options?.chainIds !== undefined &&
|
|
395
|
+
options.chainIds.length < __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size;
|
|
396
|
+
const updateMode = options?.updateMode ?? (isPartialChainFetch ? 'merge' : 'full');
|
|
397
|
+
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode });
|
|
365
398
|
if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
|
|
366
399
|
__classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
|
|
367
400
|
const durationMs = Date.now() - startTime;
|
|
@@ -372,7 +405,8 @@ export class AssetsController extends BaseController {
|
|
|
372
405
|
});
|
|
373
406
|
}
|
|
374
407
|
}
|
|
375
|
-
|
|
408
|
+
const result = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
|
|
409
|
+
return result;
|
|
376
410
|
}
|
|
377
411
|
async getAssetsBalance(accounts, options) {
|
|
378
412
|
// Reuse getAssets with dataTypes: ['balance'] only
|
|
@@ -423,10 +457,15 @@ export class AssetsController extends BaseController {
|
|
|
423
457
|
* Custom assets are included in subscription and fetch operations.
|
|
424
458
|
* Adding a custom asset also unhides it if it was previously hidden.
|
|
425
459
|
*
|
|
460
|
+
* When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
|
|
461
|
+
* flow), the token metadata is persisted immediately into `assetsInfo` so the
|
|
462
|
+
* UI can render it without waiting for the next pipeline fetch.
|
|
463
|
+
*
|
|
426
464
|
* @param accountId - The account ID to add the custom asset for.
|
|
427
465
|
* @param assetId - The CAIP-19 asset ID to add.
|
|
466
|
+
* @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
|
|
428
467
|
*/
|
|
429
|
-
async addCustomAsset(accountId, assetId) {
|
|
468
|
+
async addCustomAsset(accountId, assetId, pendingMetadata) {
|
|
430
469
|
const normalizedAssetId = normalizeAssetId(assetId);
|
|
431
470
|
log('Adding custom asset', { accountId, assetId: normalizedAssetId });
|
|
432
471
|
this.update((state) => {
|
|
@@ -446,14 +485,37 @@ export class AssetsController extends BaseController {
|
|
|
446
485
|
delete state.assetPreferences[normalizedAssetId];
|
|
447
486
|
}
|
|
448
487
|
}
|
|
488
|
+
// Persist metadata from the UI so the token is immediately renderable
|
|
489
|
+
if (pendingMetadata) {
|
|
490
|
+
const parsed = parseCaipAssetType(normalizedAssetId);
|
|
491
|
+
let tokenType = 'erc20';
|
|
492
|
+
if (parsed.assetNamespace === 'slip44') {
|
|
493
|
+
tokenType = 'native';
|
|
494
|
+
}
|
|
495
|
+
else if (parsed.assetNamespace === 'spl') {
|
|
496
|
+
tokenType = 'spl';
|
|
497
|
+
}
|
|
498
|
+
const assetMetadata = {
|
|
499
|
+
type: tokenType,
|
|
500
|
+
symbol: pendingMetadata.symbol,
|
|
501
|
+
name: pendingMetadata.name,
|
|
502
|
+
decimals: pendingMetadata.decimals,
|
|
503
|
+
image: pendingMetadata.iconUrl,
|
|
504
|
+
aggregators: pendingMetadata.aggregators,
|
|
505
|
+
occurrences: pendingMetadata.occurrences,
|
|
506
|
+
};
|
|
507
|
+
state.assetsInfo[normalizedAssetId] =
|
|
508
|
+
assetMetadata;
|
|
509
|
+
}
|
|
449
510
|
});
|
|
450
|
-
// Fetch data for the newly added custom asset
|
|
511
|
+
// Fetch data for the newly added custom asset (merge to preserve other chains)
|
|
451
512
|
const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
|
|
452
513
|
if (account) {
|
|
453
514
|
const chainId = extractChainId(normalizedAssetId);
|
|
454
515
|
await this.getAssets([account], {
|
|
455
516
|
chainIds: [chainId],
|
|
456
517
|
forceUpdate: true,
|
|
518
|
+
updateMode: 'merge',
|
|
457
519
|
});
|
|
458
520
|
}
|
|
459
521
|
}
|
|
@@ -524,6 +586,34 @@ export class AssetsController extends BaseController {
|
|
|
524
586
|
});
|
|
525
587
|
}
|
|
526
588
|
// ============================================================================
|
|
589
|
+
// CURRENT CURRENCY MANAGEMENT
|
|
590
|
+
// ============================================================================
|
|
591
|
+
/**
|
|
592
|
+
* Set the current currency.
|
|
593
|
+
*
|
|
594
|
+
* @param selectedCurrency - The ISO 4217 currency code to set.
|
|
595
|
+
*/
|
|
596
|
+
setSelectedCurrency(selectedCurrency) {
|
|
597
|
+
const previousCurrency = this.state.selectedCurrency;
|
|
598
|
+
if (previousCurrency === selectedCurrency) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
this.update((state) => {
|
|
602
|
+
state.selectedCurrency = selectedCurrency;
|
|
603
|
+
});
|
|
604
|
+
log('Current currency changed', {
|
|
605
|
+
previousCurrency,
|
|
606
|
+
selectedCurrency,
|
|
607
|
+
});
|
|
608
|
+
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
609
|
+
forceUpdate: true,
|
|
610
|
+
dataTypes: ['price'],
|
|
611
|
+
assetsForPriceUpdate: Object.values(this.state.assetsBalance).flatMap((balances) => Object.keys(balances)),
|
|
612
|
+
}).catch((error) => {
|
|
613
|
+
log('Failed to fetch asset prices after current currency change', error);
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
// ============================================================================
|
|
527
617
|
// SUBSCRIPTIONS
|
|
528
618
|
// ============================================================================
|
|
529
619
|
/**
|
|
@@ -601,9 +691,15 @@ export class AssetsController extends BaseController {
|
|
|
601
691
|
hasBalance: Boolean(response.assetsBalance),
|
|
602
692
|
hasPrice: Boolean(response.assetsPrice),
|
|
603
693
|
});
|
|
604
|
-
// Run through enrichment middlewares (
|
|
694
|
+
// Run through enrichment middlewares (Detection, then Token + Price in parallel)
|
|
605
695
|
// Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
|
|
606
|
-
const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
696
|
+
const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
697
|
+
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
|
|
698
|
+
createParallelMiddleware([
|
|
699
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
|
|
700
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
|
|
701
|
+
]),
|
|
702
|
+
], request ?? {
|
|
607
703
|
accountsWithSupportedChains: [],
|
|
608
704
|
chainIds: [],
|
|
609
705
|
dataTypes: ['balance', 'metadata', 'price'],
|
|
@@ -642,7 +738,7 @@ export class AssetsController extends BaseController {
|
|
|
642
738
|
this.messenger.unregisterActionHandler('AssetsController:unhideAsset');
|
|
643
739
|
}
|
|
644
740
|
}
|
|
645
|
-
_AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trackMetaMetricsEvent = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_backendWebsocketDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_stakedBalanceDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
|
|
741
|
+
_AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trackMetaMetricsEvent = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_backendWebsocketDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_stakedBalanceDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
|
|
646
742
|
return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
|
|
647
743
|
}, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
|
|
648
744
|
return [
|
|
@@ -692,9 +788,27 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
|
|
|
692
788
|
this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
|
|
693
789
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
|
|
694
790
|
});
|
|
695
|
-
// Keyring lifecycle:
|
|
696
|
-
this.messenger.subscribe('
|
|
697
|
-
|
|
791
|
+
// Client + Keyring lifecycle: only run when UI is open AND keyring is unlocked
|
|
792
|
+
this.messenger.subscribe('ClientController:stateChange', (isUiOpen) => {
|
|
793
|
+
__classPrivateFieldSet(this, _AssetsController_uiOpen, isUiOpen, "f");
|
|
794
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
|
|
795
|
+
}, clientControllerSelectors.selectIsUiOpen);
|
|
796
|
+
this.messenger.subscribe('KeyringController:unlock', () => {
|
|
797
|
+
__classPrivateFieldSet(this, _AssetsController_keyringUnlocked, true, "f");
|
|
798
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
|
|
799
|
+
});
|
|
800
|
+
this.messenger.subscribe('KeyringController:lock', () => {
|
|
801
|
+
__classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
|
|
802
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
|
|
803
|
+
});
|
|
804
|
+
}, _AssetsController_updateActive = function _AssetsController_updateActive() {
|
|
805
|
+
const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
|
|
806
|
+
if (shouldRun) {
|
|
807
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
|
|
811
|
+
}
|
|
698
812
|
}, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
|
|
699
813
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
700
814
|
}, _AssetsController_executeMiddlewares =
|
|
@@ -747,13 +861,46 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
|
|
|
747
861
|
}
|
|
748
862
|
}
|
|
749
863
|
return { response: result.response, durationByDataSource };
|
|
750
|
-
},
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
864
|
+
}, _AssetsController_resolveNativeAssetIds = function _AssetsController_resolveNativeAssetIds(chains) {
|
|
865
|
+
const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
|
|
866
|
+
const ids = [];
|
|
867
|
+
for (const chainId of chains) {
|
|
868
|
+
const nativeId = nativeAssetIdentifiers?.[chainId];
|
|
869
|
+
if (nativeId) {
|
|
870
|
+
ids.push(nativeId);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return ids;
|
|
874
|
+
}, _AssetsController_getNativeAssetIdsForEnabledChains = function _AssetsController_getNativeAssetIdsForEnabledChains() {
|
|
875
|
+
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
|
|
876
|
+
}, _AssetsController_getNativeAssetIdsForAccount = function _AssetsController_getNativeAssetIdsForAccount(account) {
|
|
877
|
+
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account));
|
|
878
|
+
}, _AssetsController_ensureNativeBalancesDefaultZero = function _AssetsController_ensureNativeBalancesDefaultZero() {
|
|
879
|
+
const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get);
|
|
880
|
+
if (accounts.length === 0) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
this.update((state) => {
|
|
884
|
+
const balances = state.assetsBalance;
|
|
885
|
+
for (const account of accounts) {
|
|
886
|
+
const accountId = account.id;
|
|
887
|
+
const nativeAssetIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account);
|
|
888
|
+
if (nativeAssetIds.length === 0) {
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
if (!balances[accountId]) {
|
|
892
|
+
balances[accountId] = {};
|
|
893
|
+
}
|
|
894
|
+
for (const nativeAssetId of nativeAssetIds) {
|
|
895
|
+
if (!(nativeAssetId in balances[accountId])) {
|
|
896
|
+
balances[accountId][nativeAssetId] = { amount: '0' };
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
}, _AssetsController_updateState = async function _AssetsController_updateState(response) {
|
|
756
902
|
const normalizedResponse = normalizeResponse(response);
|
|
903
|
+
const mode = normalizedResponse.updateMode ?? 'merge';
|
|
757
904
|
const releaseLock = await __classPrivateFieldGet(this, _AssetsController_controllerMutex, "f").acquire();
|
|
758
905
|
try {
|
|
759
906
|
const previousState = this.state;
|
|
@@ -779,16 +926,43 @@ async function _AssetsController_updateState(response) {
|
|
|
779
926
|
if (normalizedResponse.assetsBalance) {
|
|
780
927
|
for (const [accountId, accountBalances] of Object.entries(normalizedResponse.assetsBalance)) {
|
|
781
928
|
const previousBalances = previousState.assetsBalance[accountId] ?? {};
|
|
782
|
-
|
|
783
|
-
|
|
929
|
+
const customAssetIds = state.customAssets[accountId] ?? [];
|
|
930
|
+
// Full: response is authoritative; preserve custom assets not in response.
|
|
931
|
+
// Merge: response overlays previous balances.
|
|
932
|
+
// Callers that fetch partial data (e.g. newly added chains) must set updateMode: 'merge'.
|
|
933
|
+
const effective = mode === 'merge'
|
|
934
|
+
? { ...previousBalances, ...accountBalances }
|
|
935
|
+
: (() => {
|
|
936
|
+
const next = {
|
|
937
|
+
...accountBalances,
|
|
938
|
+
};
|
|
939
|
+
for (const customId of customAssetIds) {
|
|
940
|
+
if (!(customId in next)) {
|
|
941
|
+
const prev = previousBalances[customId];
|
|
942
|
+
next[customId] =
|
|
943
|
+
prev ?? { amount: '0' };
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return next;
|
|
947
|
+
})();
|
|
948
|
+
// Ensure native tokens have an entry (0 if missing) for chains this account supports
|
|
949
|
+
const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
|
|
950
|
+
const nativeAssetIdsForAccount = account
|
|
951
|
+
? __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account)
|
|
952
|
+
: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForEnabledChains).call(this);
|
|
953
|
+
for (const nativeAssetId of nativeAssetIdsForAccount) {
|
|
954
|
+
if (!(nativeAssetId in effective)) {
|
|
955
|
+
effective[nativeAssetId] = { amount: '0' };
|
|
956
|
+
}
|
|
784
957
|
}
|
|
785
|
-
for (const [assetId, balance] of Object.entries(
|
|
958
|
+
for (const [assetId, balance] of Object.entries(effective)) {
|
|
786
959
|
const previousBalance = previousBalances[assetId];
|
|
787
|
-
const
|
|
788
|
-
const newAmount = balanceData.amount;
|
|
960
|
+
const newAmount = balance.amount;
|
|
789
961
|
const oldAmount = previousBalance?.amount;
|
|
790
|
-
|
|
791
|
-
|
|
962
|
+
const isNewDefaultNativeZero = oldAmount === undefined &&
|
|
963
|
+
newAmount === '0' &&
|
|
964
|
+
nativeAssetIdsForAccount.includes(assetId);
|
|
965
|
+
if (oldAmount !== newAmount && !isNewDefaultNativeZero) {
|
|
792
966
|
changedBalances.push({
|
|
793
967
|
accountId,
|
|
794
968
|
assetId,
|
|
@@ -797,7 +971,7 @@ async function _AssetsController_updateState(response) {
|
|
|
797
971
|
});
|
|
798
972
|
}
|
|
799
973
|
}
|
|
800
|
-
|
|
974
|
+
balances[accountId] = effective;
|
|
801
975
|
}
|
|
802
976
|
}
|
|
803
977
|
// Update prices in state
|
|
@@ -941,6 +1115,7 @@ async function _AssetsController_updateState(response) {
|
|
|
941
1115
|
enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
|
|
942
1116
|
});
|
|
943
1117
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1118
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
|
|
944
1119
|
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
945
1120
|
chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
|
|
946
1121
|
forceUpdate: true,
|
|
@@ -975,7 +1150,7 @@ async function _AssetsController_updateState(response) {
|
|
|
975
1150
|
}
|
|
976
1151
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
|
|
977
1152
|
}, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
|
|
978
|
-
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
|
|
1153
|
+
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0 || __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size === 0) {
|
|
979
1154
|
return;
|
|
980
1155
|
}
|
|
981
1156
|
// Subscribe to balance updates (batched by data source)
|
|
@@ -1148,6 +1323,7 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1148
1323
|
forceUpdate: true,
|
|
1149
1324
|
});
|
|
1150
1325
|
}
|
|
1326
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
|
|
1151
1327
|
}, _AssetsController_handleEnabledNetworksChanged = async function _AssetsController_handleEnabledNetworksChanged(enabledNetworkMap) {
|
|
1152
1328
|
const previousChains = __classPrivateFieldGet(this, _AssetsController_enabledChains, "f");
|
|
1153
1329
|
__classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
|
|
@@ -1176,12 +1352,14 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1176
1352
|
// The data will simply not be updated until the network is re-enabled.
|
|
1177
1353
|
// Refresh subscriptions for new chain set
|
|
1178
1354
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1179
|
-
// Do one-time fetch for newly enabled chains
|
|
1355
|
+
// Do one-time fetch for newly enabled chains; merge so we keep existing chain balances
|
|
1180
1356
|
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
1181
1357
|
await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
1182
1358
|
chainIds: addedChains,
|
|
1183
1359
|
forceUpdate: true,
|
|
1360
|
+
updateMode: 'merge',
|
|
1184
1361
|
});
|
|
1185
1362
|
}
|
|
1363
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
|
|
1186
1364
|
};
|
|
1187
1365
|
//# sourceMappingURL=AssetsController.mjs.map
|