@metamask-previews/perps-controller 11.0.0-preview-9efd0b754 → 11.0.0-preview-ea8763e0c
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 +8 -0
- package/dist/PerpsController-method-action-types.cjs.map +1 -1
- package/dist/PerpsController-method-action-types.d.cts +12 -1
- package/dist/PerpsController-method-action-types.d.cts.map +1 -1
- package/dist/PerpsController-method-action-types.d.mts +12 -1
- package/dist/PerpsController-method-action-types.d.mts.map +1 -1
- package/dist/PerpsController-method-action-types.mjs.map +1 -1
- package/dist/PerpsController.cjs +519 -99
- package/dist/PerpsController.cjs.map +1 -1
- package/dist/PerpsController.d.cts +17 -4
- package/dist/PerpsController.d.cts.map +1 -1
- package/dist/PerpsController.d.mts +17 -4
- package/dist/PerpsController.d.mts.map +1 -1
- package/dist/PerpsController.mjs +522 -102
- package/dist/PerpsController.mjs.map +1 -1
- package/dist/constants/eventNames.cjs +3 -0
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +1 -0
- package/dist/constants/eventNames.d.cts.map +1 -1
- package/dist/constants/eventNames.d.mts +1 -0
- package/dist/constants/eventNames.d.mts.map +1 -1
- package/dist/constants/eventNames.mjs +3 -0
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.cjs +14 -2
- package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.cts +7 -0
- package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.mts +7 -0
- package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
- package/dist/constants/hyperLiquidConfig.mjs +11 -0
- package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
- package/dist/constants/perpsConfig.cjs +4 -1
- package/dist/constants/perpsConfig.cjs.map +1 -1
- package/dist/constants/perpsConfig.d.cts +25 -7
- package/dist/constants/perpsConfig.d.cts.map +1 -1
- package/dist/constants/perpsConfig.d.mts +25 -7
- package/dist/constants/perpsConfig.d.mts.map +1 -1
- package/dist/constants/perpsConfig.mjs +4 -1
- package/dist/constants/perpsConfig.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +148 -1
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +11 -1
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +11 -1
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +149 -2
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +15 -4
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +15 -4
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/services/MarketDataService.cjs +41 -3
- package/dist/services/MarketDataService.cjs.map +1 -1
- package/dist/services/MarketDataService.d.cts +2 -2
- package/dist/services/MarketDataService.d.cts.map +1 -1
- package/dist/services/MarketDataService.d.mts +2 -2
- package/dist/services/MarketDataService.d.mts.map +1 -1
- package/dist/services/MarketDataService.mjs +41 -3
- package/dist/services/MarketDataService.mjs.map +1 -1
- package/dist/services/ServiceContext.cjs.map +1 -1
- package/dist/services/ServiceContext.d.cts +10 -1
- package/dist/services/ServiceContext.d.cts.map +1 -1
- package/dist/services/ServiceContext.d.mts +10 -1
- package/dist/services/ServiceContext.d.mts.map +1 -1
- package/dist/services/ServiceContext.mjs.map +1 -1
- package/dist/services/TerminalMarketService.cjs +422 -7
- package/dist/services/TerminalMarketService.cjs.map +1 -1
- package/dist/services/TerminalMarketService.d.cts +10 -1
- package/dist/services/TerminalMarketService.d.cts.map +1 -1
- package/dist/services/TerminalMarketService.d.mts +10 -1
- package/dist/services/TerminalMarketService.d.mts.map +1 -1
- package/dist/services/TerminalMarketService.mjs +423 -8
- package/dist/services/TerminalMarketService.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +43 -7
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +43 -7
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/utils/marketUtils.cjs +16 -1
- package/dist/utils/marketUtils.cjs.map +1 -1
- package/dist/utils/marketUtils.d.cts +1 -0
- package/dist/utils/marketUtils.d.cts.map +1 -1
- package/dist/utils/marketUtils.d.mts +1 -0
- package/dist/utils/marketUtils.d.mts.map +1 -1
- package/dist/utils/marketUtils.mjs +14 -0
- package/dist/utils/marketUtils.mjs.map +1 -1
- package/dist/utils/perpsDiskPersistence.cjs +19 -12
- package/dist/utils/perpsDiskPersistence.cjs.map +1 -1
- package/dist/utils/perpsDiskPersistence.d.cts +5 -1
- package/dist/utils/perpsDiskPersistence.d.cts.map +1 -1
- package/dist/utils/perpsDiskPersistence.d.mts +5 -1
- package/dist/utils/perpsDiskPersistence.d.mts.map +1 -1
- package/dist/utils/perpsDiskPersistence.mjs +19 -12
- package/dist/utils/perpsDiskPersistence.mjs.map +1 -1
- package/package.json +1 -1
package/dist/PerpsController.mjs
CHANGED
|
@@ -9,15 +9,15 @@ 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_myxRegistrationPromise, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_priceDeviationLimit, _PerpsController_attributionContext, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_handlersRegistered, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_eligibilityCheckDeferred, _PerpsController_ausQueue, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_getAggregatedCacheProviderIds, _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_buildMarketAllowedFilter, _PerpsController_compilePatternsSafely, _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_hydrateCacheFromDiskSync, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload, _PerpsController_persistWatchlistToRemote, _PerpsController_syncWatchlistFromRemote;
|
|
12
|
+
var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_myxRegistrationPromise, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_priceDeviationLimit, _PerpsController_attributionContext, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_handlersRegistered, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_standaloneProviderOperations, _PerpsController_eligibilityCheckDeferred, _PerpsController_ausQueue, _PerpsController_userDiskWrite, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_getAggregatedCacheProviderIds, _PerpsController_isMarketCacheEntryCurrent, _PerpsController_isUserCacheIdentityCurrent, _PerpsController_fetchAndCacheUserDataSnapshot, _PerpsController_getOrCreateStandaloneProvider, _PerpsController_trackStandaloneProviderOperation, _PerpsController_retireStandaloneProvider, _PerpsController_cleanupStandaloneProvider, _PerpsController_getMetrics, _PerpsController_findNetworkClientIdForChain, _PerpsController_submitTransaction, _PerpsController_migrateRequestsIfNeeded, _PerpsController_withStreamPause, _PerpsController_performInitialization, _PerpsController_createProviders, _PerpsController_assignActiveProvider, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_buildMarketAllowedFilter, _PerpsController_compilePatternsSafely, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_buildGlobalSnapshotContext, _PerpsController_getStaticSnapshotDexes, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_marketPreloadQueued, _PerpsController_isPreloadingUserData, _PerpsController_userPreloadQueued, _PerpsController_userSnapshotRequests, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_hydrateCacheFromDiskSync, _PerpsController_persistUserCacheToDisk, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload, _PerpsController_persistWatchlistToRemote, _PerpsController_syncWatchlistFromRemote;
|
|
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";
|
|
16
16
|
import { CandlePeriod } from "./constants/chartConfig.mjs";
|
|
17
17
|
import { PERPS_EVENT_PROPERTY, PERPS_EVENT_VALUE } from "./constants/eventNames.mjs";
|
|
18
|
-
import { USDC_SYMBOL } from "./constants/hyperLiquidConfig.mjs";
|
|
18
|
+
import { canonicalizeHyperLiquidDexes, MAINNET_HIP3_CONFIG, TESTNET_HIP3_CONFIG, USDC_SYMBOL } from "./constants/hyperLiquidConfig.mjs";
|
|
19
19
|
import { PerpsMeasurementName } from "./constants/performanceMetrics.mjs";
|
|
20
|
-
import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG, PROVIDER_CONFIG,
|
|
20
|
+
import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG, PROVIDER_CONFIG, buildProviderCacheKey, MAX_SLIPPAGE_BOUNDS, DEFAULT_PERPS_MODE, DEFAULT_PRO_LAYOUT_PREFERENCES } from "./constants/perpsConfig.mjs";
|
|
21
21
|
import { PERPS_ERROR_CODES } from "./perpsErrorCodes.mjs";
|
|
22
22
|
import { AggregatedPerpsProvider } from "./providers/AggregatedPerpsProvider.mjs";
|
|
23
23
|
import { HyperLiquidProvider } from "./providers/HyperLiquidProvider.mjs";
|
|
@@ -35,9 +35,39 @@ import { WebSocketConnectionState, PerpsAnalyticsEvent, PerpsTraceNames, PerpsTr
|
|
|
35
35
|
import { getSelectedEvmAccountFromMessenger } from "./utils/accountUtils.mjs";
|
|
36
36
|
import { ensureError } from "./utils/errorUtils.mjs";
|
|
37
37
|
import { parseAssetName } from "./utils/hyperLiquidAdapter.mjs";
|
|
38
|
-
import { compileMarketPattern, shouldIncludeMarket } from "./utils/marketUtils.mjs";
|
|
38
|
+
import { clonePerpsMarketData, compileMarketPattern, shouldIncludeMarket } from "./utils/marketUtils.mjs";
|
|
39
39
|
import { hydrateFromDiskSync, persistMarketEntriesToDisk, persistUserEntriesToDisk } from "./utils/perpsDiskPersistence.mjs";
|
|
40
40
|
import { wait } from "./utils/wait.mjs";
|
|
41
|
+
function cloneUserDataSnapshot(snapshot) {
|
|
42
|
+
return {
|
|
43
|
+
positions: snapshot.positions.map((position) => ({
|
|
44
|
+
...position,
|
|
45
|
+
leverage: { ...position.leverage },
|
|
46
|
+
cumulativeFunding: { ...position.cumulativeFunding },
|
|
47
|
+
...(position.takeProfitOrders && {
|
|
48
|
+
takeProfitOrders: position.takeProfitOrders.map((order) => ({
|
|
49
|
+
...order,
|
|
50
|
+
})),
|
|
51
|
+
}),
|
|
52
|
+
...(position.stopLossOrders && {
|
|
53
|
+
stopLossOrders: position.stopLossOrders.map((order) => ({
|
|
54
|
+
...order,
|
|
55
|
+
})),
|
|
56
|
+
}),
|
|
57
|
+
})),
|
|
58
|
+
orders: snapshot.orders.map((order) => ({ ...order })),
|
|
59
|
+
accountState: {
|
|
60
|
+
...snapshot.accountState,
|
|
61
|
+
...(snapshot.accountState.subAccountBreakdown && {
|
|
62
|
+
subAccountBreakdown: Object.fromEntries(Object.entries(snapshot.accountState.subAccountBreakdown).map(([dex, balances]) => [dex, { ...balances }])),
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
identity: {
|
|
66
|
+
...snapshot.identity,
|
|
67
|
+
dexes: [...snapshot.identity.dexes],
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
41
71
|
/**
|
|
42
72
|
* Returns the first non-empty string from the given values.
|
|
43
73
|
* Env vars default to '' (not null/undefined), so ?? wouldn't fall through.
|
|
@@ -400,6 +430,7 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
400
430
|
'getBlockExplorerUrl',
|
|
401
431
|
'getCachedMarketDataForActiveProvider',
|
|
402
432
|
'getCachedUserDataForActiveProvider',
|
|
433
|
+
'getUserDataSnapshot',
|
|
403
434
|
'getCurrentNetwork',
|
|
404
435
|
'getFunding',
|
|
405
436
|
'getHistoricalPortfolio',
|
|
@@ -532,6 +563,7 @@ export class PerpsController extends BaseController {
|
|
|
532
563
|
_PerpsController_handlersRegistered.set(this, false);
|
|
533
564
|
_PerpsController_standaloneProviderIsTestnet.set(this, null);
|
|
534
565
|
_PerpsController_standaloneProviderHip3Version.set(this, null);
|
|
566
|
+
_PerpsController_standaloneProviderOperations.set(this, new Map());
|
|
535
567
|
_PerpsController_eligibilityCheckDeferred.set(this, void 0);
|
|
536
568
|
/**
|
|
537
569
|
* Serial promise queue for all AUS watchlist operations (hydration and
|
|
@@ -547,6 +579,7 @@ export class PerpsController extends BaseController {
|
|
|
547
579
|
* a failed operation does not stall subsequent ones.
|
|
548
580
|
*/
|
|
549
581
|
_PerpsController_ausQueue.set(this, Promise.resolve());
|
|
582
|
+
_PerpsController_userDiskWrite.set(this, Promise.resolve());
|
|
550
583
|
// Store options for dependency injection (allows core package to inject platform-specific services)
|
|
551
584
|
_PerpsController_options.set(this, void 0);
|
|
552
585
|
// Service instances (instantiated with platform dependencies)
|
|
@@ -560,7 +593,10 @@ export class PerpsController extends BaseController {
|
|
|
560
593
|
_PerpsController_rewardsIntegrationService.set(this, void 0);
|
|
561
594
|
_PerpsController_preloadTimer.set(this, null);
|
|
562
595
|
_PerpsController_isPreloading.set(this, false);
|
|
596
|
+
_PerpsController_marketPreloadQueued.set(this, false);
|
|
563
597
|
_PerpsController_isPreloadingUserData.set(this, false);
|
|
598
|
+
_PerpsController_userPreloadQueued.set(this, false);
|
|
599
|
+
_PerpsController_userSnapshotRequests.set(this, new Map());
|
|
564
600
|
_PerpsController_preloadStateUnsubscribe.set(this, null);
|
|
565
601
|
_PerpsController_accountChangeUnsubscribe.set(this, null);
|
|
566
602
|
_PerpsController_previousIsTestnet.set(this, null);
|
|
@@ -579,7 +615,9 @@ export class PerpsController extends BaseController {
|
|
|
579
615
|
__classPrivateFieldSet(this, _PerpsController_marketDataService, new MarketDataService({
|
|
580
616
|
...infrastructure,
|
|
581
617
|
terminalMarketService: infrastructure.terminalMarketService ??
|
|
582
|
-
(infrastructure.
|
|
618
|
+
(infrastructure.terminalApi?.marketDataUrl ||
|
|
619
|
+
infrastructure.terminalApiUrl ||
|
|
620
|
+
infrastructure.terminalApi?.globalSnapshotUrl
|
|
583
621
|
? new TerminalMarketService(infrastructure)
|
|
584
622
|
: undefined),
|
|
585
623
|
}), "f");
|
|
@@ -646,24 +684,20 @@ export class PerpsController extends BaseController {
|
|
|
646
684
|
if (activeProvider === 'aggregated') {
|
|
647
685
|
// Assemble from all registered provider entries
|
|
648
686
|
const assembled = [];
|
|
649
|
-
let oldestTimestamp = Infinity;
|
|
650
687
|
for (const providerId of __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getAggregatedCacheProviderIds).call(this, Object.keys(cache))) {
|
|
651
688
|
const key = buildProviderCacheKey(providerId, this.state.isTestnet);
|
|
652
689
|
const entry = cache[key];
|
|
653
690
|
if (!entry || entry.data.length === 0) {
|
|
654
691
|
continue;
|
|
655
692
|
}
|
|
656
|
-
|
|
657
|
-
|
|
693
|
+
if (!__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMarketCacheEntryCurrent).call(this, providerId, entry, options)) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
assembled.push(...clonePerpsMarketData(entry.data));
|
|
658
697
|
}
|
|
659
698
|
if (assembled.length === 0) {
|
|
660
699
|
return null;
|
|
661
700
|
}
|
|
662
|
-
// Check TTL against the oldest entry
|
|
663
|
-
if (!options?.skipTTL &&
|
|
664
|
-
Date.now() - oldestTimestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
|
|
665
|
-
return null;
|
|
666
|
-
}
|
|
667
701
|
return assembled;
|
|
668
702
|
}
|
|
669
703
|
// Single provider mode
|
|
@@ -672,11 +706,10 @@ export class PerpsController extends BaseController {
|
|
|
672
706
|
if (!entry || entry.data.length === 0) {
|
|
673
707
|
return null;
|
|
674
708
|
}
|
|
675
|
-
if (!options
|
|
676
|
-
Date.now() - entry.timestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
|
|
709
|
+
if (!__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMarketCacheEntryCurrent).call(this, activeProvider, entry, options)) {
|
|
677
710
|
return null;
|
|
678
711
|
}
|
|
679
|
-
return entry.data;
|
|
712
|
+
return clonePerpsMarketData(entry.data);
|
|
680
713
|
}
|
|
681
714
|
/**
|
|
682
715
|
* Read cached user data for the currently active provider (or aggregated).
|
|
@@ -700,18 +733,21 @@ export class PerpsController extends BaseController {
|
|
|
700
733
|
currentAddress = evmAccount?.address ?? null;
|
|
701
734
|
}
|
|
702
735
|
catch {
|
|
703
|
-
//
|
|
736
|
+
// Account identity is required before account-scoped data can be trusted.
|
|
704
737
|
}
|
|
738
|
+
if (!currentAddress) {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
const selectedAddress = currentAddress;
|
|
705
742
|
const skipTTL = options?.skipTTL ?? false;
|
|
706
|
-
const isValidEntry = (entry) => {
|
|
743
|
+
const isValidEntry = (providerId, entry) => {
|
|
707
744
|
if (!entry) {
|
|
708
745
|
return false;
|
|
709
746
|
}
|
|
710
747
|
if (!skipTTL && Date.now() - entry.timestamp >= staleCutoff) {
|
|
711
748
|
return false;
|
|
712
749
|
}
|
|
713
|
-
if (
|
|
714
|
-
entry.address.toLowerCase() !== currentAddress.toLowerCase()) {
|
|
750
|
+
if (!__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isUserCacheIdentityCurrent).call(this, providerId, entry, selectedAddress)) {
|
|
715
751
|
return false;
|
|
716
752
|
}
|
|
717
753
|
return true;
|
|
@@ -723,9 +759,9 @@ export class PerpsController extends BaseController {
|
|
|
723
759
|
let defaultAccountState = null;
|
|
724
760
|
let hasValidEntry = false;
|
|
725
761
|
for (const providerId of __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getAggregatedCacheProviderIds).call(this, Object.keys(cache))) {
|
|
726
|
-
const
|
|
727
|
-
const entry = cache[
|
|
728
|
-
if (!isValidEntry(entry)) {
|
|
762
|
+
const providerNetworkKey = buildProviderCacheKey(providerId, this.state.isTestnet);
|
|
763
|
+
const entry = cache[providerNetworkKey];
|
|
764
|
+
if (!isValidEntry(providerId, entry)) {
|
|
729
765
|
continue;
|
|
730
766
|
}
|
|
731
767
|
hasValidEntry = true;
|
|
@@ -746,9 +782,9 @@ export class PerpsController extends BaseController {
|
|
|
746
782
|
};
|
|
747
783
|
}
|
|
748
784
|
// Single provider mode
|
|
749
|
-
const
|
|
750
|
-
const entry = cache[
|
|
751
|
-
if (!entry || !isValidEntry(entry)) {
|
|
785
|
+
const providerNetworkKey = buildProviderCacheKey(activeProvider, this.state.isTestnet);
|
|
786
|
+
const entry = cache[providerNetworkKey];
|
|
787
|
+
if (!entry || !isValidEntry(activeProvider, entry)) {
|
|
752
788
|
return null;
|
|
753
789
|
}
|
|
754
790
|
return {
|
|
@@ -757,6 +793,82 @@ export class PerpsController extends BaseController {
|
|
|
757
793
|
accountState: entry.accountState,
|
|
758
794
|
};
|
|
759
795
|
}
|
|
796
|
+
/**
|
|
797
|
+
* Fetch, validate, and atomically cache a complete user-data snapshot.
|
|
798
|
+
* This remains callable after mount so consumers can seed their live channel
|
|
799
|
+
* from one coherent positions/orders/account result.
|
|
800
|
+
*
|
|
801
|
+
* @returns The accepted user-data snapshot.
|
|
802
|
+
*/
|
|
803
|
+
async getUserDataSnapshot() {
|
|
804
|
+
const evmAccount = getSelectedEvmAccountFromMessenger(this.messenger);
|
|
805
|
+
if (!evmAccount?.address) {
|
|
806
|
+
throw new Error('Cannot fetch user data snapshot without an EVM account');
|
|
807
|
+
}
|
|
808
|
+
if (this.state.activeProvider !== 'hyperliquid') {
|
|
809
|
+
throw new Error('User data snapshots require Hyperliquid provider mode');
|
|
810
|
+
}
|
|
811
|
+
const capturedActiveProvider = this.activeProviderInstance;
|
|
812
|
+
const standaloneProvider = capturedActiveProvider
|
|
813
|
+
? null
|
|
814
|
+
: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
|
|
815
|
+
const provider = capturedActiveProvider ?? standaloneProvider;
|
|
816
|
+
if (!provider) {
|
|
817
|
+
throw new Error('Cannot create standalone Hyperliquid provider');
|
|
818
|
+
}
|
|
819
|
+
const { address } = evmAccount;
|
|
820
|
+
const { isTestnet, hip3ConfigVersion } = this.state;
|
|
821
|
+
const network = isTestnet ? 'testnet' : 'mainnet';
|
|
822
|
+
const expectedDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
|
|
823
|
+
if (!expectedDexes) {
|
|
824
|
+
throw new Error('User data snapshot DEX identity is not static');
|
|
825
|
+
}
|
|
826
|
+
const isCurrent = () => {
|
|
827
|
+
let currentAddress;
|
|
828
|
+
try {
|
|
829
|
+
currentAddress = getSelectedEvmAccountFromMessenger(this.messenger)?.address;
|
|
830
|
+
}
|
|
831
|
+
catch {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
return (this.state.activeProvider === 'hyperliquid' &&
|
|
835
|
+
(!capturedActiveProvider ||
|
|
836
|
+
this.activeProviderInstance === capturedActiveProvider) &&
|
|
837
|
+
this.state.isTestnet === isTestnet &&
|
|
838
|
+
this.state.hip3ConfigVersion === hip3ConfigVersion &&
|
|
839
|
+
currentAddress?.toLowerCase() === address.toLowerCase());
|
|
840
|
+
};
|
|
841
|
+
const context = {
|
|
842
|
+
provider,
|
|
843
|
+
standaloneProvider,
|
|
844
|
+
address,
|
|
845
|
+
isTestnet,
|
|
846
|
+
hip3ConfigVersion,
|
|
847
|
+
expectedDexes,
|
|
848
|
+
isCurrent,
|
|
849
|
+
};
|
|
850
|
+
const requestKey = [
|
|
851
|
+
'hyperliquid',
|
|
852
|
+
network,
|
|
853
|
+
address.toLowerCase(),
|
|
854
|
+
hip3ConfigVersion,
|
|
855
|
+
...expectedDexes,
|
|
856
|
+
].join('|');
|
|
857
|
+
const existingRequest = __classPrivateFieldGet(this, _PerpsController_userSnapshotRequests, "f").get(requestKey);
|
|
858
|
+
if (existingRequest?.provider === provider) {
|
|
859
|
+
return existingRequest.promise;
|
|
860
|
+
}
|
|
861
|
+
const request = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_fetchAndCacheUserDataSnapshot).call(this, context);
|
|
862
|
+
__classPrivateFieldGet(this, _PerpsController_userSnapshotRequests, "f").set(requestKey, { provider, promise: request });
|
|
863
|
+
try {
|
|
864
|
+
return await request;
|
|
865
|
+
}
|
|
866
|
+
finally {
|
|
867
|
+
if (__classPrivateFieldGet(this, _PerpsController_userSnapshotRequests, "f").get(requestKey)?.promise === request) {
|
|
868
|
+
__classPrivateFieldGet(this, _PerpsController_userSnapshotRequests, "f").delete(requestKey);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
760
872
|
/**
|
|
761
873
|
* Test-observable accessor for whether a standalone provider is cached.
|
|
762
874
|
*
|
|
@@ -1532,7 +1644,10 @@ export class PerpsController extends BaseController {
|
|
|
1532
1644
|
// Fallback to cached standalone provider for pre-initialization discovery
|
|
1533
1645
|
// TODO: When adding new providers (MYX), consider a provider factory pattern
|
|
1534
1646
|
const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
|
|
1535
|
-
|
|
1647
|
+
const operation = provider.getPositions(params);
|
|
1648
|
+
return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
|
|
1649
|
+
? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
|
|
1650
|
+
: operation;
|
|
1536
1651
|
}
|
|
1537
1652
|
const provider = this.getActiveProvider();
|
|
1538
1653
|
return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getPositions({
|
|
@@ -1593,7 +1708,10 @@ export class PerpsController extends BaseController {
|
|
|
1593
1708
|
// For standalone mode, access provider directly without initialization check
|
|
1594
1709
|
if (params?.standalone && params.userAddress) {
|
|
1595
1710
|
const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
|
|
1596
|
-
|
|
1711
|
+
const operation = provider.getOpenOrders(params);
|
|
1712
|
+
return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
|
|
1713
|
+
? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
|
|
1714
|
+
: operation;
|
|
1597
1715
|
}
|
|
1598
1716
|
const provider = this.getActiveProvider();
|
|
1599
1717
|
return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getOpenOrders({
|
|
@@ -1638,7 +1756,10 @@ export class PerpsController extends BaseController {
|
|
|
1638
1756
|
// Use activeProviderInstance if available (respects provider abstraction)
|
|
1639
1757
|
// Fallback to cached standalone provider for pre-initialization discovery
|
|
1640
1758
|
const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
|
|
1641
|
-
|
|
1759
|
+
const operation = provider.getAccountState(params);
|
|
1760
|
+
return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
|
|
1761
|
+
? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
|
|
1762
|
+
: operation;
|
|
1642
1763
|
}
|
|
1643
1764
|
const provider = this.getActiveProvider();
|
|
1644
1765
|
return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getAccountState({
|
|
@@ -1676,12 +1797,15 @@ export class PerpsController extends BaseController {
|
|
|
1676
1797
|
const isMarketAllowed = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_buildMarketAllowedFilter).call(this);
|
|
1677
1798
|
if (params?.standalone) {
|
|
1678
1799
|
const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
|
|
1679
|
-
|
|
1800
|
+
const operation = __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarkets({
|
|
1680
1801
|
provider,
|
|
1681
1802
|
params,
|
|
1682
1803
|
context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMarkets'),
|
|
1683
1804
|
isMarketAllowed,
|
|
1684
1805
|
});
|
|
1806
|
+
return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
|
|
1807
|
+
? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
|
|
1808
|
+
: operation;
|
|
1685
1809
|
}
|
|
1686
1810
|
const provider = this.getActiveProvider();
|
|
1687
1811
|
return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarkets({
|
|
@@ -1707,19 +1831,26 @@ export class PerpsController extends BaseController {
|
|
|
1707
1831
|
* @returns A promise that resolves to the market data.
|
|
1708
1832
|
*/
|
|
1709
1833
|
async getMarketDataWithPrices(params) {
|
|
1834
|
+
const globalSnapshot = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_buildGlobalSnapshotContext).call(this);
|
|
1835
|
+
const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMarketDataWithPrices', {
|
|
1836
|
+
...(globalSnapshot && { globalSnapshot }),
|
|
1837
|
+
});
|
|
1710
1838
|
if (params?.standalone) {
|
|
1711
1839
|
const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
|
|
1712
|
-
|
|
1840
|
+
const operation = __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarketDataWithPrices({
|
|
1713
1841
|
provider,
|
|
1714
1842
|
params,
|
|
1715
|
-
context
|
|
1843
|
+
context,
|
|
1716
1844
|
});
|
|
1845
|
+
return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
|
|
1846
|
+
? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
|
|
1847
|
+
: operation;
|
|
1717
1848
|
}
|
|
1718
1849
|
const provider = this.getActiveProvider();
|
|
1719
1850
|
return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarketDataWithPrices({
|
|
1720
1851
|
provider,
|
|
1721
1852
|
params,
|
|
1722
|
-
context
|
|
1853
|
+
context,
|
|
1723
1854
|
});
|
|
1724
1855
|
}
|
|
1725
1856
|
/**
|
|
@@ -1740,11 +1871,17 @@ export class PerpsController extends BaseController {
|
|
|
1740
1871
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
1741
1872
|
/* fire-and-forget */
|
|
1742
1873
|
});
|
|
1874
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
1875
|
+
/* fire-and-forget */
|
|
1876
|
+
});
|
|
1743
1877
|
// Periodic refresh
|
|
1744
1878
|
__classPrivateFieldSet(this, _PerpsController_preloadTimer, setInterval(() => {
|
|
1745
1879
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
1746
1880
|
/* fire-and-forget */
|
|
1747
1881
|
});
|
|
1882
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
1883
|
+
/* fire-and-forget */
|
|
1884
|
+
});
|
|
1748
1885
|
}, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadRefreshMs)), "f");
|
|
1749
1886
|
// Watch for isTestnet / hip3ConfigVersion changes
|
|
1750
1887
|
const handler = (_state, patches) => {
|
|
@@ -1773,36 +1910,29 @@ export class PerpsController extends BaseController {
|
|
|
1773
1910
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
1774
1911
|
/* fire-and-forget */
|
|
1775
1912
|
});
|
|
1913
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
1914
|
+
/* fire-and-forget */
|
|
1915
|
+
});
|
|
1776
1916
|
}
|
|
1777
1917
|
};
|
|
1778
|
-
this.messenger.subscribe('PerpsController:
|
|
1918
|
+
this.messenger.subscribe('PerpsController:stateChanged', handler);
|
|
1779
1919
|
__classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, () => {
|
|
1780
|
-
this.messenger.unsubscribe('PerpsController:
|
|
1920
|
+
this.messenger.unsubscribe('PerpsController:stateChanged', handler);
|
|
1781
1921
|
}, "f");
|
|
1782
1922
|
// Watch for selected account changes and selected account group changes.
|
|
1783
1923
|
const accountChangeHandler = () => {
|
|
1784
1924
|
const evmAccount = getSelectedEvmAccountFromMessenger(this.messenger);
|
|
1785
1925
|
const currentAddress = evmAccount?.address ?? null;
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
// Invalidate disk-cached user data for the old account
|
|
1795
|
-
__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.diskCache
|
|
1796
|
-
.removeItem(PERPS_DISK_CACHE_USER_DATA)
|
|
1797
|
-
.catch(() => {
|
|
1926
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: account cache selection', {
|
|
1927
|
+
address: currentAddress?.toLowerCase() ?? null,
|
|
1928
|
+
availableKeys: Object.keys(this.state.cachedUserDataByProvider).sort(),
|
|
1929
|
+
});
|
|
1930
|
+
// The address guard makes the previous entry unreadable immediately;
|
|
1931
|
+
// refresh replaces it under the existing provider/network key.
|
|
1932
|
+
if (currentAddress) {
|
|
1933
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
1798
1934
|
/* fire-and-forget */
|
|
1799
1935
|
});
|
|
1800
|
-
// Only preload if the new account is an EVM account
|
|
1801
|
-
if (currentAddress) {
|
|
1802
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
1803
|
-
/* fire-and-forget */
|
|
1804
|
-
});
|
|
1805
|
-
}
|
|
1806
1936
|
}
|
|
1807
1937
|
};
|
|
1808
1938
|
this.messenger.subscribe('AccountsController:selectedAccountChange', accountChangeHandler);
|
|
@@ -1831,6 +1961,8 @@ export class PerpsController extends BaseController {
|
|
|
1831
1961
|
}
|
|
1832
1962
|
__classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
|
|
1833
1963
|
__classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
|
|
1964
|
+
__classPrivateFieldSet(this, _PerpsController_marketPreloadQueued, false, "f");
|
|
1965
|
+
__classPrivateFieldSet(this, _PerpsController_userPreloadQueued, false, "f");
|
|
1834
1966
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this).catch(() => {
|
|
1835
1967
|
/* fire-and-forget to preserve sync signature */
|
|
1836
1968
|
});
|
|
@@ -2091,6 +2223,9 @@ export class PerpsController extends BaseController {
|
|
|
2091
2223
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
2092
2224
|
/* fire-and-forget */
|
|
2093
2225
|
});
|
|
2226
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
2227
|
+
/* fire-and-forget */
|
|
2228
|
+
});
|
|
2094
2229
|
}
|
|
2095
2230
|
}
|
|
2096
2231
|
}
|
|
@@ -2200,6 +2335,9 @@ export class PerpsController extends BaseController {
|
|
|
2200
2335
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
2201
2336
|
/* fire-and-forget */
|
|
2202
2337
|
});
|
|
2338
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
2339
|
+
/* fire-and-forget */
|
|
2340
|
+
});
|
|
2203
2341
|
}
|
|
2204
2342
|
}
|
|
2205
2343
|
}
|
|
@@ -3262,7 +3400,7 @@ export class PerpsController extends BaseController {
|
|
|
3262
3400
|
return __classPrivateFieldGet(this, _PerpsController_isReinitializing, "f");
|
|
3263
3401
|
}
|
|
3264
3402
|
}
|
|
3265
|
-
_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_priceDeviationLimit = new WeakMap(), _PerpsController_attributionContext = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_handlersRegistered = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_eligibilityCheckDeferred = new WeakMap(), _PerpsController_ausQueue = 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() {
|
|
3403
|
+
_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_priceDeviationLimit = new WeakMap(), _PerpsController_attributionContext = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_handlersRegistered = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_standaloneProviderOperations = new WeakMap(), _PerpsController_eligibilityCheckDeferred = new WeakMap(), _PerpsController_ausQueue = new WeakMap(), _PerpsController_userDiskWrite = 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_marketPreloadQueued = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_userPreloadQueued = new WeakMap(), _PerpsController_userSnapshotRequests = 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() {
|
|
3266
3404
|
const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx;
|
|
3267
3405
|
// Local env-var override (MM_PERPS_MYX_PROVIDER_ENABLED) always wins —
|
|
3268
3406
|
// matches the UI selector (resolvePerpsMyxProviderEnabled) so controller
|
|
@@ -3315,6 +3453,96 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
|
|
|
3315
3453
|
}
|
|
3316
3454
|
}
|
|
3317
3455
|
return Array.from(providerIds);
|
|
3456
|
+
}, _PerpsController_isMarketCacheEntryCurrent = function _PerpsController_isMarketCacheEntryCurrent(providerId, entry, options) {
|
|
3457
|
+
if (entry.sourceExpiresAt !== undefined) {
|
|
3458
|
+
const expectedDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
|
|
3459
|
+
return (providerId === 'hyperliquid' &&
|
|
3460
|
+
Date.now() < entry.sourceExpiresAt &&
|
|
3461
|
+
entry.hip3ConfigVersion === this.state.hip3ConfigVersion &&
|
|
3462
|
+
expectedDexes !== undefined &&
|
|
3463
|
+
Array.isArray(entry.dexes) &&
|
|
3464
|
+
entry.dexes.length === expectedDexes.length &&
|
|
3465
|
+
entry.dexes.every((dex, index) => dex === expectedDexes[index]));
|
|
3466
|
+
}
|
|
3467
|
+
return (options?.skipTTL === true ||
|
|
3468
|
+
Date.now() - entry.timestamp <= __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10);
|
|
3469
|
+
}, _PerpsController_isUserCacheIdentityCurrent = function _PerpsController_isUserCacheIdentityCurrent(providerId, entry, address) {
|
|
3470
|
+
if (entry.address.toLowerCase() !== address.toLowerCase()) {
|
|
3471
|
+
return false;
|
|
3472
|
+
}
|
|
3473
|
+
if (providerId !== 'hyperliquid') {
|
|
3474
|
+
return true;
|
|
3475
|
+
}
|
|
3476
|
+
const expectedDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
|
|
3477
|
+
return (entry.hip3ConfigVersion === this.state.hip3ConfigVersion &&
|
|
3478
|
+
expectedDexes !== undefined &&
|
|
3479
|
+
Array.isArray(entry.dexes) &&
|
|
3480
|
+
entry.dexes.length === expectedDexes.length &&
|
|
3481
|
+
entry.dexes.every((dex, index) => dex === expectedDexes[index]));
|
|
3482
|
+
}, _PerpsController_fetchAndCacheUserDataSnapshot = async function _PerpsController_fetchAndCacheUserDataSnapshot(context) {
|
|
3483
|
+
const { provider, standaloneProvider, address, isTestnet, hip3ConfigVersion, expectedDexes, isCurrent, } = context;
|
|
3484
|
+
if (!isCurrent()) {
|
|
3485
|
+
throw new Error('User data snapshot context changed');
|
|
3486
|
+
}
|
|
3487
|
+
if (!provider.getUserDataSnapshot) {
|
|
3488
|
+
throw new Error('Provider has no atomic snapshot API');
|
|
3489
|
+
}
|
|
3490
|
+
const identity = {
|
|
3491
|
+
provider: 'hyperliquid',
|
|
3492
|
+
network: isTestnet ? 'testnet' : 'mainnet',
|
|
3493
|
+
hip3ConfigVersion,
|
|
3494
|
+
dexes: expectedDexes,
|
|
3495
|
+
};
|
|
3496
|
+
const snapshotRequest = provider.getUserDataSnapshot({
|
|
3497
|
+
userAddress: address,
|
|
3498
|
+
identity,
|
|
3499
|
+
});
|
|
3500
|
+
const snapshot = standaloneProvider
|
|
3501
|
+
? await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, standaloneProvider, snapshotRequest)
|
|
3502
|
+
: await snapshotRequest;
|
|
3503
|
+
if (!isCurrent()) {
|
|
3504
|
+
throw new Error('User data snapshot context changed');
|
|
3505
|
+
}
|
|
3506
|
+
const snapshotIdentity = snapshot.identity;
|
|
3507
|
+
const hasCompleteBundle = Array.isArray(snapshot.positions) &&
|
|
3508
|
+
Array.isArray(snapshot.orders) &&
|
|
3509
|
+
snapshot.accountState !== null &&
|
|
3510
|
+
typeof snapshot.accountState === 'object';
|
|
3511
|
+
const hasExactIdentity = snapshotIdentity.provider === identity.provider &&
|
|
3512
|
+
snapshotIdentity.network === identity.network &&
|
|
3513
|
+
snapshotIdentity.hip3ConfigVersion === identity.hip3ConfigVersion &&
|
|
3514
|
+
snapshotIdentity.address.toLowerCase() === address.toLowerCase() &&
|
|
3515
|
+
snapshotIdentity.dexes.length === expectedDexes.length &&
|
|
3516
|
+
snapshotIdentity.dexes.every((dex, index) => dex === expectedDexes[index]);
|
|
3517
|
+
if (!hasCompleteBundle || !hasExactIdentity) {
|
|
3518
|
+
throw new Error('User data snapshot is incomplete or mismatched');
|
|
3519
|
+
}
|
|
3520
|
+
if (!isCurrent()) {
|
|
3521
|
+
throw new Error('User data snapshot context changed');
|
|
3522
|
+
}
|
|
3523
|
+
const cachedSnapshot = cloneUserDataSnapshot(snapshot);
|
|
3524
|
+
const result = cloneUserDataSnapshot(snapshot);
|
|
3525
|
+
const timestamp = Date.now();
|
|
3526
|
+
const providerNetworkKey = buildProviderCacheKey('hyperliquid', isTestnet);
|
|
3527
|
+
this.update((state) => {
|
|
3528
|
+
state.cachedUserDataByProvider[providerNetworkKey] = {
|
|
3529
|
+
positions: cachedSnapshot.positions,
|
|
3530
|
+
orders: cachedSnapshot.orders,
|
|
3531
|
+
accountState: cachedSnapshot.accountState,
|
|
3532
|
+
timestamp,
|
|
3533
|
+
address,
|
|
3534
|
+
hip3ConfigVersion,
|
|
3535
|
+
dexes: expectedDexes,
|
|
3536
|
+
};
|
|
3537
|
+
});
|
|
3538
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_persistUserCacheToDisk).call(this);
|
|
3539
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: user cache snapshot written', {
|
|
3540
|
+
writtenKey: providerNetworkKey,
|
|
3541
|
+
availableKeys: Object.keys(this.state.cachedUserDataByProvider).sort(),
|
|
3542
|
+
positionCount: cachedSnapshot.positions.length,
|
|
3543
|
+
orderCount: cachedSnapshot.orders.length,
|
|
3544
|
+
});
|
|
3545
|
+
return result;
|
|
3318
3546
|
}, _PerpsController_getOrCreateStandaloneProvider = function _PerpsController_getOrCreateStandaloneProvider() {
|
|
3319
3547
|
const currentIsTestnet = this.state.isTestnet;
|
|
3320
3548
|
const currentHip3Version = this.state.hip3ConfigVersion ?? 0;
|
|
@@ -3323,10 +3551,13 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
|
|
|
3323
3551
|
__classPrivateFieldGet(this, _PerpsController_standaloneProviderHip3Version, "f") === currentHip3Version) {
|
|
3324
3552
|
return __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
|
|
3325
3553
|
}
|
|
3326
|
-
// Stale or missing —
|
|
3554
|
+
// Stale or missing — retire the old provider after active operations finish.
|
|
3327
3555
|
if (__classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")) {
|
|
3328
3556
|
const old = __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
|
|
3329
|
-
|
|
3557
|
+
__classPrivateFieldSet(this, _PerpsController_standaloneProvider, null, "f");
|
|
3558
|
+
__classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, null, "f");
|
|
3559
|
+
__classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, null, "f");
|
|
3560
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_retireStandaloneProvider).call(this, old).catch(() => {
|
|
3330
3561
|
/* best-effort */
|
|
3331
3562
|
});
|
|
3332
3563
|
}
|
|
@@ -3346,24 +3577,45 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
|
|
|
3346
3577
|
__classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
|
|
3347
3578
|
__classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
|
|
3348
3579
|
return __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
|
|
3580
|
+
}, _PerpsController_trackStandaloneProviderOperation = function _PerpsController_trackStandaloneProviderOperation(provider, operation) {
|
|
3581
|
+
const operations = __classPrivateFieldGet(this, _PerpsController_standaloneProviderOperations, "f").get(provider) ?? new Set();
|
|
3582
|
+
__classPrivateFieldGet(this, _PerpsController_standaloneProviderOperations, "f").set(provider, operations);
|
|
3583
|
+
const trackedOperation = operation.finally(() => {
|
|
3584
|
+
operations.delete(trackedOperation);
|
|
3585
|
+
if (operations.size === 0) {
|
|
3586
|
+
__classPrivateFieldGet(this, _PerpsController_standaloneProviderOperations, "f").delete(provider);
|
|
3587
|
+
}
|
|
3588
|
+
});
|
|
3589
|
+
operations.add(trackedOperation);
|
|
3590
|
+
return trackedOperation;
|
|
3591
|
+
}, _PerpsController_retireStandaloneProvider = async function _PerpsController_retireStandaloneProvider(provider) {
|
|
3592
|
+
const operations = __classPrivateFieldGet(this, _PerpsController_standaloneProviderOperations, "f").get(provider);
|
|
3593
|
+
if (operations?.size) {
|
|
3594
|
+
await Promise.allSettled([...operations]);
|
|
3595
|
+
}
|
|
3596
|
+
try {
|
|
3597
|
+
await provider.disconnect();
|
|
3598
|
+
}
|
|
3599
|
+
catch {
|
|
3600
|
+
/* best-effort */
|
|
3601
|
+
}
|
|
3602
|
+
finally {
|
|
3603
|
+
__classPrivateFieldGet(this, _PerpsController_standaloneProviderOperations, "f").delete(provider);
|
|
3604
|
+
}
|
|
3349
3605
|
}, _PerpsController_cleanupStandaloneProvider =
|
|
3350
3606
|
/**
|
|
3351
3607
|
* Disconnect and discard the cached standalone provider (if any).
|
|
3352
3608
|
* Best-effort — errors are silently caught.
|
|
3353
3609
|
*/
|
|
3354
3610
|
async function _PerpsController_cleanupStandaloneProvider() {
|
|
3355
|
-
|
|
3611
|
+
const provider = __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
|
|
3612
|
+
if (!provider) {
|
|
3356
3613
|
return;
|
|
3357
3614
|
}
|
|
3358
|
-
try {
|
|
3359
|
-
await __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f").disconnect();
|
|
3360
|
-
}
|
|
3361
|
-
catch {
|
|
3362
|
-
/* best-effort */
|
|
3363
|
-
}
|
|
3364
3615
|
__classPrivateFieldSet(this, _PerpsController_standaloneProvider, null, "f");
|
|
3365
3616
|
__classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, null, "f");
|
|
3366
3617
|
__classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, null, "f");
|
|
3618
|
+
await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_retireStandaloneProvider).call(this, provider);
|
|
3367
3619
|
}, _PerpsController_getMetrics = function _PerpsController_getMetrics() {
|
|
3368
3620
|
return __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.metrics;
|
|
3369
3621
|
}, _PerpsController_findNetworkClientIdForChain = function _PerpsController_findNetworkClientIdForChain(chainId) {
|
|
@@ -3697,6 +3949,60 @@ async function _PerpsController_performInitialization() {
|
|
|
3697
3949
|
__classPrivateFieldGet(this, _PerpsController_tradingService, "f").setControllerDependencies({
|
|
3698
3950
|
rewardsIntegrationService: __classPrivateFieldGet(this, _PerpsController_rewardsIntegrationService, "f"),
|
|
3699
3951
|
});
|
|
3952
|
+
}, _PerpsController_buildGlobalSnapshotContext = function _PerpsController_buildGlobalSnapshotContext() {
|
|
3953
|
+
const snapshotConfigured = Boolean(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.terminalApi?.globalSnapshotUrl) ||
|
|
3954
|
+
typeof __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.terminalMarketService
|
|
3955
|
+
?.fetchGlobalSnapshot === 'function';
|
|
3956
|
+
if (!snapshotConfigured || this.state.activeProvider !== 'hyperliquid') {
|
|
3957
|
+
return undefined;
|
|
3958
|
+
}
|
|
3959
|
+
const enabledDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
|
|
3960
|
+
if (!enabledDexes) {
|
|
3961
|
+
return undefined;
|
|
3962
|
+
}
|
|
3963
|
+
const { isTestnet, hip3ConfigVersion } = this.state;
|
|
3964
|
+
return {
|
|
3965
|
+
request: {
|
|
3966
|
+
provider: 'hyperliquid',
|
|
3967
|
+
network: isTestnet ? 'testnet' : 'mainnet',
|
|
3968
|
+
enabledDexes,
|
|
3969
|
+
},
|
|
3970
|
+
isCurrent: () => this.state.activeProvider === 'hyperliquid' &&
|
|
3971
|
+
this.state.isTestnet === isTestnet &&
|
|
3972
|
+
this.state.hip3ConfigVersion === hip3ConfigVersion,
|
|
3973
|
+
isMarketAllowed: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_buildMarketAllowedFilter).call(this),
|
|
3974
|
+
};
|
|
3975
|
+
}, _PerpsController_getStaticSnapshotDexes = function _PerpsController_getStaticSnapshotDexes() {
|
|
3976
|
+
if (!__classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f")) {
|
|
3977
|
+
return ['main'];
|
|
3978
|
+
}
|
|
3979
|
+
if (this.state.isTestnet) {
|
|
3980
|
+
return TESTNET_HIP3_CONFIG.AutoDiscoverAll
|
|
3981
|
+
? undefined
|
|
3982
|
+
: canonicalizeHyperLiquidDexes(TESTNET_HIP3_CONFIG.EnabledDexs);
|
|
3983
|
+
}
|
|
3984
|
+
if (MAINNET_HIP3_CONFIG.AutoDiscoverAll) {
|
|
3985
|
+
return undefined;
|
|
3986
|
+
}
|
|
3987
|
+
const dexes = new Set();
|
|
3988
|
+
for (const pattern of __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f")) {
|
|
3989
|
+
const colonIndex = pattern.indexOf(':');
|
|
3990
|
+
if (colonIndex <= 0) {
|
|
3991
|
+
if (/^[a-z][a-z0-9]*$/iu.test(pattern)) {
|
|
3992
|
+
dexes.add(pattern.toLowerCase());
|
|
3993
|
+
continue;
|
|
3994
|
+
}
|
|
3995
|
+
return undefined;
|
|
3996
|
+
}
|
|
3997
|
+
const dex = pattern.slice(0, colonIndex);
|
|
3998
|
+
if (dex && /^[a-z0-9][a-z0-9-]*$/u.test(dex)) {
|
|
3999
|
+
dexes.add(dex);
|
|
4000
|
+
}
|
|
4001
|
+
else {
|
|
4002
|
+
return undefined;
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
return canonicalizeHyperLiquidDexes(dexes);
|
|
3700
4006
|
}, _PerpsController_hydrateCacheFromDiskSync = function _PerpsController_hydrateCacheFromDiskSync() {
|
|
3701
4007
|
const { marketUpdates, userUpdates, stats } = hydrateFromDiskSync(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.diskCache, this.state.cachedMarketDataByProvider, this.state.cachedUserDataByProvider, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs));
|
|
3702
4008
|
const hasMarketUpdates = Object.keys(marketUpdates).length > 0;
|
|
@@ -3717,12 +4023,40 @@ async function _PerpsController_performInitialization() {
|
|
|
3717
4023
|
orders: stats.userOrders,
|
|
3718
4024
|
duration_ms: stats.durationMs,
|
|
3719
4025
|
});
|
|
4026
|
+
}, _PerpsController_persistUserCacheToDisk = function _PerpsController_persistUserCacheToDisk() {
|
|
4027
|
+
const entries = [];
|
|
4028
|
+
for (const [cacheKey, entry] of Object.entries(this.state.cachedUserDataByProvider)) {
|
|
4029
|
+
const [providerId, network] = cacheKey.split(':');
|
|
4030
|
+
if (!providerId ||
|
|
4031
|
+
(network !== 'mainnet' && network !== 'testnet') ||
|
|
4032
|
+
providerId === 'aggregated') {
|
|
4033
|
+
continue;
|
|
4034
|
+
}
|
|
4035
|
+
entries.push({
|
|
4036
|
+
providerNetworkKey: `${providerId}:${network}`,
|
|
4037
|
+
address: entry.address,
|
|
4038
|
+
positions: entry.positions,
|
|
4039
|
+
orders: entry.orders,
|
|
4040
|
+
accountState: entry.accountState,
|
|
4041
|
+
timestamp: entry.timestamp,
|
|
4042
|
+
...(entry.hip3ConfigVersion !== undefined && {
|
|
4043
|
+
hip3ConfigVersion: entry.hip3ConfigVersion,
|
|
4044
|
+
}),
|
|
4045
|
+
...(entry.dexes !== undefined && { dexes: entry.dexes }),
|
|
4046
|
+
});
|
|
4047
|
+
}
|
|
4048
|
+
__classPrivateFieldSet(this, _PerpsController_userDiskWrite, __classPrivateFieldGet(this, _PerpsController_userDiskWrite, "f")
|
|
4049
|
+
.then(() => persistUserEntriesToDisk(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.diskCache, entries))
|
|
4050
|
+
.catch(() => {
|
|
4051
|
+
// Disk persistence is best-effort and must not block live data.
|
|
4052
|
+
}), "f");
|
|
3720
4053
|
}, _PerpsController_performMarketDataPreload =
|
|
3721
4054
|
/**
|
|
3722
4055
|
* Perform a single market data preload (best-effort, no throw).
|
|
3723
4056
|
*/
|
|
3724
4057
|
async function _PerpsController_performMarketDataPreload() {
|
|
3725
4058
|
if (__classPrivateFieldGet(this, _PerpsController_isPreloading, "f")) {
|
|
4059
|
+
__classPrivateFieldSet(this, _PerpsController_marketPreloadQueued, true, "f");
|
|
3726
4060
|
return;
|
|
3727
4061
|
}
|
|
3728
4062
|
// Skip preloading during provider/network reinitialisation.
|
|
@@ -3737,9 +4071,16 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3737
4071
|
? this.state.activeProvider // includes 'aggregated'
|
|
3738
4072
|
: 'hyperliquid';
|
|
3739
4073
|
const cacheKey = buildProviderCacheKey(actualProviderId, this.state.isTestnet);
|
|
4074
|
+
const preloadContext = {
|
|
4075
|
+
activeProvider: this.state.activeProvider,
|
|
4076
|
+
isTestnet: this.state.isTestnet,
|
|
4077
|
+
hip3ConfigVersion: this.state.hip3ConfigVersion,
|
|
4078
|
+
};
|
|
4079
|
+
const staticSnapshotDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
|
|
3740
4080
|
const now = Date.now();
|
|
3741
4081
|
const existingEntry = this.state.cachedMarketDataByProvider[cacheKey];
|
|
3742
4082
|
if (existingEntry &&
|
|
4083
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMarketCacheEntryCurrent).call(this, actualProviderId, existingEntry) &&
|
|
3743
4084
|
now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
|
|
3744
4085
|
return;
|
|
3745
4086
|
}
|
|
@@ -3764,8 +4105,32 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3764
4105
|
duration_ms: Math.round(performance.now() - preloadStart),
|
|
3765
4106
|
markets: data.length,
|
|
3766
4107
|
});
|
|
4108
|
+
if (this.state.activeProvider !== preloadContext.activeProvider ||
|
|
4109
|
+
this.state.isTestnet !== preloadContext.isTestnet ||
|
|
4110
|
+
this.state.hip3ConfigVersion !== preloadContext.hip3ConfigVersion) {
|
|
4111
|
+
traceData = {
|
|
4112
|
+
success: false,
|
|
4113
|
+
error: 'Global snapshot preload context changed',
|
|
4114
|
+
};
|
|
4115
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Discarding stale global snapshot preload');
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
3767
4118
|
// Store under per-provider key(s)
|
|
3768
4119
|
const ts = Date.now();
|
|
4120
|
+
const sourceExpiries = data.flatMap((market) => market.dataSource === 'terminal-global-snapshot-mark' &&
|
|
4121
|
+
typeof market.sourceExpiresAt === 'number'
|
|
4122
|
+
? [market.sourceExpiresAt]
|
|
4123
|
+
: []);
|
|
4124
|
+
const sourceExpiresAt = data.length > 0 && sourceExpiries.length === data.length
|
|
4125
|
+
? Math.min(...sourceExpiries)
|
|
4126
|
+
: undefined;
|
|
4127
|
+
const snapshotCacheIdentity = sourceExpiresAt !== undefined && staticSnapshotDexes
|
|
4128
|
+
? {
|
|
4129
|
+
sourceExpiresAt,
|
|
4130
|
+
hip3ConfigVersion: preloadContext.hip3ConfigVersion,
|
|
4131
|
+
dexes: staticSnapshotDexes,
|
|
4132
|
+
}
|
|
4133
|
+
: {};
|
|
3769
4134
|
const marketDiskEntries = [];
|
|
3770
4135
|
if (this.state.activeProvider === 'aggregated' &&
|
|
3771
4136
|
this.activeProviderInstance) {
|
|
@@ -3812,6 +4177,7 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3812
4177
|
state.cachedMarketDataByProvider[cacheKey] = {
|
|
3813
4178
|
data,
|
|
3814
4179
|
timestamp: ts,
|
|
4180
|
+
...snapshotCacheIdentity,
|
|
3815
4181
|
};
|
|
3816
4182
|
});
|
|
3817
4183
|
}
|
|
@@ -3821,10 +4187,6 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3821
4187
|
});
|
|
3822
4188
|
traceData = { success: true, marketCount: data.length };
|
|
3823
4189
|
__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.setMeasurement(PerpsMeasurementName.PerpsMarketDataPreload, performance.now() - preloadStart, 'millisecond');
|
|
3824
|
-
// Also preload user data (fire-and-forget, non-blocking)
|
|
3825
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
3826
|
-
/* fire-and-forget */
|
|
3827
|
-
});
|
|
3828
4190
|
}
|
|
3829
4191
|
catch (error) {
|
|
3830
4192
|
traceData = {
|
|
@@ -3843,6 +4205,12 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3843
4205
|
data: traceData,
|
|
3844
4206
|
});
|
|
3845
4207
|
__classPrivateFieldSet(this, _PerpsController_isPreloading, false, "f");
|
|
4208
|
+
if (__classPrivateFieldGet(this, _PerpsController_marketPreloadQueued, "f") && __classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
|
|
4209
|
+
__classPrivateFieldSet(this, _PerpsController_marketPreloadQueued, false, "f");
|
|
4210
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
|
|
4211
|
+
// Background preload is best-effort.
|
|
4212
|
+
});
|
|
4213
|
+
}
|
|
3846
4214
|
}
|
|
3847
4215
|
}, _PerpsController_performUserDataPreload =
|
|
3848
4216
|
/**
|
|
@@ -3851,6 +4219,10 @@ async function _PerpsController_performMarketDataPreload() {
|
|
|
3851
4219
|
*/
|
|
3852
4220
|
async function _PerpsController_performUserDataPreload() {
|
|
3853
4221
|
if (__classPrivateFieldGet(this, _PerpsController_isPreloadingUserData, "f")) {
|
|
4222
|
+
__classPrivateFieldSet(this, _PerpsController_userPreloadQueued, true, "f");
|
|
4223
|
+
return;
|
|
4224
|
+
}
|
|
4225
|
+
if (__classPrivateFieldGet(this, _PerpsController_isReinitializing, "f")) {
|
|
3854
4226
|
return;
|
|
3855
4227
|
}
|
|
3856
4228
|
// Get current user address
|
|
@@ -3859,21 +4231,54 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
3859
4231
|
return;
|
|
3860
4232
|
}
|
|
3861
4233
|
const userAddress = evmAccount.address;
|
|
4234
|
+
const { activeProvider, isTestnet, hip3ConfigVersion } = this.state;
|
|
4235
|
+
const { activeProviderInstance } = this;
|
|
4236
|
+
const hyperliquidDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
|
|
4237
|
+
const isCurrent = () => {
|
|
4238
|
+
let currentAddress;
|
|
4239
|
+
try {
|
|
4240
|
+
currentAddress = getSelectedEvmAccountFromMessenger(this.messenger)?.address;
|
|
4241
|
+
}
|
|
4242
|
+
catch {
|
|
4243
|
+
return false;
|
|
4244
|
+
}
|
|
4245
|
+
return (this.state.activeProvider === activeProvider &&
|
|
4246
|
+
this.activeProviderInstance === activeProviderInstance &&
|
|
4247
|
+
this.state.isTestnet === isTestnet &&
|
|
4248
|
+
this.state.hip3ConfigVersion === hip3ConfigVersion &&
|
|
4249
|
+
currentAddress?.toLowerCase() === userAddress.toLowerCase());
|
|
4250
|
+
};
|
|
3862
4251
|
// Determine actual provider (same logic as market preload)
|
|
3863
|
-
const actualProviderId =
|
|
3864
|
-
?
|
|
4252
|
+
const actualProviderId = activeProviderInstance
|
|
4253
|
+
? activeProvider // includes 'aggregated'
|
|
3865
4254
|
: 'hyperliquid';
|
|
3866
|
-
const
|
|
4255
|
+
const providerNetworkKey = buildProviderCacheKey(actualProviderId, isTestnet);
|
|
3867
4256
|
// Skip if cache is fresh and for same account
|
|
3868
4257
|
const now = Date.now();
|
|
3869
|
-
const existingEntry = this.state.cachedUserDataByProvider[
|
|
3870
|
-
|
|
4258
|
+
const existingEntry = this.state.cachedUserDataByProvider[providerNetworkKey];
|
|
4259
|
+
const hasMatchingCache = existingEntry !== undefined &&
|
|
4260
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isUserCacheIdentityCurrent).call(this, actualProviderId, existingEntry, userAddress);
|
|
4261
|
+
const cacheAgeMs = existingEntry ? now - existingEntry.timestamp : null;
|
|
4262
|
+
const websocketState = this.getWebSocketConnectionState();
|
|
4263
|
+
let selectedEntryKey = null;
|
|
4264
|
+
if (this.state.cachedUserDataByProvider[providerNetworkKey]) {
|
|
4265
|
+
selectedEntryKey = providerNetworkKey;
|
|
4266
|
+
}
|
|
4267
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: user cache preload decision', {
|
|
4268
|
+
requestedKey: providerNetworkKey,
|
|
4269
|
+
selectedEntryKey,
|
|
4270
|
+
availableKeys: Object.keys(this.state.cachedUserDataByProvider).sort(),
|
|
4271
|
+
hasMatchingCache,
|
|
4272
|
+
cacheAgeMs,
|
|
4273
|
+
websocketState,
|
|
4274
|
+
});
|
|
4275
|
+
if (existingEntry &&
|
|
4276
|
+
hasMatchingCache &&
|
|
3871
4277
|
now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
|
|
3872
4278
|
return;
|
|
3873
4279
|
}
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Skipping user data preload — WebSocket connected');
|
|
4280
|
+
if (hasMatchingCache &&
|
|
4281
|
+
this.getWebSocketConnectionState() === WebSocketConnectionState.Connected) {
|
|
3877
4282
|
return;
|
|
3878
4283
|
}
|
|
3879
4284
|
__classPrivateFieldSet(this, _PerpsController_isPreloadingUserData, true, "f");
|
|
@@ -3886,21 +4291,38 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
3886
4291
|
id: traceId,
|
|
3887
4292
|
op: PerpsTraceOperations.Operation,
|
|
3888
4293
|
tags: {
|
|
3889
|
-
provider:
|
|
3890
|
-
isTestnet
|
|
4294
|
+
provider: activeProvider,
|
|
4295
|
+
isTestnet,
|
|
3891
4296
|
},
|
|
3892
4297
|
data: { userAddress },
|
|
3893
4298
|
});
|
|
3894
4299
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching user data in background', {
|
|
3895
4300
|
userAddress,
|
|
3896
4301
|
});
|
|
4302
|
+
if (activeProvider === 'hyperliquid') {
|
|
4303
|
+
const snapshot = await this.getUserDataSnapshot();
|
|
4304
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
|
|
4305
|
+
positionCount: snapshot.positions.length,
|
|
4306
|
+
orderCount: snapshot.orders.length,
|
|
4307
|
+
totalBalance: snapshot.accountState.totalBalance,
|
|
4308
|
+
});
|
|
4309
|
+
traceData = {
|
|
4310
|
+
success: true,
|
|
4311
|
+
positionCount: snapshot.positions.length,
|
|
4312
|
+
orderCount: snapshot.orders.length,
|
|
4313
|
+
};
|
|
4314
|
+
__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.setMeasurement(PerpsMeasurementName.PerpsUserDataPreload, performance.now() - preloadStart, 'millisecond');
|
|
4315
|
+
return;
|
|
4316
|
+
}
|
|
3897
4317
|
const [positions, orders, accountState] = await Promise.all([
|
|
3898
4318
|
this.getPositions({ standalone: true, userAddress }),
|
|
3899
4319
|
this.getOpenOrders({ standalone: true, userAddress }),
|
|
3900
4320
|
this.getAccountState({ standalone: true, userAddress }),
|
|
3901
4321
|
]);
|
|
3902
|
-
if (
|
|
3903
|
-
|
|
4322
|
+
if (!isCurrent()) {
|
|
4323
|
+
throw new Error('User data preload context changed');
|
|
4324
|
+
}
|
|
4325
|
+
if (activeProvider === 'aggregated' && activeProviderInstance) {
|
|
3904
4326
|
// Split by providerId and write one cache entry per provider key
|
|
3905
4327
|
// (mirrors the market-data preload pattern at ~line 2976)
|
|
3906
4328
|
const ts = Date.now();
|
|
@@ -3922,26 +4344,22 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
3922
4344
|
}
|
|
3923
4345
|
// AccountState — assign to its provider bucket
|
|
3924
4346
|
ensureBucket(accountState.providerId ?? fallbackProviderId).accountState = accountState;
|
|
3925
|
-
const diskEntries = [];
|
|
3926
4347
|
this.update((state) => {
|
|
3927
4348
|
for (const [pid, data] of byProvider) {
|
|
3928
|
-
const key = buildProviderCacheKey(pid,
|
|
3929
|
-
diskEntries.push({
|
|
3930
|
-
providerNetworkKey: key,
|
|
3931
|
-
address: userAddress,
|
|
3932
|
-
positions: data.positions,
|
|
3933
|
-
orders: data.orders,
|
|
3934
|
-
accountState: data.accountState,
|
|
3935
|
-
timestamp: ts,
|
|
3936
|
-
});
|
|
4349
|
+
const key = buildProviderCacheKey(pid, isTestnet);
|
|
3937
4350
|
state.cachedUserDataByProvider[key] = {
|
|
3938
4351
|
...data,
|
|
3939
4352
|
timestamp: ts,
|
|
3940
4353
|
address: userAddress,
|
|
4354
|
+
...(pid === 'hyperliquid' &&
|
|
4355
|
+
hyperliquidDexes && {
|
|
4356
|
+
hip3ConfigVersion,
|
|
4357
|
+
dexes: hyperliquidDexes,
|
|
4358
|
+
}),
|
|
3941
4359
|
};
|
|
3942
4360
|
}
|
|
3943
4361
|
// Write aggregated sentinel so the staleness guard sees it
|
|
3944
|
-
state.cachedUserDataByProvider[
|
|
4362
|
+
state.cachedUserDataByProvider[providerNetworkKey] = {
|
|
3945
4363
|
positions: [],
|
|
3946
4364
|
orders: [],
|
|
3947
4365
|
accountState: null,
|
|
@@ -3949,30 +4367,26 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
3949
4367
|
address: userAddress,
|
|
3950
4368
|
};
|
|
3951
4369
|
});
|
|
3952
|
-
|
|
4370
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_persistUserCacheToDisk).call(this);
|
|
3953
4371
|
}
|
|
3954
4372
|
else {
|
|
3955
4373
|
// Single provider — store directly under its key
|
|
3956
4374
|
const ts = Date.now();
|
|
3957
4375
|
this.update((state) => {
|
|
3958
|
-
state.cachedUserDataByProvider[
|
|
4376
|
+
state.cachedUserDataByProvider[providerNetworkKey] = {
|
|
3959
4377
|
positions,
|
|
3960
4378
|
orders,
|
|
3961
4379
|
accountState,
|
|
3962
4380
|
timestamp: ts,
|
|
3963
4381
|
address: userAddress,
|
|
4382
|
+
...(actualProviderId === 'hyperliquid' &&
|
|
4383
|
+
hyperliquidDexes && {
|
|
4384
|
+
hip3ConfigVersion,
|
|
4385
|
+
dexes: hyperliquidDexes,
|
|
4386
|
+
}),
|
|
3964
4387
|
};
|
|
3965
4388
|
});
|
|
3966
|
-
|
|
3967
|
-
{
|
|
3968
|
-
providerNetworkKey: userCacheKey,
|
|
3969
|
-
address: userAddress,
|
|
3970
|
-
positions,
|
|
3971
|
-
orders,
|
|
3972
|
-
accountState,
|
|
3973
|
-
timestamp: ts,
|
|
3974
|
-
},
|
|
3975
|
-
]);
|
|
4389
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_persistUserCacheToDisk).call(this);
|
|
3976
4390
|
}
|
|
3977
4391
|
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
|
|
3978
4392
|
positionCount: positions.length,
|
|
@@ -4003,6 +4417,12 @@ async function _PerpsController_performUserDataPreload() {
|
|
|
4003
4417
|
data: traceData,
|
|
4004
4418
|
});
|
|
4005
4419
|
__classPrivateFieldSet(this, _PerpsController_isPreloadingUserData, false, "f");
|
|
4420
|
+
if (__classPrivateFieldGet(this, _PerpsController_userPreloadQueued, "f") && __classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
|
|
4421
|
+
__classPrivateFieldSet(this, _PerpsController_userPreloadQueued, false, "f");
|
|
4422
|
+
__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
|
|
4423
|
+
// Background preload is best-effort.
|
|
4424
|
+
});
|
|
4425
|
+
}
|
|
4006
4426
|
}
|
|
4007
4427
|
}, _PerpsController_persistWatchlistToRemote =
|
|
4008
4428
|
/**
|