@metamask-previews/perps-controller 1.3.0-preview-2d89a26 → 1.3.0-preview-afe010990

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/PerpsController-method-action-types.cjs +3 -0
  3. package/dist/PerpsController-method-action-types.cjs.map +1 -0
  4. package/dist/PerpsController-method-action-types.d.cts +147 -0
  5. package/dist/PerpsController-method-action-types.d.cts.map +1 -0
  6. package/dist/PerpsController-method-action-types.d.mts +147 -0
  7. package/dist/PerpsController-method-action-types.d.mts.map +1 -0
  8. package/dist/PerpsController-method-action-types.mjs +2 -0
  9. package/dist/PerpsController-method-action-types.mjs.map +1 -0
  10. package/dist/PerpsController.cjs +488 -183
  11. package/dist/PerpsController.cjs.map +1 -1
  12. package/dist/PerpsController.d.cts +91 -131
  13. package/dist/PerpsController.d.cts.map +1 -1
  14. package/dist/PerpsController.d.mts +91 -131
  15. package/dist/PerpsController.d.mts.map +1 -1
  16. package/dist/PerpsController.mjs +485 -182
  17. package/dist/PerpsController.mjs.map +1 -1
  18. package/dist/constants/eventNames.cjs +26 -0
  19. package/dist/constants/eventNames.cjs.map +1 -1
  20. package/dist/constants/eventNames.d.cts +19 -0
  21. package/dist/constants/eventNames.d.cts.map +1 -1
  22. package/dist/constants/eventNames.d.mts +19 -0
  23. package/dist/constants/eventNames.d.mts.map +1 -1
  24. package/dist/constants/eventNames.mjs +26 -0
  25. package/dist/constants/eventNames.mjs.map +1 -1
  26. package/dist/constants/hyperLiquidConfig.cjs +24 -4
  27. package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
  28. package/dist/constants/hyperLiquidConfig.d.cts +8 -3
  29. package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
  30. package/dist/constants/hyperLiquidConfig.d.mts +8 -3
  31. package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
  32. package/dist/constants/hyperLiquidConfig.mjs +23 -3
  33. package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
  34. package/dist/constants/myxConfig.cjs +75 -51
  35. package/dist/constants/myxConfig.cjs.map +1 -1
  36. package/dist/constants/myxConfig.d.cts +58 -19
  37. package/dist/constants/myxConfig.d.cts.map +1 -1
  38. package/dist/constants/myxConfig.d.mts +58 -19
  39. package/dist/constants/myxConfig.d.mts.map +1 -1
  40. package/dist/constants/myxConfig.mjs +74 -50
  41. package/dist/constants/myxConfig.mjs.map +1 -1
  42. package/dist/constants/perpsConfig.cjs +6 -2
  43. package/dist/constants/perpsConfig.cjs.map +1 -1
  44. package/dist/constants/perpsConfig.d.cts +5 -1
  45. package/dist/constants/perpsConfig.d.cts.map +1 -1
  46. package/dist/constants/perpsConfig.d.mts +5 -1
  47. package/dist/constants/perpsConfig.d.mts.map +1 -1
  48. package/dist/constants/perpsConfig.mjs +5 -1
  49. package/dist/constants/perpsConfig.mjs.map +1 -1
  50. package/dist/index.cjs +243 -25
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +48 -5
  53. package/dist/index.d.cts.map +1 -1
  54. package/dist/index.d.mts +48 -5
  55. package/dist/index.d.mts.map +1 -1
  56. package/dist/index.mjs +36 -10
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/providers/AggregatedPerpsProvider.cjs +24 -0
  59. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
  60. package/dist/providers/AggregatedPerpsProvider.d.cts +4 -0
  61. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
  62. package/dist/providers/AggregatedPerpsProvider.d.mts +4 -0
  63. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
  64. package/dist/providers/AggregatedPerpsProvider.mjs +24 -0
  65. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
  66. package/dist/providers/HyperLiquidProvider.cjs +470 -154
  67. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  68. package/dist/providers/HyperLiquidProvider.d.cts +11 -2
  69. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  70. package/dist/providers/HyperLiquidProvider.d.mts +11 -2
  71. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  72. package/dist/providers/HyperLiquidProvider.mjs +471 -155
  73. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  74. package/dist/selectors.cjs +1 -1
  75. package/dist/selectors.cjs.map +1 -1
  76. package/dist/selectors.mjs +1 -1
  77. package/dist/selectors.mjs.map +1 -1
  78. package/dist/services/AccountService.cjs +1 -1
  79. package/dist/services/AccountService.cjs.map +1 -1
  80. package/dist/services/AccountService.d.cts.map +1 -1
  81. package/dist/services/AccountService.d.mts.map +1 -1
  82. package/dist/services/AccountService.mjs +2 -2
  83. package/dist/services/AccountService.mjs.map +1 -1
  84. package/dist/services/DepositService.cjs +2 -1
  85. package/dist/services/DepositService.cjs.map +1 -1
  86. package/dist/services/DepositService.d.cts.map +1 -1
  87. package/dist/services/DepositService.d.mts.map +1 -1
  88. package/dist/services/DepositService.mjs +2 -1
  89. package/dist/services/DepositService.mjs.map +1 -1
  90. package/dist/services/EligibilityService.cjs +8 -103
  91. package/dist/services/EligibilityService.cjs.map +1 -1
  92. package/dist/services/EligibilityService.d.cts +4 -15
  93. package/dist/services/EligibilityService.d.cts.map +1 -1
  94. package/dist/services/EligibilityService.d.mts +4 -15
  95. package/dist/services/EligibilityService.d.mts.map +1 -1
  96. package/dist/services/EligibilityService.mjs +8 -103
  97. package/dist/services/EligibilityService.mjs.map +1 -1
  98. package/dist/services/HyperLiquidSubscriptionService.cjs +252 -46
  99. package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
  100. package/dist/services/HyperLiquidSubscriptionService.d.cts +1 -0
  101. package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
  102. package/dist/services/HyperLiquidSubscriptionService.d.mts +1 -0
  103. package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
  104. package/dist/services/HyperLiquidSubscriptionService.mjs +252 -46
  105. package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
  106. package/dist/services/MarketDataService.cjs +2 -4
  107. package/dist/services/MarketDataService.cjs.map +1 -1
  108. package/dist/services/MarketDataService.d.cts.map +1 -1
  109. package/dist/services/MarketDataService.d.mts.map +1 -1
  110. package/dist/services/MarketDataService.mjs +2 -4
  111. package/dist/services/MarketDataService.mjs.map +1 -1
  112. package/dist/services/TradingService.cjs +72 -6
  113. package/dist/services/TradingService.cjs.map +1 -1
  114. package/dist/services/TradingService.d.cts.map +1 -1
  115. package/dist/services/TradingService.d.mts.map +1 -1
  116. package/dist/services/TradingService.mjs +72 -6
  117. package/dist/services/TradingService.mjs.map +1 -1
  118. package/dist/types/index.cjs.map +1 -1
  119. package/dist/types/index.d.cts +51 -3
  120. package/dist/types/index.d.cts.map +1 -1
  121. package/dist/types/index.d.mts +51 -3
  122. package/dist/types/index.d.mts.map +1 -1
  123. package/dist/types/index.mjs.map +1 -1
  124. package/dist/types/messenger.cjs.map +1 -1
  125. package/dist/types/messenger.d.cts +2 -1
  126. package/dist/types/messenger.d.cts.map +1 -1
  127. package/dist/types/messenger.d.mts +2 -1
  128. package/dist/types/messenger.d.mts.map +1 -1
  129. package/dist/types/messenger.mjs.map +1 -1
  130. package/dist/types/myx-types.cjs +19 -3
  131. package/dist/types/myx-types.cjs.map +1 -1
  132. package/dist/types/myx-types.d.cts +33 -2
  133. package/dist/types/myx-types.d.cts.map +1 -1
  134. package/dist/types/myx-types.d.mts +33 -2
  135. package/dist/types/myx-types.d.mts.map +1 -1
  136. package/dist/types/myx-types.mjs +6 -2
  137. package/dist/types/myx-types.mjs.map +1 -1
  138. package/dist/types/perps-types.cjs +3 -0
  139. package/dist/types/perps-types.cjs.map +1 -1
  140. package/dist/types/perps-types.d.cts +3 -3
  141. package/dist/types/perps-types.d.cts.map +1 -1
  142. package/dist/types/perps-types.d.mts +3 -3
  143. package/dist/types/perps-types.d.mts.map +1 -1
  144. package/dist/types/perps-types.mjs +3 -0
  145. package/dist/types/perps-types.mjs.map +1 -1
  146. package/dist/utils/accountUtils.cjs.map +1 -1
  147. package/dist/utils/accountUtils.d.cts.map +1 -1
  148. package/dist/utils/accountUtils.d.mts.map +1 -1
  149. package/dist/utils/accountUtils.mjs.map +1 -1
  150. package/dist/utils/myxAdapter.cjs +360 -15
  151. package/dist/utils/myxAdapter.cjs.map +1 -1
  152. package/dist/utils/myxAdapter.d.cts +94 -7
  153. package/dist/utils/myxAdapter.d.cts.map +1 -1
  154. package/dist/utils/myxAdapter.d.mts +94 -7
  155. package/dist/utils/myxAdapter.d.mts.map +1 -1
  156. package/dist/utils/myxAdapter.mjs +351 -16
  157. package/dist/utils/myxAdapter.mjs.map +1 -1
  158. package/package.json +4 -2
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _HyperLiquidProvider_instances, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_perpDexsCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useDexAbstraction, _HyperLiquidProvider_cachedValidatedDexs, _HyperLiquidProvider_cachedAllPerpDexs, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_ensureDexAbstractionEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_extractDexsFromAllowlist, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_getCachedSpotMeta, _HyperLiquidProvider_getCachedPerpDexs, _HyperLiquidProvider_calculateHip3FeeMultiplier, _HyperLiquidProvider_getCacheKey, _HyperLiquidProvider_fetchMarketsForDex, _HyperLiquidProvider_getUsdcTokenId, _HyperLiquidProvider_isUsdhCollateralDex, _HyperLiquidProvider_getSpotUsdhBalance, _HyperLiquidProvider_getSpotUsdcBalance, _HyperLiquidProvider_transferUsdcToSpot, _HyperLiquidProvider_swapUsdcToUsdh, _HyperLiquidProvider_ensureUsdhCollateralForOrder, _HyperLiquidProvider_buildAssetMapping, _HyperLiquidProvider_queryUserDataAcrossDexs, _HyperLiquidProvider_mapError, _HyperLiquidProvider_getErrorContext, _HyperLiquidProvider_checkBuilderFeeApproval, _HyperLiquidProvider_ensureBuilderFeeApproval, _HyperLiquidProvider_checkBuilderFeeStatus, _HyperLiquidProvider_getBalanceForDex, _HyperLiquidProvider_findSourceDexWithBalance, _HyperLiquidProvider_autoTransferForHip3Order, _HyperLiquidProvider_autoTransferBackAfterClose, _HyperLiquidProvider_calculateHip3RequiredMargin, _HyperLiquidProvider_handleHip3PostOrderRebalance, _HyperLiquidProvider_handleHip3OrderRollback, _HyperLiquidProvider_validateOrderBeforePlacement, _HyperLiquidProvider_getAssetInfo, _HyperLiquidProvider_prepareAssetForTrading, _HyperLiquidProvider_handleHip3PreOrder, _HyperLiquidProvider_submitOrderWithRollback, _HyperLiquidProvider_handleOrderError, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_isFeeCacheValid, _HyperLiquidProvider_getBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
13
+ var _HyperLiquidProvider_instances, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_cachedMarketDataWithPrices, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_perpDexsCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useDexAbstraction, _HyperLiquidProvider_cachedValidatedDexs, _HyperLiquidProvider_cachedAllPerpDexs, _HyperLiquidProvider_dexDiscoveryComplete, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_ensureDexAbstractionEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_extractDexsFromAllowlist, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_backfillAssetMapForDex, _HyperLiquidProvider_getAssetIdWithRepair, _HyperLiquidProvider_getCachedSpotMeta, _HyperLiquidProvider_getCachedPerpDexs, _HyperLiquidProvider_calculateHip3FeeMultiplier, _HyperLiquidProvider_getCacheKey, _HyperLiquidProvider_fetchMarketsForDex, _HyperLiquidProvider_getUsdcTokenId, _HyperLiquidProvider_isUsdhCollateralDex, _HyperLiquidProvider_getSpotUsdhBalance, _HyperLiquidProvider_getSpotUsdcBalance, _HyperLiquidProvider_transferUsdcToSpot, _HyperLiquidProvider_swapUsdcToUsdh, _HyperLiquidProvider_ensureUsdhCollateralForOrder, _HyperLiquidProvider_buildAssetMapping, _HyperLiquidProvider_queryUserDataAcrossDexs, _HyperLiquidProvider_mapError, _HyperLiquidProvider_getErrorContext, _HyperLiquidProvider_checkBuilderFeeApproval, _HyperLiquidProvider_ensureBuilderFeeApproval, _HyperLiquidProvider_checkBuilderFeeStatus, _HyperLiquidProvider_getBalanceForDex, _HyperLiquidProvider_findSourceDexWithBalance, _HyperLiquidProvider_autoTransferForHip3Order, _HyperLiquidProvider_autoTransferBackAfterClose, _HyperLiquidProvider_calculateHip3RequiredMargin, _HyperLiquidProvider_handleHip3PostOrderRebalance, _HyperLiquidProvider_handleHip3OrderRollback, _HyperLiquidProvider_validateOrderBeforePlacement, _HyperLiquidProvider_getAssetInfo, _HyperLiquidProvider_prepareAssetForTrading, _HyperLiquidProvider_handleHip3PreOrder, _HyperLiquidProvider_submitOrderWithRollback, _HyperLiquidProvider_handleOrderError, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_getAllMids, _HyperLiquidProvider_fetchSingleDexFresh, _HyperLiquidProvider_mergeDexResultsInto, _HyperLiquidProvider_cacheFreshMarketDataSnapshot, _HyperLiquidProvider_getStaleMarketDataSnapshot, _HyperLiquidProvider_isFeeCacheValid, _HyperLiquidProvider_getBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.HyperLiquidProvider = void 0;
16
16
  const uuid_1 = require("uuid");
@@ -69,6 +69,8 @@ class HyperLiquidProvider {
69
69
  // Cache for raw meta responses (shared across methods to avoid redundant API calls)
70
70
  // Filtering is applied on-demand (cheap array operations) - no need for separate processed cache
71
71
  _HyperLiquidProvider_cachedMetaByDex.set(this, new Map());
72
+ // Last known-good market list for stale fallback when every enabled DEX fails in one fetch window.
73
+ _HyperLiquidProvider_cachedMarketDataWithPrices.set(this, null);
72
74
  // Session cache for spot metadata (contains USDC/USDH token info for HIP-3 collateral checks)
73
75
  // Pre-fetched in ensureReadyForTrading() to avoid API failures during order placement
74
76
  _HyperLiquidProvider_cachedSpotMeta.set(this, null);
@@ -98,6 +100,10 @@ class HyperLiquidProvider {
98
100
  // Cache for validated DEXs to avoid redundant perpDexs() API calls
99
101
  _HyperLiquidProvider_cachedValidatedDexs.set(this, null);
100
102
  _HyperLiquidProvider_cachedAllPerpDexs.set(this, null);
103
+ // True once DEX discovery has succeeded with real data (not a fallback).
104
+ // When false, #ensureReadyPromise is reset after each init so the next
105
+ // caller retries DEX discovery instead of reusing a degraded mapping.
106
+ _HyperLiquidProvider_dexDiscoveryComplete.set(this, false);
101
107
  // Pending promise to deduplicate concurrent getValidatedDexs() calls
102
108
  _HyperLiquidProvider_pendingValidatedDexsPromise.set(this, null);
103
109
  // Cache for USDC token ID from spot metadata
@@ -112,6 +118,8 @@ class HyperLiquidProvider {
112
118
  // Promise-based lock to prevent race conditions in concurrent initialization
113
119
  _HyperLiquidProvider_initializationPromise.set(this, null);
114
120
  _HyperLiquidProvider_messenger.set(this, void 0);
121
+ _HyperLiquidProvider_builderAddressTestnet.set(this, void 0);
122
+ _HyperLiquidProvider_builderAddressMainnet.set(this, void 0);
115
123
  /**
116
124
  * Ensure provider is ready for TRADING operations (signing required)
117
125
  *
@@ -129,6 +137,8 @@ class HyperLiquidProvider {
129
137
  _HyperLiquidProvider_tradingSetupComplete.set(this, false);
130
138
  __classPrivateFieldSet(this, _HyperLiquidProvider_deps, options.platformDependencies, "f");
131
139
  __classPrivateFieldSet(this, _HyperLiquidProvider_messenger, options.messenger, "f");
140
+ __classPrivateFieldSet(this, _HyperLiquidProvider_builderAddressTestnet, options.builderAddressTestnet, "f");
141
+ __classPrivateFieldSet(this, _HyperLiquidProvider_builderAddressMainnet, options.builderAddressMainnet, "f");
132
142
  const isTestnet = options.isTestnet ?? false;
133
143
  // Dev-friendly defaults: Enable all markets by default for easier testing (discovery mode)
134
144
  __classPrivateFieldSet(this, _HyperLiquidProvider_hip3Enabled, options.hip3Enabled ?? false, "f");
@@ -286,7 +296,7 @@ class HyperLiquidProvider {
286
296
  // Extract DEX name for API calls (main DEX = null)
287
297
  const { dex: dexName } = (0, hyperLiquidAdapter_1.parseAssetName)(params.symbol);
288
298
  // 1. Get asset info and current price
289
- const { assetInfo, currentPrice } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
299
+ const { assetInfo, currentPrice, meta } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
290
300
  symbol: params.symbol,
291
301
  dexName,
292
302
  });
@@ -322,17 +332,11 @@ class HyperLiquidProvider {
322
332
  szDecimals: assetInfo.szDecimals,
323
333
  });
324
334
  // 4. Get asset ID and validate it exists
325
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(params.symbol);
326
- if (assetId === undefined) {
327
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Asset ID lookup failed', {
328
- requestedCoin: params.symbol,
329
- dexName: dexName ?? 'main',
330
- mapSize: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
331
- mapContainsAsset: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").has(params.symbol),
332
- allKeys: Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys()).slice(0, 20),
333
- });
334
- throw new Error(`Asset ID not found for ${params.symbol}`);
335
- }
335
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
336
+ symbol: params.symbol,
337
+ dexName,
338
+ meta,
339
+ });
336
340
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Resolved DEX-specific asset ID', {
337
341
  coin: params.symbol,
338
342
  dex: dexName ?? 'main',
@@ -509,10 +513,11 @@ class HyperLiquidProvider {
509
513
  price: orderPrice,
510
514
  szDecimals: assetInfo.szDecimals,
511
515
  });
512
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(params.newOrder.symbol);
513
- if (assetId === undefined) {
514
- throw new Error(`Asset ID not found for ${params.newOrder.symbol}`);
515
- }
516
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
517
+ symbol: params.newOrder.symbol,
518
+ dexName,
519
+ meta,
520
+ });
516
521
  // Build new order parameters
517
522
  const newOrder = {
518
523
  a: assetId,
@@ -570,10 +575,10 @@ class HyperLiquidProvider {
570
575
  // Ensure provider is ready for trading (includes signing operations)
571
576
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
572
577
  const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
573
- const asset = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(params.symbol);
574
- if (asset === undefined) {
575
- throw new Error(`Asset not found for symbol: ${params.symbol}`);
576
- }
578
+ const asset = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
579
+ symbol: params.symbol,
580
+ dexName: (0, hyperLiquidAdapter_1.parseAssetName)(params.symbol).dex,
581
+ });
577
582
  const result = await exchangeClient.cancel({
578
583
  cancels: [
579
584
  {
@@ -621,16 +626,16 @@ class HyperLiquidProvider {
621
626
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
622
627
  const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
623
628
  // Map orders to SDK format and validate coins
624
- const cancelRequests = params.map((order) => {
625
- const asset = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(order.symbol);
626
- if (asset === undefined) {
627
- throw new Error(`Asset not found for symbol: ${order.symbol}`);
628
- }
629
+ const cancelRequests = await Promise.all(params.map(async (order) => {
630
+ const asset = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
631
+ symbol: order.symbol,
632
+ dexName: (0, hyperLiquidAdapter_1.parseAssetName)(order.symbol).dex,
633
+ });
629
634
  return {
630
635
  a: asset,
631
636
  o: parseInt(order.orderId, 10),
632
637
  };
633
- });
638
+ }));
634
639
  // Single batch API call
635
640
  const result = await exchangeClient.cancel({
636
641
  cancels: cancelRequests,
@@ -723,10 +728,11 @@ class HyperLiquidProvider {
723
728
  throw new Error(`Asset ${position.symbol} not found in ${dexName ?? 'main'} DEX universe`);
724
729
  }
725
730
  // Get asset ID
726
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(position.symbol);
727
- if (assetId === undefined) {
728
- throw new Error(`Asset ID not found for ${position.symbol}`);
729
- }
731
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
732
+ symbol: position.symbol,
733
+ dexName,
734
+ meta,
735
+ });
730
736
  // Calculate position details (always full close)
731
737
  const positionSize = parseFloat(position.size);
732
738
  const isBuy = positionSize < 0; // Close opposite side
@@ -899,10 +905,10 @@ class HyperLiquidProvider {
899
905
  // Cancel existing TP/SL orders for this position
900
906
  // OPTIMIZATION: Use WebSocket cache first (0 weight), fall back to single-DEX REST (20 weight)
901
907
  // Previously: queryUserDataAcrossDexs queried ALL DEXs (20 weight × N DEXs = 40+ weight)
902
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
903
- if (assetId === undefined) {
904
- throw new Error(`Asset ID not found for ${symbol}`);
905
- }
908
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
909
+ symbol,
910
+ dexName,
911
+ });
906
912
  let cancelRequests = [];
907
913
  // Use atomic getter to prevent race condition between check and get
908
914
  const cachedOrders = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getOrdersCacheIfInitialized();
@@ -1208,10 +1214,10 @@ class HyperLiquidProvider {
1208
1214
  // Determine position direction
1209
1215
  const isBuy = parseFloat(position.size) > 0; // true for long, false for short
1210
1216
  // Get asset ID for the symbol
1211
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
1212
- if (assetId === undefined) {
1213
- throw new Error(`Asset ID not found for ${symbol}`);
1214
- }
1217
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
1218
+ symbol,
1219
+ dexName: (0, hyperLiquidAdapter_1.parseAssetName)(symbol).dex,
1220
+ });
1215
1221
  // Convert amount to micro-units (HyperLiquid SDK requirement)
1216
1222
  const amountFloat = parseFloat(amount);
1217
1223
  const ntli = Math.floor(amountFloat * 1e6);
@@ -1302,10 +1308,18 @@ class HyperLiquidProvider {
1302
1308
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
1303
1309
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault(params?.accountId);
1304
1310
  // Query positions and orders across all enabled DEXs in parallel
1305
- const [stateResults, orderResults] = await Promise.all([
1311
+ const [stateResponse, orderResponse] = await Promise.all([
1306
1312
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.clearinghouseState(userParam)),
1307
1313
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.frontendOpenOrders(userParam)),
1308
1314
  ]);
1315
+ const { results: stateResults, failedDexs: failedStateDexs } = stateResponse;
1316
+ const { results: orderResults, failedDexs: failedOrderDexs } = orderResponse;
1317
+ if (failedStateDexs.length > 0 || failedOrderDexs.length > 0) {
1318
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Partial multi-DEX position fetch completed with failures', {
1319
+ failedStateDexs: failedStateDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1320
+ failedOrderDexs: failedOrderDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1321
+ });
1322
+ }
1309
1323
  // Combine all orders from all DEXs for TP/SL lookup
1310
1324
  const allOrders = orderResults.flatMap((result) => result.data);
1311
1325
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Frontend open orders (all DEXs):', {
@@ -1604,7 +1618,12 @@ class HyperLiquidProvider {
1604
1618
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
1605
1619
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault(params?.accountId);
1606
1620
  // Query orders across all enabled DEXs in parallel
1607
- const orderResults = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.frontendOpenOrders(userParam));
1621
+ const { results: orderResults, failedDexs } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.frontendOpenOrders(userParam));
1622
+ if (failedDexs.length > 0) {
1623
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Partial multi-DEX open order fetch completed with failures', {
1624
+ failedDexs: failedDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1625
+ });
1626
+ }
1608
1627
  // Combine all orders from all DEXs
1609
1628
  const rawOrders = orderResults.flatMap((result) => result.data);
1610
1629
  // Get positions for order context (already multi-DEX aware)
@@ -1819,11 +1838,43 @@ class HyperLiquidProvider {
1819
1838
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault(params?.accountId);
1820
1839
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('User address for account state:', userAddress);
1821
1840
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Network mode:', __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'TESTNET' : 'MAINNET');
1822
- // Get Spot balance (global, not DEX-specific) and Perps states across all DEXs
1823
- const [spotState, perpsStateResults] = await Promise.all([
1841
+ // Get Spot balance (global, not DEX-specific) and Perps states across all DEXs.
1842
+ // One transient DEX failure should not blank the entire account state.
1843
+ const [spotStateResult, perpsStateResult] = await Promise.allSettled([
1824
1844
  infoClient.spotClearinghouseState({ user: userAddress }),
1825
1845
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.clearinghouseState(userParam)),
1826
1846
  ]);
1847
+ const spotState = spotStateResult.status === 'fulfilled' ? spotStateResult.value : null;
1848
+ const perpsResponse = perpsStateResult.status === 'fulfilled'
1849
+ ? perpsStateResult.value
1850
+ : {
1851
+ results: [],
1852
+ failedDexs: [
1853
+ {
1854
+ dex: null,
1855
+ error: (0, errorUtils_1.ensureError)(perpsStateResult.reason, 'HyperLiquidProvider.getAccountState.perps'),
1856
+ },
1857
+ ],
1858
+ };
1859
+ const perpsStateResults = perpsResponse.results;
1860
+ const failedPerpsDexs = perpsResponse.failedDexs;
1861
+ if (spotStateResult.status === 'rejected') {
1862
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Spot state fetch failed during account state aggregation', {
1863
+ error: (0, errorUtils_1.ensureError)(spotStateResult.reason, 'HyperLiquidProvider.getAccountState.spot').message,
1864
+ });
1865
+ }
1866
+ if (failedPerpsDexs.length > 0) {
1867
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Perps account state completed with partial DEX failures', {
1868
+ failedDexs: failedPerpsDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1869
+ });
1870
+ }
1871
+ if (perpsStateResults.length === 0) {
1872
+ const failedDexNames = failedPerpsDexs.map(({ dex }) => dex ?? 'main');
1873
+ const spotErrorMessage = spotStateResult.status === 'rejected'
1874
+ ? (0, errorUtils_1.ensureError)(spotStateResult.reason, 'HyperLiquidProvider.getAccountState.spot').message
1875
+ : undefined;
1876
+ throw new Error(`Failed to fetch account state (failedDexs=[${failedDexNames.join(',')}], spotError=${spotErrorMessage ?? 'none'})`);
1877
+ }
1827
1878
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Spot state:', spotState);
1828
1879
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Perps states (all DEXs):', {
1829
1880
  dexCount: perpsStateResults.length,
@@ -1869,7 +1920,7 @@ class HyperLiquidProvider {
1869
1920
  }));
1870
1921
  // Re-throw the error so the controller can handle it properly
1871
1922
  // This allows the UI to show proper error messages instead of zeros
1872
- throw error;
1923
+ throw (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.getAccountState');
1873
1924
  }
1874
1925
  }
1875
1926
  /**
@@ -2046,7 +2097,7 @@ class HyperLiquidProvider {
2046
2097
  * Note: This is called once during initialization and cached by PerpsStreamManager.
2047
2098
  * Real-time price updates come from WebSocket subscriptions, not this method.
2048
2099
  *
2049
- * @returns A promise that resolves to the result.
2100
+ * @returns A promise that resolves to the combined market data from all enabled DEXs.
2050
2101
  */
2051
2102
  async getMarketDataWithPrices() {
2052
2103
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Getting market data with prices via HyperLiquid SDK');
@@ -2060,106 +2111,131 @@ class HyperLiquidProvider {
2060
2111
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient({ useHttp: true });
2061
2112
  // Get enabled DEXs respecting feature flags (uses cached perpDexs)
2062
2113
  const enabledDexs = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
2063
- // Fetch meta, assetCtxs, and allMids for each enabled DEX in parallel
2064
- // Optimization: Check cache first to avoid redundant API calls when buildAssetMapping
2065
- // has already fetched, or populate cache for buildAssetMapping to reuse
2114
+ // Fetch meta, assetCtxs, and allMids for each enabled DEX in parallel.
2115
+ // Check the meta cache first to avoid redundant API calls when buildAssetMapping
2116
+ // has already populated it; on cache miss, delegate to #fetchSingleDexFresh.
2066
2117
  const dexDataResults = await Promise.all(enabledDexs.map(async (dex) => {
2067
2118
  const dexKey = dex ?? '';
2068
2119
  const dexParam = dex ?? '';
2069
- try {
2070
- let meta = null;
2071
- let assetCtxs = [];
2072
- // Check if meta is already cached (e.g., from previous fetch or buildAssetMapping)
2073
- const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dexKey);
2074
- if (cachedMeta) {
2075
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Using cached meta for ${dex ?? 'main'}`, { universeSize: cachedMeta.universe.length });
2076
- meta = cachedMeta;
2077
- // Try to get cached assetCtxs from subscription service
2078
- const cachedCtxs = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getDexAssetCtxsCache(dexKey);
2079
- if (cachedCtxs) {
2080
- assetCtxs = cachedCtxs;
2081
- }
2082
- else {
2083
- // Need fresh assetCtxs, fetch via metaAndAssetCtxs (meta will be same)
2084
- const metaAndCtxs = await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined);
2085
- assetCtxs = metaAndCtxs?.[1] || [];
2086
- // Cache assetCtxs for future calls
2087
- __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexKey, assetCtxs);
2120
+ const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dexKey);
2121
+ if (!cachedMeta) {
2122
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cache miss for ${dex ?? 'main'}, fetching`);
2123
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex);
2124
+ }
2125
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Using cached meta for ${dex ?? 'main'}`, { universeSize: cachedMeta.universe.length });
2126
+ let metaForDex = cachedMeta;
2127
+ let assetCtxs = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getDexAssetCtxsCache(dexKey) ?? [];
2128
+ let failedStep;
2129
+ let errorMessage;
2130
+ if (assetCtxs.length !== metaForDex.universe.length) {
2131
+ try {
2132
+ const freshResult = await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined);
2133
+ const freshMeta = freshResult?.[0] ?? null;
2134
+ const freshAssetCtxs = freshResult?.[1] ?? [];
2135
+ if (freshAssetCtxs.length !== freshMeta?.universe?.length) {
2136
+ return {
2137
+ dex,
2138
+ meta: null,
2139
+ assetCtxs: [],
2140
+ allMids: {},
2141
+ success: false,
2142
+ failedStep: 'metaAndAssetCtxs',
2143
+ errorMessage: 'metaAndAssetCtxs returned mismatched universe/assetCtxs lengths',
2144
+ };
2088
2145
  }
2146
+ metaForDex = freshMeta;
2147
+ assetCtxs = freshAssetCtxs;
2148
+ __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, freshMeta);
2149
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(dexKey, freshMeta);
2150
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexKey, assetCtxs);
2151
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dex, freshMeta);
2089
2152
  }
2090
- else {
2091
- // Cache miss - fetch and populate cache for buildAssetMapping to reuse
2092
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cache miss for ${dex ?? 'main'}, fetching`);
2093
- const metaAndCtxs = await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined);
2094
- meta = metaAndCtxs?.[0] || null;
2095
- assetCtxs = metaAndCtxs?.[1] || [];
2096
- // IMPORTANT: Populate cache for buildAssetMapping and other methods to reuse
2097
- if (meta?.universe) {
2098
- __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, meta);
2099
- __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(dexKey, meta);
2100
- // Also cache assetCtxs for consistency with buildAssetMapping
2101
- __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexKey, assetCtxs);
2102
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cached meta for ${dex ?? 'main'}`, { universeSize: meta.universe.length });
2103
- }
2153
+ catch (error) {
2154
+ return {
2155
+ dex,
2156
+ meta: null,
2157
+ assetCtxs: [],
2158
+ allMids: {},
2159
+ success: false,
2160
+ failedStep: 'metaAndAssetCtxs',
2161
+ errorMessage: (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.getMarketDataWithPrices.metaAndAssetCtxs').message,
2162
+ };
2104
2163
  }
2105
- // Always fetch fresh allMids for current prices
2106
- const dexAllMids = await infoClient.allMids(dexParam ? { dex: dexParam } : undefined);
2107
- return {
2108
- dex,
2109
- meta,
2110
- assetCtxs,
2111
- allMids: dexAllMids || {},
2112
- success: true,
2113
- };
2164
+ }
2165
+ let dexAllMids = {};
2166
+ try {
2167
+ dexAllMids = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAllMids).call(this, infoClient, dexParam || undefined);
2114
2168
  }
2115
2169
  catch (error) {
2116
- // Log per-DEX failures locally only — the aggregate error at the end
2117
- // of this method reports to Sentry, avoiding duplicate events.
2118
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] DEX fetch failed for ${dex ?? 'main'}`, {
2119
- error: (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.getMarketDataWithPrices').message,
2120
- });
2121
- return {
2122
- dex,
2123
- meta: null,
2124
- assetCtxs: [],
2125
- allMids: {},
2126
- success: false,
2127
- };
2170
+ failedStep = 'allMids';
2171
+ errorMessage = (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.getMarketDataWithPrices.allMids').message;
2128
2172
  }
2173
+ return {
2174
+ dex,
2175
+ meta: metaForDex,
2176
+ assetCtxs,
2177
+ allMids: dexAllMids,
2178
+ success: true,
2179
+ failedStep,
2180
+ errorMessage,
2181
+ };
2129
2182
  }));
2130
2183
  // Combine universe, assetCtxs, and allMids from all DEXs
2131
2184
  const combinedUniverse = [];
2132
2185
  const combinedAssetCtxs = [];
2133
2186
  const combinedAllMids = {};
2134
- dexDataResults.forEach((result) => {
2135
- if (result.success && result.meta?.universe) {
2136
- // Apply market filtering for HIP-3 DEXs only (main DEX returns all markets)
2137
- const marketsFromDex = result.meta.universe;
2138
- const filteredMarkets = result.dex === null
2139
- ? marketsFromDex // Main DEX: no filtering
2140
- : marketsFromDex.filter((asset) => (0, marketUtils_1.shouldIncludeMarket)(asset.name, result.dex, __classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledAllowlistPatterns, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledBlocklistPatterns, "f")));
2141
- combinedUniverse.push(...filteredMarkets);
2142
- combinedAssetCtxs.push(...result.assetCtxs);
2143
- // Merge price data from this DEX into combined prices
2144
- Object.assign(combinedAllMids, result.allMids);
2145
- }
2146
- });
2187
+ let latestDexResults = dexDataResults;
2188
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mergeDexResultsInto).call(this, dexDataResults, combinedUniverse, combinedAssetCtxs, combinedAllMids);
2147
2189
  if (combinedUniverse.length === 0) {
2148
- const failedDexs = dexDataResults
2149
- .filter((result) => !result.success)
2150
- .map((result) => result.dex ?? 'main');
2151
- const succeededDexs = dexDataResults
2152
- .filter((result) => result.success)
2153
- .map((result) => result.dex ?? 'main');
2154
- const wsState = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getConnectionState();
2155
- throw new Error(`Failed to fetch market data - no markets available (enabledDexs=${enabledDexs.length}, failed=[${failedDexs.join(',')}], succeeded=[${succeededDexs.join(',')}], wsState=${wsState})`);
2190
+ combinedUniverse.length = 0;
2191
+ combinedAssetCtxs.length = 0;
2192
+ for (const key of Object.keys(combinedAllMids)) {
2193
+ delete combinedAllMids[key];
2194
+ }
2195
+ const retryDelayMs = 2000;
2196
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] All DEXs returned empty, retrying in ${retryDelayMs}ms`);
2197
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
2198
+ const retryResults = await Promise.all(enabledDexs.map((dex) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex)));
2199
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mergeDexResultsInto).call(this, retryResults, combinedUniverse, combinedAssetCtxs, combinedAllMids);
2200
+ latestDexResults = retryResults;
2201
+ if (combinedUniverse.length === 0) {
2202
+ const failedDexs = retryResults
2203
+ .filter((result) => !result.success)
2204
+ .map((result) => result.dex ?? 'main');
2205
+ const succeededDexs = retryResults
2206
+ .filter((result) => result.success)
2207
+ .map((result) => result.dex ?? 'main');
2208
+ const failedDetails = retryResults
2209
+ .filter((result) => result.errorMessage)
2210
+ .map((result) => `${result.dex ?? 'main'}:${result.failedStep ?? 'unknown'}:${result.errorMessage}`);
2211
+ const staleMarketData = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getStaleMarketDataSnapshot).call(this);
2212
+ if (staleMarketData) {
2213
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] Returning stale cached market data after retry failure', {
2214
+ failedDexs,
2215
+ failedDetails,
2216
+ cachedAt: __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, "f")?.timestamp ?? Date.now(),
2217
+ });
2218
+ return staleMarketData;
2219
+ }
2220
+ const wsState = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getConnectionState();
2221
+ throw new Error(`Failed to fetch market data - no markets available (enabledDexs=${enabledDexs.length}, failed=[${failedDexs.join(',')}], succeeded=[${succeededDexs.join(',')}], wsState=${wsState}, details=[${failedDetails.join(';')}])`);
2222
+ }
2223
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] Retry succeeded', {
2224
+ marketCount: combinedUniverse.length,
2225
+ });
2226
+ }
2227
+ const partialFailures = latestDexResults.filter((result) => result.errorMessage);
2228
+ if (partialFailures.length > 0) {
2229
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Market data fetch completed with partial per-DEX failures', {
2230
+ failures: partialFailures.map((result) => `${result.dex ?? 'main'}:${result.failedStep ?? 'unknown'}:${result.errorMessage}`),
2231
+ });
2156
2232
  }
2157
2233
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Aggregated market data from all DEXs', {
2158
2234
  dexCount: enabledDexs.length,
2159
2235
  totalMarkets: combinedUniverse.length,
2160
- mainDexMarkets: dexDataResults[0]?.meta?.universe?.length ?? 0,
2236
+ mainDexMarkets: latestDexResults[0]?.meta?.universe?.length ?? 0,
2161
2237
  hip3Markets: combinedUniverse.length -
2162
- (dexDataResults[0]?.meta?.universe?.length ?? 0),
2238
+ (latestDexResults[0]?.meta?.universe?.length ?? 0),
2163
2239
  });
2164
2240
  // Debug: Log combinedAllMids to diagnose price lookup issues
2165
2241
  const hip3Keys = Object.keys(combinedAllMids).filter((key) => key.includes(':'));
@@ -2171,11 +2247,12 @@ class HyperLiquidProvider {
2171
2247
  samplePrices: Object.fromEntries(Object.entries(combinedAllMids).slice(0, 5)),
2172
2248
  });
2173
2249
  // Transform to UI-friendly format using standalone utility
2174
- return (0, marketDataTransform_1.transformMarketData)({
2250
+ const transformedMarketData = (0, marketDataTransform_1.transformMarketData)({
2175
2251
  universe: combinedUniverse,
2176
2252
  assetCtxs: combinedAssetCtxs,
2177
2253
  allMids: combinedAllMids,
2178
2254
  }, __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").marketDataFormatters, hyperLiquidConfig_1.HIP3_ASSET_MARKET_TYPES);
2255
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheFreshMarketDataSnapshot).call(this, transformedMarketData, latestDexResults);
2179
2256
  }
2180
2257
  /**
2181
2258
  * Validate deposit parameters according to HyperLiquid-specific rules
@@ -3307,6 +3384,7 @@ class HyperLiquidProvider {
3307
3384
  __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").clear();
3308
3385
  __classPrivateFieldSet(this, _HyperLiquidProvider_cachedSpotMeta, null, "f");
3309
3386
  __classPrivateFieldSet(this, _HyperLiquidProvider_perpDexsCache, { data: null, timestamp: 0 }, "f");
3387
+ __classPrivateFieldSet(this, _HyperLiquidProvider_dexDiscoveryComplete, false, "f");
3310
3388
  // Await pending initialization before clearing to prevent the IIFE from
3311
3389
  // setting clientsInitialized = true after disconnect completes
3312
3390
  const pendingInit = __classPrivateFieldGet(this, _HyperLiquidProvider_initializationPromise, "f");
@@ -3455,6 +3533,15 @@ class HyperLiquidProvider {
3455
3533
  throw error;
3456
3534
  }
3457
3535
  }
3536
+ async fetchHistoricalCandles(options) {
3537
+ __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").ensureInitialized();
3538
+ const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").fetchHistoricalCandles(options);
3539
+ return (result ?? {
3540
+ symbol: options.symbol,
3541
+ interval: options.interval,
3542
+ candles: [],
3543
+ });
3544
+ }
3458
3545
  /**
3459
3546
  * Get block explorer URL for an address or just the base URL
3460
3547
  *
@@ -3473,7 +3560,7 @@ class HyperLiquidProvider {
3473
3560
  }
3474
3561
  }
3475
3562
  exports.HyperLiquidProvider = HyperLiquidProvider;
3476
- _HyperLiquidProvider_deps = new WeakMap(), _HyperLiquidProvider_clientService = new WeakMap(), _HyperLiquidProvider_walletService = new WeakMap(), _HyperLiquidProvider_subscriptionService = new WeakMap(), _HyperLiquidProvider_symbolToAssetId = new WeakMap(), _HyperLiquidProvider_userFeeCache = new WeakMap(), _HyperLiquidProvider_maxLeverageCache = new WeakMap(), _HyperLiquidProvider_cachedMetaByDex = new WeakMap(), _HyperLiquidProvider_cachedSpotMeta = new WeakMap(), _HyperLiquidProvider_perpDexsCache = new WeakMap(), _HyperLiquidProvider_referralCheckCache = new WeakMap(), _HyperLiquidProvider_builderFeeCheckCache = new WeakMap(), _HyperLiquidProvider_ensureReadyPromise = new WeakMap(), _HyperLiquidProvider_pendingBuilderFeeApprovals = new WeakMap(), _HyperLiquidProvider_compiledAllowlistPatterns = new WeakMap(), _HyperLiquidProvider_compiledBlocklistPatterns = new WeakMap(), _HyperLiquidProvider_userFeeDiscountBips = new WeakMap(), _HyperLiquidProvider_hip3Enabled = new WeakMap(), _HyperLiquidProvider_allowlistMarkets = new WeakMap(), _HyperLiquidProvider_blocklistMarkets = new WeakMap(), _HyperLiquidProvider_useDexAbstraction = new WeakMap(), _HyperLiquidProvider_cachedValidatedDexs = new WeakMap(), _HyperLiquidProvider_cachedAllPerpDexs = new WeakMap(), _HyperLiquidProvider_pendingValidatedDexsPromise = new WeakMap(), _HyperLiquidProvider_cachedUsdcTokenId = new WeakMap(), _HyperLiquidProvider_errorMappings = new WeakMap(), _HyperLiquidProvider_clientsInitialized = new WeakMap(), _HyperLiquidProvider_initializationPromise = new WeakMap(), _HyperLiquidProvider_messenger = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
3563
+ _HyperLiquidProvider_deps = new WeakMap(), _HyperLiquidProvider_clientService = new WeakMap(), _HyperLiquidProvider_walletService = new WeakMap(), _HyperLiquidProvider_subscriptionService = new WeakMap(), _HyperLiquidProvider_symbolToAssetId = new WeakMap(), _HyperLiquidProvider_userFeeCache = new WeakMap(), _HyperLiquidProvider_maxLeverageCache = new WeakMap(), _HyperLiquidProvider_cachedMetaByDex = new WeakMap(), _HyperLiquidProvider_cachedMarketDataWithPrices = new WeakMap(), _HyperLiquidProvider_cachedSpotMeta = new WeakMap(), _HyperLiquidProvider_perpDexsCache = new WeakMap(), _HyperLiquidProvider_referralCheckCache = new WeakMap(), _HyperLiquidProvider_builderFeeCheckCache = new WeakMap(), _HyperLiquidProvider_ensureReadyPromise = new WeakMap(), _HyperLiquidProvider_pendingBuilderFeeApprovals = new WeakMap(), _HyperLiquidProvider_compiledAllowlistPatterns = new WeakMap(), _HyperLiquidProvider_compiledBlocklistPatterns = new WeakMap(), _HyperLiquidProvider_userFeeDiscountBips = new WeakMap(), _HyperLiquidProvider_hip3Enabled = new WeakMap(), _HyperLiquidProvider_allowlistMarkets = new WeakMap(), _HyperLiquidProvider_blocklistMarkets = new WeakMap(), _HyperLiquidProvider_useDexAbstraction = new WeakMap(), _HyperLiquidProvider_cachedValidatedDexs = new WeakMap(), _HyperLiquidProvider_cachedAllPerpDexs = new WeakMap(), _HyperLiquidProvider_dexDiscoveryComplete = new WeakMap(), _HyperLiquidProvider_pendingValidatedDexsPromise = new WeakMap(), _HyperLiquidProvider_cachedUsdcTokenId = new WeakMap(), _HyperLiquidProvider_errorMappings = new WeakMap(), _HyperLiquidProvider_clientsInitialized = new WeakMap(), _HyperLiquidProvider_initializationPromise = new WeakMap(), _HyperLiquidProvider_messenger = new WeakMap(), _HyperLiquidProvider_builderAddressTestnet = new WeakMap(), _HyperLiquidProvider_builderAddressMainnet = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
3477
3564
  const compiled = [];
3478
3565
  for (const pattern of patterns) {
3479
3566
  try {
@@ -3669,8 +3756,8 @@ async function _HyperLiquidProvider_ensureReady() {
3669
3756
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureClientsInitialized).call(this);
3670
3757
  // Verify clients are properly initialized
3671
3758
  __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").ensureInitialized();
3672
- // Build asset mapping on first call only (flags are immutable)
3673
- if (__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size === 0) {
3759
+ // Build asset mapping on first call, or retry if DEX discovery previously failed
3760
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size === 0 || !__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryComplete, "f")) {
3674
3761
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Building asset mapping', {
3675
3762
  hip3Enabled: __classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"),
3676
3763
  allowlistMarkets: __classPrivateFieldGet(this, _HyperLiquidProvider_allowlistMarkets, "f"),
@@ -3683,8 +3770,15 @@ async function _HyperLiquidProvider_ensureReady() {
3683
3770
  // This prevents QR popups when just viewing the Perps section (critical for hardware wallets)
3684
3771
  })(), "f");
3685
3772
  // Await initialization - keep the promise so subsequent calls resolve immediately
3686
- // The promise is only reset in disconnect() for clean reconnection
3773
+ // The promise is only reset in disconnect() for clean reconnection,
3774
+ // or when DEX discovery was degraded so the next caller retries.
3687
3775
  await __classPrivateFieldGet(this, _HyperLiquidProvider_ensureReadyPromise, "f");
3776
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryComplete, "f")) {
3777
+ // DEX discovery failed transiently — reset so next call retries.
3778
+ // Trading still works (main DEX mapping is populated), but HIP-3 markets
3779
+ // will be re-discovered on the next #ensureReady() call.
3780
+ __classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
3781
+ }
3688
3782
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReady] Initialization complete');
3689
3783
  }, _HyperLiquidProvider_ensureReadyForTrading = async function _HyperLiquidProvider_ensureReadyForTrading() {
3690
3784
  // First ensure basic initialization is complete
@@ -3887,20 +3981,23 @@ async function _HyperLiquidProvider_fetchValidatedDexsInternal() {
3887
3981
  allDexs = await infoClient.perpDexs();
3888
3982
  }
3889
3983
  catch (error) {
3890
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error((0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.fetchValidatedDexsInternal'), __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'getValidatedDexs.perpDexs'));
3891
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, [null], "f");
3892
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedValidatedDexs, [null], "f");
3893
- return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f");
3984
+ // debugLogger not logger.error: this is a handled transient failure — the app
3985
+ // recovers to main DEX via return [null]. Sending to Sentry as error() is noise.
3986
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[fetchValidatedDexsInternal] perpDexs() call failed, falling back to main DEX', {
3987
+ error: String(error),
3988
+ ...__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'getValidatedDexs.perpDexs'),
3989
+ });
3990
+ // Do not cache — transient error, allow retry on next call
3991
+ return [null];
3894
3992
  }
3895
- // Cache for buildAssetMapping() to avoid duplicate call
3896
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, allDexs, "f");
3897
3993
  // Validate API response
3898
3994
  if (!allDexs || !Array.isArray(allDexs)) {
3899
3995
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Failed to fetch DEX list (invalid response), falling back to main DEX only', { allDexs });
3900
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, [null], "f");
3901
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedValidatedDexs, [null], "f");
3902
- return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f");
3996
+ // Do not cache — may be transient, allow retry on next call
3997
+ return [null];
3903
3998
  }
3999
+ // Cache for buildAssetMapping() to avoid duplicate call
4000
+ __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, allDexs, "f");
3904
4001
  // Extract HIP-3 DEX names (filter out null which represents main DEX)
3905
4002
  const availableHip3Dexs = [];
3906
4003
  allDexs.forEach((dex) => {
@@ -4032,19 +4129,105 @@ async function _HyperLiquidProvider_getCachedMeta(params) {
4032
4129
  }
4033
4130
  // Cache miss or skipCache=true - fetch from API
4034
4131
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
4035
- const meta = await infoClient.meta({ dex: dexKey });
4132
+ // Pass dex only for HIP-3 DEXs; omit for main DEX (empty string).
4133
+ // Testnet API returns null when dex="" is explicitly sent.
4134
+ const meta = await infoClient.meta(dexKey ? { dex: dexKey } : undefined);
4036
4135
  // Defensive validation before caching
4037
4136
  if (!meta?.universe || !Array.isArray(meta.universe)) {
4038
4137
  throw new Error(`[HyperLiquidProvider] Invalid meta response for DEX ${dexDisplayName}: universe is ${meta?.universe ? 'not an array' : 'missing'}`);
4039
4138
  }
4040
4139
  // Store raw meta response for reuse
4041
4140
  __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, meta);
4141
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta);
4042
4142
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedMeta] Fetched and cached meta response', {
4043
4143
  dex: dexDisplayName,
4044
4144
  universeSize: meta.universe.length,
4045
4145
  skipCache,
4046
4146
  });
4047
4147
  return meta;
4148
+ }, _HyperLiquidProvider_backfillAssetMapForDex =
4149
+ /**
4150
+ * Backfill the asset ID map for a single DEX from a fresh meta response.
4151
+ * Used to repair partial asset mapping when an individual DEX becomes available later.
4152
+ *
4153
+ * @param dex - DEX name (null for main DEX).
4154
+ * @param meta - Meta response containing the DEX universe.
4155
+ * @returns True if the mapping was rebuilt for the DEX.
4156
+ */
4157
+ async function _HyperLiquidProvider_backfillAssetMapForDex(dex, meta) {
4158
+ if (!meta?.universe || !Array.isArray(meta.universe)) {
4159
+ return false;
4160
+ }
4161
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f")) {
4162
+ try {
4163
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4164
+ }
4165
+ catch (error) {
4166
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[backfillAssetMapForDex] Unable to refresh validated DEXs before rebuilding asset map', {
4167
+ dex: dex ?? 'main',
4168
+ error: (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.backfillAssetMapForDex').message,
4169
+ });
4170
+ }
4171
+ }
4172
+ const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f") ?? [null];
4173
+ const perpDexIndex = allPerpDexs.findIndex((entry) => {
4174
+ if (dex === null) {
4175
+ return entry === null;
4176
+ }
4177
+ return entry !== null && entry.name === dex;
4178
+ });
4179
+ if (perpDexIndex === -1) {
4180
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[backfillAssetMapForDex] Could not find perpDexIndex for DEX', { dex: dex ?? 'main' });
4181
+ return false;
4182
+ }
4183
+ const { symbolToAssetId } = (0, hyperLiquidAdapter_1.buildAssetMapping)({
4184
+ metaUniverse: meta.universe,
4185
+ dex,
4186
+ perpDexIndex,
4187
+ });
4188
+ symbolToAssetId.forEach((assetId, coin) => {
4189
+ __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").set(coin, assetId);
4190
+ });
4191
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[backfillAssetMapForDex] Rebuilt asset mapping for DEX', {
4192
+ dex: dex ?? 'main',
4193
+ dexAssetCount: symbolToAssetId.size,
4194
+ totalAssetCount: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
4195
+ });
4196
+ return symbolToAssetId.size > 0;
4197
+ }, _HyperLiquidProvider_getAssetIdWithRepair =
4198
+ /**
4199
+ * Resolve an asset ID, repairing the DEX-specific map when meta is available but the map is stale.
4200
+ *
4201
+ * @param params - Resolution parameters.
4202
+ * @param params.symbol - Asset symbol to resolve.
4203
+ * @param params.dexName - DEX name (null for main DEX).
4204
+ * @param params.meta - Optional pre-fetched meta for the DEX.
4205
+ * @returns The asset ID.
4206
+ */
4207
+ async function _HyperLiquidProvider_getAssetIdWithRepair(params) {
4208
+ const { symbol, dexName } = params;
4209
+ const existingAssetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
4210
+ if (existingAssetId !== undefined) {
4211
+ return existingAssetId;
4212
+ }
4213
+ const meta = params.meta ?? (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCachedMeta).call(this, { dexName: dexName ?? null }));
4214
+ const assetExistsInMeta = meta.universe.some((asset) => asset.name === symbol);
4215
+ if (assetExistsInMeta) {
4216
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta);
4217
+ const repairedAssetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
4218
+ if (repairedAssetId !== undefined) {
4219
+ return repairedAssetId;
4220
+ }
4221
+ }
4222
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Asset ID lookup failed', {
4223
+ requestedCoin: symbol,
4224
+ dexName: dexName ?? 'main',
4225
+ mapSize: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
4226
+ mapContainsAsset: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").has(symbol),
4227
+ assetExistsInMeta,
4228
+ allKeys: Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys()).slice(0, 20),
4229
+ });
4230
+ throw new Error(`Asset ID not found for ${symbol}`);
4048
4231
  }, _HyperLiquidProvider_getCachedSpotMeta =
4049
4232
  /**
4050
4233
  * Fetch spot metadata with session-based caching
@@ -4341,7 +4524,7 @@ async function _HyperLiquidProvider_swapUsdcToUsdh(amount) {
4341
4524
  if (!usdhUsdcPair) {
4342
4525
  return { success: false, error: perpsErrorCodes_1.PERPS_ERROR_CODES.SPOT_PAIR_NOT_FOUND };
4343
4526
  }
4344
- const spotAssetId = 10000 + usdhUsdcPair.index;
4527
+ const spotAssetId = hyperLiquidConfig_1.SPOT_ASSET_ID_OFFSET + usdhUsdcPair.index;
4345
4528
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Found USDH/USDC spot pair', {
4346
4529
  pairIndex: usdhUsdcPair.index,
4347
4530
  pairName: usdhUsdcPair.name,
@@ -4511,12 +4694,23 @@ async function _HyperLiquidProvider_ensureUsdhCollateralForOrder(dexName, requir
4511
4694
  */
4512
4695
  async function _HyperLiquidProvider_buildAssetMapping() {
4513
4696
  // Get feature-flag-validated DEXs to map (respects hip3Enabled and enabledDexs)
4514
- const dexsToMap = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4515
- // Use cached perpDexs array (populated by getValidatedDexs)
4516
- const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f");
4517
- if (!allPerpDexs) {
4518
- throw new Error('perpDexs not cached - getValidatedDexs must be called first');
4519
- }
4697
+ let dexsToMap;
4698
+ try {
4699
+ dexsToMap = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4700
+ }
4701
+ catch (dexError) {
4702
+ // If getValidatedDexs fails, fall back to main DEX only to keep the provider
4703
+ // functional. Without this, a transient perpDexs() failure would permanently
4704
+ // brick #ensureReady via the cached rejected promise.
4705
+ // Do not set #cachedAllPerpDexs or #cachedValidatedDexs here — leave them null
4706
+ // so #getValidatedDexs retries on the next call (same as #fetchValidatedDexsInternal).
4707
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[buildAssetMapping] getValidatedDexs failed, falling back to main DEX', { error: String(dexError) });
4708
+ dexsToMap = [null];
4709
+ }
4710
+ // Local fallback only — never write [null] into #cachedAllPerpDexs here.
4711
+ // That cache is owned exclusively by #fetchValidatedDexsInternal; writing a
4712
+ // fallback here would prevent subsequent callers from retrying perpDexs().
4713
+ const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f") ?? [null];
4520
4714
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Starting asset mapping rebuild', {
4521
4715
  dexs: dexsToMap,
4522
4716
  previousMapSize: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
@@ -4569,6 +4763,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4569
4763
  }));
4570
4764
  // Build mapping with DEX prefixes for HIP-3 DEXs using the utility function
4571
4765
  __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").clear();
4766
+ let dexDiscoveryComplete = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f") !== null;
4572
4767
  allMetas.forEach((result) => {
4573
4768
  if (result.status === 'fulfilled' &&
4574
4769
  result.value.success &&
@@ -4580,6 +4775,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4580
4775
  hasUniverse: Boolean(meta.universe),
4581
4776
  isArray: Array.isArray(meta.universe),
4582
4777
  });
4778
+ dexDiscoveryComplete = false;
4583
4779
  return;
4584
4780
  }
4585
4781
  // Find perpDexIndex for this DEX in the perpDexs array
@@ -4593,6 +4789,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4593
4789
  });
4594
4790
  if (perpDexIndex === -1) {
4595
4791
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`HyperLiquidProvider: Could not find perpDexIndex for DEX ${dex ?? 'main'}`);
4792
+ dexDiscoveryComplete = false;
4596
4793
  return;
4597
4794
  }
4598
4795
  // Use the utility function to build mapping for this DEX
@@ -4606,7 +4803,11 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4606
4803
  __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").set(coin, assetId);
4607
4804
  });
4608
4805
  }
4806
+ else {
4807
+ dexDiscoveryComplete = false;
4808
+ }
4609
4809
  });
4810
+ __classPrivateFieldSet(this, _HyperLiquidProvider_dexDiscoveryComplete, dexDiscoveryComplete, "f");
4610
4811
  const allKeys = Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys());
4611
4812
  const mainDexKeys = allKeys.filter((key) => !key.includes(':')).slice(0, 5);
4612
4813
  const hip3Keys = allKeys.filter((key) => key.includes(':')).slice(0, 10);
@@ -4637,14 +4838,26 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4637
4838
  */
4638
4839
  async function _HyperLiquidProvider_queryUserDataAcrossDexs(baseParams, queryFn) {
4639
4840
  const enabledDexs = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4640
- const results = await Promise.all(enabledDexs.map(async (dex) => {
4841
+ const settledResults = await Promise.allSettled(enabledDexs.map(async (dex) => {
4641
4842
  const params = dex
4642
4843
  ? { ...baseParams, dex }
4643
4844
  : baseParams;
4644
- const data = await queryFn(params);
4645
- return { dex, data };
4845
+ return queryFn(params);
4646
4846
  }));
4647
- return results;
4847
+ const results = [];
4848
+ const failedDexs = [];
4849
+ settledResults.forEach((result, index) => {
4850
+ const dex = enabledDexs[index];
4851
+ if (result.status === 'fulfilled') {
4852
+ results.push({ dex, data: result.value });
4853
+ return;
4854
+ }
4855
+ failedDexs.push({
4856
+ dex,
4857
+ error: (0, errorUtils_1.ensureError)(result.reason, 'HyperLiquidProvider.queryUserDataAcrossDexs'),
4858
+ });
4859
+ });
4860
+ return { results, failedDexs };
4648
4861
  }, _HyperLiquidProvider_mapError = function _HyperLiquidProvider_mapError(error) {
4649
4862
  const { message } = (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.mapError');
4650
4863
  for (const [pattern, code] of Object.entries(__classPrivateFieldGet(this, _HyperLiquidProvider_errorMappings, "f"))) {
@@ -5446,6 +5659,11 @@ async function _HyperLiquidProvider_getStandaloneValidatedDexs() {
5446
5659
  if (!allDexs || !Array.isArray(allDexs)) {
5447
5660
  return [null];
5448
5661
  }
5662
+ // Populate #cachedAllPerpDexs so buildAssetMapping can compute perpDexIndex.
5663
+ // Without this, getValidatedDexs returns from #cachedValidatedDexs (string names)
5664
+ // but #cachedAllPerpDexs (raw objects for index computation) stays null,
5665
+ // causing "Could not find perpDexIndex for DEX xyz" failures.
5666
+ __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, allDexs, "f");
5449
5667
  // Extract HIP-3 DEX names (filter out null which represents main DEX)
5450
5668
  const availableHip3Dexs = [];
5451
5669
  allDexs.forEach((dex) => {
@@ -5462,6 +5680,100 @@ async function _HyperLiquidProvider_getStandaloneValidatedDexs() {
5462
5680
  const filteredDexs = availableHip3Dexs.filter((dex) => allowedDexsFromAllowlist.includes(dex));
5463
5681
  __classPrivateFieldSet(this, _HyperLiquidProvider_cachedValidatedDexs, [null, ...filteredDexs], "f");
5464
5682
  return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f");
5683
+ }, _HyperLiquidProvider_getAllMids =
5684
+ /**
5685
+ * Get allMids for a DEX — uses WS snapshot as primary source, REST as fallback.
5686
+ *
5687
+ * @param infoClient - The HyperLiquid info client (used only on cold start).
5688
+ * @param dexParam - Optional DEX parameter (empty string for main DEX).
5689
+ * @returns allMids record.
5690
+ */
5691
+ async function _HyperLiquidProvider_getAllMids(infoClient, dexParam) {
5692
+ const wsSnapshot = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getLastAllMidsSnapshot?.(dexParam);
5693
+ if (wsSnapshot) {
5694
+ return wsSnapshot;
5695
+ }
5696
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] No WS allMids snapshot, falling back to REST', { dexParam: dexParam ?? 'main' });
5697
+ const mids = await infoClient.allMids(dexParam ? { dex: dexParam } : undefined);
5698
+ return mids ?? {};
5699
+ }, _HyperLiquidProvider_fetchSingleDexFresh = async function _HyperLiquidProvider_fetchSingleDexFresh(infoClient, dex) {
5700
+ const dexParam = dex ?? '';
5701
+ let metaAndCtxs = null;
5702
+ try {
5703
+ metaAndCtxs = (await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined));
5704
+ }
5705
+ catch (error) {
5706
+ return {
5707
+ dex,
5708
+ meta: null,
5709
+ assetCtxs: [],
5710
+ allMids: {},
5711
+ success: false,
5712
+ failedStep: 'metaAndAssetCtxs',
5713
+ errorMessage: (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.getMarketDataWithPrices.metaAndAssetCtxs').message,
5714
+ };
5715
+ }
5716
+ const meta = metaAndCtxs?.[0] ?? null;
5717
+ const assetCtxs = metaAndCtxs?.[1] ?? [];
5718
+ let dexAllMids = {};
5719
+ let allMidsErrorMessage;
5720
+ try {
5721
+ dexAllMids = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAllMids).call(this, infoClient, dexParam || undefined);
5722
+ }
5723
+ catch (error) {
5724
+ allMidsErrorMessage = (0, errorUtils_1.ensureError)(error, 'HyperLiquidProvider.getMarketDataWithPrices.allMids').message;
5725
+ }
5726
+ if (meta?.universe) {
5727
+ __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexParam, meta);
5728
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(dexParam, meta);
5729
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexParam, assetCtxs);
5730
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dex, meta);
5731
+ }
5732
+ return {
5733
+ dex,
5734
+ meta,
5735
+ assetCtxs,
5736
+ allMids: dexAllMids,
5737
+ success: Boolean(meta?.universe),
5738
+ failedStep: allMidsErrorMessage ? 'allMids' : undefined,
5739
+ errorMessage: allMidsErrorMessage,
5740
+ };
5741
+ }, _HyperLiquidProvider_mergeDexResultsInto = function _HyperLiquidProvider_mergeDexResultsInto(results, combinedUniverse, combinedAssetCtxs, combinedAllMids) {
5742
+ results.forEach((result) => {
5743
+ if (result.success && result.meta?.universe) {
5744
+ const marketsFromDex = result.meta.universe;
5745
+ const filteredMarkets = result.dex === null
5746
+ ? marketsFromDex
5747
+ : marketsFromDex.filter((asset) => (0, marketUtils_1.shouldIncludeMarket)(asset.name, result.dex, __classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledAllowlistPatterns, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledBlocklistPatterns, "f")));
5748
+ combinedUniverse.push(...filteredMarkets);
5749
+ combinedAssetCtxs.push(...result.assetCtxs);
5750
+ Object.assign(combinedAllMids, result.allMids);
5751
+ }
5752
+ });
5753
+ }, _HyperLiquidProvider_cacheFreshMarketDataSnapshot = function _HyperLiquidProvider_cacheFreshMarketDataSnapshot(marketData, results) {
5754
+ const freshMarketData = marketData.map((market) => ({
5755
+ ...market,
5756
+ isStale: false,
5757
+ }));
5758
+ __classPrivateFieldSet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, {
5759
+ data: freshMarketData.map((market) => ({ ...market })),
5760
+ timestamp: Date.now(),
5761
+ contributingDexs: results
5762
+ .filter((result) => result.success && result.meta?.universe)
5763
+ .map((result) => result.dex ?? 'main'),
5764
+ failedDexs: results
5765
+ .filter((result) => !result.success)
5766
+ .map((result) => result.dex ?? 'main'),
5767
+ }, "f");
5768
+ return freshMarketData;
5769
+ }, _HyperLiquidProvider_getStaleMarketDataSnapshot = function _HyperLiquidProvider_getStaleMarketDataSnapshot() {
5770
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, "f")) {
5771
+ return null;
5772
+ }
5773
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, "f").data.map((market) => ({
5774
+ ...market,
5775
+ isStale: true,
5776
+ }));
5465
5777
  }, _HyperLiquidProvider_isFeeCacheValid = function _HyperLiquidProvider_isFeeCacheValid(userAddress) {
5466
5778
  const cached = __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeCache, "f").get(userAddress);
5467
5779
  if (!cached) {
@@ -5469,9 +5781,13 @@ async function _HyperLiquidProvider_getStandaloneValidatedDexs() {
5469
5781
  }
5470
5782
  return Date.now() - cached.timestamp < cached.ttl;
5471
5783
  }, _HyperLiquidProvider_getBuilderAddress = function _HyperLiquidProvider_getBuilderAddress(isTestnet) {
5472
- return isTestnet
5473
- ? hyperLiquidConfig_1.BUILDER_FEE_CONFIG.TestnetBuilder
5474
- : hyperLiquidConfig_1.BUILDER_FEE_CONFIG.MainnetBuilder;
5784
+ // || intentional: env vars default to '' which must fall through to the hardcoded default
5785
+ if (isTestnet) {
5786
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
5787
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_builderAddressTestnet, "f") || hyperLiquidConfig_1.BUILDER_FEE_CONFIG.TestnetBuilder;
5788
+ }
5789
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
5790
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_builderAddressMainnet, "f") || hyperLiquidConfig_1.BUILDER_FEE_CONFIG.MainnetBuilder;
5475
5791
  }, _HyperLiquidProvider_getReferralCode = function _HyperLiquidProvider_getReferralCode(isTestnet) {
5476
5792
  return isTestnet
5477
5793
  ? hyperLiquidConfig_1.REFERRAL_CONFIG.TestnetCode