@metamask-previews/perps-controller 11.0.0-preview-ea8763e0c → 11.0.0-preview-6b4bcdab3

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +0 -8
  2. package/dist/PerpsController-method-action-types.cjs.map +1 -1
  3. package/dist/PerpsController-method-action-types.d.cts +1 -12
  4. package/dist/PerpsController-method-action-types.d.cts.map +1 -1
  5. package/dist/PerpsController-method-action-types.d.mts +1 -12
  6. package/dist/PerpsController-method-action-types.d.mts.map +1 -1
  7. package/dist/PerpsController-method-action-types.mjs.map +1 -1
  8. package/dist/PerpsController.cjs +99 -519
  9. package/dist/PerpsController.cjs.map +1 -1
  10. package/dist/PerpsController.d.cts +4 -17
  11. package/dist/PerpsController.d.cts.map +1 -1
  12. package/dist/PerpsController.d.mts +4 -17
  13. package/dist/PerpsController.d.mts.map +1 -1
  14. package/dist/PerpsController.mjs +102 -522
  15. package/dist/PerpsController.mjs.map +1 -1
  16. package/dist/constants/eventNames.cjs +0 -3
  17. package/dist/constants/eventNames.cjs.map +1 -1
  18. package/dist/constants/eventNames.d.cts +0 -1
  19. package/dist/constants/eventNames.d.cts.map +1 -1
  20. package/dist/constants/eventNames.d.mts +0 -1
  21. package/dist/constants/eventNames.d.mts.map +1 -1
  22. package/dist/constants/eventNames.mjs +0 -3
  23. package/dist/constants/eventNames.mjs.map +1 -1
  24. package/dist/constants/hyperLiquidConfig.cjs +2 -14
  25. package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
  26. package/dist/constants/hyperLiquidConfig.d.cts +0 -7
  27. package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
  28. package/dist/constants/hyperLiquidConfig.d.mts +0 -7
  29. package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
  30. package/dist/constants/hyperLiquidConfig.mjs +0 -11
  31. package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
  32. package/dist/constants/perpsConfig.cjs +1 -4
  33. package/dist/constants/perpsConfig.cjs.map +1 -1
  34. package/dist/constants/perpsConfig.d.cts +7 -25
  35. package/dist/constants/perpsConfig.d.cts.map +1 -1
  36. package/dist/constants/perpsConfig.d.mts +7 -25
  37. package/dist/constants/perpsConfig.d.mts.map +1 -1
  38. package/dist/constants/perpsConfig.mjs +1 -4
  39. package/dist/constants/perpsConfig.mjs.map +1 -1
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +3 -3
  42. package/dist/index.d.cts.map +1 -1
  43. package/dist/index.d.mts +3 -3
  44. package/dist/index.d.mts.map +1 -1
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/providers/HyperLiquidProvider.cjs +1 -148
  47. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  48. package/dist/providers/HyperLiquidProvider.d.cts +1 -11
  49. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  50. package/dist/providers/HyperLiquidProvider.d.mts +1 -11
  51. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  52. package/dist/providers/HyperLiquidProvider.mjs +2 -149
  53. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  54. package/dist/services/HyperLiquidSubscriptionService.cjs +4 -15
  55. package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
  56. package/dist/services/HyperLiquidSubscriptionService.d.cts +1 -1
  57. package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
  58. package/dist/services/HyperLiquidSubscriptionService.d.mts +1 -1
  59. package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
  60. package/dist/services/HyperLiquidSubscriptionService.mjs +4 -15
  61. package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
  62. package/dist/services/MarketDataService.cjs +3 -41
  63. package/dist/services/MarketDataService.cjs.map +1 -1
  64. package/dist/services/MarketDataService.d.cts +2 -2
  65. package/dist/services/MarketDataService.d.cts.map +1 -1
  66. package/dist/services/MarketDataService.d.mts +2 -2
  67. package/dist/services/MarketDataService.d.mts.map +1 -1
  68. package/dist/services/MarketDataService.mjs +3 -41
  69. package/dist/services/MarketDataService.mjs.map +1 -1
  70. package/dist/services/ServiceContext.cjs.map +1 -1
  71. package/dist/services/ServiceContext.d.cts +1 -10
  72. package/dist/services/ServiceContext.d.cts.map +1 -1
  73. package/dist/services/ServiceContext.d.mts +1 -10
  74. package/dist/services/ServiceContext.d.mts.map +1 -1
  75. package/dist/services/ServiceContext.mjs.map +1 -1
  76. package/dist/services/TerminalMarketService.cjs +7 -422
  77. package/dist/services/TerminalMarketService.cjs.map +1 -1
  78. package/dist/services/TerminalMarketService.d.cts +1 -10
  79. package/dist/services/TerminalMarketService.d.cts.map +1 -1
  80. package/dist/services/TerminalMarketService.d.mts +1 -10
  81. package/dist/services/TerminalMarketService.d.mts.map +1 -1
  82. package/dist/services/TerminalMarketService.mjs +8 -423
  83. package/dist/services/TerminalMarketService.mjs.map +1 -1
  84. package/dist/types/index.cjs.map +1 -1
  85. package/dist/types/index.d.cts +7 -43
  86. package/dist/types/index.d.cts.map +1 -1
  87. package/dist/types/index.d.mts +7 -43
  88. package/dist/types/index.d.mts.map +1 -1
  89. package/dist/types/index.mjs.map +1 -1
  90. package/dist/utils/marketUtils.cjs +1 -16
  91. package/dist/utils/marketUtils.cjs.map +1 -1
  92. package/dist/utils/marketUtils.d.cts +0 -1
  93. package/dist/utils/marketUtils.d.cts.map +1 -1
  94. package/dist/utils/marketUtils.d.mts +0 -1
  95. package/dist/utils/marketUtils.d.mts.map +1 -1
  96. package/dist/utils/marketUtils.mjs +0 -14
  97. package/dist/utils/marketUtils.mjs.map +1 -1
  98. package/dist/utils/perpsDiskPersistence.cjs +12 -19
  99. package/dist/utils/perpsDiskPersistence.cjs.map +1 -1
  100. package/dist/utils/perpsDiskPersistence.d.cts +1 -5
  101. package/dist/utils/perpsDiskPersistence.d.cts.map +1 -1
  102. package/dist/utils/perpsDiskPersistence.d.mts +1 -5
  103. package/dist/utils/perpsDiskPersistence.d.mts.map +1 -1
  104. package/dist/utils/perpsDiskPersistence.mjs +12 -19
  105. package/dist/utils/perpsDiskPersistence.mjs.map +1 -1
  106. package/package.json +1 -1
@@ -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_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;
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;
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 { canonicalizeHyperLiquidDexes, MAINNET_HIP3_CONFIG, TESTNET_HIP3_CONFIG, USDC_SYMBOL } from "./constants/hyperLiquidConfig.mjs";
18
+ import { USDC_SYMBOL } from "./constants/hyperLiquidConfig.mjs";
19
19
  import { PerpsMeasurementName } from "./constants/performanceMetrics.mjs";
20
- import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG, PROVIDER_CONFIG, buildProviderCacheKey, MAX_SLIPPAGE_BOUNDS, DEFAULT_PERPS_MODE, DEFAULT_PRO_LAYOUT_PREFERENCES } from "./constants/perpsConfig.mjs";
20
+ import { PERPS_CONSTANTS, MARKET_SORTING_CONFIG, PROVIDER_CONFIG, PERPS_DISK_CACHE_USER_DATA, 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,39 +35,9 @@ 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 { clonePerpsMarketData, compileMarketPattern, shouldIncludeMarket } from "./utils/marketUtils.mjs";
38
+ import { 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
- }
71
41
  /**
72
42
  * Returns the first non-empty string from the given values.
73
43
  * Env vars default to '' (not null/undefined), so ?? wouldn't fall through.
@@ -430,7 +400,6 @@ const MESSENGER_EXPOSED_METHODS = [
430
400
  'getBlockExplorerUrl',
431
401
  'getCachedMarketDataForActiveProvider',
432
402
  'getCachedUserDataForActiveProvider',
433
- 'getUserDataSnapshot',
434
403
  'getCurrentNetwork',
435
404
  'getFunding',
436
405
  'getHistoricalPortfolio',
@@ -563,7 +532,6 @@ export class PerpsController extends BaseController {
563
532
  _PerpsController_handlersRegistered.set(this, false);
564
533
  _PerpsController_standaloneProviderIsTestnet.set(this, null);
565
534
  _PerpsController_standaloneProviderHip3Version.set(this, null);
566
- _PerpsController_standaloneProviderOperations.set(this, new Map());
567
535
  _PerpsController_eligibilityCheckDeferred.set(this, void 0);
568
536
  /**
569
537
  * Serial promise queue for all AUS watchlist operations (hydration and
@@ -579,7 +547,6 @@ export class PerpsController extends BaseController {
579
547
  * a failed operation does not stall subsequent ones.
580
548
  */
581
549
  _PerpsController_ausQueue.set(this, Promise.resolve());
582
- _PerpsController_userDiskWrite.set(this, Promise.resolve());
583
550
  // Store options for dependency injection (allows core package to inject platform-specific services)
584
551
  _PerpsController_options.set(this, void 0);
585
552
  // Service instances (instantiated with platform dependencies)
@@ -593,10 +560,7 @@ export class PerpsController extends BaseController {
593
560
  _PerpsController_rewardsIntegrationService.set(this, void 0);
594
561
  _PerpsController_preloadTimer.set(this, null);
595
562
  _PerpsController_isPreloading.set(this, false);
596
- _PerpsController_marketPreloadQueued.set(this, false);
597
563
  _PerpsController_isPreloadingUserData.set(this, false);
598
- _PerpsController_userPreloadQueued.set(this, false);
599
- _PerpsController_userSnapshotRequests.set(this, new Map());
600
564
  _PerpsController_preloadStateUnsubscribe.set(this, null);
601
565
  _PerpsController_accountChangeUnsubscribe.set(this, null);
602
566
  _PerpsController_previousIsTestnet.set(this, null);
@@ -615,9 +579,7 @@ export class PerpsController extends BaseController {
615
579
  __classPrivateFieldSet(this, _PerpsController_marketDataService, new MarketDataService({
616
580
  ...infrastructure,
617
581
  terminalMarketService: infrastructure.terminalMarketService ??
618
- (infrastructure.terminalApi?.marketDataUrl ||
619
- infrastructure.terminalApiUrl ||
620
- infrastructure.terminalApi?.globalSnapshotUrl
582
+ (infrastructure.terminalApiUrl
621
583
  ? new TerminalMarketService(infrastructure)
622
584
  : undefined),
623
585
  }), "f");
@@ -684,20 +646,24 @@ export class PerpsController extends BaseController {
684
646
  if (activeProvider === 'aggregated') {
685
647
  // Assemble from all registered provider entries
686
648
  const assembled = [];
649
+ let oldestTimestamp = Infinity;
687
650
  for (const providerId of __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getAggregatedCacheProviderIds).call(this, Object.keys(cache))) {
688
651
  const key = buildProviderCacheKey(providerId, this.state.isTestnet);
689
652
  const entry = cache[key];
690
653
  if (!entry || entry.data.length === 0) {
691
654
  continue;
692
655
  }
693
- if (!__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMarketCacheEntryCurrent).call(this, providerId, entry, options)) {
694
- continue;
695
- }
696
- assembled.push(...clonePerpsMarketData(entry.data));
656
+ oldestTimestamp = Math.min(oldestTimestamp, entry.timestamp);
657
+ assembled.push(...entry.data);
697
658
  }
698
659
  if (assembled.length === 0) {
699
660
  return null;
700
661
  }
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
+ }
701
667
  return assembled;
702
668
  }
703
669
  // Single provider mode
@@ -706,10 +672,11 @@ export class PerpsController extends BaseController {
706
672
  if (!entry || entry.data.length === 0) {
707
673
  return null;
708
674
  }
709
- if (!__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMarketCacheEntryCurrent).call(this, activeProvider, entry, options)) {
675
+ if (!options?.skipTTL &&
676
+ Date.now() - entry.timestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
710
677
  return null;
711
678
  }
712
- return clonePerpsMarketData(entry.data);
679
+ return entry.data;
713
680
  }
714
681
  /**
715
682
  * Read cached user data for the currently active provider (or aggregated).
@@ -733,21 +700,18 @@ export class PerpsController extends BaseController {
733
700
  currentAddress = evmAccount?.address ?? null;
734
701
  }
735
702
  catch {
736
- // Account identity is required before account-scoped data can be trusted.
703
+ // Can't determine current account — trust the cache
737
704
  }
738
- if (!currentAddress) {
739
- return null;
740
- }
741
- const selectedAddress = currentAddress;
742
705
  const skipTTL = options?.skipTTL ?? false;
743
- const isValidEntry = (providerId, entry) => {
706
+ const isValidEntry = (entry) => {
744
707
  if (!entry) {
745
708
  return false;
746
709
  }
747
710
  if (!skipTTL && Date.now() - entry.timestamp >= staleCutoff) {
748
711
  return false;
749
712
  }
750
- if (!__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isUserCacheIdentityCurrent).call(this, providerId, entry, selectedAddress)) {
713
+ if (currentAddress &&
714
+ entry.address.toLowerCase() !== currentAddress.toLowerCase()) {
751
715
  return false;
752
716
  }
753
717
  return true;
@@ -759,9 +723,9 @@ export class PerpsController extends BaseController {
759
723
  let defaultAccountState = null;
760
724
  let hasValidEntry = false;
761
725
  for (const providerId of __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getAggregatedCacheProviderIds).call(this, Object.keys(cache))) {
762
- const providerNetworkKey = buildProviderCacheKey(providerId, this.state.isTestnet);
763
- const entry = cache[providerNetworkKey];
764
- if (!isValidEntry(providerId, entry)) {
726
+ const key = buildProviderCacheKey(providerId, this.state.isTestnet);
727
+ const entry = cache[key];
728
+ if (!isValidEntry(entry)) {
765
729
  continue;
766
730
  }
767
731
  hasValidEntry = true;
@@ -782,9 +746,9 @@ export class PerpsController extends BaseController {
782
746
  };
783
747
  }
784
748
  // Single provider mode
785
- const providerNetworkKey = buildProviderCacheKey(activeProvider, this.state.isTestnet);
786
- const entry = cache[providerNetworkKey];
787
- if (!entry || !isValidEntry(activeProvider, entry)) {
749
+ const key = buildProviderCacheKey(activeProvider, this.state.isTestnet);
750
+ const entry = cache[key];
751
+ if (!entry || !isValidEntry(entry)) {
788
752
  return null;
789
753
  }
790
754
  return {
@@ -793,82 +757,6 @@ export class PerpsController extends BaseController {
793
757
  accountState: entry.accountState,
794
758
  };
795
759
  }
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
- }
872
760
  /**
873
761
  * Test-observable accessor for whether a standalone provider is cached.
874
762
  *
@@ -1644,10 +1532,7 @@ export class PerpsController extends BaseController {
1644
1532
  // Fallback to cached standalone provider for pre-initialization discovery
1645
1533
  // TODO: When adding new providers (MYX), consider a provider factory pattern
1646
1534
  const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
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;
1535
+ return provider.getPositions(params);
1651
1536
  }
1652
1537
  const provider = this.getActiveProvider();
1653
1538
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getPositions({
@@ -1708,10 +1593,7 @@ export class PerpsController extends BaseController {
1708
1593
  // For standalone mode, access provider directly without initialization check
1709
1594
  if (params?.standalone && params.userAddress) {
1710
1595
  const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
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;
1596
+ return provider.getOpenOrders(params);
1715
1597
  }
1716
1598
  const provider = this.getActiveProvider();
1717
1599
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getOpenOrders({
@@ -1756,10 +1638,7 @@ export class PerpsController extends BaseController {
1756
1638
  // Use activeProviderInstance if available (respects provider abstraction)
1757
1639
  // Fallback to cached standalone provider for pre-initialization discovery
1758
1640
  const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
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;
1641
+ return provider.getAccountState(params);
1763
1642
  }
1764
1643
  const provider = this.getActiveProvider();
1765
1644
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getAccountState({
@@ -1797,15 +1676,12 @@ export class PerpsController extends BaseController {
1797
1676
  const isMarketAllowed = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_buildMarketAllowedFilter).call(this);
1798
1677
  if (params?.standalone) {
1799
1678
  const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1800
- const operation = __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarkets({
1679
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarkets({
1801
1680
  provider,
1802
1681
  params,
1803
1682
  context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMarkets'),
1804
1683
  isMarketAllowed,
1805
1684
  });
1806
- return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
1807
- ? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
1808
- : operation;
1809
1685
  }
1810
1686
  const provider = this.getActiveProvider();
1811
1687
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarkets({
@@ -1831,26 +1707,19 @@ export class PerpsController extends BaseController {
1831
1707
  * @returns A promise that resolves to the market data.
1832
1708
  */
1833
1709
  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
- });
1838
1710
  if (params?.standalone) {
1839
1711
  const provider = this.activeProviderInstance ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getOrCreateStandaloneProvider).call(this);
1840
- const operation = __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarketDataWithPrices({
1712
+ return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarketDataWithPrices({
1841
1713
  provider,
1842
1714
  params,
1843
- context,
1715
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMarketDataWithPrices'),
1844
1716
  });
1845
- return provider === __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")
1846
- ? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_trackStandaloneProviderOperation).call(this, provider, operation)
1847
- : operation;
1848
1717
  }
1849
1718
  const provider = this.getActiveProvider();
1850
1719
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").getMarketDataWithPrices({
1851
1720
  provider,
1852
1721
  params,
1853
- context,
1722
+ context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'getMarketDataWithPrices'),
1854
1723
  });
1855
1724
  }
1856
1725
  /**
@@ -1871,17 +1740,11 @@ export class PerpsController extends BaseController {
1871
1740
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1872
1741
  /* fire-and-forget */
1873
1742
  });
1874
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
1875
- /* fire-and-forget */
1876
- });
1877
1743
  // Periodic refresh
1878
1744
  __classPrivateFieldSet(this, _PerpsController_preloadTimer, setInterval(() => {
1879
1745
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1880
1746
  /* fire-and-forget */
1881
1747
  });
1882
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
1883
- /* fire-and-forget */
1884
- });
1885
1748
  }, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadRefreshMs)), "f");
1886
1749
  // Watch for isTestnet / hip3ConfigVersion changes
1887
1750
  const handler = (_state, patches) => {
@@ -1910,29 +1773,36 @@ export class PerpsController extends BaseController {
1910
1773
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1911
1774
  /* fire-and-forget */
1912
1775
  });
1913
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
1914
- /* fire-and-forget */
1915
- });
1916
1776
  }
1917
1777
  };
1918
- this.messenger.subscribe('PerpsController:stateChanged', handler);
1778
+ this.messenger.subscribe('PerpsController:stateChange', handler);
1919
1779
  __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, () => {
1920
- this.messenger.unsubscribe('PerpsController:stateChanged', handler);
1780
+ this.messenger.unsubscribe('PerpsController:stateChange', handler);
1921
1781
  }, "f");
1922
1782
  // Watch for selected account changes and selected account group changes.
1923
1783
  const accountChangeHandler = () => {
1924
1784
  const evmAccount = getSelectedEvmAccountFromMessenger(this.messenger);
1925
1785
  const currentAddress = evmAccount?.address ?? null;
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(() => {
1786
+ // If any cached entry belongs to a different account, clear all entries.
1787
+ // Max 4 entries (2 providers × 2 networks) — clearing all is simple and safe.
1788
+ const hasStaleEntries = Object.values(this.state.cachedUserDataByProvider).some((entry) => entry.address.toLowerCase() !== currentAddress?.toLowerCase());
1789
+ if (hasStaleEntries) {
1790
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Account changed, clearing user data cache');
1791
+ this.update((state) => {
1792
+ state.cachedUserDataByProvider = {};
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(() => {
1934
1798
  /* fire-and-forget */
1935
1799
  });
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
+ }
1936
1806
  }
1937
1807
  };
1938
1808
  this.messenger.subscribe('AccountsController:selectedAccountChange', accountChangeHandler);
@@ -1961,8 +1831,6 @@ export class PerpsController extends BaseController {
1961
1831
  }
1962
1832
  __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
1963
1833
  __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
1964
- __classPrivateFieldSet(this, _PerpsController_marketPreloadQueued, false, "f");
1965
- __classPrivateFieldSet(this, _PerpsController_userPreloadQueued, false, "f");
1966
1834
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this).catch(() => {
1967
1835
  /* fire-and-forget to preserve sync signature */
1968
1836
  });
@@ -2223,9 +2091,6 @@ export class PerpsController extends BaseController {
2223
2091
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
2224
2092
  /* fire-and-forget */
2225
2093
  });
2226
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
2227
- /* fire-and-forget */
2228
- });
2229
2094
  }
2230
2095
  }
2231
2096
  }
@@ -2335,9 +2200,6 @@ export class PerpsController extends BaseController {
2335
2200
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
2336
2201
  /* fire-and-forget */
2337
2202
  });
2338
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performUserDataPreload).call(this).catch(() => {
2339
- /* fire-and-forget */
2340
- });
2341
2203
  }
2342
2204
  }
2343
2205
  }
@@ -3400,7 +3262,7 @@ export class PerpsController extends BaseController {
3400
3262
  return __classPrivateFieldGet(this, _PerpsController_isReinitializing, "f");
3401
3263
  }
3402
3264
  }
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() {
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() {
3404
3266
  const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx;
3405
3267
  // Local env-var override (MM_PERPS_MYX_PROVIDER_ENABLED) always wins —
3406
3268
  // matches the UI selector (resolvePerpsMyxProviderEnabled) so controller
@@ -3453,96 +3315,6 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
3453
3315
  }
3454
3316
  }
3455
3317
  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;
3546
3318
  }, _PerpsController_getOrCreateStandaloneProvider = function _PerpsController_getOrCreateStandaloneProvider() {
3547
3319
  const currentIsTestnet = this.state.isTestnet;
3548
3320
  const currentHip3Version = this.state.hip3ConfigVersion ?? 0;
@@ -3551,13 +3323,10 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
3551
3323
  __classPrivateFieldGet(this, _PerpsController_standaloneProviderHip3Version, "f") === currentHip3Version) {
3552
3324
  return __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
3553
3325
  }
3554
- // Stale or missing — retire the old provider after active operations finish.
3326
+ // Stale or missing — tear down old one (fire-and-forget)
3555
3327
  if (__classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")) {
3556
3328
  const old = __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
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(() => {
3329
+ Promise.resolve(old.disconnect()).catch(() => {
3561
3330
  /* best-effort */
3562
3331
  });
3563
3332
  }
@@ -3577,45 +3346,24 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
3577
3346
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
3578
3347
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
3579
3348
  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
- }
3605
3349
  }, _PerpsController_cleanupStandaloneProvider =
3606
3350
  /**
3607
3351
  * Disconnect and discard the cached standalone provider (if any).
3608
3352
  * Best-effort — errors are silently caught.
3609
3353
  */
3610
3354
  async function _PerpsController_cleanupStandaloneProvider() {
3611
- const provider = __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f");
3612
- if (!provider) {
3355
+ if (!__classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f")) {
3613
3356
  return;
3614
3357
  }
3358
+ try {
3359
+ await __classPrivateFieldGet(this, _PerpsController_standaloneProvider, "f").disconnect();
3360
+ }
3361
+ catch {
3362
+ /* best-effort */
3363
+ }
3615
3364
  __classPrivateFieldSet(this, _PerpsController_standaloneProvider, null, "f");
3616
3365
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, null, "f");
3617
3366
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, null, "f");
3618
- await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_retireStandaloneProvider).call(this, provider);
3619
3367
  }, _PerpsController_getMetrics = function _PerpsController_getMetrics() {
3620
3368
  return __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.metrics;
3621
3369
  }, _PerpsController_findNetworkClientIdForChain = function _PerpsController_findNetworkClientIdForChain(chainId) {
@@ -3949,60 +3697,6 @@ async function _PerpsController_performInitialization() {
3949
3697
  __classPrivateFieldGet(this, _PerpsController_tradingService, "f").setControllerDependencies({
3950
3698
  rewardsIntegrationService: __classPrivateFieldGet(this, _PerpsController_rewardsIntegrationService, "f"),
3951
3699
  });
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);
4006
3700
  }, _PerpsController_hydrateCacheFromDiskSync = function _PerpsController_hydrateCacheFromDiskSync() {
4007
3701
  const { marketUpdates, userUpdates, stats } = hydrateFromDiskSync(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.diskCache, this.state.cachedMarketDataByProvider, this.state.cachedUserDataByProvider, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs));
4008
3702
  const hasMarketUpdates = Object.keys(marketUpdates).length > 0;
@@ -4023,40 +3717,12 @@ async function _PerpsController_performInitialization() {
4023
3717
  orders: stats.userOrders,
4024
3718
  duration_ms: stats.durationMs,
4025
3719
  });
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");
4053
3720
  }, _PerpsController_performMarketDataPreload =
4054
3721
  /**
4055
3722
  * Perform a single market data preload (best-effort, no throw).
4056
3723
  */
4057
3724
  async function _PerpsController_performMarketDataPreload() {
4058
3725
  if (__classPrivateFieldGet(this, _PerpsController_isPreloading, "f")) {
4059
- __classPrivateFieldSet(this, _PerpsController_marketPreloadQueued, true, "f");
4060
3726
  return;
4061
3727
  }
4062
3728
  // Skip preloading during provider/network reinitialisation.
@@ -4071,16 +3737,9 @@ async function _PerpsController_performMarketDataPreload() {
4071
3737
  ? this.state.activeProvider // includes 'aggregated'
4072
3738
  : 'hyperliquid';
4073
3739
  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);
4080
3740
  const now = Date.now();
4081
3741
  const existingEntry = this.state.cachedMarketDataByProvider[cacheKey];
4082
3742
  if (existingEntry &&
4083
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMarketCacheEntryCurrent).call(this, actualProviderId, existingEntry) &&
4084
3743
  now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
4085
3744
  return;
4086
3745
  }
@@ -4105,32 +3764,8 @@ async function _PerpsController_performMarketDataPreload() {
4105
3764
  duration_ms: Math.round(performance.now() - preloadStart),
4106
3765
  markets: data.length,
4107
3766
  });
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
- }
4118
3767
  // Store under per-provider key(s)
4119
3768
  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
- : {};
4134
3769
  const marketDiskEntries = [];
4135
3770
  if (this.state.activeProvider === 'aggregated' &&
4136
3771
  this.activeProviderInstance) {
@@ -4177,7 +3812,6 @@ async function _PerpsController_performMarketDataPreload() {
4177
3812
  state.cachedMarketDataByProvider[cacheKey] = {
4178
3813
  data,
4179
3814
  timestamp: ts,
4180
- ...snapshotCacheIdentity,
4181
3815
  };
4182
3816
  });
4183
3817
  }
@@ -4187,6 +3821,10 @@ async function _PerpsController_performMarketDataPreload() {
4187
3821
  });
4188
3822
  traceData = { success: true, marketCount: data.length };
4189
3823
  __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
+ });
4190
3828
  }
4191
3829
  catch (error) {
4192
3830
  traceData = {
@@ -4205,12 +3843,6 @@ async function _PerpsController_performMarketDataPreload() {
4205
3843
  data: traceData,
4206
3844
  });
4207
3845
  __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
- }
4214
3846
  }
4215
3847
  }, _PerpsController_performUserDataPreload =
4216
3848
  /**
@@ -4219,10 +3851,6 @@ async function _PerpsController_performMarketDataPreload() {
4219
3851
  */
4220
3852
  async function _PerpsController_performUserDataPreload() {
4221
3853
  if (__classPrivateFieldGet(this, _PerpsController_isPreloadingUserData, "f")) {
4222
- __classPrivateFieldSet(this, _PerpsController_userPreloadQueued, true, "f");
4223
- return;
4224
- }
4225
- if (__classPrivateFieldGet(this, _PerpsController_isReinitializing, "f")) {
4226
3854
  return;
4227
3855
  }
4228
3856
  // Get current user address
@@ -4231,54 +3859,21 @@ async function _PerpsController_performUserDataPreload() {
4231
3859
  return;
4232
3860
  }
4233
3861
  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
- };
4251
3862
  // Determine actual provider (same logic as market preload)
4252
- const actualProviderId = activeProviderInstance
4253
- ? activeProvider // includes 'aggregated'
3863
+ const actualProviderId = this.activeProviderInstance
3864
+ ? this.state.activeProvider // includes 'aggregated'
4254
3865
  : 'hyperliquid';
4255
- const providerNetworkKey = buildProviderCacheKey(actualProviderId, isTestnet);
3866
+ const userCacheKey = buildProviderCacheKey(actualProviderId, this.state.isTestnet);
4256
3867
  // Skip if cache is fresh and for same account
4257
3868
  const now = Date.now();
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 &&
3869
+ const existingEntry = this.state.cachedUserDataByProvider[userCacheKey];
3870
+ if (existingEntry?.address === userAddress &&
4277
3871
  now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
4278
3872
  return;
4279
3873
  }
4280
- if (hasMatchingCache &&
4281
- this.getWebSocketConnectionState() === WebSocketConnectionState.Connected) {
3874
+ // Skip standalone REST polling when WebSocket is connected — live data is streaming
3875
+ if (this.getWebSocketConnectionState() === WebSocketConnectionState.Connected) {
3876
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Skipping user data preload — WebSocket connected');
4282
3877
  return;
4283
3878
  }
4284
3879
  __classPrivateFieldSet(this, _PerpsController_isPreloadingUserData, true, "f");
@@ -4291,38 +3886,21 @@ async function _PerpsController_performUserDataPreload() {
4291
3886
  id: traceId,
4292
3887
  op: PerpsTraceOperations.Operation,
4293
3888
  tags: {
4294
- provider: activeProvider,
4295
- isTestnet,
3889
+ provider: this.state.activeProvider,
3890
+ isTestnet: this.state.isTestnet,
4296
3891
  },
4297
3892
  data: { userAddress },
4298
3893
  });
4299
3894
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching user data in background', {
4300
3895
  userAddress,
4301
3896
  });
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
- }
4317
3897
  const [positions, orders, accountState] = await Promise.all([
4318
3898
  this.getPositions({ standalone: true, userAddress }),
4319
3899
  this.getOpenOrders({ standalone: true, userAddress }),
4320
3900
  this.getAccountState({ standalone: true, userAddress }),
4321
3901
  ]);
4322
- if (!isCurrent()) {
4323
- throw new Error('User data preload context changed');
4324
- }
4325
- if (activeProvider === 'aggregated' && activeProviderInstance) {
3902
+ if (this.state.activeProvider === 'aggregated' &&
3903
+ this.activeProviderInstance) {
4326
3904
  // Split by providerId and write one cache entry per provider key
4327
3905
  // (mirrors the market-data preload pattern at ~line 2976)
4328
3906
  const ts = Date.now();
@@ -4344,22 +3922,26 @@ async function _PerpsController_performUserDataPreload() {
4344
3922
  }
4345
3923
  // AccountState — assign to its provider bucket
4346
3924
  ensureBucket(accountState.providerId ?? fallbackProviderId).accountState = accountState;
3925
+ const diskEntries = [];
4347
3926
  this.update((state) => {
4348
3927
  for (const [pid, data] of byProvider) {
4349
- const key = buildProviderCacheKey(pid, isTestnet);
3928
+ const key = buildProviderCacheKey(pid, this.state.isTestnet);
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
+ });
4350
3937
  state.cachedUserDataByProvider[key] = {
4351
3938
  ...data,
4352
3939
  timestamp: ts,
4353
3940
  address: userAddress,
4354
- ...(pid === 'hyperliquid' &&
4355
- hyperliquidDexes && {
4356
- hip3ConfigVersion,
4357
- dexes: hyperliquidDexes,
4358
- }),
4359
3941
  };
4360
3942
  }
4361
3943
  // Write aggregated sentinel so the staleness guard sees it
4362
- state.cachedUserDataByProvider[providerNetworkKey] = {
3944
+ state.cachedUserDataByProvider[userCacheKey] = {
4363
3945
  positions: [],
4364
3946
  orders: [],
4365
3947
  accountState: null,
@@ -4367,26 +3949,30 @@ async function _PerpsController_performUserDataPreload() {
4367
3949
  address: userAddress,
4368
3950
  };
4369
3951
  });
4370
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_persistUserCacheToDisk).call(this);
3952
+ persistUserEntriesToDisk(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.diskCache, diskEntries);
4371
3953
  }
4372
3954
  else {
4373
3955
  // Single provider — store directly under its key
4374
3956
  const ts = Date.now();
4375
3957
  this.update((state) => {
4376
- state.cachedUserDataByProvider[providerNetworkKey] = {
3958
+ state.cachedUserDataByProvider[userCacheKey] = {
4377
3959
  positions,
4378
3960
  orders,
4379
3961
  accountState,
4380
3962
  timestamp: ts,
4381
3963
  address: userAddress,
4382
- ...(actualProviderId === 'hyperliquid' &&
4383
- hyperliquidDexes && {
4384
- hip3ConfigVersion,
4385
- dexes: hyperliquidDexes,
4386
- }),
4387
3964
  };
4388
3965
  });
4389
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_persistUserCacheToDisk).call(this);
3966
+ persistUserEntriesToDisk(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.diskCache, [
3967
+ {
3968
+ providerNetworkKey: userCacheKey,
3969
+ address: userAddress,
3970
+ positions,
3971
+ orders,
3972
+ accountState,
3973
+ timestamp: ts,
3974
+ },
3975
+ ]);
4390
3976
  }
4391
3977
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
4392
3978
  positionCount: positions.length,
@@ -4417,12 +4003,6 @@ async function _PerpsController_performUserDataPreload() {
4417
4003
  data: traceData,
4418
4004
  });
4419
4005
  __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
- }
4426
4006
  }
4427
4007
  }, _PerpsController_persistWatchlistToRemote =
4428
4008
  /**