@metamask-previews/perps-controller 1.3.0-preview-a0caca0c0 → 1.3.0-preview-17c76be24
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 +9 -0
- package/dist/PerpsController-method-action-types.cjs +3 -0
- package/dist/PerpsController-method-action-types.cjs.map +1 -0
- package/dist/PerpsController-method-action-types.d.cts +147 -0
- package/dist/PerpsController-method-action-types.d.cts.map +1 -0
- package/dist/PerpsController-method-action-types.d.mts +147 -0
- package/dist/PerpsController-method-action-types.d.mts.map +1 -0
- package/dist/PerpsController-method-action-types.mjs +2 -0
- package/dist/PerpsController-method-action-types.mjs.map +1 -0
- package/dist/PerpsController.cjs +488 -183
- package/dist/PerpsController.cjs.map +1 -1
- package/dist/PerpsController.d.cts +91 -131
- package/dist/PerpsController.d.cts.map +1 -1
- package/dist/PerpsController.d.mts +91 -131
- package/dist/PerpsController.d.mts.map +1 -1
- package/dist/PerpsController.mjs +485 -182
- package/dist/PerpsController.mjs.map +1 -1
- package/dist/constants/eventNames.cjs +26 -0
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +19 -0
- package/dist/constants/eventNames.d.cts.map +1 -1
- package/dist/constants/eventNames.d.mts +19 -0
- package/dist/constants/eventNames.d.mts.map +1 -1
- package/dist/constants/eventNames.mjs +26 -0
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.cjs +24 -4
- package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.cts +8 -3
- package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.mts +8 -3
- package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
- package/dist/constants/hyperLiquidConfig.mjs +23 -3
- package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
- package/dist/constants/myxConfig.cjs +75 -51
- package/dist/constants/myxConfig.cjs.map +1 -1
- package/dist/constants/myxConfig.d.cts +58 -19
- package/dist/constants/myxConfig.d.cts.map +1 -1
- package/dist/constants/myxConfig.d.mts +58 -19
- package/dist/constants/myxConfig.d.mts.map +1 -1
- package/dist/constants/myxConfig.mjs +74 -50
- package/dist/constants/myxConfig.mjs.map +1 -1
- package/dist/constants/perpsConfig.cjs +6 -2
- package/dist/constants/perpsConfig.cjs.map +1 -1
- package/dist/constants/perpsConfig.d.cts +5 -1
- package/dist/constants/perpsConfig.d.cts.map +1 -1
- package/dist/constants/perpsConfig.d.mts +5 -1
- package/dist/constants/perpsConfig.d.mts.map +1 -1
- package/dist/constants/perpsConfig.mjs +5 -1
- package/dist/constants/perpsConfig.mjs.map +1 -1
- package/dist/index.cjs +243 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +48 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +36 -10
- package/dist/index.mjs.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.cjs +24 -0
- package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.d.cts +4 -0
- package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.d.mts +4 -0
- package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.mjs +24 -0
- package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +470 -154
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +11 -2
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +11 -2
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +471 -155
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/selectors.cjs +1 -1
- package/dist/selectors.cjs.map +1 -1
- package/dist/selectors.mjs +1 -1
- package/dist/selectors.mjs.map +1 -1
- package/dist/services/AccountService.cjs +1 -1
- package/dist/services/AccountService.cjs.map +1 -1
- package/dist/services/AccountService.d.cts.map +1 -1
- package/dist/services/AccountService.d.mts.map +1 -1
- package/dist/services/AccountService.mjs +2 -2
- package/dist/services/AccountService.mjs.map +1 -1
- package/dist/services/DepositService.cjs +2 -1
- package/dist/services/DepositService.cjs.map +1 -1
- package/dist/services/DepositService.d.cts.map +1 -1
- package/dist/services/DepositService.d.mts.map +1 -1
- package/dist/services/DepositService.mjs +2 -1
- package/dist/services/DepositService.mjs.map +1 -1
- package/dist/services/EligibilityService.cjs +8 -103
- package/dist/services/EligibilityService.cjs.map +1 -1
- package/dist/services/EligibilityService.d.cts +4 -15
- package/dist/services/EligibilityService.d.cts.map +1 -1
- package/dist/services/EligibilityService.d.mts +4 -15
- package/dist/services/EligibilityService.d.mts.map +1 -1
- package/dist/services/EligibilityService.mjs +8 -103
- package/dist/services/EligibilityService.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +252 -46
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts +1 -0
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts +1 -0
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +252 -46
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/services/MarketDataService.cjs +2 -4
- package/dist/services/MarketDataService.cjs.map +1 -1
- package/dist/services/MarketDataService.d.cts.map +1 -1
- package/dist/services/MarketDataService.d.mts.map +1 -1
- package/dist/services/MarketDataService.mjs +2 -4
- package/dist/services/MarketDataService.mjs.map +1 -1
- package/dist/services/TradingService.cjs +72 -6
- package/dist/services/TradingService.cjs.map +1 -1
- package/dist/services/TradingService.d.cts.map +1 -1
- package/dist/services/TradingService.d.mts.map +1 -1
- package/dist/services/TradingService.mjs +72 -6
- package/dist/services/TradingService.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +51 -3
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +51 -3
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/types/messenger.cjs.map +1 -1
- package/dist/types/messenger.d.cts +2 -1
- package/dist/types/messenger.d.cts.map +1 -1
- package/dist/types/messenger.d.mts +2 -1
- package/dist/types/messenger.d.mts.map +1 -1
- package/dist/types/messenger.mjs.map +1 -1
- package/dist/types/myx-types.cjs +19 -3
- package/dist/types/myx-types.cjs.map +1 -1
- package/dist/types/myx-types.d.cts +33 -2
- package/dist/types/myx-types.d.cts.map +1 -1
- package/dist/types/myx-types.d.mts +33 -2
- package/dist/types/myx-types.d.mts.map +1 -1
- package/dist/types/myx-types.mjs +6 -2
- package/dist/types/myx-types.mjs.map +1 -1
- package/dist/types/perps-types.cjs +3 -0
- package/dist/types/perps-types.cjs.map +1 -1
- package/dist/types/perps-types.d.cts +3 -3
- package/dist/types/perps-types.d.cts.map +1 -1
- package/dist/types/perps-types.d.mts +3 -3
- package/dist/types/perps-types.d.mts.map +1 -1
- package/dist/types/perps-types.mjs +3 -0
- package/dist/types/perps-types.mjs.map +1 -1
- package/dist/utils/accountUtils.cjs.map +1 -1
- package/dist/utils/accountUtils.d.cts.map +1 -1
- package/dist/utils/accountUtils.d.mts.map +1 -1
- package/dist/utils/accountUtils.mjs.map +1 -1
- package/dist/utils/myxAdapter.cjs +360 -15
- package/dist/utils/myxAdapter.cjs.map +1 -1
- package/dist/utils/myxAdapter.d.cts +94 -7
- package/dist/utils/myxAdapter.d.cts.map +1 -1
- package/dist/utils/myxAdapter.d.mts +94 -7
- package/dist/utils/myxAdapter.d.mts.map +1 -1
- package/dist/utils/myxAdapter.mjs +351 -16
- package/dist/utils/myxAdapter.mjs.map +1 -1
- package/package.json +5 -3
package/dist/PerpsController.mjs
CHANGED
|
@@ -9,7 +9,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
|
-
var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_eligibilityCheckDeferred, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_getOrCreateStandaloneProvider, _PerpsController_cleanupStandaloneProvider, _PerpsController_getMetrics, _PerpsController_findNetworkClientIdForChain, _PerpsController_submitTransaction, _PerpsController_migrateRequestsIfNeeded, _PerpsController_withStreamPause, _PerpsController_performInitialization, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_isPreloadingUserData, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload;
|
|
12
|
+
var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_myxRegistrationPromise, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_handlersRegistered, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_eligibilityCheckDeferred, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_marketCacheKey, _PerpsController_providerIsTestnet, _PerpsController_getOrCreateStandaloneProvider, _PerpsController_cleanupStandaloneProvider, _PerpsController_getMetrics, _PerpsController_findNetworkClientIdForChain, _PerpsController_submitTransaction, _PerpsController_migrateRequestsIfNeeded, _PerpsController_withStreamPause, _PerpsController_performInitialization, _PerpsController_createProviders, _PerpsController_assignActiveProvider, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_isPreloadingUserData, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload;
|
|
13
13
|
import { BaseController } from "@metamask/base-controller";
|
|
14
14
|
import { ORIGIN_METAMASK } from "@metamask/controller-utils";
|
|
15
15
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -34,6 +34,37 @@ import { WebSocketConnectionState, PerpsAnalyticsEvent, PerpsTraceNames, PerpsTr
|
|
|
34
34
|
import { getSelectedEvmAccount } from "./utils/accountUtils.mjs";
|
|
35
35
|
import { ensureError } from "./utils/errorUtils.mjs";
|
|
36
36
|
import { wait } from "./utils/wait.mjs";
|
|
37
|
+
/**
|
|
38
|
+
* Returns the first non-empty string from the given values.
|
|
39
|
+
* Env vars default to '' (not null/undefined), so ?? wouldn't fall through.
|
|
40
|
+
*
|
|
41
|
+
* @param vals - String values to check in order.
|
|
42
|
+
* @returns The first non-empty string, or '' if all are empty/undefined.
|
|
43
|
+
*/
|
|
44
|
+
export function firstNonEmpty(...vals) {
|
|
45
|
+
return (vals.find((val) => val !== null && val !== undefined && val !== '') ?? '');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolves MYX auth config from provider credentials, handling
|
|
49
|
+
* testnet/mainnet fallback logic.
|
|
50
|
+
*
|
|
51
|
+
* @param myx - MYX provider credentials.
|
|
52
|
+
* @param isTestnet - Whether the controller is in testnet mode.
|
|
53
|
+
* @returns Resolved appId, apiSecret, and brokerAddress.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveMyxAuthConfig(myx, isTestnet) {
|
|
56
|
+
return {
|
|
57
|
+
appId: isTestnet
|
|
58
|
+
? (myx.appIdTestnet ?? '')
|
|
59
|
+
: firstNonEmpty(myx.appIdMainnet, myx.appIdTestnet),
|
|
60
|
+
apiSecret: isTestnet
|
|
61
|
+
? (myx.apiSecretTestnet ?? '')
|
|
62
|
+
: firstNonEmpty(myx.apiSecretMainnet, myx.apiSecretTestnet),
|
|
63
|
+
brokerAddress: isTestnet
|
|
64
|
+
? (myx.brokerAddressTestnet ?? '')
|
|
65
|
+
: firstNonEmpty(myx.brokerAddressMainnet, myx.brokerAddressTestnet),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
37
68
|
// Re-export error codes from separate file to avoid circular dependencies
|
|
38
69
|
export { PERPS_ERROR_CODES } from "./perpsErrorCodes.mjs";
|
|
39
70
|
/**
|
|
@@ -101,13 +132,8 @@ export const getDefaultPerpsControllerState = () => ({
|
|
|
101
132
|
},
|
|
102
133
|
hip3ConfigVersion: 0,
|
|
103
134
|
selectedPaymentToken: null,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
cachedPositions: null,
|
|
107
|
-
cachedOrders: null,
|
|
108
|
-
cachedAccountState: null,
|
|
109
|
-
cachedUserDataTimestamp: 0,
|
|
110
|
-
cachedUserDataAddress: null,
|
|
135
|
+
cachedMarketDataByProvider: {},
|
|
136
|
+
cachedUserDataByProvider: {},
|
|
111
137
|
});
|
|
112
138
|
/**
|
|
113
139
|
* State metadata for the PerpsController
|
|
@@ -263,48 +289,18 @@ const metadata = {
|
|
|
263
289
|
includeInDebugSnapshot: false,
|
|
264
290
|
usedInUi: true,
|
|
265
291
|
},
|
|
266
|
-
|
|
292
|
+
cachedMarketDataByProvider: {
|
|
267
293
|
includeInStateLogs: false,
|
|
268
294
|
persist: false,
|
|
269
295
|
includeInDebugSnapshot: false,
|
|
270
296
|
usedInUi: true,
|
|
271
297
|
},
|
|
272
|
-
|
|
273
|
-
includeInStateLogs: false,
|
|
274
|
-
persist: false,
|
|
275
|
-
includeInDebugSnapshot: false,
|
|
276
|
-
usedInUi: false,
|
|
277
|
-
},
|
|
278
|
-
cachedPositions: {
|
|
298
|
+
cachedUserDataByProvider: {
|
|
279
299
|
includeInStateLogs: false,
|
|
280
300
|
persist: false,
|
|
281
301
|
includeInDebugSnapshot: false,
|
|
282
302
|
usedInUi: true,
|
|
283
303
|
},
|
|
284
|
-
cachedOrders: {
|
|
285
|
-
includeInStateLogs: false,
|
|
286
|
-
persist: false,
|
|
287
|
-
includeInDebugSnapshot: false,
|
|
288
|
-
usedInUi: true,
|
|
289
|
-
},
|
|
290
|
-
cachedAccountState: {
|
|
291
|
-
includeInStateLogs: false,
|
|
292
|
-
persist: false,
|
|
293
|
-
includeInDebugSnapshot: false,
|
|
294
|
-
usedInUi: true,
|
|
295
|
-
},
|
|
296
|
-
cachedUserDataTimestamp: {
|
|
297
|
-
includeInStateLogs: false,
|
|
298
|
-
persist: false,
|
|
299
|
-
includeInDebugSnapshot: false,
|
|
300
|
-
usedInUi: false,
|
|
301
|
-
},
|
|
302
|
-
cachedUserDataAddress: {
|
|
303
|
-
includeInStateLogs: false,
|
|
304
|
-
persist: false,
|
|
305
|
-
includeInDebugSnapshot: false,
|
|
306
|
-
usedInUi: false,
|
|
307
|
-
},
|
|
308
304
|
};
|
|
309
305
|
const MESSENGER_EXPOSED_METHODS = [
|
|
310
306
|
'placeOrder',
|
|
@@ -364,6 +360,8 @@ export class PerpsController extends BaseController {
|
|
|
364
360
|
this.isInitialized = false;
|
|
365
361
|
_PerpsController_initializationPromise.set(this, null);
|
|
366
362
|
_PerpsController_isReinitializing.set(this, false);
|
|
363
|
+
/** Tracks the async MYX dynamic import so performInitialization can await it. */
|
|
364
|
+
_PerpsController_myxRegistrationPromise.set(this, null);
|
|
367
365
|
this.blockedRegionList = {
|
|
368
366
|
list: [],
|
|
369
367
|
source: 'fallback',
|
|
@@ -392,6 +390,7 @@ export class PerpsController extends BaseController {
|
|
|
392
390
|
* connections) on every standalone call from the preload cycle.
|
|
393
391
|
*/
|
|
394
392
|
_PerpsController_standaloneProvider.set(this, null);
|
|
393
|
+
_PerpsController_handlersRegistered.set(this, false);
|
|
395
394
|
_PerpsController_standaloneProviderIsTestnet.set(this, null);
|
|
396
395
|
_PerpsController_standaloneProviderHip3Version.set(this, null);
|
|
397
396
|
_PerpsController_eligibilityCheckDeferred.set(this, void 0);
|
|
@@ -467,7 +466,122 @@ export class PerpsController extends BaseController {
|
|
|
467
466
|
this.providers = new Map();
|
|
468
467
|
// Migrate old persisted data without accountAddress
|
|
469
468
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_migrateRequestsIfNeeded).call(this);
|
|
470
|
-
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Read cached market data for the currently active provider (or aggregated).
|
|
472
|
+
* Returns null when no valid cache exists or when cache has expired.
|
|
473
|
+
*
|
|
474
|
+
* @returns The cached market data array, or null if no valid cache.
|
|
475
|
+
*/
|
|
476
|
+
getCachedMarketDataForActiveProvider() {
|
|
477
|
+
const { activeProvider } = this.state;
|
|
478
|
+
const cache = this.state.cachedMarketDataByProvider;
|
|
479
|
+
if (activeProvider === 'aggregated') {
|
|
480
|
+
// Assemble from all registered provider entries
|
|
481
|
+
const assembled = [];
|
|
482
|
+
let oldestTimestamp = Infinity;
|
|
483
|
+
for (const [providerId] of this.providers) {
|
|
484
|
+
const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, providerId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, providerId));
|
|
485
|
+
const entry = cache[key];
|
|
486
|
+
if (!entry || entry.data.length === 0) {
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
oldestTimestamp = Math.min(oldestTimestamp, entry.timestamp);
|
|
490
|
+
assembled.push(...entry.data);
|
|
491
|
+
}
|
|
492
|
+
if (assembled.length === 0) {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
// Check TTL against the oldest entry
|
|
496
|
+
if (Date.now() - oldestTimestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
return assembled;
|
|
500
|
+
}
|
|
501
|
+
// Single provider mode
|
|
502
|
+
const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, activeProvider, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, activeProvider));
|
|
503
|
+
const entry = cache[key];
|
|
504
|
+
if (!entry || entry.data.length === 0) {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
if (Date.now() - entry.timestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
return entry.data;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Read cached user data for the currently active provider (or aggregated).
|
|
514
|
+
* Returns null when no valid cache exists, cache has expired, or address
|
|
515
|
+
* does not match the currently selected EVM account.
|
|
516
|
+
*
|
|
517
|
+
* @returns The cached user data, or null if no valid cache.
|
|
518
|
+
*/
|
|
519
|
+
getCachedUserDataForActiveProvider() {
|
|
520
|
+
const { activeProvider } = this.state;
|
|
521
|
+
const cache = this.state.cachedUserDataByProvider;
|
|
522
|
+
const staleCutoff = __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 2; // 60s
|
|
523
|
+
// Get current user address for validation
|
|
524
|
+
let currentAddress = null;
|
|
525
|
+
try {
|
|
526
|
+
const evmAccount = getSelectedEvmAccount(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
|
|
527
|
+
currentAddress = evmAccount?.address ?? null;
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
// Can't determine current account — trust the cache
|
|
531
|
+
}
|
|
532
|
+
const isValidEntry = (entry) => {
|
|
533
|
+
if (!entry) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
if (Date.now() - entry.timestamp >= staleCutoff) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
if (currentAddress &&
|
|
540
|
+
entry.address.toLowerCase() !== currentAddress.toLowerCase()) {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
return true;
|
|
544
|
+
};
|
|
545
|
+
if (activeProvider === 'aggregated') {
|
|
546
|
+
// Assemble from all registered provider entries
|
|
547
|
+
const allPositions = [];
|
|
548
|
+
const allOrders = [];
|
|
549
|
+
let defaultAccountState = null;
|
|
550
|
+
let hasValidEntry = false;
|
|
551
|
+
for (const [providerId] of this.providers) {
|
|
552
|
+
const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, providerId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, providerId));
|
|
553
|
+
const entry = cache[key];
|
|
554
|
+
if (!isValidEntry(entry)) {
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
hasValidEntry = true;
|
|
558
|
+
allPositions.push(...entry.positions);
|
|
559
|
+
allOrders.push(...entry.orders);
|
|
560
|
+
// AccountState from default provider (hyperliquid)
|
|
561
|
+
if (providerId === 'hyperliquid') {
|
|
562
|
+
defaultAccountState = entry.accountState;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (!hasValidEntry) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
return {
|
|
569
|
+
positions: allPositions,
|
|
570
|
+
orders: allOrders,
|
|
571
|
+
accountState: defaultAccountState,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
// Single provider mode
|
|
575
|
+
const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, activeProvider, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, activeProvider));
|
|
576
|
+
const entry = cache[key];
|
|
577
|
+
if (!entry || !isValidEntry(entry)) {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
positions: entry.positions,
|
|
582
|
+
orders: entry.orders,
|
|
583
|
+
accountState: entry.accountState,
|
|
584
|
+
};
|
|
471
585
|
}
|
|
472
586
|
/**
|
|
473
587
|
* Test-observable accessor for whether a standalone provider is cached.
|
|
@@ -547,6 +661,10 @@ export class PerpsController extends BaseController {
|
|
|
547
661
|
* @returns A promise that resolves when the operation completes.
|
|
548
662
|
*/
|
|
549
663
|
async init() {
|
|
664
|
+
if (!__classPrivateFieldGet(this, _PerpsController_handlersRegistered, "f")) {
|
|
665
|
+
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
666
|
+
__classPrivateFieldSet(this, _PerpsController_handlersRegistered, true, "f");
|
|
667
|
+
}
|
|
550
668
|
if (this.isInitialized) {
|
|
551
669
|
return undefined;
|
|
552
670
|
}
|
|
@@ -556,6 +674,46 @@ export class PerpsController extends BaseController {
|
|
|
556
674
|
__classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
|
|
557
675
|
return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
|
|
558
676
|
}
|
|
677
|
+
/**
|
|
678
|
+
* Registers the MYX provider after dynamic import resolves.
|
|
679
|
+
*
|
|
680
|
+
* Extracted from the import().then() callback so it can be tested directly
|
|
681
|
+
* (Jest cannot resolve dynamic imports without --experimental-vm-modules).
|
|
682
|
+
*
|
|
683
|
+
* @param MYXProvider - Constructor class for the MYX provider.
|
|
684
|
+
*/
|
|
685
|
+
registerMYXProvider(MYXProvider) {
|
|
686
|
+
const myxIsTestnet = PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet;
|
|
687
|
+
const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx ?? {};
|
|
688
|
+
const myxAuthConfig = resolveMyxAuthConfig(myx, myxIsTestnet);
|
|
689
|
+
const myxProvider = new MYXProvider({
|
|
690
|
+
isTestnet: myxIsTestnet,
|
|
691
|
+
platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
692
|
+
messenger: this.messenger,
|
|
693
|
+
myxAuthConfig,
|
|
694
|
+
});
|
|
695
|
+
this.providers.set('myx', myxProvider);
|
|
696
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider registered', {
|
|
697
|
+
isTestnet: myxIsTestnet,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Handles errors from the MYX dynamic import.
|
|
702
|
+
*
|
|
703
|
+
* Module-not-found errors are expected (extension doesn't ship MYX) → debug log.
|
|
704
|
+
* Other errors indicate constructor/config problems → Sentry via logError.
|
|
705
|
+
*
|
|
706
|
+
* @param error - The caught error from the dynamic import or constructor.
|
|
707
|
+
*/
|
|
708
|
+
handleMYXImportError(error) {
|
|
709
|
+
const isModuleError = error?.code === 'MODULE_NOT_FOUND';
|
|
710
|
+
if (isModuleError) {
|
|
711
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider module not available, skipping registration');
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, error instanceof Error ? error : new Error(String(error)), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'createProviders.myx'));
|
|
715
|
+
}
|
|
716
|
+
}
|
|
559
717
|
/**
|
|
560
718
|
* Get the currently active provider.
|
|
561
719
|
* In aggregated mode, returns AggregatedPerpsProvider which routes to underlying providers.
|
|
@@ -816,6 +974,14 @@ export class PerpsController extends BaseController {
|
|
|
816
974
|
origin: ORIGIN_METAMASK,
|
|
817
975
|
skipInitialGasEstimate: true,
|
|
818
976
|
};
|
|
977
|
+
__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.addBreadcrumb({
|
|
978
|
+
category: 'perps',
|
|
979
|
+
message: 'Deposit action started',
|
|
980
|
+
level: 'info',
|
|
981
|
+
data: {
|
|
982
|
+
place_order_after_deposit: placeOrder === true,
|
|
983
|
+
},
|
|
984
|
+
});
|
|
819
985
|
if (placeOrder) {
|
|
820
986
|
// Use addTransaction to create transaction without navigating to confirmation screen
|
|
821
987
|
const addResult = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_submitTransaction).call(this, transaction, {
|
|
@@ -951,8 +1117,8 @@ export class PerpsController extends BaseController {
|
|
|
951
1117
|
const errorMessage = ensureError(error, 'PerpsController.depositWithOrder').message;
|
|
952
1118
|
const isCancellation = errorMessage.includes('User denied') ||
|
|
953
1119
|
errorMessage.includes('User rejected') ||
|
|
954
|
-
errorMessage.includes('cancelled') ||
|
|
955
|
-
errorMessage.includes('canceled');
|
|
1120
|
+
errorMessage.includes('User cancelled') ||
|
|
1121
|
+
errorMessage.includes('User canceled');
|
|
956
1122
|
this.update((state) => {
|
|
957
1123
|
const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
|
|
958
1124
|
if (requestToUpdate) {
|
|
@@ -1316,7 +1482,7 @@ export class PerpsController extends BaseController {
|
|
|
1316
1482
|
/* fire-and-forget */
|
|
1317
1483
|
});
|
|
1318
1484
|
}, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadRefreshMs)), "f");
|
|
1319
|
-
// Watch for isTestnet / hip3ConfigVersion
|
|
1485
|
+
// Watch for isTestnet / hip3ConfigVersion changes
|
|
1320
1486
|
const handler = (_state, patches) => {
|
|
1321
1487
|
// Early-return when no watched field changed (skips ~46 unrelated updates)
|
|
1322
1488
|
const hasRelevantChange = patches.some((patch) => typeof patch.path[0] === 'string' &&
|
|
@@ -1337,16 +1503,9 @@ export class PerpsController extends BaseController {
|
|
|
1337
1503
|
});
|
|
1338
1504
|
__classPrivateFieldSet(this, _PerpsController_previousIsTestnet, currentIsTestnet, "f");
|
|
1339
1505
|
__classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, currentHip3Version, "f");
|
|
1340
|
-
//
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
state.cachedMarketDataTimestamp = 0;
|
|
1344
|
-
state.cachedPositions = null;
|
|
1345
|
-
state.cachedOrders = null;
|
|
1346
|
-
state.cachedAccountState = null;
|
|
1347
|
-
state.cachedUserDataTimestamp = 0;
|
|
1348
|
-
state.cachedUserDataAddress = null;
|
|
1349
|
-
});
|
|
1506
|
+
// No need to clear user data cache — per-provider keys include the
|
|
1507
|
+
// network, so different networks don't collide. Re-preload will
|
|
1508
|
+
// populate the new key.
|
|
1350
1509
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
1351
1510
|
/* fire-and-forget */
|
|
1352
1511
|
});
|
|
@@ -1360,16 +1519,13 @@ export class PerpsController extends BaseController {
|
|
|
1360
1519
|
const accountChangeHandler = () => {
|
|
1361
1520
|
const evmAccount = getSelectedEvmAccount(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
|
|
1362
1521
|
const currentAddress = evmAccount?.address ?? null;
|
|
1363
|
-
// If
|
|
1364
|
-
|
|
1365
|
-
|
|
1522
|
+
// If any cached entry belongs to a different account, clear all entries.
|
|
1523
|
+
// Max 4 entries (2 providers × 2 networks) — clearing all is simple and safe.
|
|
1524
|
+
const hasStaleEntries = Object.values(this.state.cachedUserDataByProvider).some((entry) => entry.address.toLowerCase() !== currentAddress?.toLowerCase());
|
|
1525
|
+
if (hasStaleEntries) {
|
|
1366
1526
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Account changed, clearing user data cache');
|
|
1367
1527
|
this.update((state) => {
|
|
1368
|
-
state.
|
|
1369
|
-
state.cachedOrders = null;
|
|
1370
|
-
state.cachedAccountState = null;
|
|
1371
|
-
state.cachedUserDataTimestamp = 0;
|
|
1372
|
-
state.cachedUserDataAddress = null;
|
|
1528
|
+
state.cachedUserDataByProvider = {};
|
|
1373
1529
|
});
|
|
1374
1530
|
// Only preload if the new account is an EVM account
|
|
1375
1531
|
if (currentAddress) {
|
|
@@ -1602,6 +1758,15 @@ export class PerpsController extends BaseController {
|
|
|
1602
1758
|
}
|
|
1603
1759
|
finally {
|
|
1604
1760
|
__classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
|
|
1761
|
+
// Re-trigger preload now that reinit is complete and the
|
|
1762
|
+
// activeProviderInstance points to the correct network.
|
|
1763
|
+
// The state-change listener may have already fired during reinit
|
|
1764
|
+
// but was skipped due to the #isReinitializing guard.
|
|
1765
|
+
if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
|
|
1766
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
1767
|
+
/* fire-and-forget */
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1605
1770
|
}
|
|
1606
1771
|
}
|
|
1607
1772
|
/**
|
|
@@ -1648,7 +1813,7 @@ export class PerpsController extends BaseController {
|
|
|
1648
1813
|
// Provider disconnect is handled by performInitialization() during
|
|
1649
1814
|
// reinitialization. The disconnect() method skips provider teardown
|
|
1650
1815
|
// when isReinitializing is true to prevent double-disconnect.
|
|
1651
|
-
// Update state with new provider
|
|
1816
|
+
// Update state with new provider (market data cache preserved per-provider)
|
|
1652
1817
|
this.update((state) => {
|
|
1653
1818
|
state.activeProvider = providerId;
|
|
1654
1819
|
state.accountState = null;
|
|
@@ -1705,6 +1870,12 @@ export class PerpsController extends BaseController {
|
|
|
1705
1870
|
}
|
|
1706
1871
|
finally {
|
|
1707
1872
|
__classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
|
|
1873
|
+
// Re-trigger preload now that reinit is complete.
|
|
1874
|
+
if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
|
|
1875
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
1876
|
+
/* fire-and-forget */
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1708
1879
|
}
|
|
1709
1880
|
}
|
|
1710
1881
|
/**
|
|
@@ -2082,14 +2253,18 @@ export class PerpsController extends BaseController {
|
|
|
2082
2253
|
* Eligibility (Geo-Blocking)
|
|
2083
2254
|
*/
|
|
2084
2255
|
/**
|
|
2085
|
-
*
|
|
2086
|
-
* Call this after onboarding is complete when the controller was constructed
|
|
2087
|
-
* with `deferEligibilityCheck: true`.
|
|
2256
|
+
* Fetch geo location
|
|
2088
2257
|
*
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2091
|
-
|
|
2092
|
-
|
|
2258
|
+
* Returned in Country or Country-Region format
|
|
2259
|
+
* Example: FR, DE, US-MI, CA-ON
|
|
2260
|
+
*/
|
|
2261
|
+
/**
|
|
2262
|
+
* Refresh eligibility status
|
|
2263
|
+
*/
|
|
2264
|
+
/**
|
|
2265
|
+
* Resume eligibility monitoring after onboarding completes.
|
|
2266
|
+
* Clears the deferred flag and triggers an immediate eligibility check
|
|
2267
|
+
* using the current remote feature flag state.
|
|
2093
2268
|
*/
|
|
2094
2269
|
startEligibilityMonitoring() {
|
|
2095
2270
|
__classPrivateFieldSet(this, _PerpsController_eligibilityCheckDeferred, false, "f");
|
|
@@ -2112,9 +2287,6 @@ export class PerpsController extends BaseController {
|
|
|
2112
2287
|
stopEligibilityMonitoring() {
|
|
2113
2288
|
__classPrivateFieldSet(this, _PerpsController_eligibilityCheckDeferred, true, "f");
|
|
2114
2289
|
}
|
|
2115
|
-
/**
|
|
2116
|
-
* Refresh eligibility status
|
|
2117
|
-
*/
|
|
2118
2290
|
async refreshEligibility() {
|
|
2119
2291
|
if (__classPrivateFieldGet(this, _PerpsController_eligibilityCheckDeferred, "f")) {
|
|
2120
2292
|
return;
|
|
@@ -2125,9 +2297,10 @@ export class PerpsController extends BaseController {
|
|
|
2125
2297
|
// (started with remote config after it was fetched).
|
|
2126
2298
|
const versionAtStart = __classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f");
|
|
2127
2299
|
try {
|
|
2128
|
-
|
|
2300
|
+
const geoLocation = await this.messenger.call('GeolocationController:getGeolocation');
|
|
2129
2301
|
const isEligible = await __classPrivateFieldGet(this, _PerpsController_eligibilityService, "f").checkEligibility({
|
|
2130
2302
|
blockedRegions: this.blockedRegionList.list,
|
|
2303
|
+
geoLocation,
|
|
2131
2304
|
});
|
|
2132
2305
|
// Only update state if the blocked region list hasn't changed while we were awaiting.
|
|
2133
2306
|
// This prevents stale fallback-based eligibility checks from overwriting
|
|
@@ -2610,27 +2783,46 @@ export class PerpsController extends BaseController {
|
|
|
2610
2783
|
return __classPrivateFieldGet(this, _PerpsController_isReinitializing, "f");
|
|
2611
2784
|
}
|
|
2612
2785
|
}
|
|
2613
|
-
_a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _PerpsController_isReinitializing = new WeakMap(), _PerpsController_blockedRegionListVersion = new WeakMap(), _PerpsController_hip3Enabled = new WeakMap(), _PerpsController_hip3AllowlistMarkets = new WeakMap(), _PerpsController_hip3BlocklistMarkets = new WeakMap(), _PerpsController_hip3ConfigSource = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_eligibilityCheckDeferred = new WeakMap(), _PerpsController_options = new WeakMap(), _PerpsController_tradingService = new WeakMap(), _PerpsController_marketDataService = new WeakMap(), _PerpsController_accountService = new WeakMap(), _PerpsController_eligibilityService = new WeakMap(), _PerpsController_dataLakeService = new WeakMap(), _PerpsController_depositService = new WeakMap(), _PerpsController_featureFlagConfigurationService = new WeakMap(), _PerpsController_rewardsIntegrationService = new WeakMap(), _PerpsController_preloadTimer = new WeakMap(), _PerpsController_isPreloading = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_preloadStateUnsubscribe = new WeakMap(), _PerpsController_accountChangeUnsubscribe = new WeakMap(), _PerpsController_previousIsTestnet = new WeakMap(), _PerpsController_previousHip3ConfigVersion = new WeakMap(), _PerpsController_instances = new WeakSet(), _PerpsController_isMYXProviderEnabled = function _PerpsController_isMYXProviderEnabled() {
|
|
2614
|
-
const
|
|
2615
|
-
|
|
2786
|
+
_a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _PerpsController_isReinitializing = new WeakMap(), _PerpsController_myxRegistrationPromise = new WeakMap(), _PerpsController_blockedRegionListVersion = new WeakMap(), _PerpsController_hip3Enabled = new WeakMap(), _PerpsController_hip3AllowlistMarkets = new WeakMap(), _PerpsController_hip3BlocklistMarkets = new WeakMap(), _PerpsController_hip3ConfigSource = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_handlersRegistered = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_eligibilityCheckDeferred = new WeakMap(), _PerpsController_options = new WeakMap(), _PerpsController_tradingService = new WeakMap(), _PerpsController_marketDataService = new WeakMap(), _PerpsController_accountService = new WeakMap(), _PerpsController_eligibilityService = new WeakMap(), _PerpsController_dataLakeService = new WeakMap(), _PerpsController_depositService = new WeakMap(), _PerpsController_featureFlagConfigurationService = new WeakMap(), _PerpsController_rewardsIntegrationService = new WeakMap(), _PerpsController_preloadTimer = new WeakMap(), _PerpsController_isPreloading = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_preloadStateUnsubscribe = new WeakMap(), _PerpsController_accountChangeUnsubscribe = new WeakMap(), _PerpsController_previousIsTestnet = new WeakMap(), _PerpsController_previousHip3ConfigVersion = new WeakMap(), _PerpsController_instances = new WeakSet(), _PerpsController_isMYXProviderEnabled = function _PerpsController_isMYXProviderEnabled() {
|
|
2787
|
+
const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx;
|
|
2788
|
+
// Local env-var override (MM_PERPS_MYX_PROVIDER_ENABLED) always wins —
|
|
2789
|
+
// matches the UI selector (resolvePerpsMyxProviderEnabled) so controller
|
|
2790
|
+
// and UI agree on whether MYX is available.
|
|
2791
|
+
if (myx?.enabled) {
|
|
2792
|
+
return true;
|
|
2793
|
+
}
|
|
2794
|
+
// Credentials present → MYX is enabled regardless of remote flag.
|
|
2795
|
+
// Use || so empty-string env vars (default '') fall through.
|
|
2796
|
+
const hasCredentials = Boolean(
|
|
2797
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
2798
|
+
myx?.appIdTestnet || myx?.appIdMainnet);
|
|
2799
|
+
if (hasCredentials) {
|
|
2800
|
+
return true;
|
|
2801
|
+
}
|
|
2802
|
+
// No local override or credentials — check remote flag as fallback
|
|
2616
2803
|
try {
|
|
2617
|
-
const localFlag = getLocalFlag();
|
|
2618
2804
|
const remoteState = this.messenger.call('RemoteFeatureFlagController:getState');
|
|
2619
2805
|
const remoteFlag = remoteState.remoteFeatureFlags?.perpsMyxProviderEnabled;
|
|
2620
2806
|
if (isVersionGatedFeatureFlag(remoteFlag)) {
|
|
2621
2807
|
const validated = __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.featureFlags.validateVersionGated(remoteFlag);
|
|
2622
|
-
return validated ??
|
|
2808
|
+
return validated ?? false;
|
|
2623
2809
|
}
|
|
2624
|
-
return
|
|
2810
|
+
return false;
|
|
2625
2811
|
}
|
|
2626
2812
|
catch {
|
|
2627
|
-
|
|
2628
|
-
return getLocalFlag();
|
|
2813
|
+
return false;
|
|
2629
2814
|
}
|
|
2630
2815
|
}, _PerpsController_logError = function _PerpsController_logError(error, options) {
|
|
2631
2816
|
__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.logger.error(error, options);
|
|
2632
2817
|
}, _PerpsController_debugLog = function _PerpsController_debugLog(...args) {
|
|
2633
2818
|
__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.debugLogger.log(...args);
|
|
2819
|
+
}, _PerpsController_marketCacheKey = function _PerpsController_marketCacheKey(providerId, isTestnet) {
|
|
2820
|
+
return `${providerId}:${isTestnet ? 'testnet' : 'mainnet'}`;
|
|
2821
|
+
}, _PerpsController_providerIsTestnet = function _PerpsController_providerIsTestnet(providerId) {
|
|
2822
|
+
if (providerId === 'myx') {
|
|
2823
|
+
return PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet;
|
|
2824
|
+
}
|
|
2825
|
+
return this.state.isTestnet;
|
|
2634
2826
|
}, _PerpsController_getOrCreateStandaloneProvider = function _PerpsController_getOrCreateStandaloneProvider() {
|
|
2635
2827
|
const currentIsTestnet = this.state.isTestnet;
|
|
2636
2828
|
const currentHip3Version = this.state.hip3ConfigVersion ?? 0;
|
|
@@ -2653,6 +2845,10 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
|
|
|
2653
2845
|
blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
|
|
2654
2846
|
platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
2655
2847
|
messenger: this.messenger,
|
|
2848
|
+
builderAddressTestnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
|
|
2849
|
+
?.builderAddressTestnet,
|
|
2850
|
+
builderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
|
|
2851
|
+
?.builderAddressMainnet,
|
|
2656
2852
|
}), "f");
|
|
2657
2853
|
__classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
|
|
2658
2854
|
__classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
|
|
@@ -2810,89 +3006,16 @@ async function _PerpsController_performInitialization() {
|
|
|
2810
3006
|
}
|
|
2811
3007
|
this.providers.clear();
|
|
2812
3008
|
await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
const hyperLiquidProvider = new HyperLiquidProvider({
|
|
2824
|
-
isTestnet: this.state.isTestnet,
|
|
2825
|
-
hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
|
|
2826
|
-
allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
|
|
2827
|
-
blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
|
|
2828
|
-
platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
2829
|
-
messenger: this.messenger,
|
|
2830
|
-
});
|
|
2831
|
-
this.providers.set('hyperliquid', hyperLiquidProvider);
|
|
2832
|
-
// Register MYX provider if enabled via feature flag.
|
|
2833
|
-
// Uses dynamic import so @myx-trade/sdk is excluded from the bundle
|
|
2834
|
-
// unless MM_PERPS_MYX_PROVIDER_ENABLED=true is set at build time.
|
|
2835
|
-
// Wrapped in try/catch so a missing module (stripped at build time)
|
|
2836
|
-
// only skips MYX registration instead of aborting initialization.
|
|
2837
|
-
const isMYXEnabled = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMYXProviderEnabled).call(this);
|
|
2838
|
-
if (isMYXEnabled) {
|
|
2839
|
-
try {
|
|
2840
|
-
const { MYXProvider } = await import("./providers/MYXProvider.mjs");
|
|
2841
|
-
const myxProvider = new MYXProvider({
|
|
2842
|
-
isTestnet: PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet,
|
|
2843
|
-
platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
2844
|
-
});
|
|
2845
|
-
this.providers.set('myx', myxProvider);
|
|
2846
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider registered', {
|
|
2847
|
-
isTestnet: PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet,
|
|
2848
|
-
});
|
|
2849
|
-
}
|
|
2850
|
-
catch {
|
|
2851
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider module not available (stripped from build), skipping registration');
|
|
2852
|
-
}
|
|
2853
|
-
}
|
|
2854
|
-
// Set up active provider based on activeProvider value in state
|
|
2855
|
-
// 'aggregated' is treated as just another provider that wraps others
|
|
2856
|
-
if (activeProvider === 'aggregated') {
|
|
2857
|
-
// Aggregated mode: wrap in AggregatedPerpsProvider for multi-provider support
|
|
2858
|
-
this.activeProviderInstance = new AggregatedPerpsProvider({
|
|
2859
|
-
providers: this.providers,
|
|
2860
|
-
defaultProvider: 'hyperliquid',
|
|
2861
|
-
infrastructure: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
2862
|
-
});
|
|
2863
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Using aggregated provider (multi-provider)', { registeredProviders: Array.from(this.providers.keys()) });
|
|
2864
|
-
}
|
|
2865
|
-
else if (activeProvider === 'hyperliquid') {
|
|
2866
|
-
// Direct provider mode: use HyperLiquid provider directly
|
|
2867
|
-
this.activeProviderInstance = hyperLiquidProvider;
|
|
2868
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${activeProvider})`);
|
|
2869
|
-
}
|
|
2870
|
-
else if (activeProvider === 'myx') {
|
|
2871
|
-
// MYX provider mode
|
|
2872
|
-
const myxProvider = this.providers.get('myx');
|
|
2873
|
-
if (myxProvider) {
|
|
2874
|
-
this.activeProviderInstance = myxProvider;
|
|
2875
|
-
}
|
|
2876
|
-
else {
|
|
2877
|
-
// MYX feature flag is disabled — fall back to HyperLiquid
|
|
2878
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider not available (feature flag disabled), falling back to hyperliquid');
|
|
2879
|
-
this.activeProviderInstance = hyperLiquidProvider;
|
|
2880
|
-
this.update((state) => {
|
|
2881
|
-
state.activeProvider = 'hyperliquid';
|
|
2882
|
-
});
|
|
2883
|
-
}
|
|
2884
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${this.activeProviderInstance === hyperLiquidProvider ? 'hyperliquid' : activeProvider})`);
|
|
2885
|
-
}
|
|
2886
|
-
else {
|
|
2887
|
-
// Unsupported provider - throw error to prevent silent misconfiguration
|
|
2888
|
-
throw new Error(`Unsupported provider: ${String(activeProvider)}. Currently only 'hyperliquid', 'myx', and 'aggregated' are supported.`);
|
|
2889
|
-
}
|
|
2890
|
-
// Future providers can be added here with their own authentication patterns:
|
|
2891
|
-
// - Some might use API keys: new BinanceProvider({ apiKey, apiSecret })
|
|
2892
|
-
// - Some might use different wallet patterns: new GMXProvider({ signer })
|
|
2893
|
-
// - Some might not need auth at all: new DydxProvider()
|
|
2894
|
-
// Wait for WebSocket transport to be ready before marking as initialized
|
|
2895
|
-
await wait(PERPS_CONSTANTS.ReconnectionCleanupDelayMs);
|
|
3009
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createProviders).call(this);
|
|
3010
|
+
// Await MYX dynamic import (if started) so MYX is in the providers
|
|
3011
|
+
// map before we assign the active provider. Runs concurrently with
|
|
3012
|
+
// the WebSocket readiness delay for zero additional latency.
|
|
3013
|
+
await Promise.all([
|
|
3014
|
+
wait(PERPS_CONSTANTS.ReconnectionCleanupDelayMs),
|
|
3015
|
+
__classPrivateFieldGet(this, _PerpsController_myxRegistrationPromise, "f"),
|
|
3016
|
+
]);
|
|
3017
|
+
__classPrivateFieldSet(this, _PerpsController_myxRegistrationPromise, null, "f");
|
|
3018
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_assignActiveProvider).call(this);
|
|
2896
3019
|
this.isInitialized = true;
|
|
2897
3020
|
this.update((state) => {
|
|
2898
3021
|
state.initializationState = InitializationState.Initialized;
|
|
@@ -2900,7 +3023,7 @@ async function _PerpsController_performInitialization() {
|
|
|
2900
3023
|
});
|
|
2901
3024
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Providers initialized successfully', {
|
|
2902
3025
|
providerCount: this.providers.size,
|
|
2903
|
-
activeProvider,
|
|
3026
|
+
activeProvider: this.state.activeProvider,
|
|
2904
3027
|
timestamp: new Date().toISOString(),
|
|
2905
3028
|
attempts: attempt,
|
|
2906
3029
|
});
|
|
@@ -2935,6 +3058,84 @@ async function _PerpsController_performInitialization() {
|
|
|
2935
3058
|
attempts: maxAttempts,
|
|
2936
3059
|
timestamp: new Date().toISOString(),
|
|
2937
3060
|
});
|
|
3061
|
+
}, _PerpsController_createProviders = function _PerpsController_createProviders() {
|
|
3062
|
+
const { activeProvider } = this.state;
|
|
3063
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Creating provider with HIP-3 configuration', {
|
|
3064
|
+
hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
|
|
3065
|
+
hip3AllowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
|
|
3066
|
+
hip3BlocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
|
|
3067
|
+
hip3ConfigSource: __classPrivateFieldGet(this, _PerpsController_hip3ConfigSource, "f"),
|
|
3068
|
+
isTestnet: this.state.isTestnet,
|
|
3069
|
+
activeProvider,
|
|
3070
|
+
});
|
|
3071
|
+
// Always create HyperLiquid provider as the base provider
|
|
3072
|
+
const hyperLiquidProvider = new HyperLiquidProvider({
|
|
3073
|
+
isTestnet: this.state.isTestnet,
|
|
3074
|
+
hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
|
|
3075
|
+
allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
|
|
3076
|
+
blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
|
|
3077
|
+
platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
3078
|
+
messenger: this.messenger,
|
|
3079
|
+
builderAddressTestnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
|
|
3080
|
+
?.builderAddressTestnet,
|
|
3081
|
+
builderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
|
|
3082
|
+
?.builderAddressMainnet,
|
|
3083
|
+
});
|
|
3084
|
+
this.providers.set('hyperliquid', hyperLiquidProvider);
|
|
3085
|
+
// Register MYX provider if enabled via feature flag.
|
|
3086
|
+
// Dynamic import because the MYX package pulls in heavy dependencies we
|
|
3087
|
+
// don't want bundled in extension. Until MYX fixes their package, extension
|
|
3088
|
+
// doesn't ship it — the catch branch silently skips registration.
|
|
3089
|
+
// Uses .then()/.catch() instead of await because #createProviders is not async;
|
|
3090
|
+
// MYX registration completing asynchronously is fine since it's only used when
|
|
3091
|
+
// explicitly enabled and selected.
|
|
3092
|
+
const isMYXEnabled = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMYXProviderEnabled).call(this);
|
|
3093
|
+
if (isMYXEnabled) {
|
|
3094
|
+
// IMPORTANT: Must use import() — NOT require() — for core/extension tree-shaking.
|
|
3095
|
+
// require() is synchronous and bundlers include it in the main bundle.
|
|
3096
|
+
// import() enables true code splitting so MYX is excluded when not enabled.
|
|
3097
|
+
__classPrivateFieldSet(this, _PerpsController_myxRegistrationPromise, import("./providers/MYXProvider.mjs")
|
|
3098
|
+
.then(({ MYXProvider }) => {
|
|
3099
|
+
this.registerMYXProvider(MYXProvider);
|
|
3100
|
+
return undefined;
|
|
3101
|
+
})
|
|
3102
|
+
.catch((error) => this.handleMYXImportError(error)), "f");
|
|
3103
|
+
}
|
|
3104
|
+
}, _PerpsController_assignActiveProvider = function _PerpsController_assignActiveProvider() {
|
|
3105
|
+
const { activeProvider } = this.state;
|
|
3106
|
+
const hyperLiquidProvider = this.providers.get('hyperliquid');
|
|
3107
|
+
if (!hyperLiquidProvider) {
|
|
3108
|
+
throw new Error('HyperLiquid provider not registered — cannot assign active provider');
|
|
3109
|
+
}
|
|
3110
|
+
if (activeProvider === 'aggregated') {
|
|
3111
|
+
this.activeProviderInstance = new AggregatedPerpsProvider({
|
|
3112
|
+
providers: this.providers,
|
|
3113
|
+
defaultProvider: 'hyperliquid',
|
|
3114
|
+
infrastructure: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
|
|
3115
|
+
});
|
|
3116
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Using aggregated provider (multi-provider)', { registeredProviders: Array.from(this.providers.keys()) });
|
|
3117
|
+
}
|
|
3118
|
+
else if (activeProvider === 'hyperliquid') {
|
|
3119
|
+
this.activeProviderInstance = hyperLiquidProvider;
|
|
3120
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${activeProvider})`);
|
|
3121
|
+
}
|
|
3122
|
+
else if (activeProvider === 'myx') {
|
|
3123
|
+
const myxProvider = this.providers.get('myx');
|
|
3124
|
+
if (myxProvider) {
|
|
3125
|
+
this.activeProviderInstance = myxProvider;
|
|
3126
|
+
}
|
|
3127
|
+
else {
|
|
3128
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider not available, falling back to hyperliquid');
|
|
3129
|
+
this.activeProviderInstance = hyperLiquidProvider;
|
|
3130
|
+
this.update((state) => {
|
|
3131
|
+
state.activeProvider = 'hyperliquid';
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${this.activeProviderInstance === hyperLiquidProvider ? 'hyperliquid' : activeProvider})`);
|
|
3135
|
+
}
|
|
3136
|
+
else {
|
|
3137
|
+
throw new Error(`Unsupported provider: ${String(activeProvider)}. Currently only 'hyperliquid', 'myx', and 'aggregated' are supported.`);
|
|
3138
|
+
}
|
|
2938
3139
|
}, _PerpsController_getErrorContext = function _PerpsController_getErrorContext(method, extra) {
|
|
2939
3140
|
return {
|
|
2940
3141
|
tags: {
|
|
@@ -2964,7 +3165,7 @@ async function _PerpsController_performInitialization() {
|
|
|
2964
3165
|
},
|
|
2965
3166
|
stateManager: {
|
|
2966
3167
|
update: (updater) =>
|
|
2967
|
-
// @ts-expect-error TS2589 - excessively deep instantiation
|
|
3168
|
+
// @ts-expect-error TS2589 - excessively deep instantiation from BaseController generic
|
|
2968
3169
|
this.update(updater),
|
|
2969
3170
|
getState: () => __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getControllerState).call(this),
|
|
2970
3171
|
},
|
|
@@ -2982,9 +3183,22 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
2982
3183
|
if (__classPrivateFieldGet(this, _PerpsController_isPreloading, "f")) {
|
|
2983
3184
|
return;
|
|
2984
3185
|
}
|
|
3186
|
+
// Skip preloading during provider/network reinitialisation.
|
|
3187
|
+
// The activeProviderInstance still points to the OLD network's provider
|
|
3188
|
+
// until init() completes, so fetching now would store stale data under
|
|
3189
|
+
// the NEW network's cache key.
|
|
3190
|
+
if (__classPrivateFieldGet(this, _PerpsController_isReinitializing, "f")) {
|
|
3191
|
+
return;
|
|
3192
|
+
}
|
|
3193
|
+
// Determine actual provider and cache key for debounce
|
|
3194
|
+
const actualProviderId = this.activeProviderInstance
|
|
3195
|
+
? this.state.activeProvider // includes 'aggregated'
|
|
3196
|
+
: 'hyperliquid';
|
|
3197
|
+
const cacheKey = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, actualProviderId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, actualProviderId));
|
|
2985
3198
|
const now = Date.now();
|
|
2986
|
-
|
|
2987
|
-
|
|
3199
|
+
const existingEntry = this.state.cachedMarketDataByProvider[cacheKey];
|
|
3200
|
+
if (existingEntry &&
|
|
3201
|
+
now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
|
|
2988
3202
|
return;
|
|
2989
3203
|
}
|
|
2990
3204
|
__classPrivateFieldSet(this, _PerpsController_isPreloading, true, "f");
|
|
@@ -3003,10 +3217,46 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3003
3217
|
});
|
|
3004
3218
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching market data in background');
|
|
3005
3219
|
const data = await this.getMarketDataWithPrices({ standalone: true });
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3220
|
+
// Store under per-provider key(s)
|
|
3221
|
+
const ts = Date.now();
|
|
3222
|
+
if (this.state.activeProvider === 'aggregated' &&
|
|
3223
|
+
this.activeProviderInstance) {
|
|
3224
|
+
// Split returned data by providerId and store each slice
|
|
3225
|
+
const fallbackProviderId = 'hyperliquid'; // default for items missing providerId
|
|
3226
|
+
const byProvider = new Map();
|
|
3227
|
+
for (const item of data) {
|
|
3228
|
+
const pid = item.providerId ?? fallbackProviderId;
|
|
3229
|
+
const existing = byProvider.get(pid);
|
|
3230
|
+
if (existing) {
|
|
3231
|
+
existing.push(item);
|
|
3232
|
+
}
|
|
3233
|
+
else {
|
|
3234
|
+
byProvider.set(pid, [item]);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
this.update((state) => {
|
|
3238
|
+
for (const [pid, slice] of byProvider) {
|
|
3239
|
+
const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, pid, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, pid));
|
|
3240
|
+
state.cachedMarketDataByProvider[key] = {
|
|
3241
|
+
data: slice,
|
|
3242
|
+
timestamp: ts,
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
// Write aggregated sentinel so the staleness guard sees it
|
|
3246
|
+
state.cachedMarketDataByProvider[cacheKey] = {
|
|
3247
|
+
data: [], // sentinel — real data is in per-provider keys
|
|
3248
|
+
timestamp: ts,
|
|
3249
|
+
};
|
|
3250
|
+
});
|
|
3251
|
+
}
|
|
3252
|
+
else {
|
|
3253
|
+
this.update((state) => {
|
|
3254
|
+
state.cachedMarketDataByProvider[cacheKey] = {
|
|
3255
|
+
data,
|
|
3256
|
+
timestamp: ts,
|
|
3257
|
+
};
|
|
3258
|
+
});
|
|
3259
|
+
}
|
|
3010
3260
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Market data preloaded', {
|
|
3011
3261
|
marketCount: data.length,
|
|
3012
3262
|
});
|
|
@@ -3050,10 +3300,16 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
3050
3300
|
return;
|
|
3051
3301
|
}
|
|
3052
3302
|
const userAddress = evmAccount.address;
|
|
3303
|
+
// Determine actual provider (same logic as market preload)
|
|
3304
|
+
const actualProviderId = this.activeProviderInstance
|
|
3305
|
+
? this.state.activeProvider // includes 'aggregated'
|
|
3306
|
+
: 'hyperliquid';
|
|
3307
|
+
const userCacheKey = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, actualProviderId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, actualProviderId));
|
|
3053
3308
|
// Skip if cache is fresh and for same account
|
|
3054
3309
|
const now = Date.now();
|
|
3055
|
-
|
|
3056
|
-
|
|
3310
|
+
const existingEntry = this.state.cachedUserDataByProvider[userCacheKey];
|
|
3311
|
+
if (existingEntry?.address === userAddress &&
|
|
3312
|
+
now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
|
|
3057
3313
|
return;
|
|
3058
3314
|
}
|
|
3059
3315
|
// Skip standalone REST polling when WebSocket is connected — live data is streaming
|
|
@@ -3084,13 +3340,60 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
3084
3340
|
this.getOpenOrders({ standalone: true, userAddress }),
|
|
3085
3341
|
this.getAccountState({ standalone: true, userAddress }),
|
|
3086
3342
|
]);
|
|
3087
|
-
this.
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3343
|
+
if (this.state.activeProvider === 'aggregated' &&
|
|
3344
|
+
this.activeProviderInstance) {
|
|
3345
|
+
// Split by providerId and write one cache entry per provider key
|
|
3346
|
+
// (mirrors the market-data preload pattern at ~line 2976)
|
|
3347
|
+
const ts = Date.now();
|
|
3348
|
+
const fallbackProviderId = 'hyperliquid'; // default for items missing providerId
|
|
3349
|
+
const byProvider = new Map();
|
|
3350
|
+
const ensureBucket = (pid) => {
|
|
3351
|
+
let bucket = byProvider.get(pid);
|
|
3352
|
+
if (!bucket) {
|
|
3353
|
+
bucket = { positions: [], orders: [], accountState: null };
|
|
3354
|
+
byProvider.set(pid, bucket);
|
|
3355
|
+
}
|
|
3356
|
+
return bucket;
|
|
3357
|
+
};
|
|
3358
|
+
for (const pos of positions) {
|
|
3359
|
+
ensureBucket(pos.providerId ?? fallbackProviderId).positions.push(pos);
|
|
3360
|
+
}
|
|
3361
|
+
for (const order of orders) {
|
|
3362
|
+
ensureBucket(order.providerId ?? fallbackProviderId).orders.push(order);
|
|
3363
|
+
}
|
|
3364
|
+
// AccountState — assign to its provider bucket
|
|
3365
|
+
ensureBucket(accountState.providerId ?? fallbackProviderId).accountState = accountState;
|
|
3366
|
+
this.update((state) => {
|
|
3367
|
+
for (const [pid, data] of byProvider) {
|
|
3368
|
+
const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, pid, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, pid));
|
|
3369
|
+
state.cachedUserDataByProvider[key] = {
|
|
3370
|
+
...data,
|
|
3371
|
+
timestamp: ts,
|
|
3372
|
+
address: userAddress,
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
// Write aggregated sentinel so the staleness guard sees it
|
|
3376
|
+
state.cachedUserDataByProvider[userCacheKey] = {
|
|
3377
|
+
positions: [],
|
|
3378
|
+
orders: [],
|
|
3379
|
+
accountState: null,
|
|
3380
|
+
timestamp: ts,
|
|
3381
|
+
address: userAddress,
|
|
3382
|
+
};
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
else {
|
|
3386
|
+
// Single provider — store directly under its key
|
|
3387
|
+
this.update((state) => {
|
|
3388
|
+
state.cachedUserDataByProvider[userCacheKey] = {
|
|
3389
|
+
positions,
|
|
3390
|
+
orders,
|
|
3391
|
+
accountState,
|
|
3392
|
+
timestamp: Date.now(),
|
|
3393
|
+
address: userAddress,
|
|
3394
|
+
};
|
|
3395
|
+
});
|
|
3396
|
+
}
|
|
3094
3397
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
|
|
3095
3398
|
positionCount: positions.length,
|
|
3096
3399
|
orderCount: orders.length,
|