@metamask-previews/perps-controller 12.2.0-preview-e68ab1498 → 13.0.0-preview-56ae4c857

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
@@ -9,7 +9,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _PerpsController_instances, _a, _PerpsController_initializationPromise, _PerpsController_isReinitializing, _PerpsController_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;
12
+ 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;
13
13
  import { BaseController } from "@metamask/base-controller";
14
14
  import { ORIGIN_METAMASK } from "@metamask/controller-utils";
15
15
  import { v4 as uuidv4 } from "uuid";
@@ -36,6 +36,7 @@ import { getSelectedEvmAccountFromMessenger } from "./utils/accountUtils.mjs";
36
36
  import { ensureError } from "./utils/errorUtils.mjs";
37
37
  import { parseAssetName } from "./utils/hyperLiquidAdapter.mjs";
38
38
  import { clonePerpsMarketData, compileMarketPattern, shouldIncludeMarket } from "./utils/marketUtils.mjs";
39
+ import { isStrategyOrderType } from "./utils/orderTypes.mjs";
39
40
  import { hydrateFromDiskSync, persistMarketEntriesToDisk, persistUserEntriesToDisk } from "./utils/perpsDiskPersistence.mjs";
40
41
  import { wait } from "./utils/wait.mjs";
41
42
  function cloneUserDataSnapshot(snapshot) {
@@ -453,6 +454,7 @@ const MESSENGER_EXPOSED_METHODS = [
453
454
  'getCachedMarketDataForActiveProvider',
454
455
  'getCachedUserDataForActiveProvider',
455
456
  'getChaseOrders',
457
+ 'getTwapOrders',
456
458
  'getUserDataSnapshot',
457
459
  'getCurrentNetwork',
458
460
  'getFunding',
@@ -465,6 +467,7 @@ const MESSENGER_EXPOSED_METHODS = [
465
467
  'getOpenOrders',
466
468
  'getOrderBookGrouping',
467
469
  'getOrderBookPreferences',
470
+ 'getOrderCapabilities',
468
471
  'getOrderFills',
469
472
  'getOrders',
470
473
  'getPendingTradeConfiguration',
@@ -551,6 +554,8 @@ export class PerpsController extends BaseController {
551
554
  this.isInitialized = false;
552
555
  _PerpsController_initializationPromise.set(this, null);
553
556
  _PerpsController_isReinitializing.set(this, false);
557
+ _PerpsController_reinitializationOperationPromise.set(this, null);
558
+ _PerpsController_disconnectOperationPromise.set(this, null);
554
559
  /** Tracks the async MYX dynamic import so performInitialization can await it. */
555
560
  _PerpsController_myxRegistrationPromise.set(this, null);
556
561
  this.blockedRegionList = {
@@ -622,11 +627,16 @@ export class PerpsController extends BaseController {
622
627
  _PerpsController_depositService.set(this, void 0);
623
628
  _PerpsController_featureFlagConfigurationService.set(this, void 0);
624
629
  _PerpsController_rewardsIntegrationService.set(this, void 0);
630
+ _PerpsController_publishChaseOrderMaxDistanceReached.set(this, (event) => {
631
+ this.messenger.publish('PerpsController:chaseOrderMaxDistanceReached', event);
632
+ });
625
633
  _PerpsController_preloadTimer.set(this, null);
634
+ _PerpsController_preloadStartRequested.set(this, false);
626
635
  _PerpsController_isPreloading.set(this, false);
627
636
  _PerpsController_marketPreloadQueued.set(this, false);
628
637
  _PerpsController_isPreloadingUserData.set(this, false);
629
638
  _PerpsController_userPreloadQueued.set(this, false);
639
+ _PerpsController_lifecycleGeneration.set(this, 0);
630
640
  _PerpsController_userSnapshotRequests.set(this, new Map());
631
641
  _PerpsController_preloadStateUnsubscribe.set(this, null);
632
642
  _PerpsController_accountChangeUnsubscribe.set(this, null);
@@ -850,6 +860,7 @@ export class PerpsController extends BaseController {
850
860
  }
851
861
  const { address } = evmAccount;
852
862
  const { isTestnet, hip3ConfigVersion } = this.state;
863
+ const lifecycleGeneration = __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f");
853
864
  const network = isTestnet ? 'testnet' : 'mainnet';
854
865
  const expectedDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
855
866
  if (!expectedDexes) {
@@ -863,7 +874,8 @@ export class PerpsController extends BaseController {
863
874
  catch {
864
875
  return false;
865
876
  }
866
- return (this.state.activeProvider === 'hyperliquid' &&
877
+ return (__classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") === lifecycleGeneration &&
878
+ this.state.activeProvider === 'hyperliquid' &&
867
879
  (!capturedActiveProvider ||
868
880
  this.activeProviderInstance === capturedActiveProvider) &&
869
881
  this.state.isTestnet === isTestnet &&
@@ -979,18 +991,19 @@ export class PerpsController extends BaseController {
979
991
  * @returns A promise that resolves when the operation completes.
980
992
  */
981
993
  async init() {
982
- if (!__classPrivateFieldGet(this, _PerpsController_handlersRegistered, "f")) {
983
- this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
984
- __classPrivateFieldSet(this, _PerpsController_handlersRegistered, true, "f");
985
- }
986
- if (this.isInitialized) {
987
- return undefined;
988
- }
989
- if (__classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
990
- return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
994
+ while (true) {
995
+ const pendingDisconnect = __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
996
+ if (pendingDisconnect) {
997
+ await pendingDisconnect;
998
+ continue;
999
+ }
1000
+ const pendingReinitialization = __classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f");
1001
+ if (pendingReinitialization) {
1002
+ await pendingReinitialization;
1003
+ continue;
1004
+ }
1005
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
991
1006
  }
992
- __classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
993
- return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
994
1007
  }
995
1008
  /**
996
1009
  * Registers the MYX provider after dynamic import resolves.
@@ -1092,6 +1105,50 @@ export class PerpsController extends BaseController {
1092
1105
  // Return the active provider instance or null if not found
1093
1106
  return this.activeProviderInstance ?? null;
1094
1107
  }
1108
+ /**
1109
+ * Get strategy capabilities through the active provider route used by order
1110
+ * placement. The query waits for in-flight initialization and reports an
1111
+ * explicit unavailable status when no provider route can answer reliably.
1112
+ *
1113
+ * @param params - Market and optional provider route.
1114
+ * @returns Provider-owned order capabilities.
1115
+ */
1116
+ async getOrderCapabilities(params) {
1117
+ let activeProvider;
1118
+ try {
1119
+ activeProvider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1120
+ }
1121
+ catch (error) {
1122
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Order capabilities unavailable', {
1123
+ error: ensureError(error, 'PerpsController.getOrderCapabilities')
1124
+ .message,
1125
+ });
1126
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'provider_unavailable', params.providerId);
1127
+ }
1128
+ const resolvedProviderId = params.providerId ?? __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getDirectProviderId).call(this, activeProvider);
1129
+ if (__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_hasConflictingProviderRoute).call(this, params.providerId, activeProvider)) {
1130
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'provider_not_routable', resolvedProviderId);
1131
+ }
1132
+ if (!activeProvider.getOrderCapabilities) {
1133
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'not_implemented', resolvedProviderId);
1134
+ }
1135
+ try {
1136
+ const capabilities = await activeProvider.getOrderCapabilities(params);
1137
+ if (capabilities.status === 'unavailable' &&
1138
+ capabilities.providerId === undefined &&
1139
+ resolvedProviderId !== undefined) {
1140
+ return { ...capabilities, providerId: resolvedProviderId };
1141
+ }
1142
+ return capabilities;
1143
+ }
1144
+ catch (error) {
1145
+ const safeError = ensureError(error, 'PerpsController.getOrderCapabilities');
1146
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Order capabilities unavailable', {
1147
+ error: safeError.message,
1148
+ });
1149
+ return __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getUnavailableOrderCapabilities).call(this, 'provider_unavailable', resolvedProviderId);
1150
+ }
1151
+ }
1095
1152
  /**
1096
1153
  * Place a new order
1097
1154
  * Thin delegation to TradingService
@@ -1100,7 +1157,10 @@ export class PerpsController extends BaseController {
1100
1157
  * @returns The order result with order ID and status.
1101
1158
  */
1102
1159
  async placeOrder(params) {
1103
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1160
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1161
+ orderType: params.orderType,
1162
+ providerId: params.providerId,
1163
+ });
1104
1164
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1105
1165
  const result = await __classPrivateFieldGet(this, _PerpsController_tradingService, "f").placeOrder({
1106
1166
  provider,
@@ -1123,7 +1183,16 @@ export class PerpsController extends BaseController {
1123
1183
  * @returns The updated order result with order ID and status.
1124
1184
  */
1125
1185
  async editOrder(params) {
1126
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1186
+ if (isStrategyOrderType(params.newOrder.orderType)) {
1187
+ return {
1188
+ success: false,
1189
+ error: PERPS_ERROR_CODES.ORDER_EDIT_STRATEGY_UNSUPPORTED,
1190
+ };
1191
+ }
1192
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1193
+ orderType: params.newOrder.orderType,
1194
+ providerId: params.newOrder.providerId,
1195
+ });
1127
1196
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1128
1197
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").editOrder({
1129
1198
  provider,
@@ -1138,13 +1207,26 @@ export class PerpsController extends BaseController {
1138
1207
  * @returns The cancellation result with status.
1139
1208
  */
1140
1209
  async cancelOrder(params) {
1141
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1210
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1211
+ orderType: params.orderType,
1212
+ providerId: params.providerId,
1213
+ });
1142
1214
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").cancelOrder({
1143
1215
  provider,
1144
1216
  params,
1145
1217
  context: __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'cancelOrder'),
1146
1218
  });
1147
1219
  }
1220
+ /**
1221
+ * Read venue-backed TWAP lifecycle records through the active provider.
1222
+ * Providers without native TWAP history return an empty list.
1223
+ *
1224
+ * @returns Current and terminal TWAP schedules with slice fills.
1225
+ */
1226
+ async getTwapOrders() {
1227
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1228
+ return provider.getTwapOrders ? await provider.getTwapOrders() : [];
1229
+ }
1148
1230
  /**
1149
1231
  * Read the active provider's retained Chase lifecycle snapshots.
1150
1232
  * Providers without an emulated Chase implementation return an empty list.
@@ -1195,7 +1277,10 @@ export class PerpsController extends BaseController {
1195
1277
  * @returns The order result from the close position request.
1196
1278
  */
1197
1279
  async closePosition(params) {
1198
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1280
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1281
+ orderType: params.orderType,
1282
+ providerId: params.providerId,
1283
+ });
1199
1284
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1200
1285
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").closePosition({
1201
1286
  provider,
@@ -1231,7 +1316,10 @@ export class PerpsController extends BaseController {
1231
1316
  * @returns The order result from the TP/SL update.
1232
1317
  */
1233
1318
  async updatePositionTPSL(params) {
1234
- const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
1319
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
1320
+ orderType: undefined,
1321
+ providerId: params.providerId,
1322
+ });
1235
1323
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_ensureTradingServiceDeps).call(this);
1236
1324
  return __classPrivateFieldGet(this, _PerpsController_tradingService, "f").updatePositionTPSL({
1237
1325
  provider,
@@ -1917,6 +2005,11 @@ export class PerpsController extends BaseController {
1917
2005
  * Watches for isTestnet and hip3ConfigVersion changes to re-preload.
1918
2006
  */
1919
2007
  startMarketDataPreload() {
2008
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, true, "f");
2009
+ if (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2010
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnect in progress, deferring market data preload');
2011
+ return;
2012
+ }
1920
2013
  if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
1921
2014
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Preload already started, skipping');
1922
2015
  return;
@@ -2005,6 +2098,7 @@ export class PerpsController extends BaseController {
2005
2098
  */
2006
2099
  stopMarketDataPreload() {
2007
2100
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Stopping market data preload');
2101
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, false, "f");
2008
2102
  if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2009
2103
  clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
2010
2104
  __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
@@ -2113,7 +2207,10 @@ export class PerpsController extends BaseController {
2113
2207
  * @returns True if the condition is met.
2114
2208
  */
2115
2209
  async validateOrder(params) {
2116
- const provider = this.getActiveProvider();
2210
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
2211
+ orderType: params.orderType,
2212
+ providerId: params.providerId,
2213
+ });
2117
2214
  const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'validateOrder');
2118
2215
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").validateOrder({ provider, params, context });
2119
2216
  }
@@ -2124,7 +2221,10 @@ export class PerpsController extends BaseController {
2124
2221
  * @returns A promise that resolves to the result.
2125
2222
  */
2126
2223
  async validateClosePosition(params) {
2127
- const provider = this.getActiveProvider();
2224
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
2225
+ orderType: params.orderType,
2226
+ providerId: params.providerId,
2227
+ });
2128
2228
  const context = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_createServiceContext).call(this, 'validateClosePosition');
2129
2229
  return __classPrivateFieldGet(this, _PerpsController_marketDataService, "f").validateClosePosition({
2130
2230
  provider,
@@ -2217,6 +2317,9 @@ export class PerpsController extends BaseController {
2217
2317
  * @returns The toggle result with success status and current network mode.
2218
2318
  */
2219
2319
  async toggleTestnet() {
2320
+ while (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2321
+ await __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
2322
+ }
2220
2323
  // Prevent concurrent reinitializations
2221
2324
  if (this.isCurrentlyReinitializing()) {
2222
2325
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Already reinitializing, skipping toggle', {
@@ -2228,10 +2331,13 @@ export class PerpsController extends BaseController {
2228
2331
  error: PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
2229
2332
  };
2230
2333
  }
2231
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
2232
- // Store previous isTestnet for rollback on failure
2334
+ const completeReinitialization = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_beginReinitialization).call(this);
2233
2335
  const previousIsTestnet = this.state.isTestnet;
2234
2336
  try {
2337
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
2338
+ if (pendingInitialization) {
2339
+ await pendingInitialization;
2340
+ }
2235
2341
  await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2236
2342
  const previousNetwork = previousIsTestnet ? 'testnet' : 'mainnet';
2237
2343
  this.update((state) => {
@@ -2246,7 +2352,7 @@ export class PerpsController extends BaseController {
2246
2352
  // Reset initialization state and reinitialize provider with new testnet setting
2247
2353
  this.isInitialized = false;
2248
2354
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2249
- await this.init();
2355
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2250
2356
  // Check if initialization actually succeeded — performInitialization()
2251
2357
  // does not throw on failure, it sets state to Failed and resolves.
2252
2358
  if (this.state.initializationState === InitializationState.Failed) {
@@ -2272,7 +2378,7 @@ export class PerpsController extends BaseController {
2272
2378
  };
2273
2379
  }
2274
2380
  finally {
2275
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
2381
+ completeReinitialization();
2276
2382
  // Re-trigger preload now that reinit is complete and the
2277
2383
  // activeProviderInstance points to the correct network.
2278
2384
  // The state-change listener may have already fired during reinit
@@ -2296,19 +2402,8 @@ export class PerpsController extends BaseController {
2296
2402
  * @returns The switch result with success status and active provider.
2297
2403
  */
2298
2404
  async switchProvider(providerId) {
2299
- // No-op if already on this provider (regardless of init state)
2300
- if (this.state.activeProvider === providerId) {
2301
- return { success: true, providerId };
2302
- }
2303
- // Validate provider is available
2304
- // 'aggregated' is always valid, individual providers must exist in the map
2305
- const isValidProvider = providerId === 'aggregated' || this.providers.has(providerId);
2306
- if (!isValidProvider) {
2307
- return {
2308
- success: false,
2309
- providerId: this.state.activeProvider,
2310
- error: `Provider ${providerId} not available`,
2311
- };
2405
+ while (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2406
+ await __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
2312
2407
  }
2313
2408
  // Prevent concurrent switches
2314
2409
  if (this.isCurrentlyReinitializing()) {
@@ -2318,10 +2413,44 @@ export class PerpsController extends BaseController {
2318
2413
  error: PERPS_ERROR_CODES.CLIENT_REINITIALIZING,
2319
2414
  };
2320
2415
  }
2321
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
2322
- // Store previous provider for rollback on failure
2323
- const previousProvider = this.state.activeProvider;
2416
+ const completeReinitialization = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_beginReinitialization).call(this);
2417
+ let previousProvider = this.state.activeProvider;
2324
2418
  try {
2419
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
2420
+ if (pendingInitialization) {
2421
+ await pendingInitialization;
2422
+ }
2423
+ // A completed disconnect leaves no initialization promise to await. Rebuild
2424
+ // the provider registry before same-provider detection or route validation
2425
+ // so a successful switch always leaves a usable active provider.
2426
+ const needsInitialization = !this.isInitialized ||
2427
+ this.state.initializationState !== InitializationState.Initialized;
2428
+ if (needsInitialization) {
2429
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2430
+ const initializationFailed = !this.isInitialized ||
2431
+ this.state.initializationState !== InitializationState.Initialized;
2432
+ if (initializationFailed) {
2433
+ throw new Error(this.state.initializationError ?? 'Provider initialization failed');
2434
+ }
2435
+ }
2436
+ // Initialization may select a fallback provider. Read the effective
2437
+ // provider only after it settles so no-op detection and rollback both
2438
+ // use the state this switch is actually replacing.
2439
+ previousProvider = this.state.activeProvider;
2440
+ if (previousProvider === providerId) {
2441
+ return { success: true, providerId };
2442
+ }
2443
+ // Validate provider only after a pending initialization has rebuilt the
2444
+ // registry. Otherwise a switch queued behind disconnect can observe the
2445
+ // intentionally empty teardown state.
2446
+ const isValidProvider = providerId === 'aggregated' || this.providers.has(providerId);
2447
+ if (!isValidProvider) {
2448
+ return {
2449
+ success: false,
2450
+ providerId: this.state.activeProvider,
2451
+ error: `Provider ${providerId} not available`,
2452
+ };
2453
+ }
2325
2454
  await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2326
2455
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Provider switch initiated', {
2327
2456
  from: previousProvider,
@@ -2329,8 +2458,7 @@ export class PerpsController extends BaseController {
2329
2458
  timestamp: new Date().toISOString(),
2330
2459
  });
2331
2460
  // Provider disconnect is handled by performInitialization() during
2332
- // reinitialization. The disconnect() method skips provider teardown
2333
- // when isReinitializing is true to prevent double-disconnect.
2461
+ // reinitialization.
2334
2462
  // Update state with new provider (market data cache preserved per-provider)
2335
2463
  this.update((state) => {
2336
2464
  state.activeProvider = providerId;
@@ -2340,7 +2468,7 @@ export class PerpsController extends BaseController {
2340
2468
  // Reset initialization state and reinitialize
2341
2469
  this.isInitialized = false;
2342
2470
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2343
- await this.init();
2471
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2344
2472
  // Check if initialization actually succeeded — performInitialization()
2345
2473
  // does not throw on failure, it sets state to Failed and resolves.
2346
2474
  if (this.state.initializationState === InitializationState.Failed) {
@@ -2363,7 +2491,7 @@ export class PerpsController extends BaseController {
2363
2491
  try {
2364
2492
  this.isInitialized = false;
2365
2493
  __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2366
- await this.init();
2494
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_initWithoutDisconnectWait).call(this);
2367
2495
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Rollback to previous provider succeeded', {
2368
2496
  previousProvider,
2369
2497
  timestamp: new Date().toISOString(),
@@ -2387,7 +2515,7 @@ export class PerpsController extends BaseController {
2387
2515
  };
2388
2516
  }
2389
2517
  finally {
2390
- __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
2518
+ completeReinitialization();
2391
2519
  // Re-trigger preload now that reinit is complete.
2392
2520
  if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2393
2521
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performMarketDataPreload).call(this).catch(() => {
@@ -2723,14 +2851,18 @@ export class PerpsController extends BaseController {
2723
2851
  }
2724
2852
  }
2725
2853
  /**
2726
- * Calculate trading fees for the active provider
2727
- * Each provider implements its own fee structure
2854
+ * Calculate trading fees through the active provider route.
2855
+ * Each provider owns its fee policy. An explicit provider route overrides
2856
+ * the active/default provider used by placement.
2728
2857
  *
2729
2858
  * @param params - The operation parameters.
2730
2859
  * @returns The fee calculation result for the trade.
2731
2860
  */
2732
2861
  async calculateFees(params) {
2733
- const provider = this.getActiveProvider();
2862
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_resolveRoutedOrderProvider).call(this, {
2863
+ orderType: params.orderType,
2864
+ providerId: params.providerId,
2865
+ });
2734
2866
  // Preview owns subscription hydration. The submit resolver remains a pure
2735
2867
  // cache read and can therefore never start a benefits request while an
2736
2868
  // order is being signed.
@@ -2771,46 +2903,33 @@ export class PerpsController extends BaseController {
2771
2903
  * Call this when navigating away from Perps screens to prevent battery drain
2772
2904
  */
2773
2905
  async disconnect() {
2774
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnecting provider to cleanup subscriptions', {
2775
- timestamp: new Date().toISOString(),
2906
+ while (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f")) {
2907
+ // Each explicit disconnect claims a teardown after the operation already
2908
+ // in flight. This lets a later disconnect close providers created by an
2909
+ // init call that was queued behind the same earlier teardown.
2910
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, false, "f");
2911
+ await __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
2912
+ }
2913
+ // A disconnect stops the current preload session. A later start call made
2914
+ // while teardown is in flight sets this back to true and is resumed below.
2915
+ __classPrivateFieldSet(this, _PerpsController_preloadStartRequested, false, "f");
2916
+ let resolveOperation = () => undefined;
2917
+ const operation = new Promise((resolve) => {
2918
+ resolveOperation = resolve;
2776
2919
  });
2777
- // Stop preload interval and messenger subscriptions first,
2778
- // so no background work fires while we tear down providers.
2779
- if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
2780
- clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
2781
- __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
2782
- }
2783
- if (__classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f")) {
2784
- __classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f").call(this);
2785
- __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, null, "f");
2786
- }
2787
- if (__classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f")) {
2788
- __classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f").call(this);
2789
- __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, null, "f");
2920
+ __classPrivateFieldSet(this, _PerpsController_disconnectOperationPromise, operation, "f");
2921
+ try {
2922
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performDisconnect).call(this);
2790
2923
  }
2791
- __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
2792
- __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
2793
- // Only disconnect the provider if we're initialized
2794
- if (this.isInitialized && !this.isCurrentlyReinitializing()) {
2795
- try {
2796
- const provider = this.getActiveProvider();
2797
- await provider.disconnect();
2924
+ finally {
2925
+ resolveOperation();
2926
+ if (__classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f") === operation) {
2927
+ __classPrivateFieldSet(this, _PerpsController_disconnectOperationPromise, null, "f");
2798
2928
  }
2799
- catch (error) {
2800
- __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, ensureError(error, 'PerpsController.disconnect'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect'));
2929
+ if (__classPrivateFieldGet(this, _PerpsController_preloadStartRequested, "f")) {
2930
+ this.startMarketDataPreload();
2801
2931
  }
2802
2932
  }
2803
- // Clear stale reference so standalone reads don't route through old provider
2804
- this.activeProviderInstance = null;
2805
- // Cleanup cached standalone provider (if any) — awaited to prevent races
2806
- await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
2807
- // Note: Feature-flag subscription is NOT cleaned up here.
2808
- // It is a controller-lifetime concern (set once in the constructor),
2809
- // not a session-lifetime concern. Unsubscribing here would break
2810
- // geo-blocking / HIP-3 flag propagation after disconnect → reconnect.
2811
- // Reset initialization state to ensure proper reconnection
2812
- this.isInitialized = false;
2813
- __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
2814
2933
  }
2815
2934
  /**
2816
2935
  * Eligibility (Geo-Blocking)
@@ -3558,7 +3677,7 @@ export class PerpsController extends BaseController {
3558
3677
  return __classPrivateFieldGet(this, _PerpsController_isReinitializing, "f");
3559
3678
  }
3560
3679
  }
3561
- _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() {
3680
+ _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() {
3562
3681
  const myx = __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.myx;
3563
3682
  // Local env-var override (MM_PERPS_MYX_PROVIDER_ENABLED) always wins —
3564
3683
  // matches the UI selector (resolvePerpsMyxProviderEnabled) so controller
@@ -3591,16 +3710,6 @@ _a = PerpsController, _PerpsController_initializationPromise = new WeakMap(), _P
3591
3710
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.logger.error(error, options);
3592
3711
  }, _PerpsController_debugLog = function _PerpsController_debugLog(...args) {
3593
3712
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.debugLogger.log(...args);
3594
- }, _PerpsController_awaitInitializationIfInProgress =
3595
- /**
3596
- * Awaits the in-flight initialization promise if init is currently running.
3597
- * Called internally by #getActiveProviderWhenReady().
3598
- */
3599
- async function _PerpsController_awaitInitializationIfInProgress() {
3600
- if (this.state.initializationState === InitializationState.Initializing &&
3601
- __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
3602
- await __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
3603
- }
3604
3713
  }, _PerpsController_getAggregatedCacheProviderIds = function _PerpsController_getAggregatedCacheProviderIds(cacheKeys) {
3605
3714
  const providerIds = new Set();
3606
3715
  const currentNetwork = this.state.isTestnet ? 'testnet' : 'mainnet';
@@ -3745,6 +3854,7 @@ async function _PerpsController_awaitInitializationIfInProgress() {
3745
3854
  ?.subscriptionBuilderAddressTestnet,
3746
3855
  subscriptionBuilderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
3747
3856
  ?.subscriptionBuilderAddressMainnet,
3857
+ onChaseOrderMaxDistanceReached: __classPrivateFieldGet(this, _PerpsController_publishChaseOrderMaxDistanceReached, "f"),
3748
3858
  }), "f");
3749
3859
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderIsTestnet, currentIsTestnet, "f");
3750
3860
  __classPrivateFieldSet(this, _PerpsController_standaloneProviderHip3Version, currentHip3Version, "f");
@@ -3889,6 +3999,40 @@ async function _PerpsController_withStreamPause(operation, channels) {
3889
3999
  }
3890
4000
  }
3891
4001
  }
4002
+ }, _PerpsController_initWithoutDisconnectWait =
4003
+ /**
4004
+ * Initialize without waiting for disconnect. Reinitialization operations use
4005
+ * this after they have claimed the controller lifecycle.
4006
+ *
4007
+ * @returns A promise that resolves when initialization finishes.
4008
+ */
4009
+ async function _PerpsController_initWithoutDisconnectWait() {
4010
+ if (!__classPrivateFieldGet(this, _PerpsController_handlersRegistered, "f")) {
4011
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
4012
+ __classPrivateFieldSet(this, _PerpsController_handlersRegistered, true, "f");
4013
+ }
4014
+ if (this.isInitialized) {
4015
+ return undefined;
4016
+ }
4017
+ if (__classPrivateFieldGet(this, _PerpsController_initializationPromise, "f")) {
4018
+ return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4019
+ }
4020
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_performInitialization).call(this), "f");
4021
+ return __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4022
+ }, _PerpsController_beginReinitialization = function _PerpsController_beginReinitialization() {
4023
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, true, "f");
4024
+ let resolveOperation = () => undefined;
4025
+ const operation = new Promise((resolve) => {
4026
+ resolveOperation = resolve;
4027
+ });
4028
+ __classPrivateFieldSet(this, _PerpsController_reinitializationOperationPromise, operation, "f");
4029
+ return () => {
4030
+ __classPrivateFieldSet(this, _PerpsController_isReinitializing, false, "f");
4031
+ resolveOperation();
4032
+ if (__classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f") === operation) {
4033
+ __classPrivateFieldSet(this, _PerpsController_reinitializationOperationPromise, null, "f");
4034
+ }
4035
+ };
3892
4036
  }, _PerpsController_performInitialization =
3893
4037
  /**
3894
4038
  * Actual initialization implementation with retry logic
@@ -4009,6 +4153,7 @@ async function _PerpsController_performInitialization() {
4009
4153
  ?.subscriptionBuilderAddressTestnet,
4010
4154
  subscriptionBuilderAddressMainnet: __classPrivateFieldGet(this, _PerpsController_options, "f").clientConfig?.providerCredentials?.hyperliquid
4011
4155
  ?.subscriptionBuilderAddressMainnet,
4156
+ onChaseOrderMaxDistanceReached: __classPrivateFieldGet(this, _PerpsController_publishChaseOrderMaxDistanceReached, "f"),
4012
4157
  });
4013
4158
  this.providers.set('hyperliquid', hyperLiquidProvider);
4014
4159
  // Register MYX provider if enabled via feature flag.
@@ -4138,8 +4283,56 @@ async function _PerpsController_performInitialization() {
4138
4283
  * @returns The active provider once initialization completes.
4139
4284
  */
4140
4285
  async function _PerpsController_getActiveProviderWhenReady() {
4141
- await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_awaitInitializationIfInProgress).call(this);
4142
- return this.getActiveProvider();
4286
+ while (true) {
4287
+ const pendingDisconnect = __classPrivateFieldGet(this, _PerpsController_disconnectOperationPromise, "f");
4288
+ if (pendingDisconnect) {
4289
+ await pendingDisconnect;
4290
+ continue;
4291
+ }
4292
+ const pendingReinitialization = __classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f");
4293
+ if (pendingReinitialization) {
4294
+ await pendingReinitialization;
4295
+ continue;
4296
+ }
4297
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4298
+ if (this.state.initializationState === InitializationState.Initializing &&
4299
+ pendingInitialization) {
4300
+ await pendingInitialization;
4301
+ continue;
4302
+ }
4303
+ return this.getActiveProvider();
4304
+ }
4305
+ }, _PerpsController_getUnavailableOrderCapabilities = function _PerpsController_getUnavailableOrderCapabilities(reason, providerId) {
4306
+ return providerId
4307
+ ? { status: 'unavailable', providerId, reason }
4308
+ : { status: 'unavailable', reason };
4309
+ }, _PerpsController_getDirectProviderId = function _PerpsController_getDirectProviderId(provider) {
4310
+ if (provider.routesOrdersByProviderId) {
4311
+ return undefined;
4312
+ }
4313
+ return Array.from(this.providers.entries()).find(([, candidate]) => candidate === provider)?.[0];
4314
+ }, _PerpsController_hasConflictingProviderRoute = function _PerpsController_hasConflictingProviderRoute(providerId, provider) {
4315
+ return (providerId !== undefined &&
4316
+ !provider.routesOrdersByProviderId &&
4317
+ providerId !== provider.protocolId);
4318
+ }, _PerpsController_resolveRoutedOrderProvider =
4319
+ /**
4320
+ * Resolve one routed order operation after any in-flight initialization.
4321
+ *
4322
+ * @param params - Routed operation context.
4323
+ * @param params.orderType - Order type, when the operation carries one.
4324
+ * @param params.providerId - Explicit provider route, when supplied.
4325
+ * @returns The initialized provider that owns the operation.
4326
+ */
4327
+ async function _PerpsController_resolveRoutedOrderProvider(params) {
4328
+ const { orderType, providerId } = params;
4329
+ const provider = await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getActiveProviderWhenReady).call(this);
4330
+ if (__classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_hasConflictingProviderRoute).call(this, providerId, provider)) {
4331
+ throw new Error(orderType !== undefined && isStrategyOrderType(orderType)
4332
+ ? PERPS_ERROR_CODES.ORDER_STRATEGY_ROUTE_UNAVAILABLE
4333
+ : PERPS_ERROR_CODES.PROVIDER_NOT_FOUND);
4334
+ }
4335
+ return provider;
4143
4336
  }, _PerpsController_buildGlobalSnapshotContext = function _PerpsController_buildGlobalSnapshotContext() {
4144
4337
  const snapshotConfigured = Boolean(__classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.terminalApi?.globalSnapshotUrl) ||
4145
4338
  typeof __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.terminalMarketService
@@ -4266,7 +4459,12 @@ async function _PerpsController_performMarketDataPreload() {
4266
4459
  activeProvider: this.state.activeProvider,
4267
4460
  isTestnet: this.state.isTestnet,
4268
4461
  hip3ConfigVersion: this.state.hip3ConfigVersion,
4462
+ lifecycleGeneration: __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f"),
4269
4463
  };
4464
+ const isCurrent = () => __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") === preloadContext.lifecycleGeneration &&
4465
+ this.state.activeProvider === preloadContext.activeProvider &&
4466
+ this.state.isTestnet === preloadContext.isTestnet &&
4467
+ this.state.hip3ConfigVersion === preloadContext.hip3ConfigVersion;
4270
4468
  const staticSnapshotDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
4271
4469
  const now = Date.now();
4272
4470
  const existingEntry = this.state.cachedMarketDataByProvider[cacheKey];
@@ -4296,9 +4494,7 @@ async function _PerpsController_performMarketDataPreload() {
4296
4494
  duration_ms: Math.round(performance.now() - preloadStart),
4297
4495
  markets: data.length,
4298
4496
  });
4299
- if (this.state.activeProvider !== preloadContext.activeProvider ||
4300
- this.state.isTestnet !== preloadContext.isTestnet ||
4301
- this.state.hip3ConfigVersion !== preloadContext.hip3ConfigVersion) {
4497
+ if (!isCurrent()) {
4302
4498
  traceData = {
4303
4499
  success: false,
4304
4500
  error: 'Global snapshot preload context changed',
@@ -4323,6 +4519,13 @@ async function _PerpsController_performMarketDataPreload() {
4323
4519
  }
4324
4520
  : {};
4325
4521
  const marketDiskEntries = [];
4522
+ if (!isCurrent()) {
4523
+ traceData = {
4524
+ success: false,
4525
+ error: 'Global snapshot preload context changed',
4526
+ };
4527
+ return;
4528
+ }
4326
4529
  if (this.state.activeProvider === 'aggregated' &&
4327
4530
  this.activeProviderInstance) {
4328
4531
  // Split returned data by providerId and store each slice
@@ -4423,6 +4626,7 @@ async function _PerpsController_performUserDataPreload() {
4423
4626
  }
4424
4627
  const userAddress = evmAccount.address;
4425
4628
  const { activeProvider, isTestnet, hip3ConfigVersion } = this.state;
4629
+ const lifecycleGeneration = __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f");
4426
4630
  const { activeProviderInstance } = this;
4427
4631
  const hyperliquidDexes = __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getStaticSnapshotDexes).call(this);
4428
4632
  const isCurrent = () => {
@@ -4433,7 +4637,8 @@ async function _PerpsController_performUserDataPreload() {
4433
4637
  catch {
4434
4638
  return false;
4435
4639
  }
4436
- return (this.state.activeProvider === activeProvider &&
4640
+ return (__classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") === lifecycleGeneration &&
4641
+ this.state.activeProvider === activeProvider &&
4437
4642
  this.activeProviderInstance === activeProviderInstance &&
4438
4643
  this.state.isTestnet === isTestnet &&
4439
4644
  this.state.hip3ConfigVersion === hip3ConfigVersion &&
@@ -4476,6 +4681,15 @@ async function _PerpsController_performUserDataPreload() {
4476
4681
  const traceId = uuidv4();
4477
4682
  const preloadStart = performance.now();
4478
4683
  let traceData;
4684
+ const staleContextError = 'User data preload context changed';
4685
+ const discardStalePreload = () => {
4686
+ if (isCurrent()) {
4687
+ return false;
4688
+ }
4689
+ traceData = { success: false, error: staleContextError };
4690
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Discarding stale user data preload');
4691
+ return true;
4692
+ };
4479
4693
  try {
4480
4694
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.trace({
4481
4695
  name: PerpsTraceNames.UserDataPreload,
@@ -4489,6 +4703,9 @@ async function _PerpsController_performUserDataPreload() {
4489
4703
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Fetching user data in background');
4490
4704
  if (activeProvider === 'hyperliquid') {
4491
4705
  const snapshot = await this.getUserDataSnapshot();
4706
+ if (discardStalePreload()) {
4707
+ return;
4708
+ }
4492
4709
  __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: User data preloaded', {
4493
4710
  positionCount: snapshot.positions.length,
4494
4711
  orderCount: snapshot.orders.length,
@@ -4507,8 +4724,8 @@ async function _PerpsController_performUserDataPreload() {
4507
4724
  this.getOpenOrders({ standalone: true, userAddress }),
4508
4725
  this.getAccountState({ standalone: true, userAddress }),
4509
4726
  ]);
4510
- if (!isCurrent()) {
4511
- throw new Error('User data preload context changed');
4727
+ if (discardStalePreload()) {
4728
+ return;
4512
4729
  }
4513
4730
  if (activeProvider === 'aggregated' && activeProviderInstance) {
4514
4731
  // Split by providerId and write one cache entry per provider key
@@ -4532,6 +4749,9 @@ async function _PerpsController_performUserDataPreload() {
4532
4749
  }
4533
4750
  // AccountState — assign to its provider bucket
4534
4751
  ensureBucket(accountState.providerId ?? fallbackProviderId).accountState = accountState;
4752
+ if (discardStalePreload()) {
4753
+ return;
4754
+ }
4535
4755
  this.update((state) => {
4536
4756
  for (const [pid, data] of byProvider) {
4537
4757
  const key = buildProviderCacheKey(pid, isTestnet);
@@ -4560,6 +4780,9 @@ async function _PerpsController_performUserDataPreload() {
4560
4780
  else {
4561
4781
  // Single provider — store directly under its key
4562
4782
  const ts = Date.now();
4783
+ if (discardStalePreload()) {
4784
+ return;
4785
+ }
4563
4786
  this.update((state) => {
4564
4787
  state.cachedUserDataByProvider[providerNetworkKey] = {
4565
4788
  positions,
@@ -4589,6 +4812,9 @@ async function _PerpsController_performUserDataPreload() {
4589
4812
  __classPrivateFieldGet(this, _PerpsController_options, "f").infrastructure.tracer.setMeasurement(PerpsMeasurementName.PerpsUserDataPreload, performance.now() - preloadStart, 'millisecond', traceId);
4590
4813
  }
4591
4814
  catch (error) {
4815
+ if (discardStalePreload()) {
4816
+ return;
4817
+ }
4592
4818
  traceData = {
4593
4819
  success: false,
4594
4820
  error: ensureError(error, 'PerpsController.performUserDataPreload')
@@ -4612,6 +4838,70 @@ async function _PerpsController_performUserDataPreload() {
4612
4838
  });
4613
4839
  }
4614
4840
  }
4841
+ }, _PerpsController_performDisconnect =
4842
+ /**
4843
+ * Disconnect after this call has claimed the controller lifecycle.
4844
+ *
4845
+ * @returns A promise that resolves when teardown finishes.
4846
+ */
4847
+ async function _PerpsController_performDisconnect() {
4848
+ __classPrivateFieldSet(this, _PerpsController_lifecycleGeneration, __classPrivateFieldGet(this, _PerpsController_lifecycleGeneration, "f") + 1, "f");
4849
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_debugLog).call(this, 'PerpsController: Disconnecting provider to cleanup subscriptions', {
4850
+ timestamp: new Date().toISOString(),
4851
+ });
4852
+ // Stop preload interval and messenger subscriptions first,
4853
+ // so no background work fires while we tear down providers.
4854
+ if (__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f")) {
4855
+ clearInterval(__classPrivateFieldGet(this, _PerpsController_preloadTimer, "f"));
4856
+ __classPrivateFieldSet(this, _PerpsController_preloadTimer, null, "f");
4857
+ }
4858
+ if (__classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f")) {
4859
+ __classPrivateFieldGet(this, _PerpsController_preloadStateUnsubscribe, "f").call(this);
4860
+ __classPrivateFieldSet(this, _PerpsController_preloadStateUnsubscribe, null, "f");
4861
+ }
4862
+ if (__classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f")) {
4863
+ __classPrivateFieldGet(this, _PerpsController_accountChangeUnsubscribe, "f").call(this);
4864
+ __classPrivateFieldSet(this, _PerpsController_accountChangeUnsubscribe, null, "f");
4865
+ }
4866
+ __classPrivateFieldSet(this, _PerpsController_previousIsTestnet, null, "f");
4867
+ __classPrivateFieldSet(this, _PerpsController_previousHip3ConfigVersion, null, "f");
4868
+ const pendingReinitialization = __classPrivateFieldGet(this, _PerpsController_reinitializationOperationPromise, "f");
4869
+ if (pendingReinitialization) {
4870
+ await pendingReinitialization;
4871
+ }
4872
+ // Initialization owns provider creation. Let it finish before teardown so
4873
+ // it cannot repopulate providers after this method clears the references.
4874
+ const pendingInitialization = __classPrivateFieldGet(this, _PerpsController_initializationPromise, "f");
4875
+ if (pendingInitialization) {
4876
+ try {
4877
+ await pendingInitialization;
4878
+ }
4879
+ catch (error) {
4880
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, ensureError(error, 'PerpsController.disconnect.initialization'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect', {
4881
+ operation: 'awaitInitialization',
4882
+ }));
4883
+ }
4884
+ }
4885
+ const provider = this.activeProviderInstance;
4886
+ if (provider) {
4887
+ try {
4888
+ await provider.disconnect();
4889
+ }
4890
+ catch (error) {
4891
+ __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_logError).call(this, ensureError(error, 'PerpsController.disconnect'), __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_getErrorContext).call(this, 'disconnect'));
4892
+ }
4893
+ }
4894
+ // Clear stale reference so standalone reads don't route through old provider
4895
+ this.activeProviderInstance = null;
4896
+ // Cleanup cached standalone provider (if any) — awaited to prevent races
4897
+ await __classPrivateFieldGet(this, _PerpsController_instances, "m", _PerpsController_cleanupStandaloneProvider).call(this);
4898
+ // Note: Feature-flag subscription is NOT cleaned up here.
4899
+ // It is a controller-lifetime concern (set once in the constructor),
4900
+ // not a session-lifetime concern. Unsubscribing here would break
4901
+ // geo-blocking / HIP-3 flag propagation after disconnect → reconnect.
4902
+ // Reset initialization state to ensure proper reconnection
4903
+ this.isInitialized = false;
4904
+ __classPrivateFieldSet(this, _PerpsController_initializationPromise, null, "f");
4615
4905
  }, _PerpsController_persistWatchlistToRemote =
4616
4906
  /**
4617
4907
  * Writes the current local watchlist to AuthenticatedUserStorageService