@metamask/assets-controller 2.0.2 → 2.2.0
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 +39 -1
- package/dist/AssetsController-method-action-types.cjs.map +1 -1
- package/dist/AssetsController-method-action-types.d.cts +21 -1
- package/dist/AssetsController-method-action-types.d.cts.map +1 -1
- package/dist/AssetsController-method-action-types.d.mts +21 -1
- 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 +284 -89
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +59 -17
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +59 -17
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +284 -89
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/AbstractDataSource.cjs.map +1 -1
- package/dist/data-sources/AbstractDataSource.d.cts +3 -3
- package/dist/data-sources/AbstractDataSource.d.cts.map +1 -1
- package/dist/data-sources/AbstractDataSource.d.mts +3 -3
- package/dist/data-sources/AbstractDataSource.d.mts.map +1 -1
- package/dist/data-sources/AbstractDataSource.mjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs +2 -1
- 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 +2 -1
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.cjs +18 -6
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.cts +2 -2
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.mts +2 -2
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.mjs +15 -6
- 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 +23 -4
- 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 +23 -4
- 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/StakedBalanceDataSource.cjs +41 -3
- package/dist/data-sources/StakedBalanceDataSource.cjs.map +1 -1
- package/dist/data-sources/StakedBalanceDataSource.d.cts.map +1 -1
- package/dist/data-sources/StakedBalanceDataSource.d.mts.map +1 -1
- package/dist/data-sources/StakedBalanceDataSource.mjs +41 -3
- package/dist/data-sources/StakedBalanceDataSource.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/data-sources/evm-rpc-services/services/TokenDetector.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs.map +1 -1
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +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/dist/utils/formatExchangeRatesForBridge.cjs +123 -0
- package/dist/utils/formatExchangeRatesForBridge.cjs.map +1 -0
- package/dist/utils/formatExchangeRatesForBridge.d.cts +65 -0
- package/dist/utils/formatExchangeRatesForBridge.d.cts.map +1 -0
- package/dist/utils/formatExchangeRatesForBridge.d.mts +65 -0
- package/dist/utils/formatExchangeRatesForBridge.d.mts.map +1 -0
- package/dist/utils/formatExchangeRatesForBridge.mjs +119 -0
- package/dist/utils/formatExchangeRatesForBridge.mjs.map +1 -0
- package/dist/utils/index.cjs +8 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +4 -0
- package/dist/utils/index.d.cts.map +1 -0
- package/dist/utils/index.d.mts +4 -0
- package/dist/utils/index.d.mts.map +1 -0
- package/dist/utils/index.mjs +3 -0
- package/dist/utils/index.mjs.map +1 -0
- package/dist/{utils.cjs → utils/normalizeAssetId.cjs} +1 -1
- package/dist/utils/normalizeAssetId.cjs.map +1 -0
- package/dist/{utils.d.mts → utils/normalizeAssetId.d.cts} +2 -2
- package/dist/utils/normalizeAssetId.d.cts.map +1 -0
- package/dist/{utils.d.cts → utils/normalizeAssetId.d.mts} +2 -2
- package/dist/utils/normalizeAssetId.d.mts.map +1 -0
- package/dist/{utils.mjs → utils/normalizeAssetId.mjs} +1 -1
- package/dist/utils/normalizeAssetId.mjs.map +1 -0
- package/package.json +6 -5
- package/dist/utils.cjs.map +0 -1
- package/dist/utils.d.cts.map +0 -1
- package/dist/utils.d.mts.map +0 -1
- package/dist/utils.mjs.map +0 -1
|
@@ -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_onActiveChainsUpdated, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_updateActive, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _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,7 +26,8 @@ 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";
|
|
28
|
-
import {
|
|
29
|
+
import { createParallelBalanceMiddleware, createParallelMiddleware } from "./middlewares/ParallelMiddleware.mjs";
|
|
30
|
+
import { normalizeAssetId, formatExchangeRatesForBridge } from "./utils/index.mjs";
|
|
29
31
|
// ============================================================================
|
|
30
32
|
// CONTROLLER CONSTANTS
|
|
31
33
|
// ============================================================================
|
|
@@ -36,6 +38,7 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
36
38
|
'getAssetsBalance',
|
|
37
39
|
'getAssetMetadata',
|
|
38
40
|
'getAssetsPrice',
|
|
41
|
+
'getExchangeRatesForBridge',
|
|
39
42
|
'addCustomAsset',
|
|
40
43
|
'removeCustomAsset',
|
|
41
44
|
'getCustomAssets',
|
|
@@ -57,6 +60,7 @@ export function getDefaultAssetsControllerState() {
|
|
|
57
60
|
assetsPrice: {},
|
|
58
61
|
customAssets: {},
|
|
59
62
|
assetPreferences: {},
|
|
63
|
+
selectedCurrency: 'usd',
|
|
60
64
|
};
|
|
61
65
|
}
|
|
62
66
|
// ============================================================================
|
|
@@ -93,6 +97,12 @@ const stateMetadata = {
|
|
|
93
97
|
includeInDebugSnapshot: false,
|
|
94
98
|
usedInUi: true,
|
|
95
99
|
},
|
|
100
|
+
selectedCurrency: {
|
|
101
|
+
persist: true,
|
|
102
|
+
includeInStateLogs: false,
|
|
103
|
+
includeInDebugSnapshot: false,
|
|
104
|
+
usedInUi: true,
|
|
105
|
+
},
|
|
96
106
|
};
|
|
97
107
|
// ============================================================================
|
|
98
108
|
// HELPER FUNCTIONS
|
|
@@ -146,6 +156,9 @@ function normalizeResponse(response) {
|
|
|
146
156
|
if (response.errors) {
|
|
147
157
|
normalized.errors = { ...response.errors };
|
|
148
158
|
}
|
|
159
|
+
if (response.updateMode) {
|
|
160
|
+
normalized.updateMode = response.updateMode;
|
|
161
|
+
}
|
|
149
162
|
return normalized;
|
|
150
163
|
}
|
|
151
164
|
// ============================================================================
|
|
@@ -167,8 +180,10 @@ function normalizeResponse(response) {
|
|
|
167
180
|
* based on which chains they support. When active chains change, the controller
|
|
168
181
|
* dynamically adjusts subscriptions.
|
|
169
182
|
*
|
|
170
|
-
* 4. **Keyring Lifecycle**:
|
|
171
|
-
*
|
|
183
|
+
* 4. **Client + Keyring Lifecycle**: Starts subscriptions only when both the UI is
|
|
184
|
+
* open (ClientController) and the wallet is unlocked (KeyringController).
|
|
185
|
+
* Stops when either the UI closes or the keyring locks. See client-controller
|
|
186
|
+
* README for the combined pattern.
|
|
172
187
|
*
|
|
173
188
|
* ## Architecture
|
|
174
189
|
*
|
|
@@ -198,6 +213,10 @@ export class AssetsController extends BaseController {
|
|
|
198
213
|
_AssetsController_trackMetaMetricsEvent.set(this, void 0);
|
|
199
214
|
/** Whether we have already reported first init fetch for this session (reset on #stop). */
|
|
200
215
|
_AssetsController_firstInitFetchReported.set(this, false);
|
|
216
|
+
/** Whether the client (UI) is open. Combined with #keyringUnlocked for #updateActive. */
|
|
217
|
+
_AssetsController_uiOpen.set(this, false);
|
|
218
|
+
/** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
|
|
219
|
+
_AssetsController_keyringUnlocked.set(this, false);
|
|
201
220
|
_AssetsController_controllerMutex.set(this, new Mutex());
|
|
202
221
|
/**
|
|
203
222
|
* Active balance subscriptions keyed by account ID.
|
|
@@ -217,36 +236,37 @@ export class AssetsController extends BaseController {
|
|
|
217
236
|
_AssetsController_detectionMiddleware.set(this, void 0);
|
|
218
237
|
_AssetsController_tokenDataSource.set(this, void 0);
|
|
219
238
|
_AssetsController_unsubscribeBasicFunctionality.set(this, null);
|
|
239
|
+
_AssetsController_onActiveChainsUpdated.set(this, void 0);
|
|
220
240
|
__classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
|
|
221
241
|
__classPrivateFieldSet(this, _AssetsController_isBasicFunctionality, isBasicFunctionality ?? (() => true), "f");
|
|
222
242
|
__classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
|
|
223
243
|
__classPrivateFieldSet(this, _AssetsController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
|
|
224
244
|
const rpcConfig = rpcDataSourceConfig ?? {};
|
|
225
|
-
|
|
226
|
-
this.
|
|
227
|
-
};
|
|
245
|
+
__classPrivateFieldSet(this, _AssetsController_onActiveChainsUpdated, (dataSourceName, chains, previousChains) => {
|
|
246
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleActiveChainsUpdate).call(this, dataSourceName, chains, previousChains);
|
|
247
|
+
}, "f");
|
|
228
248
|
__classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource({
|
|
229
249
|
messenger: this.messenger,
|
|
230
250
|
queryApiClient,
|
|
231
|
-
onActiveChainsUpdated,
|
|
251
|
+
onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
|
|
232
252
|
}), "f");
|
|
233
253
|
__classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource({
|
|
234
254
|
queryApiClient,
|
|
235
|
-
onActiveChainsUpdated,
|
|
255
|
+
onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
|
|
236
256
|
...accountsApiDataSourceConfig,
|
|
237
257
|
}), "f");
|
|
238
258
|
__classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource({
|
|
239
259
|
messenger: this.messenger,
|
|
240
|
-
onActiveChainsUpdated,
|
|
260
|
+
onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
|
|
241
261
|
}), "f");
|
|
242
262
|
__classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource({
|
|
243
263
|
messenger: this.messenger,
|
|
244
|
-
onActiveChainsUpdated,
|
|
264
|
+
onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
|
|
245
265
|
...rpcConfig,
|
|
246
266
|
}), "f");
|
|
247
267
|
__classPrivateFieldSet(this, _AssetsController_stakedBalanceDataSource, new StakedBalanceDataSource({
|
|
248
268
|
messenger: this.messenger,
|
|
249
|
-
onActiveChainsUpdated,
|
|
269
|
+
onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
|
|
250
270
|
...stakedBalanceDataSourceConfig,
|
|
251
271
|
}), "f");
|
|
252
272
|
__classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource({
|
|
@@ -254,6 +274,7 @@ export class AssetsController extends BaseController {
|
|
|
254
274
|
}), "f");
|
|
255
275
|
__classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource({
|
|
256
276
|
queryApiClient,
|
|
277
|
+
getSelectedCurrency: () => this.state.selectedCurrency,
|
|
257
278
|
...priceDataSourceConfig,
|
|
258
279
|
}), "f");
|
|
259
280
|
__classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware(), "f");
|
|
@@ -267,7 +288,7 @@ export class AssetsController extends BaseController {
|
|
|
267
288
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
|
|
268
289
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
|
|
269
290
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
|
|
270
|
-
// Subscriptions start only
|
|
291
|
+
// Subscriptions start only when both UI is open and keyring unlocked -> #updateActive().
|
|
271
292
|
// Subscribe to basic-functionality changes after construction so a synchronous
|
|
272
293
|
// onChange during subscribe cannot run before data sources are initialized.
|
|
273
294
|
if (subscribeToBasicFunctionalityChange) {
|
|
@@ -277,52 +298,14 @@ export class AssetsController extends BaseController {
|
|
|
277
298
|
}
|
|
278
299
|
}
|
|
279
300
|
}
|
|
280
|
-
// ============================================================================
|
|
281
|
-
// DATA SOURCE CHAIN MANAGEMENT
|
|
282
|
-
// ============================================================================
|
|
283
301
|
/**
|
|
284
|
-
*
|
|
285
|
-
* Used
|
|
286
|
-
*
|
|
287
|
-
* - On any add/remove: re-subscribes to data sources so chain assignment stays correct.
|
|
288
|
-
* - When chains are added: fetches balances for the new chains (for selected accounts on enabled networks).
|
|
302
|
+
* Returns the callback passed to data sources for reporting active chain updates.
|
|
303
|
+
* Used by tests to simulate a data source reporting chain changes.
|
|
289
304
|
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
* @param dataSourceId - The identifier of the data source reporting the change.
|
|
293
|
-
* @param activeChains - Currently active (supported and available) chain IDs for this source.
|
|
294
|
-
* @param previousChains - Previous chains; used to compute added/removed.
|
|
305
|
+
* @returns The onActiveChainsUpdated callback.
|
|
295
306
|
*/
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
log('Data source active chains changed', {
|
|
301
|
-
dataSourceId,
|
|
302
|
-
chainCount: activeChains.length,
|
|
303
|
-
chains: activeChains,
|
|
304
|
-
});
|
|
305
|
-
const previous = previousChains;
|
|
306
|
-
const previousSet = new Set(previous);
|
|
307
|
-
const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
|
|
308
|
-
const removedChains = previous.filter((ch) => !activeChains.includes(ch));
|
|
309
|
-
if (addedChains.length > 0 || removedChains.length > 0) {
|
|
310
|
-
// Refresh subscriptions to use updated data source availability
|
|
311
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
312
|
-
}
|
|
313
|
-
// If chains were added and we have selected accounts, do one-time fetch
|
|
314
|
-
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
315
|
-
const addedEnabledChains = addedChains.filter((chain) => __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").has(chain));
|
|
316
|
-
if (addedEnabledChains.length > 0) {
|
|
317
|
-
log('Fetching balances for newly added chains', { addedEnabledChains });
|
|
318
|
-
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
319
|
-
chainIds: addedEnabledChains,
|
|
320
|
-
forceUpdate: true,
|
|
321
|
-
}).catch((error) => {
|
|
322
|
-
log('Failed to fetch balance for added chains', { error });
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
}
|
|
307
|
+
getOnActiveChainsUpdated() {
|
|
308
|
+
return __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f");
|
|
326
309
|
}
|
|
327
310
|
// ============================================================================
|
|
328
311
|
// PUBLIC API: QUERY METHODS
|
|
@@ -331,6 +314,9 @@ export class AssetsController extends BaseController {
|
|
|
331
314
|
const chainIds = options?.chainIds ?? [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")];
|
|
332
315
|
const assetTypes = options?.assetTypes ?? ['fungible'];
|
|
333
316
|
const dataTypes = options?.dataTypes ?? ['balance', 'metadata', 'price'];
|
|
317
|
+
if (accounts.length === 0 || chainIds.length === 0) {
|
|
318
|
+
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
|
|
319
|
+
}
|
|
334
320
|
// Collect custom assets for all requested accounts
|
|
335
321
|
const customAssets = [];
|
|
336
322
|
for (const account of accounts) {
|
|
@@ -344,16 +330,21 @@ export class AssetsController extends BaseController {
|
|
|
344
330
|
dataTypes,
|
|
345
331
|
customAssets: customAssets.length > 0 ? customAssets : undefined,
|
|
346
332
|
forceUpdate: true,
|
|
333
|
+
assetsForPriceUpdate: options?.assetsForPriceUpdate,
|
|
347
334
|
});
|
|
348
335
|
const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
|
|
349
336
|
? [
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
337
|
+
createParallelBalanceMiddleware([
|
|
338
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
|
|
339
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
|
|
340
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
|
|
341
|
+
__classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
|
|
342
|
+
]),
|
|
354
343
|
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
|
|
355
|
-
|
|
356
|
-
|
|
344
|
+
createParallelMiddleware([
|
|
345
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
|
|
346
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
|
|
347
|
+
]),
|
|
357
348
|
]
|
|
358
349
|
: [
|
|
359
350
|
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
|
|
@@ -361,7 +352,12 @@ export class AssetsController extends BaseController {
|
|
|
361
352
|
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
|
|
362
353
|
];
|
|
363
354
|
const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
|
|
364
|
-
|
|
355
|
+
// Default to 'merge' when fetching a subset of chains so we don't wipe
|
|
356
|
+
// balances from chains that weren't included in this fetch.
|
|
357
|
+
const isPartialChainFetch = options?.chainIds !== undefined &&
|
|
358
|
+
options.chainIds.length < __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size;
|
|
359
|
+
const updateMode = options?.updateMode ?? (isPartialChainFetch ? 'merge' : 'full');
|
|
360
|
+
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode });
|
|
365
361
|
if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
|
|
366
362
|
__classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
|
|
367
363
|
const durationMs = Date.now() - startTime;
|
|
@@ -372,7 +368,8 @@ export class AssetsController extends BaseController {
|
|
|
372
368
|
});
|
|
373
369
|
}
|
|
374
370
|
}
|
|
375
|
-
|
|
371
|
+
const result = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
|
|
372
|
+
return result;
|
|
376
373
|
}
|
|
377
374
|
async getAssetsBalance(accounts, options) {
|
|
378
375
|
// Reuse getAssets with dataTypes: ['balance'] only
|
|
@@ -415,6 +412,28 @@ export class AssetsController extends BaseController {
|
|
|
415
412
|
}
|
|
416
413
|
return result;
|
|
417
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* Returns exchange rates in the format expected by the bridge controller
|
|
417
|
+
* (conversionRates, currencyRates, marketData, currentCurrency) so that
|
|
418
|
+
* when useAssetsControllerForRates is true the bridge can use a single
|
|
419
|
+
* action instead of MultichainAssetsRatesController, TokenRatesController,
|
|
420
|
+
* and CurrencyRateController.
|
|
421
|
+
*
|
|
422
|
+
* @param options - Optional options for bridge rate conversion.
|
|
423
|
+
* @param options.usdToSelectedCurrencyRate - When selectedCurrency is not 'usd', pass 1 USD = this many units of selected currency so that currencyRates and conversionRates use correct user-currency vs USD values; otherwise the bridge USD conversion will be wrong for non-USD currencies.
|
|
424
|
+
* @returns Bridge-compatible exchange rate state derived from assetsPrice and selectedCurrency.
|
|
425
|
+
*/
|
|
426
|
+
getExchangeRatesForBridge(options) {
|
|
427
|
+
const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
|
|
428
|
+
const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
|
|
429
|
+
return formatExchangeRatesForBridge({
|
|
430
|
+
assetsPrice: this.state.assetsPrice,
|
|
431
|
+
selectedCurrency: this.state.selectedCurrency,
|
|
432
|
+
nativeAssetIdentifiers,
|
|
433
|
+
networkConfigurationsByChainId,
|
|
434
|
+
usdToSelectedCurrencyRate: options?.usdToSelectedCurrencyRate,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
418
437
|
// ============================================================================
|
|
419
438
|
// CUSTOM ASSETS MANAGEMENT
|
|
420
439
|
// ============================================================================
|
|
@@ -423,10 +442,15 @@ export class AssetsController extends BaseController {
|
|
|
423
442
|
* Custom assets are included in subscription and fetch operations.
|
|
424
443
|
* Adding a custom asset also unhides it if it was previously hidden.
|
|
425
444
|
*
|
|
445
|
+
* When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
|
|
446
|
+
* flow), the token metadata is persisted immediately into `assetsInfo` so the
|
|
447
|
+
* UI can render it without waiting for the next pipeline fetch.
|
|
448
|
+
*
|
|
426
449
|
* @param accountId - The account ID to add the custom asset for.
|
|
427
450
|
* @param assetId - The CAIP-19 asset ID to add.
|
|
451
|
+
* @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
|
|
428
452
|
*/
|
|
429
|
-
async addCustomAsset(accountId, assetId) {
|
|
453
|
+
async addCustomAsset(accountId, assetId, pendingMetadata) {
|
|
430
454
|
const normalizedAssetId = normalizeAssetId(assetId);
|
|
431
455
|
log('Adding custom asset', { accountId, assetId: normalizedAssetId });
|
|
432
456
|
this.update((state) => {
|
|
@@ -446,14 +470,37 @@ export class AssetsController extends BaseController {
|
|
|
446
470
|
delete state.assetPreferences[normalizedAssetId];
|
|
447
471
|
}
|
|
448
472
|
}
|
|
473
|
+
// Persist metadata from the UI so the token is immediately renderable
|
|
474
|
+
if (pendingMetadata) {
|
|
475
|
+
const parsed = parseCaipAssetType(normalizedAssetId);
|
|
476
|
+
let tokenType = 'erc20';
|
|
477
|
+
if (parsed.assetNamespace === 'slip44') {
|
|
478
|
+
tokenType = 'native';
|
|
479
|
+
}
|
|
480
|
+
else if (parsed.assetNamespace === 'spl') {
|
|
481
|
+
tokenType = 'spl';
|
|
482
|
+
}
|
|
483
|
+
const assetMetadata = {
|
|
484
|
+
type: tokenType,
|
|
485
|
+
symbol: pendingMetadata.symbol,
|
|
486
|
+
name: pendingMetadata.name,
|
|
487
|
+
decimals: pendingMetadata.decimals,
|
|
488
|
+
image: pendingMetadata.iconUrl,
|
|
489
|
+
aggregators: pendingMetadata.aggregators,
|
|
490
|
+
occurrences: pendingMetadata.occurrences,
|
|
491
|
+
};
|
|
492
|
+
state.assetsInfo[normalizedAssetId] =
|
|
493
|
+
assetMetadata;
|
|
494
|
+
}
|
|
449
495
|
});
|
|
450
|
-
// Fetch data for the newly added custom asset
|
|
496
|
+
// Fetch data for the newly added custom asset (merge to preserve other chains)
|
|
451
497
|
const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
|
|
452
498
|
if (account) {
|
|
453
499
|
const chainId = extractChainId(normalizedAssetId);
|
|
454
500
|
await this.getAssets([account], {
|
|
455
501
|
chainIds: [chainId],
|
|
456
502
|
forceUpdate: true,
|
|
503
|
+
updateMode: 'merge',
|
|
457
504
|
});
|
|
458
505
|
}
|
|
459
506
|
}
|
|
@@ -524,6 +571,34 @@ export class AssetsController extends BaseController {
|
|
|
524
571
|
});
|
|
525
572
|
}
|
|
526
573
|
// ============================================================================
|
|
574
|
+
// CURRENT CURRENCY MANAGEMENT
|
|
575
|
+
// ============================================================================
|
|
576
|
+
/**
|
|
577
|
+
* Set the current currency.
|
|
578
|
+
*
|
|
579
|
+
* @param selectedCurrency - The ISO 4217 currency code to set.
|
|
580
|
+
*/
|
|
581
|
+
setSelectedCurrency(selectedCurrency) {
|
|
582
|
+
const previousCurrency = this.state.selectedCurrency;
|
|
583
|
+
if (previousCurrency === selectedCurrency) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
this.update((state) => {
|
|
587
|
+
state.selectedCurrency = selectedCurrency;
|
|
588
|
+
});
|
|
589
|
+
log('Current currency changed', {
|
|
590
|
+
previousCurrency,
|
|
591
|
+
selectedCurrency,
|
|
592
|
+
});
|
|
593
|
+
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
594
|
+
forceUpdate: true,
|
|
595
|
+
dataTypes: ['price'],
|
|
596
|
+
assetsForPriceUpdate: Object.values(this.state.assetsBalance).flatMap((balances) => Object.keys(balances)),
|
|
597
|
+
}).catch((error) => {
|
|
598
|
+
log('Failed to fetch asset prices after current currency change', error);
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
// ============================================================================
|
|
527
602
|
// SUBSCRIPTIONS
|
|
528
603
|
// ============================================================================
|
|
529
604
|
/**
|
|
@@ -601,9 +676,15 @@ export class AssetsController extends BaseController {
|
|
|
601
676
|
hasBalance: Boolean(response.assetsBalance),
|
|
602
677
|
hasPrice: Boolean(response.assetsPrice),
|
|
603
678
|
});
|
|
604
|
-
// Run through enrichment middlewares (
|
|
679
|
+
// Run through enrichment middlewares (Detection, then Token + Price in parallel)
|
|
605
680
|
// 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, [
|
|
681
|
+
const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
682
|
+
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
|
|
683
|
+
createParallelMiddleware([
|
|
684
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
|
|
685
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
|
|
686
|
+
]),
|
|
687
|
+
], request ?? {
|
|
607
688
|
accountsWithSupportedChains: [],
|
|
608
689
|
chainIds: [],
|
|
609
690
|
dataTypes: ['balance', 'metadata', 'price'],
|
|
@@ -635,6 +716,7 @@ export class AssetsController extends BaseController {
|
|
|
635
716
|
this.messenger.unregisterActionHandler('AssetsController:getAssetsBalance');
|
|
636
717
|
this.messenger.unregisterActionHandler('AssetsController:getAssetMetadata');
|
|
637
718
|
this.messenger.unregisterActionHandler('AssetsController:getAssetsPrice');
|
|
719
|
+
this.messenger.unregisterActionHandler('AssetsController:getExchangeRatesForBridge');
|
|
638
720
|
this.messenger.unregisterActionHandler('AssetsController:addCustomAsset');
|
|
639
721
|
this.messenger.unregisterActionHandler('AssetsController:removeCustomAsset');
|
|
640
722
|
this.messenger.unregisterActionHandler('AssetsController:getCustomAssets');
|
|
@@ -642,7 +724,7 @@ export class AssetsController extends BaseController {
|
|
|
642
724
|
this.messenger.unregisterActionHandler('AssetsController:unhideAsset');
|
|
643
725
|
}
|
|
644
726
|
}
|
|
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() {
|
|
727
|
+
_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_onActiveChainsUpdated = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
|
|
646
728
|
return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
|
|
647
729
|
}, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
|
|
648
730
|
return [
|
|
@@ -692,11 +774,60 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
|
|
|
692
774
|
this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
|
|
693
775
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
|
|
694
776
|
});
|
|
695
|
-
// Keyring lifecycle:
|
|
696
|
-
this.messenger.subscribe('
|
|
697
|
-
|
|
777
|
+
// Client + Keyring lifecycle: only run when UI is open AND keyring is unlocked
|
|
778
|
+
this.messenger.subscribe('ClientController:stateChange', (isUiOpen) => {
|
|
779
|
+
__classPrivateFieldSet(this, _AssetsController_uiOpen, isUiOpen, "f");
|
|
780
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
|
|
781
|
+
}, clientControllerSelectors.selectIsUiOpen);
|
|
782
|
+
this.messenger.subscribe('KeyringController:unlock', () => {
|
|
783
|
+
__classPrivateFieldSet(this, _AssetsController_keyringUnlocked, true, "f");
|
|
784
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
|
|
785
|
+
});
|
|
786
|
+
this.messenger.subscribe('KeyringController:lock', () => {
|
|
787
|
+
__classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
|
|
788
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
|
|
789
|
+
});
|
|
790
|
+
}, _AssetsController_updateActive = function _AssetsController_updateActive() {
|
|
791
|
+
const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
|
|
792
|
+
if (shouldRun) {
|
|
793
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
|
|
797
|
+
}
|
|
698
798
|
}, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
|
|
699
799
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
800
|
+
}, _AssetsController_handleActiveChainsUpdate = function _AssetsController_handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
|
|
801
|
+
if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
log('Data source active chains changed', {
|
|
805
|
+
dataSourceId,
|
|
806
|
+
chainCount: activeChains.length,
|
|
807
|
+
chains: activeChains,
|
|
808
|
+
});
|
|
809
|
+
const previous = previousChains;
|
|
810
|
+
const previousSet = new Set(previous);
|
|
811
|
+
const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
|
|
812
|
+
const removedChains = previous.filter((ch) => !activeChains.includes(ch));
|
|
813
|
+
if (addedChains.length > 0 || removedChains.length > 0) {
|
|
814
|
+
// Refresh subscriptions to use updated data source availability
|
|
815
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
816
|
+
}
|
|
817
|
+
// If chains were added and we have selected accounts, do one-time fetch
|
|
818
|
+
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
819
|
+
const addedEnabledChains = addedChains.filter((chain) => __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").has(chain));
|
|
820
|
+
if (addedEnabledChains.length > 0) {
|
|
821
|
+
log('Fetching balances for newly added chains', { addedEnabledChains });
|
|
822
|
+
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
823
|
+
chainIds: addedEnabledChains,
|
|
824
|
+
forceUpdate: true,
|
|
825
|
+
updateMode: 'merge',
|
|
826
|
+
}).catch((error) => {
|
|
827
|
+
log('Failed to fetch balance for added chains', { error });
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
}
|
|
700
831
|
}, _AssetsController_executeMiddlewares =
|
|
701
832
|
// ============================================================================
|
|
702
833
|
// MIDDLEWARE EXECUTION
|
|
@@ -747,13 +878,46 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
|
|
|
747
878
|
}
|
|
748
879
|
}
|
|
749
880
|
return { response: result.response, durationByDataSource };
|
|
750
|
-
},
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
881
|
+
}, _AssetsController_resolveNativeAssetIds = function _AssetsController_resolveNativeAssetIds(chains) {
|
|
882
|
+
const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
|
|
883
|
+
const ids = [];
|
|
884
|
+
for (const chainId of chains) {
|
|
885
|
+
const nativeId = nativeAssetIdentifiers?.[chainId];
|
|
886
|
+
if (nativeId) {
|
|
887
|
+
ids.push(nativeId);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return ids;
|
|
891
|
+
}, _AssetsController_getNativeAssetIdsForEnabledChains = function _AssetsController_getNativeAssetIdsForEnabledChains() {
|
|
892
|
+
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
|
|
893
|
+
}, _AssetsController_getNativeAssetIdsForAccount = function _AssetsController_getNativeAssetIdsForAccount(account) {
|
|
894
|
+
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account));
|
|
895
|
+
}, _AssetsController_ensureNativeBalancesDefaultZero = function _AssetsController_ensureNativeBalancesDefaultZero() {
|
|
896
|
+
const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get);
|
|
897
|
+
if (accounts.length === 0) {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
this.update((state) => {
|
|
901
|
+
const balances = state.assetsBalance;
|
|
902
|
+
for (const account of accounts) {
|
|
903
|
+
const accountId = account.id;
|
|
904
|
+
const nativeAssetIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account);
|
|
905
|
+
if (nativeAssetIds.length === 0) {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (!balances[accountId]) {
|
|
909
|
+
balances[accountId] = {};
|
|
910
|
+
}
|
|
911
|
+
for (const nativeAssetId of nativeAssetIds) {
|
|
912
|
+
if (!(nativeAssetId in balances[accountId])) {
|
|
913
|
+
balances[accountId][nativeAssetId] = { amount: '0' };
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
}, _AssetsController_updateState = async function _AssetsController_updateState(response) {
|
|
756
919
|
const normalizedResponse = normalizeResponse(response);
|
|
920
|
+
const mode = normalizedResponse.updateMode ?? 'merge';
|
|
757
921
|
const releaseLock = await __classPrivateFieldGet(this, _AssetsController_controllerMutex, "f").acquire();
|
|
758
922
|
try {
|
|
759
923
|
const previousState = this.state;
|
|
@@ -779,16 +943,43 @@ async function _AssetsController_updateState(response) {
|
|
|
779
943
|
if (normalizedResponse.assetsBalance) {
|
|
780
944
|
for (const [accountId, accountBalances] of Object.entries(normalizedResponse.assetsBalance)) {
|
|
781
945
|
const previousBalances = previousState.assetsBalance[accountId] ?? {};
|
|
782
|
-
|
|
783
|
-
|
|
946
|
+
const customAssetIds = state.customAssets[accountId] ?? [];
|
|
947
|
+
// Full: response is authoritative; preserve custom assets not in response.
|
|
948
|
+
// Merge: response overlays previous balances.
|
|
949
|
+
// Callers that fetch partial data (e.g. newly added chains) must set updateMode: 'merge'.
|
|
950
|
+
const effective = mode === 'merge'
|
|
951
|
+
? { ...previousBalances, ...accountBalances }
|
|
952
|
+
: (() => {
|
|
953
|
+
const next = {
|
|
954
|
+
...accountBalances,
|
|
955
|
+
};
|
|
956
|
+
for (const customId of customAssetIds) {
|
|
957
|
+
if (!(customId in next)) {
|
|
958
|
+
const prev = previousBalances[customId];
|
|
959
|
+
next[customId] =
|
|
960
|
+
prev ?? { amount: '0' };
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return next;
|
|
964
|
+
})();
|
|
965
|
+
// Ensure native tokens have an entry (0 if missing) for chains this account supports
|
|
966
|
+
const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
|
|
967
|
+
const nativeAssetIdsForAccount = account
|
|
968
|
+
? __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account)
|
|
969
|
+
: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForEnabledChains).call(this);
|
|
970
|
+
for (const nativeAssetId of nativeAssetIdsForAccount) {
|
|
971
|
+
if (!(nativeAssetId in effective)) {
|
|
972
|
+
effective[nativeAssetId] = { amount: '0' };
|
|
973
|
+
}
|
|
784
974
|
}
|
|
785
|
-
for (const [assetId, balance] of Object.entries(
|
|
975
|
+
for (const [assetId, balance] of Object.entries(effective)) {
|
|
786
976
|
const previousBalance = previousBalances[assetId];
|
|
787
|
-
const
|
|
788
|
-
const newAmount = balanceData.amount;
|
|
977
|
+
const newAmount = balance.amount;
|
|
789
978
|
const oldAmount = previousBalance?.amount;
|
|
790
|
-
|
|
791
|
-
|
|
979
|
+
const isNewDefaultNativeZero = oldAmount === undefined &&
|
|
980
|
+
newAmount === '0' &&
|
|
981
|
+
nativeAssetIdsForAccount.includes(assetId);
|
|
982
|
+
if (oldAmount !== newAmount && !isNewDefaultNativeZero) {
|
|
792
983
|
changedBalances.push({
|
|
793
984
|
accountId,
|
|
794
985
|
assetId,
|
|
@@ -797,7 +988,7 @@ async function _AssetsController_updateState(response) {
|
|
|
797
988
|
});
|
|
798
989
|
}
|
|
799
990
|
}
|
|
800
|
-
|
|
991
|
+
balances[accountId] = effective;
|
|
801
992
|
}
|
|
802
993
|
}
|
|
803
994
|
// Update prices in state
|
|
@@ -941,6 +1132,7 @@ async function _AssetsController_updateState(response) {
|
|
|
941
1132
|
enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
|
|
942
1133
|
});
|
|
943
1134
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1135
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
|
|
944
1136
|
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
945
1137
|
chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
|
|
946
1138
|
forceUpdate: true,
|
|
@@ -975,7 +1167,7 @@ async function _AssetsController_updateState(response) {
|
|
|
975
1167
|
}
|
|
976
1168
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
|
|
977
1169
|
}, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
|
|
978
|
-
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
|
|
1170
|
+
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0 || __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size === 0) {
|
|
979
1171
|
return;
|
|
980
1172
|
}
|
|
981
1173
|
// Subscribe to balance updates (batched by data source)
|
|
@@ -1064,7 +1256,7 @@ async function _AssetsController_updateState(response) {
|
|
|
1064
1256
|
}),
|
|
1065
1257
|
subscriptionId: subscriptionKey,
|
|
1066
1258
|
isUpdate,
|
|
1067
|
-
onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
|
|
1259
|
+
onAssetsUpdate: (response, request) => this.handleAssetsUpdate(response, sourceId, request),
|
|
1068
1260
|
getAssetsState: () => this.state,
|
|
1069
1261
|
};
|
|
1070
1262
|
source.subscribe(subscribeReq).catch((error) => {
|
|
@@ -1148,6 +1340,7 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1148
1340
|
forceUpdate: true,
|
|
1149
1341
|
});
|
|
1150
1342
|
}
|
|
1343
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
|
|
1151
1344
|
}, _AssetsController_handleEnabledNetworksChanged = async function _AssetsController_handleEnabledNetworksChanged(enabledNetworkMap) {
|
|
1152
1345
|
const previousChains = __classPrivateFieldGet(this, _AssetsController_enabledChains, "f");
|
|
1153
1346
|
__classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
|
|
@@ -1176,12 +1369,14 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1176
1369
|
// The data will simply not be updated until the network is re-enabled.
|
|
1177
1370
|
// Refresh subscriptions for new chain set
|
|
1178
1371
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1179
|
-
// Do one-time fetch for newly enabled chains
|
|
1372
|
+
// Do one-time fetch for newly enabled chains; merge so we keep existing chain balances
|
|
1180
1373
|
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
1181
1374
|
await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
1182
1375
|
chainIds: addedChains,
|
|
1183
1376
|
forceUpdate: true,
|
|
1377
|
+
updateMode: 'merge',
|
|
1184
1378
|
});
|
|
1185
1379
|
}
|
|
1380
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
|
|
1186
1381
|
};
|
|
1187
1382
|
//# sourceMappingURL=AssetsController.mjs.map
|