@metamask/assets-controller 0.1.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 +31 -3
- 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 +273 -247
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +55 -93
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +55 -93
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +273 -247
- 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 -62
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
- package/dist/data-sources/RpcDataSource.d.mts +16 -62
- 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/evm-rpc-services/clients/MulticallClient.cjs +27 -35
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs +27 -35
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.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 +63 -18
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +63 -18
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +4 -4
- 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,19 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
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");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
2
7
|
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
8
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
9
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
10
|
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");
|
|
6
11
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
12
|
};
|
|
8
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
-
};
|
|
13
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
|
-
var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_defaultUpdateInterval, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get,
|
|
16
|
+
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;
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.AssetsController = exports.getDefaultAssetsControllerState = void 0;
|
|
19
19
|
const base_controller_1 = require("@metamask/base-controller");
|
|
@@ -21,19 +21,38 @@ const utils_1 = require("@metamask/utils");
|
|
|
21
21
|
const async_mutex_1 = require("async-mutex");
|
|
22
22
|
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
23
23
|
const lodash_1 = require("lodash");
|
|
24
|
+
const AccountsApiDataSource_1 = require("./data-sources/AccountsApiDataSource.cjs");
|
|
25
|
+
const BackendWebsocketDataSource_1 = require("./data-sources/BackendWebsocketDataSource.cjs");
|
|
26
|
+
const PriceDataSource_1 = require("./data-sources/PriceDataSource.cjs");
|
|
27
|
+
const RpcDataSource_1 = require("./data-sources/RpcDataSource.cjs");
|
|
28
|
+
const SnapDataSource_1 = require("./data-sources/SnapDataSource.cjs");
|
|
29
|
+
const TokenDataSource_1 = require("./data-sources/TokenDataSource.cjs");
|
|
24
30
|
const logger_1 = require("./logger.cjs");
|
|
31
|
+
const DetectionMiddleware_1 = require("./middlewares/DetectionMiddleware.cjs");
|
|
25
32
|
const utils_2 = require("./utils.cjs");
|
|
26
33
|
// ============================================================================
|
|
27
34
|
// CONTROLLER CONSTANTS
|
|
28
35
|
// ============================================================================
|
|
29
36
|
const CONTROLLER_NAME = 'AssetsController';
|
|
37
|
+
/** Method names exposed as messenger actions (AssetsController:getAssets, etc.) */
|
|
38
|
+
const MESSENGER_EXPOSED_METHODS = [
|
|
39
|
+
'getAssets',
|
|
40
|
+
'getAssetsBalance',
|
|
41
|
+
'getAssetMetadata',
|
|
42
|
+
'getAssetsPrice',
|
|
43
|
+
'addCustomAsset',
|
|
44
|
+
'removeCustomAsset',
|
|
45
|
+
'getCustomAssets',
|
|
46
|
+
'hideAsset',
|
|
47
|
+
'unhideAsset',
|
|
48
|
+
];
|
|
30
49
|
/** Default polling interval hint for data sources (30 seconds) */
|
|
31
50
|
const DEFAULT_POLLING_INTERVAL_MS = 30000;
|
|
32
51
|
const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_NAME);
|
|
33
52
|
/**
|
|
34
53
|
* Returns the default state for AssetsController.
|
|
35
54
|
*
|
|
36
|
-
* @returns The default AssetsController state with empty
|
|
55
|
+
* @returns The default AssetsController state with empty maps.
|
|
37
56
|
*/
|
|
38
57
|
function getDefaultAssetsControllerState() {
|
|
39
58
|
return {
|
|
@@ -41,6 +60,7 @@ function getDefaultAssetsControllerState() {
|
|
|
41
60
|
assetsBalance: {},
|
|
42
61
|
assetsPrice: {},
|
|
43
62
|
customAssets: {},
|
|
63
|
+
assetPreferences: {},
|
|
44
64
|
};
|
|
45
65
|
}
|
|
46
66
|
exports.getDefaultAssetsControllerState = getDefaultAssetsControllerState;
|
|
@@ -72,6 +92,12 @@ const stateMetadata = {
|
|
|
72
92
|
includeInDebugSnapshot: false,
|
|
73
93
|
usedInUi: true,
|
|
74
94
|
},
|
|
95
|
+
assetPreferences: {
|
|
96
|
+
persist: true,
|
|
97
|
+
includeInStateLogs: false,
|
|
98
|
+
includeInDebugSnapshot: false,
|
|
99
|
+
usedInUi: true,
|
|
100
|
+
},
|
|
75
101
|
};
|
|
76
102
|
// ============================================================================
|
|
77
103
|
// HELPER FUNCTIONS
|
|
@@ -146,13 +172,8 @@ function normalizeResponse(response) {
|
|
|
146
172
|
* based on which chains they support. When active chains change, the controller
|
|
147
173
|
* dynamically adjusts subscriptions.
|
|
148
174
|
*
|
|
149
|
-
* 4. **
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* ## App Lifecycle
|
|
153
|
-
*
|
|
154
|
-
* - **App Opened** (`AppStateController:appOpened`): Starts subscriptions, fetches initial data
|
|
155
|
-
* - **App Closed** (`AppStateController:appClosed`): Stops all subscriptions to conserve resources
|
|
175
|
+
* 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
|
|
176
|
+
* start/stop subscriptions when the wallet is unlocked or locked.
|
|
156
177
|
*
|
|
157
178
|
* ## Architecture
|
|
158
179
|
*
|
|
@@ -161,7 +182,7 @@ function normalizeResponse(response) {
|
|
|
161
182
|
* - The controller does NOT manage polling - it simply receives pushed updates
|
|
162
183
|
*/
|
|
163
184
|
class AssetsController extends base_controller_1.BaseController {
|
|
164
|
-
constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, }) {
|
|
185
|
+
constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, queryApiClient, rpcDataSourceConfig, }) {
|
|
165
186
|
super({
|
|
166
187
|
name: CONTROLLER_NAME,
|
|
167
188
|
messenger,
|
|
@@ -186,79 +207,82 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
186
207
|
_AssetsController_activeSubscriptions.set(this, new Map());
|
|
187
208
|
/** Currently enabled chains from NetworkEnablementController */
|
|
188
209
|
_AssetsController_enabledChains.set(this, new Set());
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
210
|
+
_AssetsController_backendWebsocketDataSource.set(this, void 0);
|
|
211
|
+
_AssetsController_accountsApiDataSource.set(this, void 0);
|
|
212
|
+
_AssetsController_snapDataSource.set(this, void 0);
|
|
213
|
+
_AssetsController_rpcDataSource.set(this, void 0);
|
|
214
|
+
_AssetsController_priceDataSource.set(this, void 0);
|
|
215
|
+
_AssetsController_detectionMiddleware.set(this, void 0);
|
|
216
|
+
_AssetsController_tokenDataSource.set(this, void 0);
|
|
195
217
|
__classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
|
|
196
218
|
__classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
|
|
219
|
+
const rpcConfig = rpcDataSourceConfig ?? {};
|
|
220
|
+
const onActiveChainsUpdated = (dataSourceName, chains, previousChains) => this.handleActiveChainsUpdate(dataSourceName, chains, previousChains);
|
|
221
|
+
__classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource_1.BackendWebsocketDataSource({
|
|
222
|
+
messenger: this.messenger,
|
|
223
|
+
queryApiClient,
|
|
224
|
+
onActiveChainsUpdated,
|
|
225
|
+
}), "f");
|
|
226
|
+
__classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource_1.AccountsApiDataSource({
|
|
227
|
+
queryApiClient,
|
|
228
|
+
onActiveChainsUpdated,
|
|
229
|
+
}), "f");
|
|
230
|
+
__classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource_1.SnapDataSource({
|
|
231
|
+
messenger: this.messenger,
|
|
232
|
+
onActiveChainsUpdated,
|
|
233
|
+
}), "f");
|
|
234
|
+
__classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource_1.RpcDataSource({
|
|
235
|
+
messenger: this.messenger,
|
|
236
|
+
onActiveChainsUpdated,
|
|
237
|
+
...rpcConfig,
|
|
238
|
+
}), "f");
|
|
239
|
+
__classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource_1.TokenDataSource({
|
|
240
|
+
queryApiClient,
|
|
241
|
+
}), "f");
|
|
242
|
+
__classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource_1.PriceDataSource({
|
|
243
|
+
queryApiClient,
|
|
244
|
+
}), "f");
|
|
245
|
+
__classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware_1.DetectionMiddleware(), "f");
|
|
197
246
|
if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
|
|
198
247
|
log('AssetsController is disabled, skipping initialization');
|
|
199
248
|
return;
|
|
200
249
|
}
|
|
201
250
|
log('Initializing AssetsController', {
|
|
202
|
-
defaultUpdateInterval,
|
|
251
|
+
defaultUpdateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
|
|
203
252
|
});
|
|
204
253
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
|
|
205
254
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
|
|
206
255
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
|
|
207
|
-
// Register data sources (order = subscription priority)
|
|
208
|
-
this.registerDataSources([
|
|
209
|
-
'BackendWebsocketDataSource', // Real-time push updates
|
|
210
|
-
'AccountsApiDataSource', // HTTP polling fallback
|
|
211
|
-
'SnapDataSource', // Solana/Bitcoin/Tron snaps
|
|
212
|
-
'RpcDataSource', // Direct blockchain queries
|
|
213
|
-
]);
|
|
214
|
-
}
|
|
215
|
-
// ============================================================================
|
|
216
|
-
// DATA SOURCE MANAGEMENT
|
|
217
|
-
// ============================================================================
|
|
218
|
-
/**
|
|
219
|
-
* Register data sources with the controller.
|
|
220
|
-
* Order of the array determines subscription order.
|
|
221
|
-
*
|
|
222
|
-
* Data sources report chain changes by calling `AssetsController:activeChainsUpdate` action.
|
|
223
|
-
*
|
|
224
|
-
* @param dataSourceIds - Array of data source identifiers to register.
|
|
225
|
-
*/
|
|
226
|
-
registerDataSources(dataSourceIds) {
|
|
227
|
-
for (const id of dataSourceIds) {
|
|
228
|
-
log('Registering data source', { id });
|
|
229
|
-
// Initialize available chains tracking for this source
|
|
230
|
-
__classPrivateFieldGet(this, _AssetsController_dataSources, "f").set(id, new Set());
|
|
231
|
-
}
|
|
232
256
|
}
|
|
233
257
|
// ============================================================================
|
|
234
258
|
// DATA SOURCE CHAIN MANAGEMENT
|
|
235
259
|
// ============================================================================
|
|
236
260
|
/**
|
|
237
|
-
* Handle when a data source's
|
|
238
|
-
*
|
|
239
|
-
*
|
|
261
|
+
* Handle when a data source's supported chains change.
|
|
262
|
+
* Used to refresh balance subscriptions and run a one-time fetch when a new chain is supported.
|
|
263
|
+
*
|
|
264
|
+
* - On any add/remove: re-subscribes to data sources so chain assignment stays correct.
|
|
265
|
+
* - When chains are added: fetches balances for the new chains (for selected accounts on enabled networks).
|
|
240
266
|
*
|
|
241
|
-
*
|
|
267
|
+
* Controller does not store chains; sources report via this callback. previousChains is required for diff.
|
|
242
268
|
*
|
|
243
269
|
* @param dataSourceId - The identifier of the data source reporting the change.
|
|
244
|
-
* @param activeChains -
|
|
270
|
+
* @param activeChains - Currently active (supported and available) chain IDs for this source.
|
|
271
|
+
* @param previousChains - Previous chains; used to compute added/removed.
|
|
245
272
|
*/
|
|
246
|
-
handleActiveChainsUpdate(dataSourceId, activeChains) {
|
|
273
|
+
handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
|
|
247
274
|
log('Data source active chains changed', {
|
|
248
275
|
dataSourceId,
|
|
249
276
|
chainCount: activeChains.length,
|
|
250
277
|
chains: activeChains,
|
|
251
278
|
});
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
// Check for changes
|
|
257
|
-
const addedChains = activeChains.filter((chain) => !previousChains.has(chain));
|
|
258
|
-
const removedChains = Array.from(previousChains).filter((chain) => !newChains.has(chain));
|
|
279
|
+
const previous = previousChains;
|
|
280
|
+
const previousSet = new Set(previous);
|
|
281
|
+
const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
|
|
282
|
+
const removedChains = previous.filter((ch) => !activeChains.includes(ch));
|
|
259
283
|
if (addedChains.length > 0 || removedChains.length > 0) {
|
|
260
284
|
// Refresh subscriptions to use updated data source availability
|
|
261
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
285
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
262
286
|
}
|
|
263
287
|
// If chains were added and we have selected accounts, do one-time fetch
|
|
264
288
|
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
@@ -288,21 +312,20 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
288
312
|
customAssets.push(...accountCustomAssets);
|
|
289
313
|
}
|
|
290
314
|
if (options?.forceUpdate) {
|
|
291
|
-
const
|
|
292
|
-
this.messenger.call('AccountsApiDataSource:getAssetsMiddleware'),
|
|
293
|
-
this.messenger.call('SnapDataSource:getAssetsMiddleware'),
|
|
294
|
-
this.messenger.call('RpcDataSource:getAssetsMiddleware'),
|
|
295
|
-
this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
|
|
296
|
-
this.messenger.call('TokenDataSource:getAssetsMiddleware'),
|
|
297
|
-
this.messenger.call('PriceDataSource:getAssetsMiddleware'),
|
|
298
|
-
], {
|
|
299
|
-
accounts,
|
|
300
|
-
chainIds,
|
|
315
|
+
const request = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
|
|
301
316
|
assetTypes,
|
|
302
317
|
dataTypes,
|
|
303
318
|
customAssets: customAssets.length > 0 ? customAssets : undefined,
|
|
304
319
|
forceUpdate: true,
|
|
305
320
|
});
|
|
321
|
+
const response = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
322
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f").assetsMiddleware,
|
|
323
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f").assetsMiddleware,
|
|
324
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").assetsMiddleware,
|
|
325
|
+
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f").assetsMiddleware,
|
|
326
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f").assetsMiddleware,
|
|
327
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").assetsMiddleware,
|
|
328
|
+
], request);
|
|
306
329
|
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
|
|
307
330
|
}
|
|
308
331
|
return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
|
|
@@ -354,6 +377,7 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
354
377
|
/**
|
|
355
378
|
* Add a custom asset for an account.
|
|
356
379
|
* Custom assets are included in subscription and fetch operations.
|
|
380
|
+
* Adding a custom asset also unhides it if it was previously hidden.
|
|
357
381
|
*
|
|
358
382
|
* @param accountId - The account ID to add the custom asset for.
|
|
359
383
|
* @param assetId - The CAIP-19 asset ID to add.
|
|
@@ -370,6 +394,14 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
370
394
|
if (!customAssets[accountId].includes(normalizedAssetId)) {
|
|
371
395
|
customAssets[accountId].push(normalizedAssetId);
|
|
372
396
|
}
|
|
397
|
+
// Unhide the asset if it was hidden (via assetPreferences)
|
|
398
|
+
const prefs = state.assetPreferences[normalizedAssetId];
|
|
399
|
+
if (prefs?.hidden) {
|
|
400
|
+
delete prefs.hidden;
|
|
401
|
+
if (Object.keys(prefs).length === 0) {
|
|
402
|
+
delete state.assetPreferences[normalizedAssetId];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
373
405
|
});
|
|
374
406
|
// Fetch data for the newly added custom asset
|
|
375
407
|
const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
|
|
@@ -391,12 +423,11 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
391
423
|
const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
|
|
392
424
|
log('Removing custom asset', { accountId, assetId: normalizedAssetId });
|
|
393
425
|
this.update((state) => {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
customAssets[accountId] = customAssets[accountId].filter((id) => id !== normalizedAssetId);
|
|
426
|
+
if (state.customAssets[accountId]) {
|
|
427
|
+
state.customAssets[accountId] = state.customAssets[accountId].filter((id) => id !== normalizedAssetId);
|
|
397
428
|
// Clean up empty arrays
|
|
398
|
-
if (customAssets[accountId].length === 0) {
|
|
399
|
-
delete customAssets[accountId];
|
|
429
|
+
if (state.customAssets[accountId].length === 0) {
|
|
430
|
+
delete state.customAssets[accountId];
|
|
400
431
|
}
|
|
401
432
|
}
|
|
402
433
|
});
|
|
@@ -408,8 +439,49 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
408
439
|
* @returns Array of CAIP-19 asset IDs for the account's custom assets.
|
|
409
440
|
*/
|
|
410
441
|
getCustomAssets(accountId) {
|
|
411
|
-
return
|
|
442
|
+
return this.state.customAssets[accountId] ?? [];
|
|
412
443
|
}
|
|
444
|
+
// ============================================================================
|
|
445
|
+
// HIDDEN ASSETS MANAGEMENT
|
|
446
|
+
// ============================================================================
|
|
447
|
+
/**
|
|
448
|
+
* Hide an asset globally.
|
|
449
|
+
* Hidden assets are excluded from the asset list returned by getAssets.
|
|
450
|
+
* The hidden state is stored in assetPreferences.
|
|
451
|
+
*
|
|
452
|
+
* @param assetId - The CAIP-19 asset ID to hide.
|
|
453
|
+
*/
|
|
454
|
+
hideAsset(assetId) {
|
|
455
|
+
const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
|
|
456
|
+
log('Hiding asset', { assetId: normalizedAssetId });
|
|
457
|
+
this.update((state) => {
|
|
458
|
+
if (!state.assetPreferences[normalizedAssetId]) {
|
|
459
|
+
state.assetPreferences[normalizedAssetId] = {};
|
|
460
|
+
}
|
|
461
|
+
state.assetPreferences[normalizedAssetId].hidden = true;
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Unhide an asset globally.
|
|
466
|
+
*
|
|
467
|
+
* @param assetId - The CAIP-19 asset ID to unhide.
|
|
468
|
+
*/
|
|
469
|
+
unhideAsset(assetId) {
|
|
470
|
+
const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
|
|
471
|
+
log('Unhiding asset', { assetId: normalizedAssetId });
|
|
472
|
+
this.update((state) => {
|
|
473
|
+
const prefs = state.assetPreferences[normalizedAssetId];
|
|
474
|
+
if (prefs) {
|
|
475
|
+
delete prefs.hidden;
|
|
476
|
+
if (Object.keys(prefs).length === 0) {
|
|
477
|
+
delete state.assetPreferences[normalizedAssetId];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
// ============================================================================
|
|
483
|
+
// SUBSCRIPTIONS
|
|
484
|
+
// ============================================================================
|
|
413
485
|
/**
|
|
414
486
|
* Subscribe to price updates for all assets held by the given accounts.
|
|
415
487
|
* Polls PriceDataSource which fetches prices from balance state.
|
|
@@ -424,19 +496,17 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
424
496
|
const subscriptionKey = 'ds:PriceDataSource';
|
|
425
497
|
const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
|
|
426
498
|
const isUpdate = existingSubscription !== undefined;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
.call('PriceDataSource:subscribe', {
|
|
430
|
-
request: {
|
|
431
|
-
accounts,
|
|
432
|
-
chainIds,
|
|
499
|
+
const subscribeReq = {
|
|
500
|
+
request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
|
|
433
501
|
dataTypes: ['price'],
|
|
434
502
|
updateInterval,
|
|
435
|
-
},
|
|
503
|
+
}),
|
|
436
504
|
subscriptionId: subscriptionKey,
|
|
437
505
|
isUpdate,
|
|
438
|
-
|
|
439
|
-
|
|
506
|
+
onAssetsUpdate: (response) => this.handleAssetsUpdate(response, 'PriceDataSource'),
|
|
507
|
+
getAssetsState: () => this.state,
|
|
508
|
+
};
|
|
509
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").subscribe(subscribeReq).catch(console.error);
|
|
440
510
|
// Track subscription
|
|
441
511
|
const subscription = {
|
|
442
512
|
chains: chainIds,
|
|
@@ -458,37 +528,55 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
458
528
|
if (!existingSubscription) {
|
|
459
529
|
return;
|
|
460
530
|
}
|
|
461
|
-
|
|
462
|
-
this.messenger
|
|
463
|
-
.call('PriceDataSource:unsubscribe', subscriptionKey)
|
|
464
|
-
.catch(console.error);
|
|
531
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").unsubscribe(subscriptionKey).catch(console.error);
|
|
465
532
|
existingSubscription.unsubscribe();
|
|
466
533
|
}
|
|
467
534
|
/**
|
|
468
535
|
* Handle assets updated from a data source.
|
|
469
|
-
* Called via
|
|
536
|
+
* Called via the onAssetsUpdate callback passed in SubscriptionRequest when the controller subscribes to a data source.
|
|
537
|
+
* Enriches the response with token metadata (via middlewares) before updating state.
|
|
470
538
|
*
|
|
471
539
|
* @param response - The data response with updated assets
|
|
472
540
|
* @param sourceId - The data source ID reporting the update
|
|
541
|
+
* @param request - Optional original request for context when enriching
|
|
473
542
|
*/
|
|
474
|
-
async handleAssetsUpdate(response, sourceId) {
|
|
543
|
+
async handleAssetsUpdate(response, sourceId, request) {
|
|
475
544
|
log('Assets updated from data source', {
|
|
476
545
|
sourceId,
|
|
477
546
|
hasBalance: Boolean(response.assetsBalance),
|
|
478
547
|
hasPrice: Boolean(response.assetsPrice),
|
|
479
548
|
});
|
|
480
|
-
|
|
549
|
+
// Run through enrichment middlewares (Event Stack: Detection → Token → Price)
|
|
550
|
+
// Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
|
|
551
|
+
const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
552
|
+
__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f").assetsMiddleware,
|
|
553
|
+
__classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f").assetsMiddleware,
|
|
554
|
+
__classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").assetsMiddleware,
|
|
555
|
+
], request ?? {
|
|
556
|
+
accountsWithSupportedChains: [],
|
|
557
|
+
chainIds: [],
|
|
558
|
+
dataTypes: ['balance', 'metadata', 'price'],
|
|
559
|
+
}, response);
|
|
560
|
+
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
|
|
481
561
|
}
|
|
482
562
|
// ============================================================================
|
|
483
563
|
// CLEANUP
|
|
484
564
|
// ============================================================================
|
|
485
565
|
destroy() {
|
|
486
566
|
log('Destroying AssetsController', {
|
|
487
|
-
dataSourceCount: __classPrivateFieldGet(this,
|
|
567
|
+
dataSourceCount: __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_subscriptionBalanceDataSources_get).length,
|
|
488
568
|
subscriptionCount: __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size,
|
|
489
569
|
});
|
|
490
|
-
//
|
|
491
|
-
__classPrivateFieldGet(this,
|
|
570
|
+
// Destroy instantiated data sources
|
|
571
|
+
__classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f")?.destroy?.();
|
|
572
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f")?.destroy?.();
|
|
573
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f")?.destroy?.();
|
|
574
|
+
if (__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f") &&
|
|
575
|
+
'destroy' in __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f") &&
|
|
576
|
+
typeof __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").destroy ===
|
|
577
|
+
'function') {
|
|
578
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f").destroy();
|
|
579
|
+
}
|
|
492
580
|
// Stop all active subscriptions
|
|
493
581
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
|
|
494
582
|
// Unregister action handlers
|
|
@@ -496,16 +584,23 @@ class AssetsController extends base_controller_1.BaseController {
|
|
|
496
584
|
this.messenger.unregisterActionHandler('AssetsController:getAssetsBalance');
|
|
497
585
|
this.messenger.unregisterActionHandler('AssetsController:getAssetMetadata');
|
|
498
586
|
this.messenger.unregisterActionHandler('AssetsController:getAssetsPrice');
|
|
499
|
-
this.messenger.unregisterActionHandler('AssetsController:activeChainsUpdate');
|
|
500
|
-
this.messenger.unregisterActionHandler('AssetsController:assetsUpdate');
|
|
501
587
|
this.messenger.unregisterActionHandler('AssetsController:addCustomAsset');
|
|
502
588
|
this.messenger.unregisterActionHandler('AssetsController:removeCustomAsset');
|
|
503
589
|
this.messenger.unregisterActionHandler('AssetsController:getCustomAssets');
|
|
590
|
+
this.messenger.unregisterActionHandler('AssetsController:hideAsset');
|
|
591
|
+
this.messenger.unregisterActionHandler('AssetsController:unhideAsset');
|
|
504
592
|
}
|
|
505
593
|
}
|
|
506
594
|
exports.AssetsController = AssetsController;
|
|
507
|
-
_AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(),
|
|
595
|
+
_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() {
|
|
508
596
|
return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
|
|
597
|
+
}, _AssetsController_subscriptionBalanceDataSources_get = function _AssetsController_subscriptionBalanceDataSources_get() {
|
|
598
|
+
return [
|
|
599
|
+
__classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f"),
|
|
600
|
+
__classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
|
|
601
|
+
__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
|
|
602
|
+
__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
|
|
603
|
+
];
|
|
509
604
|
}, _AssetsController_initializeState = function _AssetsController_initializeState() {
|
|
510
605
|
const { enabledNetworkMap } = this.messenger.call('NetworkEnablementController:getState');
|
|
511
606
|
__classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
|
|
@@ -547,22 +642,11 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInte
|
|
|
547
642
|
this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
|
|
548
643
|
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
|
|
549
644
|
});
|
|
550
|
-
// App lifecycle: start when opened, stop when closed
|
|
551
|
-
this.messenger.subscribe('AppStateController:appOpened', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
|
|
552
|
-
this.messenger.subscribe('AppStateController:appClosed', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
|
|
553
645
|
// Keyring lifecycle: start when unlocked, stop when locked
|
|
554
646
|
this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
|
|
555
647
|
this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
|
|
556
648
|
}, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
|
|
557
|
-
this.messenger.
|
|
558
|
-
this.messenger.registerActionHandler('AssetsController:getAssetsBalance', this.getAssetsBalance.bind(this));
|
|
559
|
-
this.messenger.registerActionHandler('AssetsController:getAssetMetadata', this.getAssetMetadata.bind(this));
|
|
560
|
-
this.messenger.registerActionHandler('AssetsController:getAssetsPrice', this.getAssetsPrice.bind(this));
|
|
561
|
-
this.messenger.registerActionHandler('AssetsController:activeChainsUpdate', this.handleActiveChainsUpdate.bind(this));
|
|
562
|
-
this.messenger.registerActionHandler('AssetsController:assetsUpdate', this.handleAssetsUpdate.bind(this));
|
|
563
|
-
this.messenger.registerActionHandler('AssetsController:addCustomAsset', this.addCustomAsset.bind(this));
|
|
564
|
-
this.messenger.registerActionHandler('AssetsController:removeCustomAsset', this.removeCustomAsset.bind(this));
|
|
565
|
-
this.messenger.registerActionHandler('AssetsController:getCustomAssets', this.getCustomAssets.bind(this));
|
|
649
|
+
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
566
650
|
}, _AssetsController_executeMiddlewares =
|
|
567
651
|
// ============================================================================
|
|
568
652
|
// MIDDLEWARE EXECUTION
|
|
@@ -591,32 +675,6 @@ async function _AssetsController_executeMiddlewares(middlewares, request, initia
|
|
|
591
675
|
getAssetsState: () => this.state,
|
|
592
676
|
});
|
|
593
677
|
return result.response;
|
|
594
|
-
}, _AssetsController_assignChainsToDataSources = function _AssetsController_assignChainsToDataSources(requestedChains) {
|
|
595
|
-
const assignment = new Map();
|
|
596
|
-
const remainingChains = new Set(requestedChains);
|
|
597
|
-
for (const sourceId of __classPrivateFieldGet(this, _AssetsController_dataSources, "f").keys()) {
|
|
598
|
-
// Get available chains for this data source
|
|
599
|
-
const availableChains = __classPrivateFieldGet(this, _AssetsController_dataSources, "f").get(sourceId);
|
|
600
|
-
if (!availableChains || availableChains.size === 0) {
|
|
601
|
-
continue;
|
|
602
|
-
}
|
|
603
|
-
const chainsForThisSource = [];
|
|
604
|
-
for (const chainId of remainingChains) {
|
|
605
|
-
// Check if this chain is available on this source
|
|
606
|
-
if (availableChains.has(chainId)) {
|
|
607
|
-
chainsForThisSource.push(chainId);
|
|
608
|
-
remainingChains.delete(chainId);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
if (chainsForThisSource.length > 0) {
|
|
612
|
-
assignment.set(sourceId, chainsForThisSource);
|
|
613
|
-
log('Assigned chains to data source', {
|
|
614
|
-
sourceId,
|
|
615
|
-
chains: chainsForThisSource,
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
return assignment;
|
|
620
678
|
}, _AssetsController_updateState =
|
|
621
679
|
// ============================================================================
|
|
622
680
|
// STATE MANAGEMENT
|
|
@@ -634,7 +692,7 @@ async function _AssetsController_updateState(response) {
|
|
|
634
692
|
const changedBalances = [];
|
|
635
693
|
const changedMetadata = [];
|
|
636
694
|
this.update((state) => {
|
|
637
|
-
// Use type assertions to avoid deep type instantiation issues with Draft
|
|
695
|
+
// Use type assertions to avoid deep type instantiation issues with Immer Draft types
|
|
638
696
|
const metadata = state.assetsMetadata;
|
|
639
697
|
const balances = state.assetsBalance;
|
|
640
698
|
const prices = state.assetsPrice;
|
|
@@ -745,16 +803,21 @@ async function _AssetsController_updateState(response) {
|
|
|
745
803
|
const accountBalances = this.state.assetsBalance[account.id] ?? {};
|
|
746
804
|
for (const [assetId, balance] of Object.entries(accountBalances)) {
|
|
747
805
|
const typedAssetId = assetId;
|
|
748
|
-
const assetChainId = extractChainId(typedAssetId);
|
|
749
|
-
if (!chainIdSet.has(assetChainId)) {
|
|
750
|
-
continue;
|
|
751
|
-
}
|
|
752
806
|
const metadataRaw = this.state.assetsMetadata[typedAssetId];
|
|
753
807
|
// Skip assets without metadata
|
|
754
808
|
if (!metadataRaw) {
|
|
755
809
|
continue;
|
|
756
810
|
}
|
|
757
811
|
const metadata = metadataRaw;
|
|
812
|
+
// Skip hidden assets (assetPreferences)
|
|
813
|
+
const prefs = this.state.assetPreferences[typedAssetId];
|
|
814
|
+
if (prefs?.hidden) {
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
const assetChainId = extractChainId(typedAssetId);
|
|
818
|
+
if (!chainIdSet.has(assetChainId)) {
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
758
821
|
// Filter by asset type
|
|
759
822
|
const tokenAssetType = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_tokenStandardToAssetType).call(this, metadata.type);
|
|
760
823
|
if (!assetTypeSet.has(tokenAssetType)) {
|
|
@@ -805,7 +868,7 @@ async function _AssetsController_updateState(response) {
|
|
|
805
868
|
selectedAccountCount: __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length,
|
|
806
869
|
enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
|
|
807
870
|
});
|
|
808
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
871
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
809
872
|
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
810
873
|
this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
811
874
|
chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
|
|
@@ -826,77 +889,67 @@ async function _AssetsController_updateState(response) {
|
|
|
826
889
|
// Convert to array first to avoid modifying map during iteration
|
|
827
890
|
const subscriptionKeys = [...__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").keys()];
|
|
828
891
|
for (const subscriptionKey of subscriptionKeys) {
|
|
829
|
-
// Extract sourceId from subscription key (format: "ds:${sourceId}")
|
|
830
892
|
if (subscriptionKey.startsWith('ds:')) {
|
|
831
893
|
const sourceId = subscriptionKey.slice(3);
|
|
832
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "
|
|
894
|
+
const source = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_subscriptionBalanceDataSources_get).find((ds) => ds.getName() === sourceId);
|
|
895
|
+
if (source) {
|
|
896
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
|
|
897
|
+
}
|
|
833
898
|
}
|
|
834
899
|
}
|
|
835
900
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
|
|
836
|
-
},
|
|
901
|
+
}, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
|
|
837
902
|
if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
|
|
838
903
|
return;
|
|
839
904
|
}
|
|
840
905
|
// Subscribe to balance updates (batched by data source)
|
|
841
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this)
|
|
906
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [
|
|
907
|
+
...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f"),
|
|
908
|
+
]);
|
|
842
909
|
// Subscribe to price updates for all assets held by selected accounts
|
|
843
910
|
this.subscribeAssetsPrice(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
|
|
844
|
-
}, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance() {
|
|
845
|
-
|
|
846
|
-
const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
|
|
847
|
-
// Step 2: Split by data source active chains (ordered by priority)
|
|
848
|
-
// Get all chains that need to be subscribed
|
|
911
|
+
}, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance(accounts, chainIds) {
|
|
912
|
+
const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, accounts, new Set(chainIds));
|
|
849
913
|
const remainingChains = new Set(chainToAccounts.keys());
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
const assignedChains = chainAssignment.get(sourceId);
|
|
859
|
-
if (!assignedChains || assignedChains.length === 0) {
|
|
860
|
-
// Unsubscribe from data sources with no assigned chains
|
|
861
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, sourceId);
|
|
862
|
-
continue;
|
|
914
|
+
for (const source of __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_subscriptionBalanceDataSources_get)) {
|
|
915
|
+
const availableChains = new Set(source.getActiveChainsSync());
|
|
916
|
+
const assignedChains = [];
|
|
917
|
+
for (const chainId of remainingChains) {
|
|
918
|
+
if (availableChains.has(chainId)) {
|
|
919
|
+
assignedChains.push(chainId);
|
|
920
|
+
remainingChains.delete(chainId);
|
|
921
|
+
}
|
|
863
922
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
if (accountsForSource.length === 0) {
|
|
923
|
+
if (assignedChains.length === 0) {
|
|
924
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
|
|
867
925
|
continue;
|
|
868
926
|
}
|
|
869
|
-
|
|
870
|
-
|
|
927
|
+
const seenIds = new Set();
|
|
928
|
+
const accountsForSource = assignedChains
|
|
929
|
+
.flatMap((chainId) => chainToAccounts.get(chainId) ?? [])
|
|
930
|
+
.filter((account) => !seenIds.has(account.id) && (seenIds.add(account.id), true));
|
|
931
|
+
if (accountsForSource.length > 0) {
|
|
932
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accountsForSource, assignedChains);
|
|
933
|
+
}
|
|
871
934
|
}
|
|
872
935
|
}, _AssetsController_buildChainToAccountsMap = function _AssetsController_buildChainToAccountsMap(accounts, chainsToSubscribe) {
|
|
873
936
|
const chainToAccounts = new Map();
|
|
874
937
|
for (const account of accounts) {
|
|
875
|
-
const
|
|
876
|
-
for (const chainId of accountChains) {
|
|
938
|
+
for (const chainId of __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account)) {
|
|
877
939
|
if (!chainsToSubscribe.has(chainId)) {
|
|
878
940
|
continue;
|
|
879
941
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
}
|
|
885
|
-
return chainToAccounts;
|
|
886
|
-
}, _AssetsController_getAccountsForChains = function _AssetsController_getAccountsForChains(chains, chainToAccounts) {
|
|
887
|
-
const accountIds = new Set();
|
|
888
|
-
const accounts = [];
|
|
889
|
-
for (const chainId of chains) {
|
|
890
|
-
const chainAccounts = chainToAccounts.get(chainId) ?? [];
|
|
891
|
-
for (const account of chainAccounts) {
|
|
892
|
-
if (!accountIds.has(account.id)) {
|
|
893
|
-
accountIds.add(account.id);
|
|
894
|
-
accounts.push(account);
|
|
942
|
+
let list = chainToAccounts.get(chainId);
|
|
943
|
+
if (!list) {
|
|
944
|
+
list = [];
|
|
945
|
+
chainToAccounts.set(chainId, list);
|
|
895
946
|
}
|
|
947
|
+
list.push(account);
|
|
896
948
|
}
|
|
897
949
|
}
|
|
898
|
-
return
|
|
899
|
-
},
|
|
950
|
+
return chainToAccounts;
|
|
951
|
+
}, _AssetsController_subscribeDataSource = function _AssetsController_subscribeDataSource(source, accounts, chains) {
|
|
952
|
+
const sourceId = source.getName();
|
|
900
953
|
const subscriptionKey = `ds:${sourceId}`;
|
|
901
954
|
const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
|
|
902
955
|
const isUpdate = existingSubscription !== undefined;
|
|
@@ -907,53 +960,49 @@ async function _AssetsController_updateState(response) {
|
|
|
907
960
|
accountCount: accounts.length,
|
|
908
961
|
chainCount: chains.length,
|
|
909
962
|
});
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
}
|
|
925
|
-
catch (error) {
|
|
926
|
-
console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
|
|
927
|
-
}
|
|
928
|
-
})().catch(console.error);
|
|
963
|
+
const subscribeReq = {
|
|
964
|
+
request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chains, {
|
|
965
|
+
assetTypes: ['fungible'],
|
|
966
|
+
dataTypes: ['balance'],
|
|
967
|
+
updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
|
|
968
|
+
}),
|
|
969
|
+
subscriptionId: subscriptionKey,
|
|
970
|
+
isUpdate,
|
|
971
|
+
onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
|
|
972
|
+
getAssetsState: () => this.state,
|
|
973
|
+
};
|
|
974
|
+
source.subscribe(subscribeReq).catch((error) => {
|
|
975
|
+
console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
|
|
976
|
+
});
|
|
929
977
|
// Track subscription
|
|
930
978
|
const subscription = {
|
|
931
979
|
chains,
|
|
932
980
|
accountId: subscriptionKey,
|
|
933
981
|
assetTypes: ['fungible'],
|
|
934
|
-
dataTypes: ['balance'
|
|
982
|
+
dataTypes: ['balance'],
|
|
935
983
|
unsubscribe: () => {
|
|
936
984
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").delete(subscriptionKey);
|
|
937
985
|
},
|
|
938
986
|
};
|
|
939
987
|
__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").set(subscriptionKey, subscription);
|
|
940
|
-
}, _AssetsController_unsubscribeDataSource = function _AssetsController_unsubscribeDataSource(
|
|
941
|
-
const subscriptionKey = `ds:${
|
|
988
|
+
}, _AssetsController_unsubscribeDataSource = function _AssetsController_unsubscribeDataSource(source) {
|
|
989
|
+
const subscriptionKey = `ds:${source.getName()}`;
|
|
942
990
|
const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
|
|
943
991
|
if (existingSubscription) {
|
|
944
|
-
|
|
945
|
-
(async () => {
|
|
946
|
-
try {
|
|
947
|
-
await this.messenger.call(`${sourceId}:unsubscribe`, subscriptionKey);
|
|
948
|
-
}
|
|
949
|
-
catch {
|
|
950
|
-
// Ignore errors - source may not have been subscribed
|
|
951
|
-
}
|
|
952
|
-
})().catch(() => {
|
|
953
|
-
// Ignore errors - source may not have been subscribed
|
|
954
|
-
});
|
|
992
|
+
source.unsubscribe(subscriptionKey).catch(() => undefined);
|
|
955
993
|
existingSubscription.unsubscribe();
|
|
956
994
|
}
|
|
995
|
+
}, _AssetsController_buildDataRequest = function _AssetsController_buildDataRequest(accounts, chainIds, partial = {}) {
|
|
996
|
+
const chainIdSet = new Set(chainIds);
|
|
997
|
+
const accountsWithSupportedChains = accounts.map((account) => ({
|
|
998
|
+
account,
|
|
999
|
+
supportedChains: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account).filter((chain) => chainIdSet.has(chain)),
|
|
1000
|
+
}));
|
|
1001
|
+
return {
|
|
1002
|
+
accountsWithSupportedChains,
|
|
1003
|
+
chainIds,
|
|
1004
|
+
...partial,
|
|
1005
|
+
};
|
|
957
1006
|
}, _AssetsController_getEnabledChainsForAccount = function _AssetsController_getEnabledChainsForAccount(account) {
|
|
958
1007
|
// Account scopes are CAIP-2 chain IDs like "eip155:1", "solana:mainnet", "bip122:..."
|
|
959
1008
|
const scopes = account.scopes ?? [];
|
|
@@ -988,7 +1037,7 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
988
1037
|
accountIds: accounts.map((a) => a.id),
|
|
989
1038
|
});
|
|
990
1039
|
// Subscribe and fetch for the new account group
|
|
991
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
1040
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
992
1041
|
if (accounts.length > 0) {
|
|
993
1042
|
await this.getAssets(accounts, {
|
|
994
1043
|
chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
|
|
@@ -1022,7 +1071,7 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1022
1071
|
// Users may want to see historical balances even if the network is currently disabled.
|
|
1023
1072
|
// The data will simply not be updated until the network is re-enabled.
|
|
1024
1073
|
// Refresh subscriptions for new chain set
|
|
1025
|
-
__classPrivateFieldGet(this, _AssetsController_instances, "m",
|
|
1074
|
+
__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
|
|
1026
1075
|
// Do one-time fetch for newly enabled chains
|
|
1027
1076
|
if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
|
|
1028
1077
|
await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
|
|
@@ -1030,28 +1079,5 @@ async function _AssetsController_handleAccountGroupChanged() {
|
|
|
1030
1079
|
forceUpdate: true,
|
|
1031
1080
|
});
|
|
1032
1081
|
}
|
|
1033
|
-
}, _AssetsController_handleSubscriptionUpdate =
|
|
1034
|
-
/**
|
|
1035
|
-
* Handle an async update from a data source subscription.
|
|
1036
|
-
* Enriches response with token metadata before updating state.
|
|
1037
|
-
*
|
|
1038
|
-
* @param response - The data response from the data source.
|
|
1039
|
-
* @param _sourceId - The source ID (unused but kept for logging context).
|
|
1040
|
-
* @param request - Optional original request for context.
|
|
1041
|
-
*/
|
|
1042
|
-
async function _AssetsController_handleSubscriptionUpdate(response, _sourceId, request) {
|
|
1043
|
-
// Run through enrichment middlewares (Event Stack: Detection → Token → Price)
|
|
1044
|
-
// Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
|
|
1045
|
-
const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
|
|
1046
|
-
this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
|
|
1047
|
-
this.messenger.call('TokenDataSource:getAssetsMiddleware'),
|
|
1048
|
-
this.messenger.call('PriceDataSource:getAssetsMiddleware'),
|
|
1049
|
-
], request ?? {
|
|
1050
|
-
accounts: [],
|
|
1051
|
-
chainIds: [],
|
|
1052
|
-
dataTypes: ['balance', 'metadata', 'price'],
|
|
1053
|
-
}, response);
|
|
1054
|
-
// Update state
|
|
1055
|
-
await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
|
|
1056
1082
|
};
|
|
1057
1083
|
//# sourceMappingURL=AssetsController.cjs.map
|