@metamask/assets-controller 0.2.0 → 1.0.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 +17 -1
- package/dist/AssetsController-method-action-types.cjs +7 -0
- package/dist/AssetsController-method-action-types.cjs.map +1 -0
- package/dist/AssetsController-method-action-types.d.cts +78 -0
- package/dist/AssetsController-method-action-types.d.cts.map +1 -0
- package/dist/AssetsController-method-action-types.d.mts +78 -0
- package/dist/AssetsController-method-action-types.d.mts.map +1 -0
- package/dist/AssetsController-method-action-types.mjs +6 -0
- package/dist/AssetsController-method-action-types.mjs.map +1 -0
- package/dist/AssetsController.cjs +201 -237
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +29 -92
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +29 -92
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +201 -237
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/AbstractDataSource.cjs +8 -0
- package/dist/data-sources/AbstractDataSource.cjs.map +1 -1
- package/dist/data-sources/AbstractDataSource.d.cts +16 -1
- package/dist/data-sources/AbstractDataSource.d.cts.map +1 -1
- package/dist/data-sources/AbstractDataSource.d.mts +16 -1
- package/dist/data-sources/AbstractDataSource.d.mts.map +1 -1
- package/dist/data-sources/AbstractDataSource.mjs +8 -0
- package/dist/data-sources/AbstractDataSource.mjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.cjs +25 -99
- package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.cts +5 -67
- package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.d.mts +5 -67
- package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
- package/dist/data-sources/AccountsApiDataSource.mjs +24 -97
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.cjs +138 -45
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.cts +19 -66
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.mts +19 -66
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.mjs +138 -45
- package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
- package/dist/data-sources/PriceDataSource.cjs +22 -44
- package/dist/data-sources/PriceDataSource.cjs.map +1 -1
- package/dist/data-sources/PriceDataSource.d.cts +6 -89
- package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
- package/dist/data-sources/PriceDataSource.d.mts +6 -89
- package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
- package/dist/data-sources/PriceDataSource.mjs +22 -44
- package/dist/data-sources/PriceDataSource.mjs.map +1 -1
- package/dist/data-sources/RpcDataSource.cjs +64 -102
- package/dist/data-sources/RpcDataSource.cjs.map +1 -1
- package/dist/data-sources/RpcDataSource.d.cts +16 -55
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
- package/dist/data-sources/RpcDataSource.d.mts +16 -55
- package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
- package/dist/data-sources/RpcDataSource.mjs +64 -102
- package/dist/data-sources/RpcDataSource.mjs.map +1 -1
- package/dist/data-sources/SnapDataSource.cjs +32 -30
- package/dist/data-sources/SnapDataSource.cjs.map +1 -1
- package/dist/data-sources/SnapDataSource.d.cts +7 -44
- package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
- package/dist/data-sources/SnapDataSource.d.mts +7 -44
- package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
- package/dist/data-sources/SnapDataSource.mjs +32 -30
- package/dist/data-sources/SnapDataSource.mjs.map +1 -1
- package/dist/data-sources/TokenDataSource.cjs +3 -16
- package/dist/data-sources/TokenDataSource.cjs.map +1 -1
- package/dist/data-sources/TokenDataSource.d.cts +2 -25
- package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
- package/dist/data-sources/TokenDataSource.d.mts +2 -25
- package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
- package/dist/data-sources/TokenDataSource.mjs +3 -16
- package/dist/data-sources/TokenDataSource.mjs.map +1 -1
- package/dist/data-sources/index.cjs +1 -6
- package/dist/data-sources/index.cjs.map +1 -1
- package/dist/data-sources/index.d.cts +6 -7
- package/dist/data-sources/index.d.cts.map +1 -1
- package/dist/data-sources/index.d.mts +6 -7
- package/dist/data-sources/index.d.mts.map +1 -1
- package/dist/data-sources/index.mjs +1 -3
- package/dist/data-sources/index.mjs.map +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +11 -11
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.cjs +4 -27
- package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.cts +3 -26
- package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.d.mts +3 -26
- package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
- package/dist/middlewares/DetectionMiddleware.mjs +4 -27
- package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.d.cts +1 -1
- package/dist/middlewares/index.d.cts.map +1 -1
- package/dist/middlewares/index.d.mts +1 -1
- package/dist/middlewares/index.d.mts.map +1 -1
- package/dist/middlewares/index.mjs.map +1 -1
- package/dist/selectors/balance.cjs +306 -0
- package/dist/selectors/balance.cjs.map +1 -0
- package/dist/selectors/balance.d.cts +22 -0
- package/dist/selectors/balance.d.cts.map +1 -0
- package/dist/selectors/balance.d.mts +22 -0
- package/dist/selectors/balance.d.mts.map +1 -0
- package/dist/selectors/balance.mjs +297 -0
- package/dist/selectors/balance.mjs.map +1 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +53 -18
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +53 -18
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/data-sources/initDataSources.cjs +0 -215
- package/dist/data-sources/initDataSources.cjs.map +0 -1
- package/dist/data-sources/initDataSources.d.cts +0 -140
- package/dist/data-sources/initDataSources.d.cts.map +0 -1
- package/dist/data-sources/initDataSources.d.mts +0 -140
- package/dist/data-sources/initDataSources.d.mts.map +0 -1
- package/dist/data-sources/initDataSources.mjs +0 -210
- package/dist/data-sources/initDataSources.mjs.map +0 -1
|
@@ -1,27 +1,46 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
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");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
1
6
|
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
7
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
8
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
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");
|
|
5
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
11
|
};
|
|
7
|
-
var
|
|
8
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
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
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
-
};
|
|
12
|
-
var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_defaultUpdateInterval, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_dataSources, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_assignChainsToDataSources, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeToDataSources, _AssetsController_subscribeAssetsBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_getAccountsForChains, _AssetsController_subscribeToDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleSubscriptionUpdate;
|
|
12
|
+
var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_defaultUpdateInterval, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_subscriptionBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _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_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
|
|
13
13
|
import { BaseController } from "@metamask/base-controller";
|
|
14
14
|
import { parseCaipAssetType } from "@metamask/utils";
|
|
15
15
|
import { Mutex } from "async-mutex";
|
|
16
16
|
import BigNumberJS from "bignumber.js";
|
|
17
17
|
import $lodash from "lodash";
|
|
18
18
|
const { isEqual } = $lodash;
|
|
19
|
+
import { AccountsApiDataSource } from "./data-sources/AccountsApiDataSource.mjs";
|
|
20
|
+
import { BackendWebsocketDataSource } from "./data-sources/BackendWebsocketDataSource.mjs";
|
|
21
|
+
import { PriceDataSource } from "./data-sources/PriceDataSource.mjs";
|
|
22
|
+
import { RpcDataSource } from "./data-sources/RpcDataSource.mjs";
|
|
23
|
+
import { SnapDataSource } from "./data-sources/SnapDataSource.mjs";
|
|
24
|
+
import { TokenDataSource } from "./data-sources/TokenDataSource.mjs";
|
|
19
25
|
import { projectLogger, createModuleLogger } from "./logger.mjs";
|
|
26
|
+
import { DetectionMiddleware } from "./middlewares/DetectionMiddleware.mjs";
|
|
20
27
|
import { normalizeAssetId } from "./utils.mjs";
|
|
21
28
|
// ============================================================================
|
|
22
29
|
// CONTROLLER CONSTANTS
|
|
23
30
|
// ============================================================================
|
|
24
31
|
const CONTROLLER_NAME = 'AssetsController';
|
|
32
|
+
/** Method names exposed as messenger actions (AssetsController:getAssets, etc.) */
|
|
33
|
+
const MESSENGER_EXPOSED_METHODS = [
|
|
34
|
+
'getAssets',
|
|
35
|
+
'getAssetsBalance',
|
|
36
|
+
'getAssetMetadata',
|
|
37
|
+
'getAssetsPrice',
|
|
38
|
+
'addCustomAsset',
|
|
39
|
+
'removeCustomAsset',
|
|
40
|
+
'getCustomAssets',
|
|
41
|
+
'hideAsset',
|
|
42
|
+
'unhideAsset',
|
|
43
|
+
];
|
|
25
44
|
/** Default polling interval hint for data sources (30 seconds) */
|
|
26
45
|
const DEFAULT_POLLING_INTERVAL_MS = 30000;
|
|
27
46
|
const log = createModuleLogger(projectLogger, CONTROLLER_NAME);
|
|
@@ -147,13 +166,8 @@ function normalizeResponse(response) {
|
|
|
147
166
|
* based on which chains they support. When active chains change, the controller
|
|
148
167
|
* dynamically adjusts subscriptions.
|
|
149
168
|
*
|
|
150
|
-
* 4. **
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* ## App Lifecycle
|
|
154
|
-
*
|
|
155
|
-
* - **App Opened** (`AppStateController:appOpened`): Starts subscriptions, fetches initial data
|
|
156
|
-
* - **App Closed** (`AppStateController:appClosed`): Stops all subscriptions to conserve resources
|
|
169
|
+
* 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
|
|
170
|
+
* start/stop subscriptions when the wallet is unlocked or locked.
|
|
157
171
|
*
|
|
158
172
|
* ## Architecture
|
|
159
173
|
*
|
|
@@ -162,7 +176,7 @@ function normalizeResponse(response) {
|
|
|
162
176
|
* - The controller does NOT manage polling - it simply receives pushed updates
|
|
163
177
|
*/
|
|
164
178
|
export class AssetsController extends BaseController {
|
|
165
|
-
constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, }) {
|
|
179
|
+
constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, queryApiClient, rpcDataSourceConfig, }) {
|
|
166
180
|
super({
|
|
167
181
|
name: CONTROLLER_NAME,
|
|
168
182
|
messenger,
|
|
@@ -187,79 +201,82 @@ export class AssetsController extends BaseController {
|
|
|
187
201
|
_AssetsController_activeSubscriptions.set(this, new Map());
|
|
188
202
|
/** Currently enabled chains from NetworkEnablementController */
|
|
189
203
|
_AssetsController_enabledChains.set(this, new Set());
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
204
|
+
_AssetsController_backendWebsocketDataSource.set(this, void 0);
|
|
205
|
+
_AssetsController_accountsApiDataSource.set(this, void 0);
|
|
206
|
+
_AssetsController_snapDataSource.set(this, void 0);
|
|
207
|
+
_AssetsController_rpcDataSource.set(this, void 0);
|
|
208
|
+
_AssetsController_priceDataSource.set(this, void 0);
|
|
209
|
+
_AssetsController_detectionMiddleware.set(this, void 0);
|
|
210
|
+
_AssetsController_tokenDataSource.set(this, void 0);
|
|
196
211
|
__classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
|
|
197
212
|
__classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
|
|
213
|
+
const rpcConfig = rpcDataSourceConfig ?? {};
|
|
214
|
+
const onActiveChainsUpdated = (dataSourceName, chains, previousChains) => this.handleActiveChainsUpdate(dataSourceName, chains, previousChains);
|
|
215
|
+
__classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource({
|
|
216
|
+
messenger: this.messenger,
|
|
217
|
+
queryApiClient,
|
|
218
|
+
onActiveChainsUpdated,
|
|
219
|
+
}), "f");
|
|
220
|
+
__classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource({
|
|
221
|
+
queryApiClient,
|
|
222
|
+
onActiveChainsUpdated,
|
|
223
|
+
}), "f");
|
|
224
|
+
__classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource({
|
|
225
|
+
messenger: this.messenger,
|
|
226
|
+
onActiveChainsUpdated,
|
|
227
|
+
}), "f");
|
|
228
|
+
__classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource({
|
|
229
|
+
messenger: this.messenger,
|
|
230
|
+
onActiveChainsUpdated,
|
|
231
|
+
...rpcConfig,
|
|
232
|
+
}), "f");
|
|
233
|
+
__classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource({
|
|
234
|
+
queryApiClient,
|
|
235
|
+
}), "f");
|
|
236
|
+
__classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource({
|
|
237
|
+
queryApiClient,
|
|
238
|
+
}), "f");
|
|
239
|
+
__classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware(), "f");
|
|
198
240
|
if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
|
|
199
241
|
log('AssetsController is disabled, skipping initialization');
|
|
200
242
|
return;
|
|
201
243
|
}
|
|
202
244
|
log('Initializing AssetsController', {
|
|
203
|
-
defaultUpdateInterval,
|
|
245
|
+
defaultUpdateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
|
|
204
246
|
});
|
|
205
247
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
|
|
206
248
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
|
|
207
249
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
|
|
208
|
-
// Register data sources (order = subscription priority)
|
|
209
|
-
this.registerDataSources([
|
|
210
|
-
'BackendWebsocketDataSource', // Real-time push updates
|
|
211
|
-
'AccountsApiDataSource', // HTTP polling fallback
|
|
212
|
-
'SnapDataSource', // Solana/Bitcoin/Tron snaps
|
|
213
|
-
'RpcDataSource', // Direct blockchain queries
|
|
214
|
-
]);
|
|
215
|
-
}
|
|
216
|
-
// ============================================================================
|
|
217
|
-
// DATA SOURCE MANAGEMENT
|
|
218
|
-
// ============================================================================
|
|
219
|
-
/**
|
|
220
|
-
* Register data sources with the controller.
|
|
221
|
-
* Order of the array determines subscription order.
|
|
222
|
-
*
|
|
223
|
-
* Data sources report chain changes by calling `AssetsController:activeChainsUpdate` action.
|
|
224
|
-
*
|
|
225
|
-
* @param dataSourceIds - Array of data source identifiers to register.
|
|
226
|
-
*/
|
|
227
|
-
registerDataSources(dataSourceIds) {
|
|
228
|
-
for (const id of dataSourceIds) {
|
|
229
|
-
log('Registering data source', { id });
|
|
230
|
-
// Initialize available chains tracking for this source
|
|
231
|
-
__classPrivateFieldGet(this, _AssetsController_dataSources, "f").set(id, new Set());
|
|
232
|
-
}
|
|
233
250
|
}
|
|
234
251
|
// ============================================================================
|
|
235
252
|
// DATA SOURCE CHAIN MANAGEMENT
|
|
236
253
|
// ============================================================================
|
|
237
254
|
/**
|
|
238
|
-
* Handle when a data source's
|
|
239
|
-
*
|
|
240
|
-
*
|
|
255
|
+
* Handle when a data source's supported chains change.
|
|
256
|
+
* Used to refresh balance subscriptions and run a one-time fetch when a new chain is supported.
|
|
257
|
+
*
|
|
258
|
+
* - On any add/remove: re-subscribes to data sources so chain assignment stays correct.
|
|
259
|
+
* - When chains are added: fetches balances for the new chains (for selected accounts on enabled networks).
|
|
241
260
|
*
|
|
242
|
-
*
|
|
261
|
+
* Controller does not store chains; sources report via this callback. previousChains is required for diff.
|
|
243
262
|
*
|
|
244
263
|
* @param dataSourceId - The identifier of the data source reporting the change.
|
|
245
|
-
* @param activeChains -
|
|
264
|
+
* @param activeChains - Currently active (supported and available) chain IDs for this source.
|
|
265
|
+
* @param previousChains - Previous chains; used to compute added/removed.
|
|
246
266
|
*/
|
|
247
|
-
handleActiveChainsUpdate(dataSourceId, activeChains) {
|
|
267
|
+
handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
|
|
248
268
|
log('Data source active chains changed', {
|
|
249
269
|
dataSourceId,
|
|
250
270
|
chainCount: activeChains.length,
|
|
251
271
|
chains: activeChains,
|
|
252
272
|
});
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// Check for changes
|
|
258
|
-
const addedChains = activeChains.filter((chain) => !previousChains.has(chain));
|
|
259
|
-
const removedChains = Array.from(previousChains).filter((chain) => !newChains.has(chain));
|
|
273
|
+
const previous = previousChains;
|
|
274
|
+
const previousSet = new Set(previous);
|
|
275
|
+
const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
|
|
276
|
+
const removedChains = previous.filter((ch) => !activeChains.includes(ch));
|
|
260
277
|
if (addedChains.length > 0 || removedChains.length > 0) {
|
|
261
278
|
// Refresh subscriptions to use updated data source availability
|
|
262
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
279
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
263
280
|
}
|
|
264
281
|
// If chains were added and we have selected accounts, do one-time fetch
|
|
265
282
|
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
@@ -289,21 +306,20 @@ export class AssetsController extends BaseController {
|
|
|
289
306
|
customAssets.push(...accountCustomAssets);
|
|
290
307
|
}
|
|
291
308
|
if (options?.forceUpdate) {
|
|
292
|
-
const
|
|
293
|
-
this.messenger.call('AccountsApiDataSource:getAssetsMiddleware'),
|
|
294
|
-
this.messenger.call('SnapDataSource:getAssetsMiddleware'),
|
|
295
|
-
this.messenger.call('RpcDataSource:getAssetsMiddleware'),
|
|
296
|
-
this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
|
|
297
|
-
this.messenger.call('TokenDataSource:getAssetsMiddleware'),
|
|
298
|
-
this.messenger.call('PriceDataSource:getAssetsMiddleware'),
|
|
299
|
-
], {
|
|
300
|
-
accounts,
|
|
301
|
-
chainIds,
|
|
309
|
+
const request = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
|
|
302
310
|
assetTypes,
|
|
303
311
|
dataTypes,
|
|
304
312
|
customAssets: customAssets.length > 0 ? customAssets : undefined,
|
|
305
313
|
forceUpdate: true,
|
|
306
314
|
});
|
|
315
|
+
const response = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
316
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f").assetsMiddleware,
|
|
317
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f").assetsMiddleware,
|
|
318
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").assetsMiddleware,
|
|
319
|
+
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f").assetsMiddleware,
|
|
320
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f").assetsMiddleware,
|
|
321
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").assetsMiddleware,
|
|
322
|
+
], request);
|
|
307
323
|
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
|
|
308
324
|
}
|
|
309
325
|
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
|
|
@@ -457,6 +473,9 @@ export class AssetsController extends BaseController {
|
|
|
457
473
|
}
|
|
458
474
|
});
|
|
459
475
|
}
|
|
476
|
+
// ============================================================================
|
|
477
|
+
// SUBSCRIPTIONS
|
|
478
|
+
// ============================================================================
|
|
460
479
|
/**
|
|
461
480
|
* Subscribe to price updates for all assets held by the given accounts.
|
|
462
481
|
* Polls PriceDataSource which fetches prices from balance state.
|
|
@@ -471,19 +490,17 @@ export class AssetsController extends BaseController {
|
|
|
471
490
|
const subscriptionKey = 'ds:PriceDataSource';
|
|
472
491
|
const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
|
|
473
492
|
const isUpdate = existingSubscription !== undefined;
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
.call('PriceDataSource:subscribe', {
|
|
477
|
-
request: {
|
|
478
|
-
accounts,
|
|
479
|
-
chainIds,
|
|
493
|
+
const subscribeReq = {
|
|
494
|
+
request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
|
|
480
495
|
dataTypes: ['price'],
|
|
481
496
|
updateInterval,
|
|
482
|
-
},
|
|
497
|
+
}),
|
|
483
498
|
subscriptionId: subscriptionKey,
|
|
484
499
|
isUpdate,
|
|
485
|
-
|
|
486
|
-
|
|
500
|
+
onAssetsUpdate: (response) => this.handleAssetsUpdate(response, 'PriceDataSource'),
|
|
501
|
+
getAssetsState: () => this.state,
|
|
502
|
+
};
|
|
503
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").subscribe(subscribeReq).catch(console.error);
|
|
487
504
|
// Track subscription
|
|
488
505
|
const subscription = {
|
|
489
506
|
chains: chainIds,
|
|
@@ -505,37 +522,55 @@ export class AssetsController extends BaseController {
|
|
|
505
522
|
if (!existingSubscription) {
|
|
506
523
|
return;
|
|
507
524
|
}
|
|
508
|
-
|
|
509
|
-
this.messenger
|
|
510
|
-
.call('PriceDataSource:unsubscribe', subscriptionKey)
|
|
511
|
-
.catch(console.error);
|
|
525
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").unsubscribe(subscriptionKey).catch(console.error);
|
|
512
526
|
existingSubscription.unsubscribe();
|
|
513
527
|
}
|
|
514
528
|
/**
|
|
515
529
|
* Handle assets updated from a data source.
|
|
516
|
-
* Called via
|
|
530
|
+
* Called via the onAssetsUpdate callback passed in SubscriptionRequest when the controller subscribes to a data source.
|
|
531
|
+
* Enriches the response with token metadata (via middlewares) before updating state.
|
|
517
532
|
*
|
|
518
533
|
* @param response - The data response with updated assets
|
|
519
534
|
* @param sourceId - The data source ID reporting the update
|
|
535
|
+
* @param request - Optional original request for context when enriching
|
|
520
536
|
*/
|
|
521
|
-
async handleAssetsUpdate(response, sourceId) {
|
|
537
|
+
async handleAssetsUpdate(response, sourceId, request) {
|
|
522
538
|
log('Assets updated from data source', {
|
|
523
539
|
sourceId,
|
|
524
540
|
hasBalance: Boolean(response.assetsBalance),
|
|
525
541
|
hasPrice: Boolean(response.assetsPrice),
|
|
526
542
|
});
|
|
527
|
-
|
|
543
|
+
// Run through enrichment middlewares (Event Stack: Detection → Token → Price)
|
|
544
|
+
// Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
|
|
545
|
+
const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
546
|
+
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f").assetsMiddleware,
|
|
547
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f").assetsMiddleware,
|
|
548
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").assetsMiddleware,
|
|
549
|
+
], request ?? {
|
|
550
|
+
accountsWithSupportedChains: [],
|
|
551
|
+
chainIds: [],
|
|
552
|
+
dataTypes: ['balance', 'metadata', 'price'],
|
|
553
|
+
}, response);
|
|
554
|
+
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
|
|
528
555
|
}
|
|
529
556
|
// ============================================================================
|
|
530
557
|
// CLEANUP
|
|
531
558
|
// ============================================================================
|
|
532
559
|
destroy() {
|
|
533
560
|
log('Destroying AssetsController', {
|
|
534
|
-
dataSourceCount: __classPrivateFieldGet(this,
|
|
561
|
+
dataSourceCount: __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_subscriptionBalanceDataSources_get).length,
|
|
535
562
|
subscriptionCount: __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size,
|
|
536
563
|
});
|
|
537
|
-
//
|
|
538
|
-
__classPrivateFieldGet(this,
|
|
564
|
+
// Destroy instantiated data sources
|
|
565
|
+
__classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f")?.destroy?.();
|
|
566
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f")?.destroy?.();
|
|
567
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f")?.destroy?.();
|
|
568
|
+
if (__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f") &&
|
|
569
|
+
'destroy' in __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f") &&
|
|
570
|
+
typeof __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").destroy ===
|
|
571
|
+
'function') {
|
|
572
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").destroy();
|
|
573
|
+
}
|
|
539
574
|
// Stop all active subscriptions
|
|
540
575
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
|
|
541
576
|
// Unregister action handlers
|
|
@@ -543,8 +578,6 @@ export class AssetsController extends BaseController {
|
|
|
543
578
|
this.messenger.unregisterActionHandler('AssetsController:getAssetsBalance');
|
|
544
579
|
this.messenger.unregisterActionHandler('AssetsController:getAssetMetadata');
|
|
545
580
|
this.messenger.unregisterActionHandler('AssetsController:getAssetsPrice');
|
|
546
|
-
this.messenger.unregisterActionHandler('AssetsController:activeChainsUpdate');
|
|
547
|
-
this.messenger.unregisterActionHandler('AssetsController:assetsUpdate');
|
|
548
581
|
this.messenger.unregisterActionHandler('AssetsController:addCustomAsset');
|
|
549
582
|
this.messenger.unregisterActionHandler('AssetsController:removeCustomAsset');
|
|
550
583
|
this.messenger.unregisterActionHandler('AssetsController:getCustomAssets');
|
|
@@ -552,8 +585,15 @@ export class AssetsController extends BaseController {
|
|
|
552
585
|
this.messenger.unregisterActionHandler('AssetsController:unhideAsset');
|
|
553
586
|
}
|
|
554
587
|
}
|
|
555
|
-
_AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(),
|
|
588
|
+
_AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInterval = 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_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
|
|
556
589
|
return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
|
|
590
|
+
}, _AssetsController_subscriptionBalanceDataSources_get = function _AssetsController_subscriptionBalanceDataSources_get() {
|
|
591
|
+
return [
|
|
592
|
+
__classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f"),
|
|
593
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
|
|
594
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
|
|
595
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
|
|
596
|
+
];
|
|
557
597
|
}, _AssetsController_initializeState = function _AssetsController_initializeState() {
|
|
558
598
|
const { enabledNetworkMap } = this.messenger.call('NetworkEnablementController:getState');
|
|
559
599
|
__classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
|
|
@@ -595,24 +635,11 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInte
|
|
|
595
635
|
this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
|
|
596
636
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
|
|
597
637
|
});
|
|
598
|
-
// App lifecycle: start when opened, stop when closed
|
|
599
|
-
this.messenger.subscribe('AppStateController:appOpened', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
|
|
600
|
-
this.messenger.subscribe('AppStateController:appClosed', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
|
|
601
638
|
// Keyring lifecycle: start when unlocked, stop when locked
|
|
602
639
|
this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
|
|
603
640
|
this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
|
|
604
641
|
}, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
|
|
605
|
-
this.messenger.
|
|
606
|
-
this.messenger.registerActionHandler('AssetsController:getAssetsBalance', this.getAssetsBalance.bind(this));
|
|
607
|
-
this.messenger.registerActionHandler('AssetsController:getAssetMetadata', this.getAssetMetadata.bind(this));
|
|
608
|
-
this.messenger.registerActionHandler('AssetsController:getAssetsPrice', this.getAssetsPrice.bind(this));
|
|
609
|
-
this.messenger.registerActionHandler('AssetsController:activeChainsUpdate', this.handleActiveChainsUpdate.bind(this));
|
|
610
|
-
this.messenger.registerActionHandler('AssetsController:assetsUpdate', this.handleAssetsUpdate.bind(this));
|
|
611
|
-
this.messenger.registerActionHandler('AssetsController:addCustomAsset', this.addCustomAsset.bind(this));
|
|
612
|
-
this.messenger.registerActionHandler('AssetsController:removeCustomAsset', this.removeCustomAsset.bind(this));
|
|
613
|
-
this.messenger.registerActionHandler('AssetsController:getCustomAssets', this.getCustomAssets.bind(this));
|
|
614
|
-
this.messenger.registerActionHandler('AssetsController:hideAsset', this.hideAsset.bind(this));
|
|
615
|
-
this.messenger.registerActionHandler('AssetsController:unhideAsset', this.unhideAsset.bind(this));
|
|
642
|
+
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
616
643
|
}, _AssetsController_executeMiddlewares =
|
|
617
644
|
// ============================================================================
|
|
618
645
|
// MIDDLEWARE EXECUTION
|
|
@@ -641,32 +668,6 @@ async function _AssetsController_executeMiddlewares(middlewares, request, initia
|
|
|
641
668
|
getAssetsState: () => this.state,
|
|
642
669
|
});
|
|
643
670
|
return result.response;
|
|
644
|
-
}, _AssetsController_assignChainsToDataSources = function _AssetsController_assignChainsToDataSources(requestedChains) {
|
|
645
|
-
const assignment = new Map();
|
|
646
|
-
const remainingChains = new Set(requestedChains);
|
|
647
|
-
for (const sourceId of __classPrivateFieldGet(this, _AssetsController_dataSources, "f").keys()) {
|
|
648
|
-
// Get available chains for this data source
|
|
649
|
-
const availableChains = __classPrivateFieldGet(this, _AssetsController_dataSources, "f").get(sourceId);
|
|
650
|
-
if (!availableChains || availableChains.size === 0) {
|
|
651
|
-
continue;
|
|
652
|
-
}
|
|
653
|
-
const chainsForThisSource = [];
|
|
654
|
-
for (const chainId of remainingChains) {
|
|
655
|
-
// Check if this chain is available on this source
|
|
656
|
-
if (availableChains.has(chainId)) {
|
|
657
|
-
chainsForThisSource.push(chainId);
|
|
658
|
-
remainingChains.delete(chainId);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
if (chainsForThisSource.length > 0) {
|
|
662
|
-
assignment.set(sourceId, chainsForThisSource);
|
|
663
|
-
log('Assigned chains to data source', {
|
|
664
|
-
sourceId,
|
|
665
|
-
chains: chainsForThisSource,
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
return assignment;
|
|
670
671
|
}, _AssetsController_updateState =
|
|
671
672
|
// ============================================================================
|
|
672
673
|
// STATE MANAGEMENT
|
|
@@ -860,7 +861,7 @@ async function _AssetsController_updateState(response) {
|
|
|
860
861
|
selectedAccountCount: __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length,
|
|
861
862
|
enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
|
|
862
863
|
});
|
|
863
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
864
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
864
865
|
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
865
866
|
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
866
867
|
chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
|
|
@@ -881,77 +882,67 @@ async function _AssetsController_updateState(response) {
|
|
|
881
882
|
// Convert to array first to avoid modifying map during iteration
|
|
882
883
|
const subscriptionKeys = [...__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").keys()];
|
|
883
884
|
for (const subscriptionKey of subscriptionKeys) {
|
|
884
|
-
// Extract sourceId from subscription key (format: "ds:${sourceId}")
|
|
885
885
|
if (subscriptionKey.startsWith('ds:')) {
|
|
886
886
|
const sourceId = subscriptionKey.slice(3);
|
|
887
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "
|
|
887
|
+
const source = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_subscriptionBalanceDataSources_get).find((ds) => ds.getName() === sourceId);
|
|
888
|
+
if (source) {
|
|
889
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
|
|
890
|
+
}
|
|
888
891
|
}
|
|
889
892
|
}
|
|
890
893
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
|
|
891
|
-
},
|
|
894
|
+
}, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
|
|
892
895
|
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
|
|
893
896
|
return;
|
|
894
897
|
}
|
|
895
898
|
// Subscribe to balance updates (batched by data source)
|
|
896
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this)
|
|
899
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [
|
|
900
|
+
...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f"),
|
|
901
|
+
]);
|
|
897
902
|
// Subscribe to price updates for all assets held by selected accounts
|
|
898
903
|
this.subscribeAssetsPrice(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
|
|
899
|
-
}, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance() {
|
|
900
|
-
|
|
901
|
-
const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
|
|
902
|
-
// Step 2: Split by data source active chains (ordered by priority)
|
|
903
|
-
// Get all chains that need to be subscribed
|
|
904
|
+
}, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance(accounts, chainIds) {
|
|
905
|
+
const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, accounts, new Set(chainIds));
|
|
904
906
|
const remainingChains = new Set(chainToAccounts.keys());
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
const assignedChains = chainAssignment.get(sourceId);
|
|
914
|
-
if (!assignedChains || assignedChains.length === 0) {
|
|
915
|
-
// Unsubscribe from data sources with no assigned chains
|
|
916
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, sourceId);
|
|
917
|
-
continue;
|
|
907
|
+
for (const source of __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_subscriptionBalanceDataSources_get)) {
|
|
908
|
+
const availableChains = new Set(source.getActiveChainsSync());
|
|
909
|
+
const assignedChains = [];
|
|
910
|
+
for (const chainId of remainingChains) {
|
|
911
|
+
if (availableChains.has(chainId)) {
|
|
912
|
+
assignedChains.push(chainId);
|
|
913
|
+
remainingChains.delete(chainId);
|
|
914
|
+
}
|
|
918
915
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
if (accountsForSource.length === 0) {
|
|
916
|
+
if (assignedChains.length === 0) {
|
|
917
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
|
|
922
918
|
continue;
|
|
923
919
|
}
|
|
924
|
-
|
|
925
|
-
|
|
920
|
+
const seenIds = new Set();
|
|
921
|
+
const accountsForSource = assignedChains
|
|
922
|
+
.flatMap((chainId) => chainToAccounts.get(chainId) ?? [])
|
|
923
|
+
.filter((account) => !seenIds.has(account.id) && (seenIds.add(account.id), true));
|
|
924
|
+
if (accountsForSource.length > 0) {
|
|
925
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accountsForSource, assignedChains);
|
|
926
|
+
}
|
|
926
927
|
}
|
|
927
928
|
}, _AssetsController_buildChainToAccountsMap = function _AssetsController_buildChainToAccountsMap(accounts, chainsToSubscribe) {
|
|
928
929
|
const chainToAccounts = new Map();
|
|
929
930
|
for (const account of accounts) {
|
|
930
|
-
const
|
|
931
|
-
for (const chainId of accountChains) {
|
|
931
|
+
for (const chainId of __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account)) {
|
|
932
932
|
if (!chainsToSubscribe.has(chainId)) {
|
|
933
933
|
continue;
|
|
934
934
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
940
|
-
return chainToAccounts;
|
|
941
|
-
}, _AssetsController_getAccountsForChains = function _AssetsController_getAccountsForChains(chains, chainToAccounts) {
|
|
942
|
-
const accountIds = new Set();
|
|
943
|
-
const accounts = [];
|
|
944
|
-
for (const chainId of chains) {
|
|
945
|
-
const chainAccounts = chainToAccounts.get(chainId) ?? [];
|
|
946
|
-
for (const account of chainAccounts) {
|
|
947
|
-
if (!accountIds.has(account.id)) {
|
|
948
|
-
accountIds.add(account.id);
|
|
949
|
-
accounts.push(account);
|
|
935
|
+
let list = chainToAccounts.get(chainId);
|
|
936
|
+
if (!list) {
|
|
937
|
+
list = [];
|
|
938
|
+
chainToAccounts.set(chainId, list);
|
|
950
939
|
}
|
|
940
|
+
list.push(account);
|
|
951
941
|
}
|
|
952
942
|
}
|
|
953
|
-
return
|
|
954
|
-
},
|
|
943
|
+
return chainToAccounts;
|
|
944
|
+
}, _AssetsController_subscribeDataSource = function _AssetsController_subscribeDataSource(source, accounts, chains) {
|
|
945
|
+
const sourceId = source.getName();
|
|
955
946
|
const subscriptionKey = `ds:${sourceId}`;
|
|
956
947
|
const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
|
|
957
948
|
const isUpdate = existingSubscription !== undefined;
|
|
@@ -962,53 +953,49 @@ async function _AssetsController_updateState(response) {
|
|
|
962
953
|
accountCount: accounts.length,
|
|
963
954
|
chainCount: chains.length,
|
|
964
955
|
});
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
}
|
|
980
|
-
catch (error) {
|
|
981
|
-
console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
|
|
982
|
-
}
|
|
983
|
-
})().catch(console.error);
|
|
956
|
+
const subscribeReq = {
|
|
957
|
+
request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chains, {
|
|
958
|
+
assetTypes: ['fungible'],
|
|
959
|
+
dataTypes: ['balance'],
|
|
960
|
+
updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
|
|
961
|
+
}),
|
|
962
|
+
subscriptionId: subscriptionKey,
|
|
963
|
+
isUpdate,
|
|
964
|
+
onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
|
|
965
|
+
getAssetsState: () => this.state,
|
|
966
|
+
};
|
|
967
|
+
source.subscribe(subscribeReq).catch((error) => {
|
|
968
|
+
console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
|
|
969
|
+
});
|
|
984
970
|
// Track subscription
|
|
985
971
|
const subscription = {
|
|
986
972
|
chains,
|
|
987
973
|
accountId: subscriptionKey,
|
|
988
974
|
assetTypes: ['fungible'],
|
|
989
|
-
dataTypes: ['balance'
|
|
975
|
+
dataTypes: ['balance'],
|
|
990
976
|
unsubscribe: () => {
|
|
991
977
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").delete(subscriptionKey);
|
|
992
978
|
},
|
|
993
979
|
};
|
|
994
980
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").set(subscriptionKey, subscription);
|
|
995
|
-
}, _AssetsController_unsubscribeDataSource = function _AssetsController_unsubscribeDataSource(
|
|
996
|
-
const subscriptionKey = `ds:${
|
|
981
|
+
}, _AssetsController_unsubscribeDataSource = function _AssetsController_unsubscribeDataSource(source) {
|
|
982
|
+
const subscriptionKey = `ds:${source.getName()}`;
|
|
997
983
|
const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
|
|
998
984
|
if (existingSubscription) {
|
|
999
|
-
|
|
1000
|
-
(async () => {
|
|
1001
|
-
try {
|
|
1002
|
-
await this.messenger.call(`${sourceId}:unsubscribe`, subscriptionKey);
|
|
1003
|
-
}
|
|
1004
|
-
catch {
|
|
1005
|
-
// Ignore errors - source may not have been subscribed
|
|
1006
|
-
}
|
|
1007
|
-
})().catch(() => {
|
|
1008
|
-
// Ignore errors - source may not have been subscribed
|
|
1009
|
-
});
|
|
985
|
+
source.unsubscribe(subscriptionKey).catch(() => undefined);
|
|
1010
986
|
existingSubscription.unsubscribe();
|
|
1011
987
|
}
|
|
988
|
+
}, _AssetsController_buildDataRequest = function _AssetsController_buildDataRequest(accounts, chainIds, partial = {}) {
|
|
989
|
+
const chainIdSet = new Set(chainIds);
|
|
990
|
+
const accountsWithSupportedChains = accounts.map((account) => ({
|
|
991
|
+
account,
|
|
992
|
+
supportedChains: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account).filter((chain) => chainIdSet.has(chain)),
|
|
993
|
+
}));
|
|
994
|
+
return {
|
|
995
|
+
accountsWithSupportedChains,
|
|
996
|
+
chainIds,
|
|
997
|
+
...partial,
|
|
998
|
+
};
|
|
1012
999
|
}, _AssetsController_getEnabledChainsForAccount = function _AssetsController_getEnabledChainsForAccount(account) {
|
|
1013
1000
|
// Account scopes are CAIP-2 chain IDs like "eip155:1", "solana:mainnet", "bip122:..."
|
|
1014
1001
|
const scopes = account.scopes ?? [];
|
|
@@ -1043,7 +1030,7 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1043
1030
|
accountIds: accounts.map((a) => a.id),
|
|
1044
1031
|
});
|
|
1045
1032
|
// Subscribe and fetch for the new account group
|
|
1046
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
1033
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1047
1034
|
if (accounts.length > 0) {
|
|
1048
1035
|
await this.getAssets(accounts, {
|
|
1049
1036
|
chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
|
|
@@ -1077,7 +1064,7 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1077
1064
|
// Users may want to see historical balances even if the network is currently disabled.
|
|
1078
1065
|
// The data will simply not be updated until the network is re-enabled.
|
|
1079
1066
|
// Refresh subscriptions for new chain set
|
|
1080
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
1067
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1081
1068
|
// Do one-time fetch for newly enabled chains
|
|
1082
1069
|
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
1083
1070
|
await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
@@ -1085,28 +1072,5 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1085
1072
|
forceUpdate: true,
|
|
1086
1073
|
});
|
|
1087
1074
|
}
|
|
1088
|
-
}, _AssetsController_handleSubscriptionUpdate =
|
|
1089
|
-
/**
|
|
1090
|
-
* Handle an async update from a data source subscription.
|
|
1091
|
-
* Enriches response with token metadata before updating state.
|
|
1092
|
-
*
|
|
1093
|
-
* @param response - The data response from the data source.
|
|
1094
|
-
* @param _sourceId - The source ID (unused but kept for logging context).
|
|
1095
|
-
* @param request - Optional original request for context.
|
|
1096
|
-
*/
|
|
1097
|
-
async function _AssetsController_handleSubscriptionUpdate(response, _sourceId, request) {
|
|
1098
|
-
// Run through enrichment middlewares (Event Stack: Detection → Token → Price)
|
|
1099
|
-
// Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
|
|
1100
|
-
const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
1101
|
-
this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
|
|
1102
|
-
this.messenger.call('TokenDataSource:getAssetsMiddleware'),
|
|
1103
|
-
this.messenger.call('PriceDataSource:getAssetsMiddleware'),
|
|
1104
|
-
], request ?? {
|
|
1105
|
-
accounts: [],
|
|
1106
|
-
chainIds: [],
|
|
1107
|
-
dataTypes: ['balance', 'metadata', 'price'],
|
|
1108
|
-
}, response);
|
|
1109
|
-
// Update state
|
|
1110
|
-
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
|
|
1111
1075
|
};
|
|
1112
1076
|
//# sourceMappingURL=AssetsController.mjs.map
|