@metamask-previews/perps-controller 1.3.0-preview-17c76be24 → 1.3.0-preview-3ce0062c4

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 (158) hide show
  1. package/CHANGELOG.md +0 -9
  2. package/dist/PerpsController.cjs +183 -488
  3. package/dist/PerpsController.cjs.map +1 -1
  4. package/dist/PerpsController.d.cts +131 -91
  5. package/dist/PerpsController.d.cts.map +1 -1
  6. package/dist/PerpsController.d.mts +131 -91
  7. package/dist/PerpsController.d.mts.map +1 -1
  8. package/dist/PerpsController.mjs +182 -485
  9. package/dist/PerpsController.mjs.map +1 -1
  10. package/dist/constants/eventNames.cjs +0 -26
  11. package/dist/constants/eventNames.cjs.map +1 -1
  12. package/dist/constants/eventNames.d.cts +0 -19
  13. package/dist/constants/eventNames.d.cts.map +1 -1
  14. package/dist/constants/eventNames.d.mts +0 -19
  15. package/dist/constants/eventNames.d.mts.map +1 -1
  16. package/dist/constants/eventNames.mjs +0 -26
  17. package/dist/constants/eventNames.mjs.map +1 -1
  18. package/dist/constants/hyperLiquidConfig.cjs +4 -24
  19. package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
  20. package/dist/constants/hyperLiquidConfig.d.cts +3 -8
  21. package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
  22. package/dist/constants/hyperLiquidConfig.d.mts +3 -8
  23. package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
  24. package/dist/constants/hyperLiquidConfig.mjs +3 -23
  25. package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
  26. package/dist/constants/myxConfig.cjs +51 -75
  27. package/dist/constants/myxConfig.cjs.map +1 -1
  28. package/dist/constants/myxConfig.d.cts +19 -58
  29. package/dist/constants/myxConfig.d.cts.map +1 -1
  30. package/dist/constants/myxConfig.d.mts +19 -58
  31. package/dist/constants/myxConfig.d.mts.map +1 -1
  32. package/dist/constants/myxConfig.mjs +50 -74
  33. package/dist/constants/myxConfig.mjs.map +1 -1
  34. package/dist/constants/perpsConfig.cjs +2 -6
  35. package/dist/constants/perpsConfig.cjs.map +1 -1
  36. package/dist/constants/perpsConfig.d.cts +1 -5
  37. package/dist/constants/perpsConfig.d.cts.map +1 -1
  38. package/dist/constants/perpsConfig.d.mts +1 -5
  39. package/dist/constants/perpsConfig.d.mts.map +1 -1
  40. package/dist/constants/perpsConfig.mjs +1 -5
  41. package/dist/constants/perpsConfig.mjs.map +1 -1
  42. package/dist/index.cjs +25 -243
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +5 -48
  45. package/dist/index.d.cts.map +1 -1
  46. package/dist/index.d.mts +5 -48
  47. package/dist/index.d.mts.map +1 -1
  48. package/dist/index.mjs +10 -36
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/providers/AggregatedPerpsProvider.cjs +0 -24
  51. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
  52. package/dist/providers/AggregatedPerpsProvider.d.cts +0 -4
  53. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
  54. package/dist/providers/AggregatedPerpsProvider.d.mts +0 -4
  55. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
  56. package/dist/providers/AggregatedPerpsProvider.mjs +0 -24
  57. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
  58. package/dist/providers/HyperLiquidProvider.cjs +154 -470
  59. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  60. package/dist/providers/HyperLiquidProvider.d.cts +2 -11
  61. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  62. package/dist/providers/HyperLiquidProvider.d.mts +2 -11
  63. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  64. package/dist/providers/HyperLiquidProvider.mjs +155 -471
  65. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  66. package/dist/selectors.cjs +1 -1
  67. package/dist/selectors.cjs.map +1 -1
  68. package/dist/selectors.mjs +1 -1
  69. package/dist/selectors.mjs.map +1 -1
  70. package/dist/services/AccountService.cjs +1 -1
  71. package/dist/services/AccountService.cjs.map +1 -1
  72. package/dist/services/AccountService.d.cts.map +1 -1
  73. package/dist/services/AccountService.d.mts.map +1 -1
  74. package/dist/services/AccountService.mjs +2 -2
  75. package/dist/services/AccountService.mjs.map +1 -1
  76. package/dist/services/DepositService.cjs +1 -2
  77. package/dist/services/DepositService.cjs.map +1 -1
  78. package/dist/services/DepositService.d.cts.map +1 -1
  79. package/dist/services/DepositService.d.mts.map +1 -1
  80. package/dist/services/DepositService.mjs +1 -2
  81. package/dist/services/DepositService.mjs.map +1 -1
  82. package/dist/services/EligibilityService.cjs +103 -8
  83. package/dist/services/EligibilityService.cjs.map +1 -1
  84. package/dist/services/EligibilityService.d.cts +15 -4
  85. package/dist/services/EligibilityService.d.cts.map +1 -1
  86. package/dist/services/EligibilityService.d.mts +15 -4
  87. package/dist/services/EligibilityService.d.mts.map +1 -1
  88. package/dist/services/EligibilityService.mjs +103 -8
  89. package/dist/services/EligibilityService.mjs.map +1 -1
  90. package/dist/services/HyperLiquidSubscriptionService.cjs +46 -252
  91. package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
  92. package/dist/services/HyperLiquidSubscriptionService.d.cts +0 -1
  93. package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
  94. package/dist/services/HyperLiquidSubscriptionService.d.mts +0 -1
  95. package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
  96. package/dist/services/HyperLiquidSubscriptionService.mjs +46 -252
  97. package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
  98. package/dist/services/MarketDataService.cjs +4 -2
  99. package/dist/services/MarketDataService.cjs.map +1 -1
  100. package/dist/services/MarketDataService.d.cts.map +1 -1
  101. package/dist/services/MarketDataService.d.mts.map +1 -1
  102. package/dist/services/MarketDataService.mjs +4 -2
  103. package/dist/services/MarketDataService.mjs.map +1 -1
  104. package/dist/services/TradingService.cjs +6 -72
  105. package/dist/services/TradingService.cjs.map +1 -1
  106. package/dist/services/TradingService.d.cts.map +1 -1
  107. package/dist/services/TradingService.d.mts.map +1 -1
  108. package/dist/services/TradingService.mjs +6 -72
  109. package/dist/services/TradingService.mjs.map +1 -1
  110. package/dist/types/index.cjs.map +1 -1
  111. package/dist/types/index.d.cts +3 -51
  112. package/dist/types/index.d.cts.map +1 -1
  113. package/dist/types/index.d.mts +3 -51
  114. package/dist/types/index.d.mts.map +1 -1
  115. package/dist/types/index.mjs.map +1 -1
  116. package/dist/types/messenger.cjs.map +1 -1
  117. package/dist/types/messenger.d.cts +1 -2
  118. package/dist/types/messenger.d.cts.map +1 -1
  119. package/dist/types/messenger.d.mts +1 -2
  120. package/dist/types/messenger.d.mts.map +1 -1
  121. package/dist/types/messenger.mjs.map +1 -1
  122. package/dist/types/myx-types.cjs +3 -19
  123. package/dist/types/myx-types.cjs.map +1 -1
  124. package/dist/types/myx-types.d.cts +2 -33
  125. package/dist/types/myx-types.d.cts.map +1 -1
  126. package/dist/types/myx-types.d.mts +2 -33
  127. package/dist/types/myx-types.d.mts.map +1 -1
  128. package/dist/types/myx-types.mjs +2 -6
  129. package/dist/types/myx-types.mjs.map +1 -1
  130. package/dist/types/perps-types.cjs +0 -3
  131. package/dist/types/perps-types.cjs.map +1 -1
  132. package/dist/types/perps-types.d.cts +3 -3
  133. package/dist/types/perps-types.d.cts.map +1 -1
  134. package/dist/types/perps-types.d.mts +3 -3
  135. package/dist/types/perps-types.d.mts.map +1 -1
  136. package/dist/types/perps-types.mjs +0 -3
  137. package/dist/types/perps-types.mjs.map +1 -1
  138. package/dist/utils/accountUtils.cjs.map +1 -1
  139. package/dist/utils/accountUtils.d.cts.map +1 -1
  140. package/dist/utils/accountUtils.d.mts.map +1 -1
  141. package/dist/utils/accountUtils.mjs.map +1 -1
  142. package/dist/utils/myxAdapter.cjs +15 -360
  143. package/dist/utils/myxAdapter.cjs.map +1 -1
  144. package/dist/utils/myxAdapter.d.cts +7 -94
  145. package/dist/utils/myxAdapter.d.cts.map +1 -1
  146. package/dist/utils/myxAdapter.d.mts +7 -94
  147. package/dist/utils/myxAdapter.d.mts.map +1 -1
  148. package/dist/utils/myxAdapter.mjs +16 -351
  149. package/dist/utils/myxAdapter.mjs.map +1 -1
  150. package/package.json +3 -5
  151. package/dist/PerpsController-method-action-types.cjs +0 -3
  152. package/dist/PerpsController-method-action-types.cjs.map +0 -1
  153. package/dist/PerpsController-method-action-types.d.cts +0 -147
  154. package/dist/PerpsController-method-action-types.d.cts.map +0 -1
  155. package/dist/PerpsController-method-action-types.d.mts +0 -147
  156. package/dist/PerpsController-method-action-types.d.mts.map +0 -1
  157. package/dist/PerpsController-method-action-types.mjs +0 -2
  158. package/dist/PerpsController-method-action-types.mjs.map +0 -1
@@ -10,9 +10,9 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
12
  };
13
- var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_myxRegistrationPromise, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_handlersRegistered, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_eligibilityCheckDeferred, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_marketCacheKey, _PerpsController_providerIsTestnet, _PerpsController_getOrCreateStandaloneProvider, _PerpsController_cleanupStandaloneProvider, _PerpsController_getMetrics, _PerpsController_findNetworkClientIdForChain, _PerpsController_submitTransaction, _PerpsController_migrateRequestsIfNeeded, _PerpsController_withStreamPause, _PerpsController_performInitialization, _PerpsController_createProviders, _PerpsController_assignActiveProvider, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_isPreloadingUserData, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload;
13
+ var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_blockedRegionListVersion, _PerpsController_hip3Enabled, _PerpsController_hip3AllowlistMarkets, _PerpsController_hip3BlocklistMarkets, _PerpsController_hip3ConfigSource, _PerpsController_isMYXProviderEnabled, _PerpsController_standaloneProvider, _PerpsController_standaloneProviderIsTestnet, _PerpsController_standaloneProviderHip3Version, _PerpsController_eligibilityCheckDeferred, _PerpsController_options, _PerpsController_tradingService, _PerpsController_marketDataService, _PerpsController_accountService, _PerpsController_eligibilityService, _PerpsController_dataLakeService, _PerpsController_depositService, _PerpsController_featureFlagConfigurationService, _PerpsController_rewardsIntegrationService, _PerpsController_logError, _PerpsController_debugLog, _PerpsController_getOrCreateStandaloneProvider, _PerpsController_cleanupStandaloneProvider, _PerpsController_getMetrics, _PerpsController_findNetworkClientIdForChain, _PerpsController_submitTransaction, _PerpsController_migrateRequestsIfNeeded, _PerpsController_withStreamPause, _PerpsController_performInitialization, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_isPreloadingUserData, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.PerpsController = exports.getDefaultPerpsControllerState = exports.InitializationState = exports.PERPS_ERROR_CODES = exports.resolveMyxAuthConfig = exports.firstNonEmpty = void 0;
15
+ exports.PerpsController = exports.getDefaultPerpsControllerState = exports.InitializationState = exports.PERPS_ERROR_CODES = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
17
17
  const controller_utils_1 = require("@metamask/controller-utils");
18
18
  const uuid_1 = require("uuid");
@@ -37,39 +37,6 @@ const types_1 = require("./types/index.cjs");
37
37
  const accountUtils_1 = require("./utils/accountUtils.cjs");
38
38
  const errorUtils_1 = require("./utils/errorUtils.cjs");
39
39
  const wait_1 = require("./utils/wait.cjs");
40
- /**
41
- * Returns the first non-empty string from the given values.
42
- * Env vars default to '' (not null/undefined), so ?? wouldn't fall through.
43
- *
44
- * @param vals - String values to check in order.
45
- * @returns The first non-empty string, or '' if all are empty/undefined.
46
- */
47
- function firstNonEmpty(...vals) {
48
- return (vals.find((val) => val !== null && val !== undefined && val !== '') ?? '');
49
- }
50
- exports.firstNonEmpty = firstNonEmpty;
51
- /**
52
- * Resolves MYX auth config from provider credentials, handling
53
- * testnet/mainnet fallback logic.
54
- *
55
- * @param myx - MYX provider credentials.
56
- * @param isTestnet - Whether the controller is in testnet mode.
57
- * @returns Resolved appId, apiSecret, and brokerAddress.
58
- */
59
- function resolveMyxAuthConfig(myx, isTestnet) {
60
- return {
61
- appId: isTestnet
62
- ? (myx.appIdTestnet ?? '')
63
- : firstNonEmpty(myx.appIdMainnet, myx.appIdTestnet),
64
- apiSecret: isTestnet
65
- ? (myx.apiSecretTestnet ?? '')
66
- : firstNonEmpty(myx.apiSecretMainnet, myx.apiSecretTestnet),
67
- brokerAddress: isTestnet
68
- ? (myx.brokerAddressTestnet ?? '')
69
- : firstNonEmpty(myx.brokerAddressMainnet, myx.brokerAddressTestnet),
70
- };
71
- }
72
- exports.resolveMyxAuthConfig = resolveMyxAuthConfig;
73
40
  // Re-export error codes from separate file to avoid circular dependencies
74
41
  var perpsErrorCodes_2 = require("./perpsErrorCodes.cjs");
75
42
  Object.defineProperty(exports, "PERPS_ERROR_CODES", { enumerable: true, get: function () { return perpsErrorCodes_2.PERPS_ERROR_CODES; } });
@@ -138,8 +105,13 @@ const getDefaultPerpsControllerState = () => ({
138
105
  },
139
106
  hip3ConfigVersion: 0,
140
107
  selectedPaymentToken: null,
141
- cachedMarketDataByProvider: {},
142
- cachedUserDataByProvider: {},
108
+ cachedMarketData: null,
109
+ cachedMarketDataTimestamp: 0,
110
+ cachedPositions: null,
111
+ cachedOrders: null,
112
+ cachedAccountState: null,
113
+ cachedUserDataTimestamp: 0,
114
+ cachedUserDataAddress: null,
143
115
  });
144
116
  exports.getDefaultPerpsControllerState = getDefaultPerpsControllerState;
145
117
  /**
@@ -296,18 +268,48 @@ const metadata = {
296
268
  includeInDebugSnapshot: false,
297
269
  usedInUi: true,
298
270
  },
299
- cachedMarketDataByProvider: {
271
+ cachedMarketData: {
300
272
  includeInStateLogs: false,
301
273
  persist: false,
302
274
  includeInDebugSnapshot: false,
303
275
  usedInUi: true,
304
276
  },
305
- cachedUserDataByProvider: {
277
+ cachedMarketDataTimestamp: {
278
+ includeInStateLogs: false,
279
+ persist: false,
280
+ includeInDebugSnapshot: false,
281
+ usedInUi: false,
282
+ },
283
+ cachedPositions: {
306
284
  includeInStateLogs: false,
307
285
  persist: false,
308
286
  includeInDebugSnapshot: false,
309
287
  usedInUi: true,
310
288
  },
289
+ cachedOrders: {
290
+ includeInStateLogs: false,
291
+ persist: false,
292
+ includeInDebugSnapshot: false,
293
+ usedInUi: true,
294
+ },
295
+ cachedAccountState: {
296
+ includeInStateLogs: false,
297
+ persist: false,
298
+ includeInDebugSnapshot: false,
299
+ usedInUi: true,
300
+ },
301
+ cachedUserDataTimestamp: {
302
+ includeInStateLogs: false,
303
+ persist: false,
304
+ includeInDebugSnapshot: false,
305
+ usedInUi: false,
306
+ },
307
+ cachedUserDataAddress: {
308
+ includeInStateLogs: false,
309
+ persist: false,
310
+ includeInDebugSnapshot: false,
311
+ usedInUi: false,
312
+ },
311
313
  };
312
314
  const MESSENGER_EXPOSED_METHODS = [
313
315
  'placeOrder',
@@ -367,8 +369,6 @@ class PerpsController extends base_controller_1.BaseController {
367
369
  this.isInitialized = false;
368
370
  _PerpsController_initializationPromise.set(this, null);
369
371
  _PerpsController_isReinitializing.set(this, false);
370
- /** Tracks the async MYX dynamic import so performInitialization can await it. */
371
- _PerpsController_myxRegistrationPromise.set(this, null);
372
372
  this.blockedRegionList = {
373
373
  list: [],
374
374
  source: 'fallback',
@@ -397,7 +397,6 @@ class PerpsController extends base_controller_1.BaseController {
397
397
  * connections) on every standalone call from the preload cycle.
398
398
  */
399
399
  _PerpsController_standaloneProvider.set(this, null);
400
- _PerpsController_handlersRegistered.set(this, false);
401
400
  _PerpsController_standaloneProviderIsTestnet.set(this, null);
402
401
  _PerpsController_standaloneProviderHip3Version.set(this, null);
403
402
  _PerpsController_eligibilityCheckDeferred.set(this, void 0);
@@ -473,122 +472,7 @@ class PerpsController extends base_controller_1.BaseController {
473
472
  this.providers = new Map();
474
473
  // Migrate old persisted data without accountAddress
475
474
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_migrateRequestsIfNeeded).call(this);
476
- }
477
- /**
478
- * Read cached market data for the currently active provider (or aggregated).
479
- * Returns null when no valid cache exists or when cache has expired.
480
- *
481
- * @returns The cached market data array, or null if no valid cache.
482
- */
483
- getCachedMarketDataForActiveProvider() {
484
- const { activeProvider } = this.state;
485
- const cache = this.state.cachedMarketDataByProvider;
486
- if (activeProvider === 'aggregated') {
487
- // Assemble from all registered provider entries
488
- const assembled = [];
489
- let oldestTimestamp = Infinity;
490
- for (const [providerId] of this.providers) {
491
- const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, providerId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, providerId));
492
- const entry = cache[key];
493
- if (!entry || entry.data.length === 0) {
494
- continue;
495
- }
496
- oldestTimestamp = Math.min(oldestTimestamp, entry.timestamp);
497
- assembled.push(...entry.data);
498
- }
499
- if (assembled.length === 0) {
500
- return null;
501
- }
502
- // Check TTL against the oldest entry
503
- if (Date.now() - oldestTimestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
504
- return null;
505
- }
506
- return assembled;
507
- }
508
- // Single provider mode
509
- const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, activeProvider, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, activeProvider));
510
- const entry = cache[key];
511
- if (!entry || entry.data.length === 0) {
512
- return null;
513
- }
514
- if (Date.now() - entry.timestamp > __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 10) {
515
- return null;
516
- }
517
- return entry.data;
518
- }
519
- /**
520
- * Read cached user data for the currently active provider (or aggregated).
521
- * Returns null when no valid cache exists, cache has expired, or address
522
- * does not match the currently selected EVM account.
523
- *
524
- * @returns The cached user data, or null if no valid cache.
525
- */
526
- getCachedUserDataForActiveProvider() {
527
- const { activeProvider } = this.state;
528
- const cache = this.state.cachedUserDataByProvider;
529
- const staleCutoff = __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs) * 2; // 60s
530
- // Get current user address for validation
531
- let currentAddress = null;
532
- try {
533
- const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
534
- currentAddress = evmAccount?.address ?? null;
535
- }
536
- catch {
537
- // Can't determine current account — trust the cache
538
- }
539
- const isValidEntry = (entry) => {
540
- if (!entry) {
541
- return false;
542
- }
543
- if (Date.now() - entry.timestamp >= staleCutoff) {
544
- return false;
545
- }
546
- if (currentAddress &&
547
- entry.address.toLowerCase() !== currentAddress.toLowerCase()) {
548
- return false;
549
- }
550
- return true;
551
- };
552
- if (activeProvider === 'aggregated') {
553
- // Assemble from all registered provider entries
554
- const allPositions = [];
555
- const allOrders = [];
556
- let defaultAccountState = null;
557
- let hasValidEntry = false;
558
- for (const [providerId] of this.providers) {
559
- const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, providerId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, providerId));
560
- const entry = cache[key];
561
- if (!isValidEntry(entry)) {
562
- continue;
563
- }
564
- hasValidEntry = true;
565
- allPositions.push(...entry.positions);
566
- allOrders.push(...entry.orders);
567
- // AccountState from default provider (hyperliquid)
568
- if (providerId === 'hyperliquid') {
569
- defaultAccountState = entry.accountState;
570
- }
571
- }
572
- if (!hasValidEntry) {
573
- return null;
574
- }
575
- return {
576
- positions: allPositions,
577
- orders: allOrders,
578
- accountState: defaultAccountState,
579
- };
580
- }
581
- // Single provider mode
582
- const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, activeProvider, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, activeProvider));
583
- const entry = cache[key];
584
- if (!entry || !isValidEntry(entry)) {
585
- return null;
586
- }
587
- return {
588
- positions: entry.positions,
589
- orders: entry.orders,
590
- accountState: entry.accountState,
591
- };
475
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
592
476
  }
593
477
  /**
594
478
  * Test-observable accessor for whether a standalone provider is cached.
@@ -668,10 +552,6 @@ class PerpsController extends base_controller_1.BaseController {
668
552
  * @returns A promise that resolves when the operation completes.
669
553
  */
670
554
  async init() {
671
- if (!__classPrivateFieldGet(this, _PerpsController_handlersRegistered, "f")) {
672
- this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
673
- __classPrivateFieldSet(this, _PerpsController_handlersRegistered, true, "f");
674
- }
675
555
  if (this.isInitialized) {
676
556
  return undefined;
677
557
  }
@@ -681,46 +561,6 @@ class PerpsController extends base_controller_1.BaseController {
681
561
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
682
562
  return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
683
563
  }
684
- /**
685
- * Registers the MYX provider after dynamic import resolves.
686
- *
687
- * Extracted from the import().then() callback so it can be tested directly
688
- * (Jest cannot resolve dynamic imports without --experimental-vm-modules).
689
- *
690
- * @param MYXProvider - Constructor class for the MYX provider.
691
- */
692
- registerMYXProvider(MYXProvider) {
693
- const myxIsTestnet = perpsConfig_1.PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet;
694
- const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx ?? {};
695
- const myxAuthConfig = resolveMyxAuthConfig(myx, myxIsTestnet);
696
- const myxProvider = new MYXProvider({
697
- isTestnet: myxIsTestnet,
698
- platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
699
- messenger: this.messenger,
700
- myxAuthConfig,
701
- });
702
- this.providers.set('myx', myxProvider);
703
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider registered', {
704
- isTestnet: myxIsTestnet,
705
- });
706
- }
707
- /**
708
- * Handles errors from the MYX dynamic import.
709
- *
710
- * Module-not-found errors are expected (extension doesn't ship MYX) → debug log.
711
- * Other errors indicate constructor/config problems → Sentry via logError.
712
- *
713
- * @param error - The caught error from the dynamic import or constructor.
714
- */
715
- handleMYXImportError(error) {
716
- const isModuleError = error?.code === 'MODULE_NOT_FOUND';
717
- if (isModuleError) {
718
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider module not available, skipping registration');
719
- }
720
- else {
721
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, error instanceof Error ? error : new Error(String(error)), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'createProviders.myx'));
722
- }
723
- }
724
564
  /**
725
565
  * Get the currently active provider.
726
566
  * In aggregated mode, returns AggregatedPerpsProvider which routes to underlying providers.
@@ -981,14 +821,6 @@ class PerpsController extends base_controller_1.BaseController {
981
821
  origin: controller_utils_1.ORIGIN_METAMASK,
982
822
  skipInitialGasEstimate: true,
983
823
  };
984
- __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.addBreadcrumb({
985
- category: 'perps',
986
- message: 'Deposit action started',
987
- level: 'info',
988
- data: {
989
- place_order_after_deposit: placeOrder === true,
990
- },
991
- });
992
824
  if (placeOrder) {
993
825
  // Use addTransaction to create transaction without navigating to confirmation screen
994
826
  const addResult = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_submitTransaction).call(this, transaction, {
@@ -1124,8 +956,8 @@ class PerpsController extends base_controller_1.BaseController {
1124
956
  const errorMessage = (0, errorUtils_1.ensureError)(error, 'PerpsController.depositWithOrder').message;
1125
957
  const isCancellation = errorMessage.includes('User denied') ||
1126
958
  errorMessage.includes('User rejected') ||
1127
- errorMessage.includes('User cancelled') ||
1128
- errorMessage.includes('User canceled');
959
+ errorMessage.includes('cancelled') ||
960
+ errorMessage.includes('canceled');
1129
961
  this.update((state) => {
1130
962
  const requestToUpdate = state.depositRequests.find((req) => req.id === currentDepositId);
1131
963
  if (requestToUpdate) {
@@ -1489,7 +1321,7 @@ class PerpsController extends base_controller_1.BaseController {
1489
1321
  /* fire-and-forget */
1490
1322
  });
1491
1323
  }, __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadRefreshMs)), "f");
1492
- // Watch for isTestnet / hip3ConfigVersion changes
1324
+ // Watch for isTestnet / hip3ConfigVersion / cachedUserDataAddress changes
1493
1325
  const handler = (_state, patches) => {
1494
1326
  // Early-return when no watched field changed (skips ~46 unrelated updates)
1495
1327
  const hasRelevantChange = patches.some((patch) => typeof patch.path[0] === 'string' &&
@@ -1510,9 +1342,16 @@ class PerpsController extends base_controller_1.BaseController {
1510
1342
  });
1511
1343
  __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, currentIsTestnet, "f");
1512
1344
  __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, currentHip3Version, "f");
1513
- // No need to clear user data cache — per-provider keys include the
1514
- // network, so different networks don't collide. Re-preload will
1515
- // populate the new key.
1345
+ // Clear stale cache (market + user data)
1346
+ this.update((state) => {
1347
+ state.cachedMarketData = null;
1348
+ state.cachedMarketDataTimestamp = 0;
1349
+ state.cachedPositions = null;
1350
+ state.cachedOrders = null;
1351
+ state.cachedAccountState = null;
1352
+ state.cachedUserDataTimestamp = 0;
1353
+ state.cachedUserDataAddress = null;
1354
+ });
1516
1355
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1517
1356
  /* fire-and-forget */
1518
1357
  });
@@ -1526,13 +1365,16 @@ class PerpsController extends base_controller_1.BaseController {
1526
1365
  const accountChangeHandler = () => {
1527
1366
  const evmAccount = (0, accountUtils_1.getSelectedEvmAccount)(this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup'));
1528
1367
  const currentAddress = evmAccount?.address ?? null;
1529
- // If any cached entry belongs to a different account, clear all entries.
1530
- // Max 4 entries (2 providers × 2 networks) — clearing all is simple and safe.
1531
- const hasStaleEntries = Object.values(this.state.cachedUserDataByProvider).some((entry) => entry.address.toLowerCase() !== currentAddress?.toLowerCase());
1532
- if (hasStaleEntries) {
1368
+ // If there's cached data from a different account (or no EVM account now), clear it
1369
+ if (this.state.cachedUserDataAddress !== null &&
1370
+ currentAddress !== this.state.cachedUserDataAddress) {
1533
1371
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Account changed, clearing user data cache');
1534
1372
  this.update((state) => {
1535
- state.cachedUserDataByProvider = {};
1373
+ state.cachedPositions = null;
1374
+ state.cachedOrders = null;
1375
+ state.cachedAccountState = null;
1376
+ state.cachedUserDataTimestamp = 0;
1377
+ state.cachedUserDataAddress = null;
1536
1378
  });
1537
1379
  // Only preload if the new account is an EVM account
1538
1380
  if (currentAddress) {
@@ -1765,15 +1607,6 @@ class PerpsController extends base_controller_1.BaseController {
1765
1607
  }
1766
1608
  finally {
1767
1609
  __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
1768
- // Re-trigger preload now that reinit is complete and the
1769
- // activeProviderInstance points to the correct network.
1770
- // The state-change listener may have already fired during reinit
1771
- // but was skipped due to the #isReinitializing guard.
1772
- if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
1773
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1774
- /* fire-and-forget */
1775
- });
1776
- }
1777
1610
  }
1778
1611
  }
1779
1612
  /**
@@ -1820,7 +1653,7 @@ class PerpsController extends base_controller_1.BaseController {
1820
1653
  // Provider disconnect is handled by performInitialization() during
1821
1654
  // reinitialization. The disconnect() method skips provider teardown
1822
1655
  // when isReinitializing is true to prevent double-disconnect.
1823
- // Update state with new provider (market data cache preserved per-provider)
1656
+ // Update state with new provider
1824
1657
  this.update((state) => {
1825
1658
  state.activeProvider = providerId;
1826
1659
  state.accountState = null;
@@ -1877,12 +1710,6 @@ class PerpsController extends base_controller_1.BaseController {
1877
1710
  }
1878
1711
  finally {
1879
1712
  __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
1880
- // Re-trigger preload now that reinit is complete.
1881
- if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
1882
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
1883
- /* fire-and-forget */
1884
- });
1885
- }
1886
1713
  }
1887
1714
  }
1888
1715
  /**
@@ -2260,18 +2087,14 @@ class PerpsController extends base_controller_1.BaseController {
2260
2087
  * Eligibility (Geo-Blocking)
2261
2088
  */
2262
2089
  /**
2263
- * Fetch geo location
2090
+ * Activates geo-blocking eligibility monitoring.
2091
+ * Call this after onboarding is complete when the controller was constructed
2092
+ * with `deferEligibilityCheck: true`.
2264
2093
  *
2265
- * Returned in Country or Country-Region format
2266
- * Example: FR, DE, US-MI, CA-ON
2267
- */
2268
- /**
2269
- * Refresh eligibility status
2270
- */
2271
- /**
2272
- * Resume eligibility monitoring after onboarding completes.
2273
- * Clears the deferred flag and triggers an immediate eligibility check
2274
- * using the current remote feature flag state.
2094
+ * Reads the current RemoteFeatureFlagController state, performs the initial
2095
+ * eligibility check, and unblocks the existing stateChange subscription so
2096
+ * future feature-flag updates flow through normally.
2097
+ * Safe to call multiple times; subsequent calls simply re-check eligibility.
2275
2098
  */
2276
2099
  startEligibilityMonitoring() {
2277
2100
  __classPrivateFieldSet(this, _PerpsController_eligibilityCheckDeferred, false, "f");
@@ -2294,6 +2117,9 @@ class PerpsController extends base_controller_1.BaseController {
2294
2117
  stopEligibilityMonitoring() {
2295
2118
  __classPrivateFieldSet(this, _PerpsController_eligibilityCheckDeferred, true, "f");
2296
2119
  }
2120
+ /**
2121
+ * Refresh eligibility status
2122
+ */
2297
2123
  async refreshEligibility() {
2298
2124
  if (__classPrivateFieldGet(this, _PerpsController_eligibilityCheckDeferred, "f")) {
2299
2125
  return;
@@ -2304,10 +2130,9 @@ class PerpsController extends base_controller_1.BaseController {
2304
2130
  // (started with remote config after it was fetched).
2305
2131
  const versionAtStart = __classPrivateFieldGet(this, _PerpsController_blockedRegionListVersion, "f");
2306
2132
  try {
2307
- const geoLocation = await this.messenger.call('GeolocationController:getGeolocation');
2133
+ // TODO: It would be good to have this location before we call this async function to avoid the race condition
2308
2134
  const isEligible = await __classPrivateFieldGet(this, _PerpsController_eligibilityService, "f").checkEligibility({
2309
2135
  blockedRegions: this.blockedRegionList.list,
2310
- geoLocation,
2311
2136
  });
2312
2137
  // Only update state if the blocked region list hasn't changed while we were awaiting.
2313
2138
  // This prevents stale fallback-based eligibility checks from overwriting
@@ -2791,46 +2616,27 @@ class PerpsController extends base_controller_1.BaseController {
2791
2616
  }
2792
2617
  }
2793
2618
  exports.PerpsController = PerpsController;
2794
- _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _PerpsController_isReinitializing = new WeakMap(), _PerpsController_myxRegistrationPromise = new WeakMap(), _PerpsController_blockedRegionListVersion = new WeakMap(), _PerpsController_hip3Enabled = new WeakMap(), _PerpsController_hip3AllowlistMarkets = new WeakMap(), _PerpsController_hip3BlocklistMarkets = new WeakMap(), _PerpsController_hip3ConfigSource = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_handlersRegistered = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_eligibilityCheckDeferred = new WeakMap(), _PerpsController_options = new WeakMap(), _PerpsController_tradingService = new WeakMap(), _PerpsController_marketDataService = new WeakMap(), _PerpsController_accountService = new WeakMap(), _PerpsController_eligibilityService = new WeakMap(), _PerpsController_dataLakeService = new WeakMap(), _PerpsController_depositService = new WeakMap(), _PerpsController_featureFlagConfigurationService = new WeakMap(), _PerpsController_rewardsIntegrationService = new WeakMap(), _PerpsController_preloadTimer = new WeakMap(), _PerpsController_isPreloading = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_preloadStateUnsubscribe = new WeakMap(), _PerpsController_accountChangeUnsubscribe = new WeakMap(), _PerpsController_previousIsTestnet = new WeakMap(), _PerpsController_previousHip3ConfigVersion = new WeakMap(), _PerpsController_instances = new WeakSet(), _PerpsController_isMYXProviderEnabled = function _PerpsController_isMYXProviderEnabled() {
2795
- const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx;
2796
- // Local env-var override (MM_PERPS_MYX_PROVIDER_ENABLED) always wins —
2797
- // matches the UI selector (resolvePerpsMyxProviderEnabled) so controller
2798
- // and UI agree on whether MYX is available.
2799
- if (myx?.enabled) {
2800
- return true;
2801
- }
2802
- // Credentials present → MYX is enabled regardless of remote flag.
2803
- // Use || so empty-string env vars (default '') fall through.
2804
- const hasCredentials = Boolean(
2805
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
2806
- myx?.appIdTestnet || myx?.appIdMainnet);
2807
- if (hasCredentials) {
2808
- return true;
2809
- }
2810
- // No local override or credentials — check remote flag as fallback
2619
+ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _PerpsController_isReinitializing = new WeakMap(), _PerpsController_blockedRegionListVersion = new WeakMap(), _PerpsController_hip3Enabled = new WeakMap(), _PerpsController_hip3AllowlistMarkets = new WeakMap(), _PerpsController_hip3BlocklistMarkets = new WeakMap(), _PerpsController_hip3ConfigSource = new WeakMap(), _PerpsController_standaloneProvider = new WeakMap(), _PerpsController_standaloneProviderIsTestnet = new WeakMap(), _PerpsController_standaloneProviderHip3Version = new WeakMap(), _PerpsController_eligibilityCheckDeferred = new WeakMap(), _PerpsController_options = new WeakMap(), _PerpsController_tradingService = new WeakMap(), _PerpsController_marketDataService = new WeakMap(), _PerpsController_accountService = new WeakMap(), _PerpsController_eligibilityService = new WeakMap(), _PerpsController_dataLakeService = new WeakMap(), _PerpsController_depositService = new WeakMap(), _PerpsController_featureFlagConfigurationService = new WeakMap(), _PerpsController_rewardsIntegrationService = new WeakMap(), _PerpsController_preloadTimer = new WeakMap(), _PerpsController_isPreloading = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_preloadStateUnsubscribe = new WeakMap(), _PerpsController_accountChangeUnsubscribe = new WeakMap(), _PerpsController_previousIsTestnet = new WeakMap(), _PerpsController_previousHip3ConfigVersion = new WeakMap(), _PerpsController_instances = new WeakSet(), _PerpsController_isMYXProviderEnabled = function _PerpsController_isMYXProviderEnabled() {
2620
+ const getLocalFlag = () => typeof globalThis.process !== 'undefined' &&
2621
+ globalThis.process.env?.MM_PERPS_MYX_PROVIDER_ENABLED === 'true';
2811
2622
  try {
2623
+ const localFlag = getLocalFlag();
2812
2624
  const remoteState = this.messenger.call('RemoteFeatureFlagController:getState');
2813
2625
  const remoteFlag = remoteState.remoteFeatureFlags?.perpsMyxProviderEnabled;
2814
2626
  if ((0, types_1.isVersionGatedFeatureFlag)(remoteFlag)) {
2815
2627
  const validated = __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.featureFlags.validateVersionGated(remoteFlag);
2816
- return validated ?? false;
2628
+ return validated ?? localFlag;
2817
2629
  }
2818
- return false;
2630
+ return localFlag;
2819
2631
  }
2820
2632
  catch {
2821
- return false;
2633
+ // If RemoteFeatureFlagController not ready, use fallback
2634
+ return getLocalFlag();
2822
2635
  }
2823
2636
  }, _PerpsController_logError = function _PerpsController_logError(error, options) {
2824
2637
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.logger.error(error, options);
2825
2638
  }, _PerpsController_debugLog = function _PerpsController_debugLog(...args) {
2826
2639
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.debugLogger.log(...args);
2827
- }, _PerpsController_marketCacheKey = function _PerpsController_marketCacheKey(providerId, isTestnet) {
2828
- return `${providerId}:${isTestnet ? 'testnet' : 'mainnet'}`;
2829
- }, _PerpsController_providerIsTestnet = function _PerpsController_providerIsTestnet(providerId) {
2830
- if (providerId === 'myx') {
2831
- return perpsConfig_1.PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet;
2832
- }
2833
- return this.state.isTestnet;
2834
2640
  }, _PerpsController_getOrCreateStandaloneProvider = function _PerpsController_getOrCreateStandaloneProvider() {
2835
2641
  const currentIsTestnet = this.state.isTestnet;
2836
2642
  const currentHip3Version = this.state.hip3ConfigVersion ?? 0;
@@ -2853,10 +2659,6 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
2853
2659
  blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
2854
2660
  platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2855
2661
  messenger: this.messenger,
2856
- builderAddressTestnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
2857
- ?.builderAddressTestnet,
2858
- builderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
2859
- ?.builderAddressMainnet,
2860
2662
  }), "f");
2861
2663
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
2862
2664
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
@@ -3014,16 +2816,89 @@ async function _PerpsController_performInitialization() {
3014
2816
  }
3015
2817
  this.providers.clear();
3016
2818
  await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
3017
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createProviders).call(this);
3018
- // Await MYX dynamic import (if started) so MYX is in the providers
3019
- // map before we assign the active provider. Runs concurrently with
3020
- // the WebSocket readiness delay for zero additional latency.
3021
- await Promise.all([
3022
- (0, wait_1.wait)(perpsConfig_1.PERPS_CONSTANTS.ReconnectionCleanupDelayMs),
3023
- __classPrivateFieldGet(this, _PerpsController_myxRegistrationPromise, "f"),
3024
- ]);
3025
- __classPrivateFieldSet(this, _PerpsController_myxRegistrationPromise, null, "f");
3026
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_assignActiveProvider).call(this);
2819
+ const { activeProvider } = this.state;
2820
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Creating provider with HIP-3 configuration', {
2821
+ hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
2822
+ hip3AllowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
2823
+ hip3BlocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
2824
+ hip3ConfigSource: __classPrivateFieldGet(this, _PerpsController_hip3ConfigSource, "f"),
2825
+ isTestnet: this.state.isTestnet,
2826
+ activeProvider,
2827
+ });
2828
+ // Always create HyperLiquid provider as the base provider
2829
+ const hyperLiquidProvider = new HyperLiquidProvider_1.HyperLiquidProvider({
2830
+ isTestnet: this.state.isTestnet,
2831
+ hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
2832
+ allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
2833
+ blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
2834
+ platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2835
+ messenger: this.messenger,
2836
+ });
2837
+ this.providers.set('hyperliquid', hyperLiquidProvider);
2838
+ // Register MYX provider if enabled via feature flag.
2839
+ // Uses dynamic import so @myx-trade/sdk is excluded from the bundle
2840
+ // unless MM_PERPS_MYX_PROVIDER_ENABLED=true is set at build time.
2841
+ // Wrapped in try/catch so a missing module (stripped at build time)
2842
+ // only skips MYX registration instead of aborting initialization.
2843
+ const isMYXEnabled = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMYXProviderEnabled).call(this);
2844
+ if (isMYXEnabled) {
2845
+ try {
2846
+ const { MYXProvider } = await import("./providers/MYXProvider.cjs");
2847
+ const myxProvider = new MYXProvider({
2848
+ isTestnet: perpsConfig_1.PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet,
2849
+ platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2850
+ });
2851
+ this.providers.set('myx', myxProvider);
2852
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider registered', {
2853
+ isTestnet: perpsConfig_1.PROVIDER_CONFIG.MYX_TESTNET_ONLY || this.state.isTestnet,
2854
+ });
2855
+ }
2856
+ catch {
2857
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider module not available (stripped from build), skipping registration');
2858
+ }
2859
+ }
2860
+ // Set up active provider based on activeProvider value in state
2861
+ // 'aggregated' is treated as just another provider that wraps others
2862
+ if (activeProvider === 'aggregated') {
2863
+ // Aggregated mode: wrap in AggregatedPerpsProvider for multi-provider support
2864
+ this.activeProviderInstance = new AggregatedPerpsProvider_1.AggregatedPerpsProvider({
2865
+ providers: this.providers,
2866
+ defaultProvider: 'hyperliquid',
2867
+ infrastructure: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
2868
+ });
2869
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Using aggregated provider (multi-provider)', { registeredProviders: Array.from(this.providers.keys()) });
2870
+ }
2871
+ else if (activeProvider === 'hyperliquid') {
2872
+ // Direct provider mode: use HyperLiquid provider directly
2873
+ this.activeProviderInstance = hyperLiquidProvider;
2874
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${activeProvider})`);
2875
+ }
2876
+ else if (activeProvider === 'myx') {
2877
+ // MYX provider mode
2878
+ const myxProvider = this.providers.get('myx');
2879
+ if (myxProvider) {
2880
+ this.activeProviderInstance = myxProvider;
2881
+ }
2882
+ else {
2883
+ // MYX feature flag is disabled — fall back to HyperLiquid
2884
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider not available (feature flag disabled), falling back to hyperliquid');
2885
+ this.activeProviderInstance = hyperLiquidProvider;
2886
+ this.update((state) => {
2887
+ state.activeProvider = 'hyperliquid';
2888
+ });
2889
+ }
2890
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${this.activeProviderInstance === hyperLiquidProvider ? 'hyperliquid' : activeProvider})`);
2891
+ }
2892
+ else {
2893
+ // Unsupported provider - throw error to prevent silent misconfiguration
2894
+ throw new Error(`Unsupported provider: ${String(activeProvider)}. Currently only 'hyperliquid', 'myx', and 'aggregated' are supported.`);
2895
+ }
2896
+ // Future providers can be added here with their own authentication patterns:
2897
+ // - Some might use API keys: new BinanceProvider({ apiKey, apiSecret })
2898
+ // - Some might use different wallet patterns: new GMXProvider({ signer })
2899
+ // - Some might not need auth at all: new DydxProvider()
2900
+ // Wait for WebSocket transport to be ready before marking as initialized
2901
+ await (0, wait_1.wait)(perpsConfig_1.PERPS_CONSTANTS.ReconnectionCleanupDelayMs);
3027
2902
  this.isInitialized = true;
3028
2903
  this.update((state) => {
3029
2904
  state.initializationState = InitializationState.Initialized;
@@ -3031,7 +2906,7 @@ async function _PerpsController_performInitialization() {
3031
2906
  });
3032
2907
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Providers initialized successfully', {
3033
2908
  providerCount: this.providers.size,
3034
- activeProvider: this.state.activeProvider,
2909
+ activeProvider,
3035
2910
  timestamp: new Date().toISOString(),
3036
2911
  attempts: attempt,
3037
2912
  });
@@ -3066,84 +2941,6 @@ async function _PerpsController_performInitialization() {
3066
2941
  attempts: maxAttempts,
3067
2942
  timestamp: new Date().toISOString(),
3068
2943
  });
3069
- }, _PerpsController_createProviders = function _PerpsController_createProviders() {
3070
- const { activeProvider } = this.state;
3071
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Creating provider with HIP-3 configuration', {
3072
- hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
3073
- hip3AllowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
3074
- hip3BlocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
3075
- hip3ConfigSource: __classPrivateFieldGet(this, _PerpsController_hip3ConfigSource, "f"),
3076
- isTestnet: this.state.isTestnet,
3077
- activeProvider,
3078
- });
3079
- // Always create HyperLiquid provider as the base provider
3080
- const hyperLiquidProvider = new HyperLiquidProvider_1.HyperLiquidProvider({
3081
- isTestnet: this.state.isTestnet,
3082
- hip3Enabled: __classPrivateFieldGet(this, _PerpsController_hip3Enabled, "f"),
3083
- allowlistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3AllowlistMarkets, "f"),
3084
- blocklistMarkets: __classPrivateFieldGet(this, _PerpsController_hip3BlocklistMarkets, "f"),
3085
- platformDependencies: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
3086
- messenger: this.messenger,
3087
- builderAddressTestnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
3088
- ?.builderAddressTestnet,
3089
- builderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
3090
- ?.builderAddressMainnet,
3091
- });
3092
- this.providers.set('hyperliquid', hyperLiquidProvider);
3093
- // Register MYX provider if enabled via feature flag.
3094
- // Dynamic import because the MYX package pulls in heavy dependencies we
3095
- // don't want bundled in extension. Until MYX fixes their package, extension
3096
- // doesn't ship it — the catch branch silently skips registration.
3097
- // Uses .then()/.catch() instead of await because #createProviders is not async;
3098
- // MYX registration completing asynchronously is fine since it's only used when
3099
- // explicitly enabled and selected.
3100
- const isMYXEnabled = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_isMYXProviderEnabled).call(this);
3101
- if (isMYXEnabled) {
3102
- // IMPORTANT: Must use import() — NOT require() — for core/extension tree-shaking.
3103
- // require() is synchronous and bundlers include it in the main bundle.
3104
- // import() enables true code splitting so MYX is excluded when not enabled.
3105
- __classPrivateFieldSet(this, _PerpsController_myxRegistrationPromise, import("./providers/MYXProvider.cjs")
3106
- .then(({ MYXProvider }) => {
3107
- this.registerMYXProvider(MYXProvider);
3108
- return undefined;
3109
- })
3110
- .catch((error) => this.handleMYXImportError(error)), "f");
3111
- }
3112
- }, _PerpsController_assignActiveProvider = function _PerpsController_assignActiveProvider() {
3113
- const { activeProvider } = this.state;
3114
- const hyperLiquidProvider = this.providers.get('hyperliquid');
3115
- if (!hyperLiquidProvider) {
3116
- throw new Error('HyperLiquid provider not registered — cannot assign active provider');
3117
- }
3118
- if (activeProvider === 'aggregated') {
3119
- this.activeProviderInstance = new AggregatedPerpsProvider_1.AggregatedPerpsProvider({
3120
- providers: this.providers,
3121
- defaultProvider: 'hyperliquid',
3122
- infrastructure: __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure,
3123
- });
3124
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Using aggregated provider (multi-provider)', { registeredProviders: Array.from(this.providers.keys()) });
3125
- }
3126
- else if (activeProvider === 'hyperliquid') {
3127
- this.activeProviderInstance = hyperLiquidProvider;
3128
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${activeProvider})`);
3129
- }
3130
- else if (activeProvider === 'myx') {
3131
- const myxProvider = this.providers.get('myx');
3132
- if (myxProvider) {
3133
- this.activeProviderInstance = myxProvider;
3134
- }
3135
- else {
3136
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: MYX provider not available, falling back to hyperliquid');
3137
- this.activeProviderInstance = hyperLiquidProvider;
3138
- this.update((state) => {
3139
- state.activeProvider = 'hyperliquid';
3140
- });
3141
- }
3142
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, `PerpsController: Using direct provider (${this.activeProviderInstance === hyperLiquidProvider ? 'hyperliquid' : activeProvider})`);
3143
- }
3144
- else {
3145
- throw new Error(`Unsupported provider: ${String(activeProvider)}. Currently only 'hyperliquid', 'myx', and 'aggregated' are supported.`);
3146
- }
3147
2944
  }, _PerpsController_getErrorContext = function _PerpsController_getErrorContext(method, extra) {
3148
2945
  return {
3149
2946
  tags: {
@@ -3173,7 +2970,7 @@ async function _PerpsController_performInitialization() {
3173
2970
  },
3174
2971
  stateManager: {
3175
2972
  update: (updater) =>
3176
- // @ts-expect-error TS2589 - excessively deep instantiation from BaseController generic
2973
+ // @ts-expect-error TS2589 - excessively deep instantiation when inferring stateManager from BaseController
3177
2974
  this.update(updater),
3178
2975
  getState: () => __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getControllerState).call(this),
3179
2976
  },
@@ -3191,22 +2988,9 @@ async function _PerpsController_performMarketDataPreload() {
3191
2988
  if (__classPrivateFieldGet(this, _PerpsController_isPreloading, "f")) {
3192
2989
  return;
3193
2990
  }
3194
- // Skip preloading during provider/network reinitialisation.
3195
- // The activeProviderInstance still points to the OLD network's provider
3196
- // until init() completes, so fetching now would store stale data under
3197
- // the NEW network's cache key.
3198
- if (__classPrivateFieldGet(this, _PerpsController_isReinitializing, "f")) {
3199
- return;
3200
- }
3201
- // Determine actual provider and cache key for debounce
3202
- const actualProviderId = this.activeProviderInstance
3203
- ? this.state.activeProvider // includes 'aggregated'
3204
- : 'hyperliquid';
3205
- const cacheKey = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, actualProviderId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, actualProviderId));
3206
2991
  const now = Date.now();
3207
- const existingEntry = this.state.cachedMarketDataByProvider[cacheKey];
3208
- if (existingEntry &&
3209
- now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
2992
+ if (now - this.state.cachedMarketDataTimestamp <
2993
+ __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
3210
2994
  return;
3211
2995
  }
3212
2996
  __classPrivateFieldSet(this, _PerpsController_isPreloading, true, "f");
@@ -3225,46 +3009,10 @@ async function _PerpsController_performMarketDataPreload() {
3225
3009
  });
3226
3010
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching market data in background');
3227
3011
  const data = await this.getMarketDataWithPrices({ standalone: true });
3228
- // Store under per-provider key(s)
3229
- const ts = Date.now();
3230
- if (this.state.activeProvider === 'aggregated' &&
3231
- this.activeProviderInstance) {
3232
- // Split returned data by providerId and store each slice
3233
- const fallbackProviderId = 'hyperliquid'; // default for items missing providerId
3234
- const byProvider = new Map();
3235
- for (const item of data) {
3236
- const pid = item.providerId ?? fallbackProviderId;
3237
- const existing = byProvider.get(pid);
3238
- if (existing) {
3239
- existing.push(item);
3240
- }
3241
- else {
3242
- byProvider.set(pid, [item]);
3243
- }
3244
- }
3245
- this.update((state) => {
3246
- for (const [pid, slice] of byProvider) {
3247
- const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, pid, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, pid));
3248
- state.cachedMarketDataByProvider[key] = {
3249
- data: slice,
3250
- timestamp: ts,
3251
- };
3252
- }
3253
- // Write aggregated sentinel so the staleness guard sees it
3254
- state.cachedMarketDataByProvider[cacheKey] = {
3255
- data: [], // sentinel — real data is in per-provider keys
3256
- timestamp: ts,
3257
- };
3258
- });
3259
- }
3260
- else {
3261
- this.update((state) => {
3262
- state.cachedMarketDataByProvider[cacheKey] = {
3263
- data,
3264
- timestamp: ts,
3265
- };
3266
- });
3267
- }
3012
+ this.update((state) => {
3013
+ state.cachedMarketData = data;
3014
+ state.cachedMarketDataTimestamp = Date.now();
3015
+ });
3268
3016
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Market data preloaded', {
3269
3017
  marketCount: data.length,
3270
3018
  });
@@ -3308,16 +3056,10 @@ async function _PerpsController_performUserDataPreload() {
3308
3056
  return;
3309
3057
  }
3310
3058
  const userAddress = evmAccount.address;
3311
- // Determine actual provider (same logic as market preload)
3312
- const actualProviderId = this.activeProviderInstance
3313
- ? this.state.activeProvider // includes 'aggregated'
3314
- : 'hyperliquid';
3315
- const userCacheKey = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, actualProviderId, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, actualProviderId));
3316
3059
  // Skip if cache is fresh and for same account
3317
3060
  const now = Date.now();
3318
- const existingEntry = this.state.cachedUserDataByProvider[userCacheKey];
3319
- if (existingEntry?.address === userAddress &&
3320
- now - existingEntry.timestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
3061
+ if (this.state.cachedUserDataAddress === userAddress &&
3062
+ now - this.state.cachedUserDataTimestamp < __classPrivateFieldGet(_a, _a, "f", _PerpsController_preloadGuardMs)) {
3321
3063
  return;
3322
3064
  }
3323
3065
  // Skip standalone REST polling when WebSocket is connected — live data is streaming
@@ -3348,60 +3090,13 @@ async function _PerpsController_performUserDataPreload() {
3348
3090
  this.getOpenOrders({ standalone: true, userAddress }),
3349
3091
  this.getAccountState({ standalone: true, userAddress }),
3350
3092
  ]);
3351
- if (this.state.activeProvider === 'aggregated' &&
3352
- this.activeProviderInstance) {
3353
- // Split by providerId and write one cache entry per provider key
3354
- // (mirrors the market-data preload pattern at ~line 2976)
3355
- const ts = Date.now();
3356
- const fallbackProviderId = 'hyperliquid'; // default for items missing providerId
3357
- const byProvider = new Map();
3358
- const ensureBucket = (pid) => {
3359
- let bucket = byProvider.get(pid);
3360
- if (!bucket) {
3361
- bucket = { positions: [], orders: [], accountState: null };
3362
- byProvider.set(pid, bucket);
3363
- }
3364
- return bucket;
3365
- };
3366
- for (const pos of positions) {
3367
- ensureBucket(pos.providerId ?? fallbackProviderId).positions.push(pos);
3368
- }
3369
- for (const order of orders) {
3370
- ensureBucket(order.providerId ?? fallbackProviderId).orders.push(order);
3371
- }
3372
- // AccountState — assign to its provider bucket
3373
- ensureBucket(accountState.providerId ?? fallbackProviderId).accountState = accountState;
3374
- this.update((state) => {
3375
- for (const [pid, data] of byProvider) {
3376
- const key = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_marketCacheKey).call(this, pid, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_providerIsTestnet).call(this, pid));
3377
- state.cachedUserDataByProvider[key] = {
3378
- ...data,
3379
- timestamp: ts,
3380
- address: userAddress,
3381
- };
3382
- }
3383
- // Write aggregated sentinel so the staleness guard sees it
3384
- state.cachedUserDataByProvider[userCacheKey] = {
3385
- positions: [],
3386
- orders: [],
3387
- accountState: null,
3388
- timestamp: ts,
3389
- address: userAddress,
3390
- };
3391
- });
3392
- }
3393
- else {
3394
- // Single provider — store directly under its key
3395
- this.update((state) => {
3396
- state.cachedUserDataByProvider[userCacheKey] = {
3397
- positions,
3398
- orders,
3399
- accountState,
3400
- timestamp: Date.now(),
3401
- address: userAddress,
3402
- };
3403
- });
3404
- }
3093
+ this.update((state) => {
3094
+ state.cachedPositions = positions;
3095
+ state.cachedOrders = orders;
3096
+ state.cachedAccountState = accountState;
3097
+ state.cachedUserDataTimestamp = Date.now();
3098
+ state.cachedUserDataAddress = userAddress;
3099
+ });
3405
3100
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
3406
3101
  positionCount: positions.length,
3407
3102
  orderCount: orders.length,