@metamask-previews/perps-controller 12.2.0-preview-e68ab1498 → 13.0.0-preview-4b37525

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 +15 -6
  2. package/dist/PerpsController-method-action-types.cjs.map +1 -1
  3. package/dist/PerpsController-method-action-types.d.cts +26 -3
  4. package/dist/PerpsController-method-action-types.d.cts.map +1 -1
  5. package/dist/PerpsController-method-action-types.d.mts +26 -3
  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 +392 -102
  9. package/dist/PerpsController.cjs.map +1 -1
  10. package/dist/PerpsController.d.cts +26 -7
  11. package/dist/PerpsController.d.cts.map +1 -1
  12. package/dist/PerpsController.d.mts +26 -7
  13. package/dist/PerpsController.d.mts.map +1 -1
  14. package/dist/PerpsController.mjs +392 -102
  15. package/dist/PerpsController.mjs.map +1 -1
  16. package/dist/constants/eventNames.cjs +1 -1
  17. package/dist/constants/eventNames.cjs.map +1 -1
  18. package/dist/constants/eventNames.d.cts +1 -1
  19. package/dist/constants/eventNames.d.mts +1 -1
  20. package/dist/constants/eventNames.mjs +1 -1
  21. package/dist/constants/eventNames.mjs.map +1 -1
  22. package/dist/constants/hyperLiquidConfig.cjs +14 -2
  23. package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
  24. package/dist/constants/hyperLiquidConfig.d.cts +10 -0
  25. package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
  26. package/dist/constants/hyperLiquidConfig.d.mts +10 -0
  27. package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
  28. package/dist/constants/hyperLiquidConfig.mjs +12 -0
  29. package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
  30. package/dist/constants/perpsConfig.cjs +3 -4
  31. package/dist/constants/perpsConfig.cjs.map +1 -1
  32. package/dist/constants/perpsConfig.d.cts +2 -4
  33. package/dist/constants/perpsConfig.d.cts.map +1 -1
  34. package/dist/constants/perpsConfig.d.mts +2 -4
  35. package/dist/constants/perpsConfig.d.mts.map +1 -1
  36. package/dist/constants/perpsConfig.mjs +3 -4
  37. package/dist/constants/perpsConfig.mjs.map +1 -1
  38. package/dist/index.cjs +8 -6
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +4 -3
  41. package/dist/index.d.cts.map +1 -1
  42. package/dist/index.d.mts +4 -3
  43. package/dist/index.d.mts.map +1 -1
  44. package/dist/index.mjs +1 -0
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/perpsErrorCodes.cjs +5 -1
  47. package/dist/perpsErrorCodes.cjs.map +1 -1
  48. package/dist/perpsErrorCodes.d.cts +4 -0
  49. package/dist/perpsErrorCodes.d.cts.map +1 -1
  50. package/dist/perpsErrorCodes.d.mts +4 -0
  51. package/dist/perpsErrorCodes.d.mts.map +1 -1
  52. package/dist/perpsErrorCodes.mjs +5 -1
  53. package/dist/perpsErrorCodes.mjs.map +1 -1
  54. package/dist/providers/AggregatedPerpsProvider.cjs +104 -14
  55. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
  56. package/dist/providers/AggregatedPerpsProvider.d.cts +34 -2
  57. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
  58. package/dist/providers/AggregatedPerpsProvider.d.mts +34 -2
  59. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
  60. package/dist/providers/AggregatedPerpsProvider.mjs +102 -13
  61. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
  62. package/dist/providers/HyperLiquidProvider.cjs +2141 -637
  63. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  64. package/dist/providers/HyperLiquidProvider.d.cts +37 -17
  65. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  66. package/dist/providers/HyperLiquidProvider.d.mts +37 -17
  67. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  68. package/dist/providers/HyperLiquidProvider.mjs +2146 -642
  69. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  70. package/dist/types/index.cjs.map +1 -1
  71. package/dist/types/index.d.cts +96 -3
  72. package/dist/types/index.d.cts.map +1 -1
  73. package/dist/types/index.d.mts +96 -3
  74. package/dist/types/index.d.mts.map +1 -1
  75. package/dist/types/index.mjs.map +1 -1
  76. package/dist/utils/capabilitySymbols.cjs +25 -0
  77. package/dist/utils/capabilitySymbols.cjs.map +1 -0
  78. package/dist/utils/capabilitySymbols.d.cts +15 -0
  79. package/dist/utils/capabilitySymbols.d.cts.map +1 -0
  80. package/dist/utils/capabilitySymbols.d.mts +15 -0
  81. package/dist/utils/capabilitySymbols.d.mts.map +1 -0
  82. package/dist/utils/capabilitySymbols.mjs +21 -0
  83. package/dist/utils/capabilitySymbols.mjs.map +1 -0
  84. package/dist/utils/hyperLiquidAdapter.cjs +20 -1
  85. package/dist/utils/hyperLiquidAdapter.cjs.map +1 -1
  86. package/dist/utils/hyperLiquidAdapter.d.cts +1 -0
  87. package/dist/utils/hyperLiquidAdapter.d.cts.map +1 -1
  88. package/dist/utils/hyperLiquidAdapter.d.mts +1 -0
  89. package/dist/utils/hyperLiquidAdapter.d.mts.map +1 -1
  90. package/dist/utils/hyperLiquidAdapter.mjs +19 -0
  91. package/dist/utils/hyperLiquidAdapter.mjs.map +1 -1
  92. package/dist/utils/hyperLiquidValidation.cjs +1 -1
  93. package/dist/utils/hyperLiquidValidation.cjs.map +1 -1
  94. package/dist/utils/hyperLiquidValidation.d.cts +1 -1
  95. package/dist/utils/hyperLiquidValidation.d.mts +1 -1
  96. package/dist/utils/hyperLiquidValidation.mjs +1 -1
  97. package/dist/utils/hyperLiquidValidation.mjs.map +1 -1
  98. package/dist/utils/stringParseUtils.cjs +17 -1
  99. package/dist/utils/stringParseUtils.cjs.map +1 -1
  100. package/dist/utils/stringParseUtils.d.cts +8 -0
  101. package/dist/utils/stringParseUtils.d.cts.map +1 -1
  102. package/dist/utils/stringParseUtils.d.mts +8 -0
  103. package/dist/utils/stringParseUtils.d.mts.map +1 -1
  104. package/dist/utils/stringParseUtils.mjs +15 -0
  105. package/dist/utils/stringParseUtils.mjs.map +1 -1
  106. package/package.json +1 -1
@@ -10,7 +10,7 @@ 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_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_awaitInitializationIfInProgress, _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_getActiveProviderWhenReady, _PerpsController_buildGlobalSnapshotContext, _PerpsController_getStaticSnapshotDexes, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_isPreloading, _PerpsController_marketPreloadQueued, _PerpsController_isPreloadingUserData, _PerpsController_userPreloadQueued, _PerpsController_userSnapshotRequests, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_hydrateCacheFromDiskSync, _PerpsController_persistUserCacheToDisk, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload, _PerpsController_persistWatchlistToRemote, _PerpsController_syncWatchlistFromRemote;
13
+ var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_reinitializationOperationPromise, _PerpsController_disconnectOperationPromise, _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_publishChaseOrderMaxDistanceReached, _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_initWithoutDisconnectWait, _PerpsController_beginReinitialization, _PerpsController_performInitialization, _PerpsController_createProviders, _PerpsController_assignActiveProvider, _PerpsController_getErrorContext, _PerpsController_getControllerState, _PerpsController_buildMarketAllowedFilter, _PerpsController_compilePatternsSafely, _PerpsController_createServiceContext, _PerpsController_ensureTradingServiceDeps, _PerpsController_getActiveProviderWhenReady, _PerpsController_getUnavailableOrderCapabilities, _PerpsController_getDirectProviderId, _PerpsController_hasConflictingProviderRoute, _PerpsController_resolveRoutedOrderProvider, _PerpsController_buildGlobalSnapshotContext, _PerpsController_getStaticSnapshotDexes, _PerpsController_preloadWatchedPaths, _PerpsController_preloadTimer, _PerpsController_preloadStartRequested, _PerpsController_isPreloading, _PerpsController_marketPreloadQueued, _PerpsController_isPreloadingUserData, _PerpsController_userPreloadQueued, _PerpsController_lifecycleGeneration, _PerpsController_userSnapshotRequests, _PerpsController_preloadStateUnsubscribe, _PerpsController_accountChangeUnsubscribe, _PerpsController_previousIsTestnet, _PerpsController_previousHip3ConfigVersion, _PerpsController_preloadRefreshMs, _PerpsController_preloadGuardMs, _PerpsController_hydrateCacheFromDiskSync, _PerpsController_persistUserCacheToDisk, _PerpsController_performMarketDataPreload, _PerpsController_performUserDataPreload, _PerpsController_performDisconnect, _PerpsController_persistWatchlistToRemote, _PerpsController_syncWatchlistFromRemote;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.PerpsController = exports.getDefaultPerpsControllerState = exports.DEFAULT_SELECTED_ORDER_TYPE = exports.DEFAULT_PRO_LAYOUT_PREFERENCES = exports.DEFAULT_PERPS_MODE = exports.DEFAULT_ORDER_BOOK_PREFERENCES = exports.PerpsMode = exports.InitializationState = exports.PERPS_ERROR_CODES = exports.resolveMyxAuthConfig = exports.resolveWatchlistExchangeKey = exports.firstNonEmpty = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
@@ -39,6 +39,7 @@ const accountUtils_js_1 = require("./utils/accountUtils.cjs");
39
39
  const errorUtils_js_1 = require("./utils/errorUtils.cjs");
40
40
  const hyperLiquidAdapter_js_1 = require("./utils/hyperLiquidAdapter.cjs");
41
41
  const marketUtils_js_1 = require("./utils/marketUtils.cjs");
42
+ const orderTypes_js_1 = require("./utils/orderTypes.cjs");
42
43
  const perpsDiskPersistence_js_1 = require("./utils/perpsDiskPersistence.cjs");
43
44
  const wait_js_1 = require("./utils/wait.cjs");
44
45
  function cloneUserDataSnapshot(snapshot) {
@@ -466,6 +467,7 @@ const MESSENGER_EXPOSED_METHODS = [
466
467
  'getCachedMarketDataForActiveProvider',
467
468
  'getCachedUserDataForActiveProvider',
468
469
  'getChaseOrders',
470
+ 'getTwapOrders',
469
471
  'getUserDataSnapshot',
470
472
  'getCurrentNetwork',
471
473
  'getFunding',
@@ -478,6 +480,7 @@ const MESSENGER_EXPOSED_METHODS = [
478
480
  'getOpenOrders',
479
481
  'getOrderBookGrouping',
480
482
  'getOrderBookPreferences',
483
+ 'getOrderCapabilities',
481
484
  'getOrderFills',
482
485
  'getOrders',
483
486
  'getPendingTradeConfiguration',
@@ -564,6 +567,8 @@ class PerpsController extends base_controller_1.BaseController {
564
567
  this.isInitialized = false;
565
568
  _PerpsController_initializationPromise.set(this, null);
566
569
  _PerpsController_isReinitializing.set(this, false);
570
+ _PerpsController_reinitializationOperationPromise.set(this, null);
571
+ _PerpsController_disconnectOperationPromise.set(this, null);
567
572
  /** Tracks the async MYX dynamic import so performInitialization can await it. */
568
573
  _PerpsController_myxRegistrationPromise.set(this, null);
569
574
  this.blockedRegionList = {
@@ -635,11 +640,16 @@ class PerpsController extends base_controller_1.BaseController {
635
640
  _PerpsController_depositService.set(this, void 0);
636
641
  _PerpsController_featureFlagConfigurationService.set(this, void 0);
637
642
  _PerpsController_rewardsIntegrationService.set(this, void 0);
643
+ _PerpsController_publishChaseOrderMaxDistanceReached.set(this, (event) => {
644
+ this.messenger.publish('PerpsController:chaseOrderMaxDistanceReached', event);
645
+ });
638
646
  _PerpsController_preloadTimer.set(this, null);
647
+ _PerpsController_preloadStartRequested.set(this, false);
639
648
  _PerpsController_isPreloading.set(this, false);
640
649
  _PerpsController_marketPreloadQueued.set(this, false);
641
650
  _PerpsController_isPreloadingUserData.set(this, false);
642
651
  _PerpsController_userPreloadQueued.set(this, false);
652
+ _PerpsController_lifecycleGeneration.set(this, 0);
643
653
  _PerpsController_userSnapshotRequests.set(this, new Map());
644
654
  _PerpsController_preloadStateUnsubscribe.set(this, null);
645
655
  _PerpsController_accountChangeUnsubscribe.set(this, null);
@@ -863,6 +873,7 @@ class PerpsController extends base_controller_1.BaseController {
863
873
  }
864
874
  const { address } = evmAccount;
865
875
  const { isTestnet, hip3ConfigVersion } = this.state;
876
+ const lifecycleGeneration = __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f");
866
877
  const network = isTestnet ? 'testnet' : 'mainnet';
867
878
  const expectedDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
868
879
  if (!expectedDexes) {
@@ -876,7 +887,8 @@ class PerpsController extends base_controller_1.BaseController {
876
887
  catch {
877
888
  return false;
878
889
  }
879
- return (this.state.activeProvider === 'hyperliquid' &&
890
+ return (__classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") === lifecycleGeneration &&
891
+ this.state.activeProvider === 'hyperliquid' &&
880
892
  (!capturedActiveProvider ||
881
893
  this.activeProviderInstance === capturedActiveProvider) &&
882
894
  this.state.isTestnet === isTestnet &&
@@ -992,18 +1004,19 @@ class PerpsController extends base_controller_1.BaseController {
992
1004
  * @returns A promise that resolves when the operation completes.
993
1005
  */
994
1006
  async init() {
995
- if (!__classPrivateFieldGet(this, _PerpsController_handlersRegistered, "f")) {
996
- this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
997
- __classPrivateFieldSet(this, _PerpsController_handlersRegistered, true, "f");
998
- }
999
- if (this.isInitialized) {
1000
- return undefined;
1001
- }
1002
- if (__classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
1003
- return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
1007
+ while (true) {
1008
+ const pendingDisconnect = __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
1009
+ if (pendingDisconnect) {
1010
+ await pendingDisconnect;
1011
+ continue;
1012
+ }
1013
+ const pendingReinitialization = __classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f");
1014
+ if (pendingReinitialization) {
1015
+ await pendingReinitialization;
1016
+ continue;
1017
+ }
1018
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
1004
1019
  }
1005
- __classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
1006
- return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
1007
1020
  }
1008
1021
  /**
1009
1022
  * Registers the MYX provider after dynamic import resolves.
@@ -1105,6 +1118,50 @@ class PerpsController extends base_controller_1.BaseController {
1105
1118
  // Return the active provider instance or null if not found
1106
1119
  return this.activeProviderInstance ?? null;
1107
1120
  }
1121
+ /**
1122
+ * Get strategy capabilities through the active provider route used by order
1123
+ * placement. The query waits for in-flight initialization and reports an
1124
+ * explicit unavailable status when no provider route can answer reliably.
1125
+ *
1126
+ * @param params - Market and optional provider route.
1127
+ * @returns Provider-owned order capabilities.
1128
+ */
1129
+ async getOrderCapabilities(params) {
1130
+ let activeProvider;
1131
+ try {
1132
+ activeProvider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1133
+ }
1134
+ catch (error) {
1135
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Order capabilities unavailable', {
1136
+ error: (0, errorUtils_js_1.ensureError)(error, 'PerpsController.getOrderCapabilities')
1137
+ .message,
1138
+ });
1139
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'provider_unavailable', params.providerId);
1140
+ }
1141
+ const resolvedProviderId = params.providerId ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getDirectProviderId).call(this, activeProvider);
1142
+ if (__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_hasConflictingProviderRoute).call(this, params.providerId, activeProvider)) {
1143
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'provider_not_routable', resolvedProviderId);
1144
+ }
1145
+ if (!activeProvider.getOrderCapabilities) {
1146
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'not_implemented', resolvedProviderId);
1147
+ }
1148
+ try {
1149
+ const capabilities = await activeProvider.getOrderCapabilities(params);
1150
+ if (capabilities.status === 'unavailable' &&
1151
+ capabilities.providerId === undefined &&
1152
+ resolvedProviderId !== undefined) {
1153
+ return { ...capabilities, providerId: resolvedProviderId };
1154
+ }
1155
+ return capabilities;
1156
+ }
1157
+ catch (error) {
1158
+ const safeError = (0, errorUtils_js_1.ensureError)(error, 'PerpsController.getOrderCapabilities');
1159
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Order capabilities unavailable', {
1160
+ error: safeError.message,
1161
+ });
1162
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'provider_unavailable', resolvedProviderId);
1163
+ }
1164
+ }
1108
1165
  /**
1109
1166
  * Place a new order
1110
1167
  * Thin delegation to TradingService
@@ -1113,7 +1170,10 @@ class PerpsController extends base_controller_1.BaseController {
1113
1170
  * @returns The order result with order ID and status.
1114
1171
  */
1115
1172
  async placeOrder(params) {
1116
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1173
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1174
+ orderType: params.orderType,
1175
+ providerId: params.providerId,
1176
+ });
1117
1177
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1118
1178
  const result = await __classPrivateFieldGet(this, _PerpsController_tradingService, "f").placeOrder({
1119
1179
  provider,
@@ -1136,7 +1196,16 @@ class PerpsController extends base_controller_1.BaseController {
1136
1196
  * @returns The updated order result with order ID and status.
1137
1197
  */
1138
1198
  async editOrder(params) {
1139
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1199
+ if ((0, orderTypes_js_1.isStrategyOrderType)(params.newOrder.orderType)) {
1200
+ return {
1201
+ success: false,
1202
+ error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_EDIT_STRATEGY_UNSUPPORTED,
1203
+ };
1204
+ }
1205
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1206
+ orderType: params.newOrder.orderType,
1207
+ providerId: params.newOrder.providerId,
1208
+ });
1140
1209
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1141
1210
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").editOrder({
1142
1211
  provider,
@@ -1151,13 +1220,26 @@ class PerpsController extends base_controller_1.BaseController {
1151
1220
  * @returns The cancellation result with status.
1152
1221
  */
1153
1222
  async cancelOrder(params) {
1154
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1223
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1224
+ orderType: params.orderType,
1225
+ providerId: params.providerId,
1226
+ });
1155
1227
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").cancelOrder({
1156
1228
  provider,
1157
1229
  params,
1158
1230
  context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'cancelOrder'),
1159
1231
  });
1160
1232
  }
1233
+ /**
1234
+ * Read venue-backed TWAP lifecycle records through the active provider.
1235
+ * Providers without native TWAP history return an empty list.
1236
+ *
1237
+ * @returns Current and terminal TWAP schedules with slice fills.
1238
+ */
1239
+ async getTwapOrders() {
1240
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1241
+ return provider.getTwapOrders ? await provider.getTwapOrders() : [];
1242
+ }
1161
1243
  /**
1162
1244
  * Read the active provider's retained Chase lifecycle snapshots.
1163
1245
  * Providers without an emulated Chase implementation return an empty list.
@@ -1208,7 +1290,10 @@ class PerpsController extends base_controller_1.BaseController {
1208
1290
  * @returns The order result from the close position request.
1209
1291
  */
1210
1292
  async closePosition(params) {
1211
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1293
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1294
+ orderType: params.orderType,
1295
+ providerId: params.providerId,
1296
+ });
1212
1297
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1213
1298
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").closePosition({
1214
1299
  provider,
@@ -1244,7 +1329,10 @@ class PerpsController extends base_controller_1.BaseController {
1244
1329
  * @returns The order result from the TP/SL update.
1245
1330
  */
1246
1331
  async updatePositionTPSL(params) {
1247
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1332
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1333
+ orderType: undefined,
1334
+ providerId: params.providerId,
1335
+ });
1248
1336
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1249
1337
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").updatePositionTPSL({
1250
1338
  provider,
@@ -1930,6 +2018,11 @@ class PerpsController extends base_controller_1.BaseController {
1930
2018
  * Watches for isTestnet and hip3ConfigVersion changes to re-preload.
1931
2019
  */
1932
2020
  startMarketDataPreload() {
2021
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, true, "f");
2022
+ if (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2023
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnect in progress, deferring market data preload');
2024
+ return;
2025
+ }
1933
2026
  if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
1934
2027
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Preload already started, skipping');
1935
2028
  return;
@@ -2018,6 +2111,7 @@ class PerpsController extends base_controller_1.BaseController {
2018
2111
  */
2019
2112
  stopMarketDataPreload() {
2020
2113
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Stopping market data preload');
2114
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, false, "f");
2021
2115
  if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2022
2116
  clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
2023
2117
  __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
@@ -2126,7 +2220,10 @@ class PerpsController extends base_controller_1.BaseController {
2126
2220
  * @returns True if the condition is met.
2127
2221
  */
2128
2222
  async validateOrder(params) {
2129
- const provider = this.getActiveProvider();
2223
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
2224
+ orderType: params.orderType,
2225
+ providerId: params.providerId,
2226
+ });
2130
2227
  const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'validateOrder');
2131
2228
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").validateOrder({ provider, params, context });
2132
2229
  }
@@ -2137,7 +2234,10 @@ class PerpsController extends base_controller_1.BaseController {
2137
2234
  * @returns A promise that resolves to the result.
2138
2235
  */
2139
2236
  async validateClosePosition(params) {
2140
- const provider = this.getActiveProvider();
2237
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
2238
+ orderType: params.orderType,
2239
+ providerId: params.providerId,
2240
+ });
2141
2241
  const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'validateClosePosition');
2142
2242
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").validateClosePosition({
2143
2243
  provider,
@@ -2230,6 +2330,9 @@ class PerpsController extends base_controller_1.BaseController {
2230
2330
  * @returns The toggle result with success status and current network mode.
2231
2331
  */
2232
2332
  async toggleTestnet() {
2333
+ while (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2334
+ await __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
2335
+ }
2233
2336
  // Prevent concurrent reinitializations
2234
2337
  if (this.isCurrentlyReinitializing()) {
2235
2338
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Already reinitializing, skipping toggle', {
@@ -2241,10 +2344,13 @@ class PerpsController extends base_controller_1.BaseController {
2241
2344
  error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
2242
2345
  };
2243
2346
  }
2244
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
2245
- // Store previous isTestnet for rollback on failure
2347
+ const completeReinitialization = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_beginReinitialization).call(this);
2246
2348
  const previousIsTestnet = this.state.isTestnet;
2247
2349
  try {
2350
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
2351
+ if (pendingInitialization) {
2352
+ await pendingInitialization;
2353
+ }
2248
2354
  await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2249
2355
  const previousNetwork = previousIsTestnet ? 'testnet' : 'mainnet';
2250
2356
  this.update((state) => {
@@ -2259,7 +2365,7 @@ class PerpsController extends base_controller_1.BaseController {
2259
2365
  // Reset initialization state and reinitialize provider with new testnet setting
2260
2366
  this.isInitialized = false;
2261
2367
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2262
- await this.init();
2368
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2263
2369
  // Check if initialization actually succeeded — performInitialization()
2264
2370
  // does not throw on failure, it sets state to Failed and resolves.
2265
2371
  if (this.state.initializationState === InitializationState.Failed) {
@@ -2285,7 +2391,7 @@ class PerpsController extends base_controller_1.BaseController {
2285
2391
  };
2286
2392
  }
2287
2393
  finally {
2288
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
2394
+ completeReinitialization();
2289
2395
  // Re-trigger preload now that reinit is complete and the
2290
2396
  // activeProviderInstance points to the correct network.
2291
2397
  // The state-change listener may have already fired during reinit
@@ -2309,19 +2415,8 @@ class PerpsController extends base_controller_1.BaseController {
2309
2415
  * @returns The switch result with success status and active provider.
2310
2416
  */
2311
2417
  async switchProvider(providerId) {
2312
- // No-op if already on this provider (regardless of init state)
2313
- if (this.state.activeProvider === providerId) {
2314
- return { success: true, providerId };
2315
- }
2316
- // Validate provider is available
2317
- // 'aggregated' is always valid, individual providers must exist in the map
2318
- const isValidProvider = providerId === 'aggregated' || this.providers.has(providerId);
2319
- if (!isValidProvider) {
2320
- return {
2321
- success: false,
2322
- providerId: this.state.activeProvider,
2323
- error: `Provider ${providerId} not available`,
2324
- };
2418
+ while (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2419
+ await __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
2325
2420
  }
2326
2421
  // Prevent concurrent switches
2327
2422
  if (this.isCurrentlyReinitializing()) {
@@ -2331,10 +2426,44 @@ class PerpsController extends base_controller_1.BaseController {
2331
2426
  error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
2332
2427
  };
2333
2428
  }
2334
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
2335
- // Store previous provider for rollback on failure
2336
- const previousProvider = this.state.activeProvider;
2429
+ const completeReinitialization = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_beginReinitialization).call(this);
2430
+ let previousProvider = this.state.activeProvider;
2337
2431
  try {
2432
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
2433
+ if (pendingInitialization) {
2434
+ await pendingInitialization;
2435
+ }
2436
+ // A completed disconnect leaves no initialization promise to await. Rebuild
2437
+ // the provider registry before same-provider detection or route validation
2438
+ // so a successful switch always leaves a usable active provider.
2439
+ const needsInitialization = !this.isInitialized ||
2440
+ this.state.initializationState !== InitializationState.Initialized;
2441
+ if (needsInitialization) {
2442
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2443
+ const initializationFailed = !this.isInitialized ||
2444
+ this.state.initializationState !== InitializationState.Initialized;
2445
+ if (initializationFailed) {
2446
+ throw new Error(this.state.initializationError ?? 'Provider initialization failed');
2447
+ }
2448
+ }
2449
+ // Initialization may select a fallback provider. Read the effective
2450
+ // provider only after it settles so no-op detection and rollback both
2451
+ // use the state this switch is actually replacing.
2452
+ previousProvider = this.state.activeProvider;
2453
+ if (previousProvider === providerId) {
2454
+ return { success: true, providerId };
2455
+ }
2456
+ // Validate provider only after a pending initialization has rebuilt the
2457
+ // registry. Otherwise a switch queued behind disconnect can observe the
2458
+ // intentionally empty teardown state.
2459
+ const isValidProvider = providerId === 'aggregated' || this.providers.has(providerId);
2460
+ if (!isValidProvider) {
2461
+ return {
2462
+ success: false,
2463
+ providerId: this.state.activeProvider,
2464
+ error: `Provider ${providerId} not available`,
2465
+ };
2466
+ }
2338
2467
  await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2339
2468
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Provider switch initiated', {
2340
2469
  from: previousProvider,
@@ -2342,8 +2471,7 @@ class PerpsController extends base_controller_1.BaseController {
2342
2471
  timestamp: new Date().toISOString(),
2343
2472
  });
2344
2473
  // Provider disconnect is handled by performInitialization() during
2345
- // reinitialization. The disconnect() method skips provider teardown
2346
- // when isReinitializing is true to prevent double-disconnect.
2474
+ // reinitialization.
2347
2475
  // Update state with new provider (market data cache preserved per-provider)
2348
2476
  this.update((state) => {
2349
2477
  state.activeProvider = providerId;
@@ -2353,7 +2481,7 @@ class PerpsController extends base_controller_1.BaseController {
2353
2481
  // Reset initialization state and reinitialize
2354
2482
  this.isInitialized = false;
2355
2483
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2356
- await this.init();
2484
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2357
2485
  // Check if initialization actually succeeded — performInitialization()
2358
2486
  // does not throw on failure, it sets state to Failed and resolves.
2359
2487
  if (this.state.initializationState === InitializationState.Failed) {
@@ -2376,7 +2504,7 @@ class PerpsController extends base_controller_1.BaseController {
2376
2504
  try {
2377
2505
  this.isInitialized = false;
2378
2506
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2379
- await this.init();
2507
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2380
2508
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Rollback to previous provider succeeded', {
2381
2509
  previousProvider,
2382
2510
  timestamp: new Date().toISOString(),
@@ -2400,7 +2528,7 @@ class PerpsController extends base_controller_1.BaseController {
2400
2528
  };
2401
2529
  }
2402
2530
  finally {
2403
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
2531
+ completeReinitialization();
2404
2532
  // Re-trigger preload now that reinit is complete.
2405
2533
  if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2406
2534
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
@@ -2736,14 +2864,18 @@ class PerpsController extends base_controller_1.BaseController {
2736
2864
  }
2737
2865
  }
2738
2866
  /**
2739
- * Calculate trading fees for the active provider
2740
- * Each provider implements its own fee structure
2867
+ * Calculate trading fees through the active provider route.
2868
+ * Each provider owns its fee policy. An explicit provider route overrides
2869
+ * the active/default provider used by placement.
2741
2870
  *
2742
2871
  * @param params - The operation parameters.
2743
2872
  * @returns The fee calculation result for the trade.
2744
2873
  */
2745
2874
  async calculateFees(params) {
2746
- const provider = this.getActiveProvider();
2875
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
2876
+ orderType: params.orderType,
2877
+ providerId: params.providerId,
2878
+ });
2747
2879
  // Preview owns subscription hydration. The submit resolver remains a pure
2748
2880
  // cache read and can therefore never start a benefits request while an
2749
2881
  // order is being signed.
@@ -2784,46 +2916,33 @@ class PerpsController extends base_controller_1.BaseController {
2784
2916
  * Call this when navigating away from Perps screens to prevent battery drain
2785
2917
  */
2786
2918
  async disconnect() {
2787
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnecting provider to cleanup subscriptions', {
2788
- timestamp: new Date().toISOString(),
2919
+ while (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2920
+ // Each explicit disconnect claims a teardown after the operation already
2921
+ // in flight. This lets a later disconnect close providers created by an
2922
+ // init call that was queued behind the same earlier teardown.
2923
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, false, "f");
2924
+ await __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
2925
+ }
2926
+ // A disconnect stops the current preload session. A later start call made
2927
+ // while teardown is in flight sets this back to true and is resumed below.
2928
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, false, "f");
2929
+ let resolveOperation = () => undefined;
2930
+ const operation = new Promise((resolve) => {
2931
+ resolveOperation = resolve;
2789
2932
  });
2790
- // Stop preload interval and messenger subscriptions first,
2791
- // so no background work fires while we tear down providers.
2792
- if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2793
- clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
2794
- __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
2795
- }
2796
- if (__classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f")) {
2797
- __classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f").call(this);
2798
- __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, null, "f");
2799
- }
2800
- if (__classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f")) {
2801
- __classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f").call(this);
2802
- __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, null, "f");
2933
+ __classPrivateFieldSet(this, _PerpsController_disconnectOperationPromise, operation, "f");
2934
+ try {
2935
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performDisconnect).call(this);
2803
2936
  }
2804
- __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
2805
- __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
2806
- // Only disconnect the provider if we're initialized
2807
- if (this.isInitialized && !this.isCurrentlyReinitializing()) {
2808
- try {
2809
- const provider = this.getActiveProvider();
2810
- await provider.disconnect();
2937
+ finally {
2938
+ resolveOperation();
2939
+ if (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f") === operation) {
2940
+ __classPrivateFieldSet(this, _PerpsController_disconnectOperationPromise, null, "f");
2811
2941
  }
2812
- catch (error) {
2813
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_js_1.ensureError)(error, 'PerpsController.disconnect'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect'));
2942
+ if (__classPrivateFieldGet(this, _PerpsController_preloadStartRequested, "f")) {
2943
+ this.startMarketDataPreload();
2814
2944
  }
2815
2945
  }
2816
- // Clear stale reference so standalone reads don't route through old provider
2817
- this.activeProviderInstance = null;
2818
- // Cleanup cached standalone provider (if any) — awaited to prevent races
2819
- await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2820
- // Note: Feature-flag subscription is NOT cleaned up here.
2821
- // It is a controller-lifetime concern (set once in the constructor),
2822
- // not a session-lifetime concern. Unsubscribing here would break
2823
- // geo-blocking / HIP-3 flag propagation after disconnect → reconnect.
2824
- // Reset initialization state to ensure proper reconnection
2825
- this.isInitialized = false;
2826
- __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2827
2946
  }
2828
2947
  /**
2829
2948
  * Eligibility (Geo-Blocking)
@@ -3572,7 +3691,7 @@ class PerpsController extends base_controller_1.BaseController {
3572
3691
  }
3573
3692
  }
3574
3693
  exports.PerpsController = PerpsController;
3575
- _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() {
3694
+ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _PerpsController_isReinitializing = new WeakMap(), _PerpsController_reinitializationOperationPromise = new WeakMap(), _PerpsController_disconnectOperationPromise = 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_publishChaseOrderMaxDistanceReached = new WeakMap(), _PerpsController_preloadTimer = new WeakMap(), _PerpsController_preloadStartRequested = new WeakMap(), _PerpsController_isPreloading = new WeakMap(), _PerpsController_marketPreloadQueued = new WeakMap(), _PerpsController_isPreloadingUserData = new WeakMap(), _PerpsController_userPreloadQueued = new WeakMap(), _PerpsController_lifecycleGeneration = 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() {
3576
3695
  const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx;
3577
3696
  // Local env-var override (MM_PERPS_MYX_PROVIDER_ENABLED) always wins —
3578
3697
  // matches the UI selector (resolvePerpsMyxProviderEnabled) so controller
@@ -3605,16 +3724,6 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
3605
3724
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.logger.error(error, options);
3606
3725
  }, _PerpsController_debugLog = function _PerpsController_debugLog(...args) {
3607
3726
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.debugLogger.log(...args);
3608
- }, _PerpsController_awaitInitializationIfInProgress =
3609
- /**
3610
- * Awaits the in-flight initialization promise if init is currently running.
3611
- * Called internally by #getActiveProviderWhenReady().
3612
- */
3613
- async function _PerpsController_awaitInitializationIfInProgress() {
3614
- if (this.state.initializationState === InitializationState.Initializing &&
3615
- __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
3616
- await __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
3617
- }
3618
3727
  }, _PerpsController_getAggregatedCacheProviderIds = function _PerpsController_getAggregatedCacheProviderIds(cacheKeys) {
3619
3728
  const providerIds = new Set();
3620
3729
  const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
@@ -3759,6 +3868,7 @@ async function _PerpsController_awaitInitializationIfInProgress() {
3759
3868
  ?.subscriptionBuilderAddressTestnet,
3760
3869
  subscriptionBuilderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
3761
3870
  ?.subscriptionBuilderAddressMainnet,
3871
+ onChaseOrderMaxDistanceReached: __classPrivateFieldGet(this, _PerpsController_publishChaseOrderMaxDistanceReached, "f"),
3762
3872
  }), "f");
3763
3873
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
3764
3874
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
@@ -3903,6 +4013,40 @@ async function _PerpsController_withStreamPause(operation, channels) {
3903
4013
  }
3904
4014
  }
3905
4015
  }
4016
+ }, _PerpsController_initWithoutDisconnectWait =
4017
+ /**
4018
+ * Initialize without waiting for disconnect. Reinitialization operations use
4019
+ * this after they have claimed the controller lifecycle.
4020
+ *
4021
+ * @returns A promise that resolves when initialization finishes.
4022
+ */
4023
+ async function _PerpsController_initWithoutDisconnectWait() {
4024
+ if (!__classPrivateFieldGet(this, _PerpsController_handlersRegistered, "f")) {
4025
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
4026
+ __classPrivateFieldSet(this, _PerpsController_handlersRegistered, true, "f");
4027
+ }
4028
+ if (this.isInitialized) {
4029
+ return undefined;
4030
+ }
4031
+ if (__classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
4032
+ return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4033
+ }
4034
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
4035
+ return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4036
+ }, _PerpsController_beginReinitialization = function _PerpsController_beginReinitialization() {
4037
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
4038
+ let resolveOperation = () => undefined;
4039
+ const operation = new Promise((resolve) => {
4040
+ resolveOperation = resolve;
4041
+ });
4042
+ __classPrivateFieldSet(this, _PerpsController_reinitializationOperationPromise, operation, "f");
4043
+ return () => {
4044
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
4045
+ resolveOperation();
4046
+ if (__classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f") === operation) {
4047
+ __classPrivateFieldSet(this, _PerpsController_reinitializationOperationPromise, null, "f");
4048
+ }
4049
+ };
3906
4050
  }, _PerpsController_performInitialization =
3907
4051
  /**
3908
4052
  * Actual initialization implementation with retry logic
@@ -4023,6 +4167,7 @@ async function _PerpsController_performInitialization() {
4023
4167
  ?.subscriptionBuilderAddressTestnet,
4024
4168
  subscriptionBuilderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
4025
4169
  ?.subscriptionBuilderAddressMainnet,
4170
+ onChaseOrderMaxDistanceReached: __classPrivateFieldGet(this, _PerpsController_publishChaseOrderMaxDistanceReached, "f"),
4026
4171
  });
4027
4172
  this.providers.set('hyperliquid', hyperLiquidProvider);
4028
4173
  // Register MYX provider if enabled via feature flag.
@@ -4152,8 +4297,56 @@ async function _PerpsController_performInitialization() {
4152
4297
  * @returns The active provider once initialization completes.
4153
4298
  */
4154
4299
  async function _PerpsController_getActiveProviderWhenReady() {
4155
- await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_awaitInitializationIfInProgress).call(this);
4156
- return this.getActiveProvider();
4300
+ while (true) {
4301
+ const pendingDisconnect = __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
4302
+ if (pendingDisconnect) {
4303
+ await pendingDisconnect;
4304
+ continue;
4305
+ }
4306
+ const pendingReinitialization = __classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f");
4307
+ if (pendingReinitialization) {
4308
+ await pendingReinitialization;
4309
+ continue;
4310
+ }
4311
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4312
+ if (this.state.initializationState === InitializationState.Initializing &&
4313
+ pendingInitialization) {
4314
+ await pendingInitialization;
4315
+ continue;
4316
+ }
4317
+ return this.getActiveProvider();
4318
+ }
4319
+ }, _PerpsController_getUnavailableOrderCapabilities = function _PerpsController_getUnavailableOrderCapabilities(reason, providerId) {
4320
+ return providerId
4321
+ ? { status: 'unavailable', providerId, reason }
4322
+ : { status: 'unavailable', reason };
4323
+ }, _PerpsController_getDirectProviderId = function _PerpsController_getDirectProviderId(provider) {
4324
+ if (provider.routesOrdersByProviderId) {
4325
+ return undefined;
4326
+ }
4327
+ return Array.from(this.providers.entries()).find(([, candidate]) => candidate === provider)?.[0];
4328
+ }, _PerpsController_hasConflictingProviderRoute = function _PerpsController_hasConflictingProviderRoute(providerId, provider) {
4329
+ return (providerId !== undefined &&
4330
+ !provider.routesOrdersByProviderId &&
4331
+ providerId !== provider.protocolId);
4332
+ }, _PerpsController_resolveRoutedOrderProvider =
4333
+ /**
4334
+ * Resolve one routed order operation after any in-flight initialization.
4335
+ *
4336
+ * @param params - Routed operation context.
4337
+ * @param params.orderType - Order type, when the operation carries one.
4338
+ * @param params.providerId - Explicit provider route, when supplied.
4339
+ * @returns The initialized provider that owns the operation.
4340
+ */
4341
+ async function _PerpsController_resolveRoutedOrderProvider(params) {
4342
+ const { orderType, providerId } = params;
4343
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
4344
+ if (__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_hasConflictingProviderRoute).call(this, providerId, provider)) {
4345
+ throw new Error(orderType !== undefined && (0, orderTypes_js_1.isStrategyOrderType)(orderType)
4346
+ ? perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_ROUTE_UNAVAILABLE
4347
+ : perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_NOT_FOUND);
4348
+ }
4349
+ return provider;
4157
4350
  }, _PerpsController_buildGlobalSnapshotContext = function _PerpsController_buildGlobalSnapshotContext() {
4158
4351
  const snapshotConfigured = Boolean(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.terminalApi?.globalSnapshotUrl) ||
4159
4352
  typeof __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.terminalMarketService
@@ -4280,7 +4473,12 @@ async function _PerpsController_performMarketDataPreload() {
4280
4473
  activeProvider: this.state.activeProvider,
4281
4474
  isTestnet: this.state.isTestnet,
4282
4475
  hip3ConfigVersion: this.state.hip3ConfigVersion,
4476
+ lifecycleGeneration: __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f"),
4283
4477
  };
4478
+ const isCurrent = () => __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") === preloadContext.lifecycleGeneration &&
4479
+ this.state.activeProvider === preloadContext.activeProvider &&
4480
+ this.state.isTestnet === preloadContext.isTestnet &&
4481
+ this.state.hip3ConfigVersion === preloadContext.hip3ConfigVersion;
4284
4482
  const staticSnapshotDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
4285
4483
  const now = Date.now();
4286
4484
  const existingEntry = this.state.cachedMarketDataByProvider[cacheKey];
@@ -4310,9 +4508,7 @@ async function _PerpsController_performMarketDataPreload() {
4310
4508
  duration_ms: Math.round(performance.now() - preloadStart),
4311
4509
  markets: data.length,
4312
4510
  });
4313
- if (this.state.activeProvider !== preloadContext.activeProvider ||
4314
- this.state.isTestnet !== preloadContext.isTestnet ||
4315
- this.state.hip3ConfigVersion !== preloadContext.hip3ConfigVersion) {
4511
+ if (!isCurrent()) {
4316
4512
  traceData = {
4317
4513
  success: false,
4318
4514
  error: 'Global snapshot preload context changed',
@@ -4337,6 +4533,13 @@ async function _PerpsController_performMarketDataPreload() {
4337
4533
  }
4338
4534
  : {};
4339
4535
  const marketDiskEntries = [];
4536
+ if (!isCurrent()) {
4537
+ traceData = {
4538
+ success: false,
4539
+ error: 'Global snapshot preload context changed',
4540
+ };
4541
+ return;
4542
+ }
4340
4543
  if (this.state.activeProvider === 'aggregated' &&
4341
4544
  this.activeProviderInstance) {
4342
4545
  // Split returned data by providerId and store each slice
@@ -4437,6 +4640,7 @@ async function _PerpsController_performUserDataPreload() {
4437
4640
  }
4438
4641
  const userAddress = evmAccount.address;
4439
4642
  const { activeProvider, isTestnet, hip3ConfigVersion } = this.state;
4643
+ const lifecycleGeneration = __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f");
4440
4644
  const { activeProviderInstance } = this;
4441
4645
  const hyperliquidDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
4442
4646
  const isCurrent = () => {
@@ -4447,7 +4651,8 @@ async function _PerpsController_performUserDataPreload() {
4447
4651
  catch {
4448
4652
  return false;
4449
4653
  }
4450
- return (this.state.activeProvider === activeProvider &&
4654
+ return (__classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") === lifecycleGeneration &&
4655
+ this.state.activeProvider === activeProvider &&
4451
4656
  this.activeProviderInstance === activeProviderInstance &&
4452
4657
  this.state.isTestnet === isTestnet &&
4453
4658
  this.state.hip3ConfigVersion === hip3ConfigVersion &&
@@ -4490,6 +4695,15 @@ async function _PerpsController_performUserDataPreload() {
4490
4695
  const traceId = (0, uuid_1.v4)();
4491
4696
  const preloadStart = performance.now();
4492
4697
  let traceData;
4698
+ const staleContextError = 'User data preload context changed';
4699
+ const discardStalePreload = () => {
4700
+ if (isCurrent()) {
4701
+ return false;
4702
+ }
4703
+ traceData = { success: false, error: staleContextError };
4704
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Discarding stale user data preload');
4705
+ return true;
4706
+ };
4493
4707
  try {
4494
4708
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.trace({
4495
4709
  name: index_js_1.PerpsTraceNames.UserDataPreload,
@@ -4503,6 +4717,9 @@ async function _PerpsController_performUserDataPreload() {
4503
4717
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching user data in background');
4504
4718
  if (activeProvider === 'hyperliquid') {
4505
4719
  const snapshot = await this.getUserDataSnapshot();
4720
+ if (discardStalePreload()) {
4721
+ return;
4722
+ }
4506
4723
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
4507
4724
  positionCount: snapshot.positions.length,
4508
4725
  orderCount: snapshot.orders.length,
@@ -4521,8 +4738,8 @@ async function _PerpsController_performUserDataPreload() {
4521
4738
  this.getOpenOrders({ standalone: true, userAddress }),
4522
4739
  this.getAccountState({ standalone: true, userAddress }),
4523
4740
  ]);
4524
- if (!isCurrent()) {
4525
- throw new Error('User data preload context changed');
4741
+ if (discardStalePreload()) {
4742
+ return;
4526
4743
  }
4527
4744
  if (activeProvider === 'aggregated' && activeProviderInstance) {
4528
4745
  // Split by providerId and write one cache entry per provider key
@@ -4546,6 +4763,9 @@ async function _PerpsController_performUserDataPreload() {
4546
4763
  }
4547
4764
  // AccountState — assign to its provider bucket
4548
4765
  ensureBucket(accountState.providerId ?? fallbackProviderId).accountState = accountState;
4766
+ if (discardStalePreload()) {
4767
+ return;
4768
+ }
4549
4769
  this.update((state) => {
4550
4770
  for (const [pid, data] of byProvider) {
4551
4771
  const key = (0, perpsConfig_js_1.buildProviderCacheKey)(pid, isTestnet);
@@ -4574,6 +4794,9 @@ async function _PerpsController_performUserDataPreload() {
4574
4794
  else {
4575
4795
  // Single provider — store directly under its key
4576
4796
  const ts = Date.now();
4797
+ if (discardStalePreload()) {
4798
+ return;
4799
+ }
4577
4800
  this.update((state) => {
4578
4801
  state.cachedUserDataByProvider[providerNetworkKey] = {
4579
4802
  positions,
@@ -4603,6 +4826,9 @@ async function _PerpsController_performUserDataPreload() {
4603
4826
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.setMeasurement(performanceMetrics_js_1.PerpsMeasurementName.PerpsUserDataPreload, performance.now() - preloadStart, 'millisecond', traceId);
4604
4827
  }
4605
4828
  catch (error) {
4829
+ if (discardStalePreload()) {
4830
+ return;
4831
+ }
4606
4832
  traceData = {
4607
4833
  success: false,
4608
4834
  error: (0, errorUtils_js_1.ensureError)(error, 'PerpsController.performUserDataPreload')
@@ -4626,6 +4852,70 @@ async function _PerpsController_performUserDataPreload() {
4626
4852
  });
4627
4853
  }
4628
4854
  }
4855
+ }, _PerpsController_performDisconnect =
4856
+ /**
4857
+ * Disconnect after this call has claimed the controller lifecycle.
4858
+ *
4859
+ * @returns A promise that resolves when teardown finishes.
4860
+ */
4861
+ async function _PerpsController_performDisconnect() {
4862
+ __classPrivateFieldSet(this, _PerpsController_lifecycleGeneration, __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") + 1, "f");
4863
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnecting provider to cleanup subscriptions', {
4864
+ timestamp: new Date().toISOString(),
4865
+ });
4866
+ // Stop preload interval and messenger subscriptions first,
4867
+ // so no background work fires while we tear down providers.
4868
+ if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
4869
+ clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
4870
+ __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
4871
+ }
4872
+ if (__classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f")) {
4873
+ __classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f").call(this);
4874
+ __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, null, "f");
4875
+ }
4876
+ if (__classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f")) {
4877
+ __classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f").call(this);
4878
+ __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, null, "f");
4879
+ }
4880
+ __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
4881
+ __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
4882
+ const pendingReinitialization = __classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f");
4883
+ if (pendingReinitialization) {
4884
+ await pendingReinitialization;
4885
+ }
4886
+ // Initialization owns provider creation. Let it finish before teardown so
4887
+ // it cannot repopulate providers after this method clears the references.
4888
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4889
+ if (pendingInitialization) {
4890
+ try {
4891
+ await pendingInitialization;
4892
+ }
4893
+ catch (error) {
4894
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_js_1.ensureError)(error, 'PerpsController.disconnect.initialization'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect', {
4895
+ operation: 'awaitInitialization',
4896
+ }));
4897
+ }
4898
+ }
4899
+ const provider = this.activeProviderInstance;
4900
+ if (provider) {
4901
+ try {
4902
+ await provider.disconnect();
4903
+ }
4904
+ catch (error) {
4905
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, (0, errorUtils_js_1.ensureError)(error, 'PerpsController.disconnect'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect'));
4906
+ }
4907
+ }
4908
+ // Clear stale reference so standalone reads don't route through old provider
4909
+ this.activeProviderInstance = null;
4910
+ // Cleanup cached standalone provider (if any) — awaited to prevent races
4911
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
4912
+ // Note: Feature-flag subscription is NOT cleaned up here.
4913
+ // It is a controller-lifetime concern (set once in the constructor),
4914
+ // not a session-lifetime concern. Unsubscribing here would break
4915
+ // geo-blocking / HIP-3 flag propagation after disconnect → reconnect.
4916
+ // Reset initialization state to ensure proper reconnection
4917
+ this.isInitialized = false;
4918
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
4629
4919
  }, _PerpsController_persistWatchlistToRemote =
4630
4920
  /**
4631
4921
  * Writes the current local watchlist to AuthenticatedUserStorageService