@metamask-previews/perps-controller 1.3.0-preview-a0caca0c0 → 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
@@ -9,9 +9,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  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");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- 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;
12
+ 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;
13
13
  import { v4 as uuidv4 } from "uuid";
14
- import { BASIS_POINTS_DIVISOR, BUILDER_FEE_CONFIG, FEE_RATES, getBridgeInfo, getChainId, HIP3_ASSET_MARKET_TYPES, HIP3_FEE_CONFIG, HIP3_MARGIN_CONFIG, HYPERLIQUID_WITHDRAWAL_MINUTES, MAINNET_HIP3_CONFIG, REFERRAL_CONFIG, TESTNET_HIP3_CONFIG, TRADING_DEFAULTS, USDC_DECIMALS, USDH_CONFIG } from "../constants/hyperLiquidConfig.mjs";
14
+ import { BASIS_POINTS_DIVISOR, BUILDER_FEE_CONFIG, FEE_RATES, getBridgeInfo, getChainId, HIP3_ASSET_MARKET_TYPES, HIP3_FEE_CONFIG, HIP3_MARGIN_CONFIG, HYPERLIQUID_WITHDRAWAL_MINUTES, MAINNET_HIP3_CONFIG, REFERRAL_CONFIG, SPOT_ASSET_ID_OFFSET, TESTNET_HIP3_CONFIG, TRADING_DEFAULTS, USDC_DECIMALS, USDH_CONFIG } from "../constants/hyperLiquidConfig.mjs";
15
15
  import { ORDER_SLIPPAGE_CONFIG, PERFORMANCE_CONFIG, PERPS_CONSTANTS, TP_SL_CONFIG, WITHDRAWAL_CONSTANTS } from "../constants/perpsConfig.mjs";
16
16
  import { PERPS_TRANSACTIONS_HISTORY_CONSTANTS } from "../constants/transactionsHistoryConfig.mjs";
17
17
  import { PERPS_ERROR_CODES } from "../perpsErrorCodes.mjs";
@@ -66,6 +66,8 @@ export class HyperLiquidProvider {
66
66
  // Cache for raw meta responses (shared across methods to avoid redundant API calls)
67
67
  // Filtering is applied on-demand (cheap array operations) - no need for separate processed cache
68
68
  _HyperLiquidProvider_cachedMetaByDex.set(this, new Map());
69
+ // Last known-good market list for stale fallback when every enabled DEX fails in one fetch window.
70
+ _HyperLiquidProvider_cachedMarketDataWithPrices.set(this, null);
69
71
  // Session cache for spot metadata (contains USDC/USDH token info for HIP-3 collateral checks)
70
72
  // Pre-fetched in ensureReadyForTrading() to avoid API failures during order placement
71
73
  _HyperLiquidProvider_cachedSpotMeta.set(this, null);
@@ -95,6 +97,10 @@ export class HyperLiquidProvider {
95
97
  // Cache for validated DEXs to avoid redundant perpDexs() API calls
96
98
  _HyperLiquidProvider_cachedValidatedDexs.set(this, null);
97
99
  _HyperLiquidProvider_cachedAllPerpDexs.set(this, null);
100
+ // True once DEX discovery has succeeded with real data (not a fallback).
101
+ // When false, #ensureReadyPromise is reset after each init so the next
102
+ // caller retries DEX discovery instead of reusing a degraded mapping.
103
+ _HyperLiquidProvider_dexDiscoveryComplete.set(this, false);
98
104
  // Pending promise to deduplicate concurrent getValidatedDexs() calls
99
105
  _HyperLiquidProvider_pendingValidatedDexsPromise.set(this, null);
100
106
  // Cache for USDC token ID from spot metadata
@@ -109,6 +115,8 @@ export class HyperLiquidProvider {
109
115
  // Promise-based lock to prevent race conditions in concurrent initialization
110
116
  _HyperLiquidProvider_initializationPromise.set(this, null);
111
117
  _HyperLiquidProvider_messenger.set(this, void 0);
118
+ _HyperLiquidProvider_builderAddressTestnet.set(this, void 0);
119
+ _HyperLiquidProvider_builderAddressMainnet.set(this, void 0);
112
120
  /**
113
121
  * Ensure provider is ready for TRADING operations (signing required)
114
122
  *
@@ -126,6 +134,8 @@ export class HyperLiquidProvider {
126
134
  _HyperLiquidProvider_tradingSetupComplete.set(this, false);
127
135
  __classPrivateFieldSet(this, _HyperLiquidProvider_deps, options.platformDependencies, "f");
128
136
  __classPrivateFieldSet(this, _HyperLiquidProvider_messenger, options.messenger, "f");
137
+ __classPrivateFieldSet(this, _HyperLiquidProvider_builderAddressTestnet, options.builderAddressTestnet, "f");
138
+ __classPrivateFieldSet(this, _HyperLiquidProvider_builderAddressMainnet, options.builderAddressMainnet, "f");
129
139
  const isTestnet = options.isTestnet ?? false;
130
140
  // Dev-friendly defaults: Enable all markets by default for easier testing (discovery mode)
131
141
  __classPrivateFieldSet(this, _HyperLiquidProvider_hip3Enabled, options.hip3Enabled ?? false, "f");
@@ -283,7 +293,7 @@ export class HyperLiquidProvider {
283
293
  // Extract DEX name for API calls (main DEX = null)
284
294
  const { dex: dexName } = parseAssetName(params.symbol);
285
295
  // 1. Get asset info and current price
286
- const { assetInfo, currentPrice } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
296
+ const { assetInfo, currentPrice, meta } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
287
297
  symbol: params.symbol,
288
298
  dexName,
289
299
  });
@@ -319,17 +329,11 @@ export class HyperLiquidProvider {
319
329
  szDecimals: assetInfo.szDecimals,
320
330
  });
321
331
  // 4. Get asset ID and validate it exists
322
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(params.symbol);
323
- if (assetId === undefined) {
324
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Asset ID lookup failed', {
325
- requestedCoin: params.symbol,
326
- dexName: dexName ?? 'main',
327
- mapSize: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
328
- mapContainsAsset: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").has(params.symbol),
329
- allKeys: Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys()).slice(0, 20),
330
- });
331
- throw new Error(`Asset ID not found for ${params.symbol}`);
332
- }
332
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
333
+ symbol: params.symbol,
334
+ dexName,
335
+ meta,
336
+ });
333
337
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Resolved DEX-specific asset ID', {
334
338
  coin: params.symbol,
335
339
  dex: dexName ?? 'main',
@@ -506,10 +510,11 @@ export class HyperLiquidProvider {
506
510
  price: orderPrice,
507
511
  szDecimals: assetInfo.szDecimals,
508
512
  });
509
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(params.newOrder.symbol);
510
- if (assetId === undefined) {
511
- throw new Error(`Asset ID not found for ${params.newOrder.symbol}`);
512
- }
513
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
514
+ symbol: params.newOrder.symbol,
515
+ dexName,
516
+ meta,
517
+ });
513
518
  // Build new order parameters
514
519
  const newOrder = {
515
520
  a: assetId,
@@ -567,10 +572,10 @@ export class HyperLiquidProvider {
567
572
  // Ensure provider is ready for trading (includes signing operations)
568
573
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
569
574
  const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
570
- const asset = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(params.symbol);
571
- if (asset === undefined) {
572
- throw new Error(`Asset not found for symbol: ${params.symbol}`);
573
- }
575
+ const asset = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
576
+ symbol: params.symbol,
577
+ dexName: parseAssetName(params.symbol).dex,
578
+ });
574
579
  const result = await exchangeClient.cancel({
575
580
  cancels: [
576
581
  {
@@ -618,16 +623,16 @@ export class HyperLiquidProvider {
618
623
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
619
624
  const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
620
625
  // Map orders to SDK format and validate coins
621
- const cancelRequests = params.map((order) => {
622
- const asset = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(order.symbol);
623
- if (asset === undefined) {
624
- throw new Error(`Asset not found for symbol: ${order.symbol}`);
625
- }
626
+ const cancelRequests = await Promise.all(params.map(async (order) => {
627
+ const asset = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
628
+ symbol: order.symbol,
629
+ dexName: parseAssetName(order.symbol).dex,
630
+ });
626
631
  return {
627
632
  a: asset,
628
633
  o: parseInt(order.orderId, 10),
629
634
  };
630
- });
635
+ }));
631
636
  // Single batch API call
632
637
  const result = await exchangeClient.cancel({
633
638
  cancels: cancelRequests,
@@ -720,10 +725,11 @@ export class HyperLiquidProvider {
720
725
  throw new Error(`Asset ${position.symbol} not found in ${dexName ?? 'main'} DEX universe`);
721
726
  }
722
727
  // Get asset ID
723
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(position.symbol);
724
- if (assetId === undefined) {
725
- throw new Error(`Asset ID not found for ${position.symbol}`);
726
- }
728
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
729
+ symbol: position.symbol,
730
+ dexName,
731
+ meta,
732
+ });
727
733
  // Calculate position details (always full close)
728
734
  const positionSize = parseFloat(position.size);
729
735
  const isBuy = positionSize < 0; // Close opposite side
@@ -896,10 +902,10 @@ export class HyperLiquidProvider {
896
902
  // Cancel existing TP/SL orders for this position
897
903
  // OPTIMIZATION: Use WebSocket cache first (0 weight), fall back to single-DEX REST (20 weight)
898
904
  // Previously: queryUserDataAcrossDexs queried ALL DEXs (20 weight × N DEXs = 40+ weight)
899
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
900
- if (assetId === undefined) {
901
- throw new Error(`Asset ID not found for ${symbol}`);
902
- }
905
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
906
+ symbol,
907
+ dexName,
908
+ });
903
909
  let cancelRequests = [];
904
910
  // Use atomic getter to prevent race condition between check and get
905
911
  const cachedOrders = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getOrdersCacheIfInitialized();
@@ -1205,10 +1211,10 @@ export class HyperLiquidProvider {
1205
1211
  // Determine position direction
1206
1212
  const isBuy = parseFloat(position.size) > 0; // true for long, false for short
1207
1213
  // Get asset ID for the symbol
1208
- const assetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
1209
- if (assetId === undefined) {
1210
- throw new Error(`Asset ID not found for ${symbol}`);
1211
- }
1214
+ const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
1215
+ symbol,
1216
+ dexName: parseAssetName(symbol).dex,
1217
+ });
1212
1218
  // Convert amount to micro-units (HyperLiquid SDK requirement)
1213
1219
  const amountFloat = parseFloat(amount);
1214
1220
  const ntli = Math.floor(amountFloat * 1e6);
@@ -1299,10 +1305,18 @@ export class HyperLiquidProvider {
1299
1305
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
1300
1306
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault(params?.accountId);
1301
1307
  // Query positions and orders across all enabled DEXs in parallel
1302
- const [stateResults, orderResults] = await Promise.all([
1308
+ const [stateResponse, orderResponse] = await Promise.all([
1303
1309
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.clearinghouseState(userParam)),
1304
1310
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.frontendOpenOrders(userParam)),
1305
1311
  ]);
1312
+ const { results: stateResults, failedDexs: failedStateDexs } = stateResponse;
1313
+ const { results: orderResults, failedDexs: failedOrderDexs } = orderResponse;
1314
+ if (failedStateDexs.length > 0 || failedOrderDexs.length > 0) {
1315
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Partial multi-DEX position fetch completed with failures', {
1316
+ failedStateDexs: failedStateDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1317
+ failedOrderDexs: failedOrderDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1318
+ });
1319
+ }
1306
1320
  // Combine all orders from all DEXs for TP/SL lookup
1307
1321
  const allOrders = orderResults.flatMap((result) => result.data);
1308
1322
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Frontend open orders (all DEXs):', {
@@ -1601,7 +1615,12 @@ export class HyperLiquidProvider {
1601
1615
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
1602
1616
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault(params?.accountId);
1603
1617
  // Query orders across all enabled DEXs in parallel
1604
- const orderResults = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.frontendOpenOrders(userParam));
1618
+ const { results: orderResults, failedDexs } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.frontendOpenOrders(userParam));
1619
+ if (failedDexs.length > 0) {
1620
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Partial multi-DEX open order fetch completed with failures', {
1621
+ failedDexs: failedDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1622
+ });
1623
+ }
1605
1624
  // Combine all orders from all DEXs
1606
1625
  const rawOrders = orderResults.flatMap((result) => result.data);
1607
1626
  // Get positions for order context (already multi-DEX aware)
@@ -1816,11 +1835,43 @@ export class HyperLiquidProvider {
1816
1835
  const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault(params?.accountId);
1817
1836
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('User address for account state:', userAddress);
1818
1837
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Network mode:', __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'TESTNET' : 'MAINNET');
1819
- // Get Spot balance (global, not DEX-specific) and Perps states across all DEXs
1820
- const [spotState, perpsStateResults] = await Promise.all([
1838
+ // Get Spot balance (global, not DEX-specific) and Perps states across all DEXs.
1839
+ // One transient DEX failure should not blank the entire account state.
1840
+ const [spotStateResult, perpsStateResult] = await Promise.allSettled([
1821
1841
  infoClient.spotClearinghouseState({ user: userAddress }),
1822
1842
  __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_queryUserDataAcrossDexs).call(this, { user: userAddress }, (userParam) => infoClient.clearinghouseState(userParam)),
1823
1843
  ]);
1844
+ const spotState = spotStateResult.status === 'fulfilled' ? spotStateResult.value : null;
1845
+ const perpsResponse = perpsStateResult.status === 'fulfilled'
1846
+ ? perpsStateResult.value
1847
+ : {
1848
+ results: [],
1849
+ failedDexs: [
1850
+ {
1851
+ dex: null,
1852
+ error: ensureError(perpsStateResult.reason, 'HyperLiquidProvider.getAccountState.perps'),
1853
+ },
1854
+ ],
1855
+ };
1856
+ const perpsStateResults = perpsResponse.results;
1857
+ const failedPerpsDexs = perpsResponse.failedDexs;
1858
+ if (spotStateResult.status === 'rejected') {
1859
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Spot state fetch failed during account state aggregation', {
1860
+ error: ensureError(spotStateResult.reason, 'HyperLiquidProvider.getAccountState.spot').message,
1861
+ });
1862
+ }
1863
+ if (failedPerpsDexs.length > 0) {
1864
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Perps account state completed with partial DEX failures', {
1865
+ failedDexs: failedPerpsDexs.map(({ dex, error }) => `${dex ?? 'main'}:${error.message}`),
1866
+ });
1867
+ }
1868
+ if (perpsStateResults.length === 0) {
1869
+ const failedDexNames = failedPerpsDexs.map(({ dex }) => dex ?? 'main');
1870
+ const spotErrorMessage = spotStateResult.status === 'rejected'
1871
+ ? ensureError(spotStateResult.reason, 'HyperLiquidProvider.getAccountState.spot').message
1872
+ : undefined;
1873
+ throw new Error(`Failed to fetch account state (failedDexs=[${failedDexNames.join(',')}], spotError=${spotErrorMessage ?? 'none'})`);
1874
+ }
1824
1875
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Spot state:', spotState);
1825
1876
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Perps states (all DEXs):', {
1826
1877
  dexCount: perpsStateResults.length,
@@ -1866,7 +1917,7 @@ export class HyperLiquidProvider {
1866
1917
  }));
1867
1918
  // Re-throw the error so the controller can handle it properly
1868
1919
  // This allows the UI to show proper error messages instead of zeros
1869
- throw error;
1920
+ throw ensureError(error, 'HyperLiquidProvider.getAccountState');
1870
1921
  }
1871
1922
  }
1872
1923
  /**
@@ -2043,7 +2094,7 @@ export class HyperLiquidProvider {
2043
2094
  * Note: This is called once during initialization and cached by PerpsStreamManager.
2044
2095
  * Real-time price updates come from WebSocket subscriptions, not this method.
2045
2096
  *
2046
- * @returns A promise that resolves to the result.
2097
+ * @returns A promise that resolves to the combined market data from all enabled DEXs.
2047
2098
  */
2048
2099
  async getMarketDataWithPrices() {
2049
2100
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Getting market data with prices via HyperLiquid SDK');
@@ -2057,106 +2108,131 @@ export class HyperLiquidProvider {
2057
2108
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient({ useHttp: true });
2058
2109
  // Get enabled DEXs respecting feature flags (uses cached perpDexs)
2059
2110
  const enabledDexs = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
2060
- // Fetch meta, assetCtxs, and allMids for each enabled DEX in parallel
2061
- // Optimization: Check cache first to avoid redundant API calls when buildAssetMapping
2062
- // has already fetched, or populate cache for buildAssetMapping to reuse
2111
+ // Fetch meta, assetCtxs, and allMids for each enabled DEX in parallel.
2112
+ // Check the meta cache first to avoid redundant API calls when buildAssetMapping
2113
+ // has already populated it; on cache miss, delegate to #fetchSingleDexFresh.
2063
2114
  const dexDataResults = await Promise.all(enabledDexs.map(async (dex) => {
2064
2115
  const dexKey = dex ?? '';
2065
2116
  const dexParam = dex ?? '';
2066
- try {
2067
- let meta = null;
2068
- let assetCtxs = [];
2069
- // Check if meta is already cached (e.g., from previous fetch or buildAssetMapping)
2070
- const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dexKey);
2071
- if (cachedMeta) {
2072
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Using cached meta for ${dex ?? 'main'}`, { universeSize: cachedMeta.universe.length });
2073
- meta = cachedMeta;
2074
- // Try to get cached assetCtxs from subscription service
2075
- const cachedCtxs = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getDexAssetCtxsCache(dexKey);
2076
- if (cachedCtxs) {
2077
- assetCtxs = cachedCtxs;
2078
- }
2079
- else {
2080
- // Need fresh assetCtxs, fetch via metaAndAssetCtxs (meta will be same)
2081
- const metaAndCtxs = await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined);
2082
- assetCtxs = metaAndCtxs?.[1] || [];
2083
- // Cache assetCtxs for future calls
2084
- __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexKey, assetCtxs);
2117
+ const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dexKey);
2118
+ if (!cachedMeta) {
2119
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cache miss for ${dex ?? 'main'}, fetching`);
2120
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex);
2121
+ }
2122
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Using cached meta for ${dex ?? 'main'}`, { universeSize: cachedMeta.universe.length });
2123
+ let metaForDex = cachedMeta;
2124
+ let assetCtxs = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getDexAssetCtxsCache(dexKey) ?? [];
2125
+ let failedStep;
2126
+ let errorMessage;
2127
+ if (assetCtxs.length !== metaForDex.universe.length) {
2128
+ try {
2129
+ const freshResult = await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined);
2130
+ const freshMeta = freshResult?.[0] ?? null;
2131
+ const freshAssetCtxs = freshResult?.[1] ?? [];
2132
+ if (freshAssetCtxs.length !== freshMeta?.universe?.length) {
2133
+ return {
2134
+ dex,
2135
+ meta: null,
2136
+ assetCtxs: [],
2137
+ allMids: {},
2138
+ success: false,
2139
+ failedStep: 'metaAndAssetCtxs',
2140
+ errorMessage: 'metaAndAssetCtxs returned mismatched universe/assetCtxs lengths',
2141
+ };
2085
2142
  }
2143
+ metaForDex = freshMeta;
2144
+ assetCtxs = freshAssetCtxs;
2145
+ __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, freshMeta);
2146
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(dexKey, freshMeta);
2147
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexKey, assetCtxs);
2148
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dex, freshMeta);
2086
2149
  }
2087
- else {
2088
- // Cache miss - fetch and populate cache for buildAssetMapping to reuse
2089
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cache miss for ${dex ?? 'main'}, fetching`);
2090
- const metaAndCtxs = await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined);
2091
- meta = metaAndCtxs?.[0] || null;
2092
- assetCtxs = metaAndCtxs?.[1] || [];
2093
- // IMPORTANT: Populate cache for buildAssetMapping and other methods to reuse
2094
- if (meta?.universe) {
2095
- __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, meta);
2096
- __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(dexKey, meta);
2097
- // Also cache assetCtxs for consistency with buildAssetMapping
2098
- __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexKey, assetCtxs);
2099
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cached meta for ${dex ?? 'main'}`, { universeSize: meta.universe.length });
2100
- }
2150
+ catch (error) {
2151
+ return {
2152
+ dex,
2153
+ meta: null,
2154
+ assetCtxs: [],
2155
+ allMids: {},
2156
+ success: false,
2157
+ failedStep: 'metaAndAssetCtxs',
2158
+ errorMessage: ensureError(error, 'HyperLiquidProvider.getMarketDataWithPrices.metaAndAssetCtxs').message,
2159
+ };
2101
2160
  }
2102
- // Always fetch fresh allMids for current prices
2103
- const dexAllMids = await infoClient.allMids(dexParam ? { dex: dexParam } : undefined);
2104
- return {
2105
- dex,
2106
- meta,
2107
- assetCtxs,
2108
- allMids: dexAllMids || {},
2109
- success: true,
2110
- };
2161
+ }
2162
+ let dexAllMids = {};
2163
+ try {
2164
+ dexAllMids = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAllMids).call(this, infoClient, dexParam || undefined);
2111
2165
  }
2112
2166
  catch (error) {
2113
- // Log per-DEX failures locally only — the aggregate error at the end
2114
- // of this method reports to Sentry, avoiding duplicate events.
2115
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] DEX fetch failed for ${dex ?? 'main'}`, {
2116
- error: ensureError(error, 'HyperLiquidProvider.getMarketDataWithPrices').message,
2117
- });
2118
- return {
2119
- dex,
2120
- meta: null,
2121
- assetCtxs: [],
2122
- allMids: {},
2123
- success: false,
2124
- };
2167
+ failedStep = 'allMids';
2168
+ errorMessage = ensureError(error, 'HyperLiquidProvider.getMarketDataWithPrices.allMids').message;
2125
2169
  }
2170
+ return {
2171
+ dex,
2172
+ meta: metaForDex,
2173
+ assetCtxs,
2174
+ allMids: dexAllMids,
2175
+ success: true,
2176
+ failedStep,
2177
+ errorMessage,
2178
+ };
2126
2179
  }));
2127
2180
  // Combine universe, assetCtxs, and allMids from all DEXs
2128
2181
  const combinedUniverse = [];
2129
2182
  const combinedAssetCtxs = [];
2130
2183
  const combinedAllMids = {};
2131
- dexDataResults.forEach((result) => {
2132
- if (result.success && result.meta?.universe) {
2133
- // Apply market filtering for HIP-3 DEXs only (main DEX returns all markets)
2134
- const marketsFromDex = result.meta.universe;
2135
- const filteredMarkets = result.dex === null
2136
- ? marketsFromDex // Main DEX: no filtering
2137
- : marketsFromDex.filter((asset) => shouldIncludeMarket(asset.name, result.dex, __classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledAllowlistPatterns, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledBlocklistPatterns, "f")));
2138
- combinedUniverse.push(...filteredMarkets);
2139
- combinedAssetCtxs.push(...result.assetCtxs);
2140
- // Merge price data from this DEX into combined prices
2141
- Object.assign(combinedAllMids, result.allMids);
2142
- }
2143
- });
2184
+ let latestDexResults = dexDataResults;
2185
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mergeDexResultsInto).call(this, dexDataResults, combinedUniverse, combinedAssetCtxs, combinedAllMids);
2144
2186
  if (combinedUniverse.length === 0) {
2145
- const failedDexs = dexDataResults
2146
- .filter((result) => !result.success)
2147
- .map((result) => result.dex ?? 'main');
2148
- const succeededDexs = dexDataResults
2149
- .filter((result) => result.success)
2150
- .map((result) => result.dex ?? 'main');
2151
- const wsState = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getConnectionState();
2152
- throw new Error(`Failed to fetch market data - no markets available (enabledDexs=${enabledDexs.length}, failed=[${failedDexs.join(',')}], succeeded=[${succeededDexs.join(',')}], wsState=${wsState})`);
2187
+ combinedUniverse.length = 0;
2188
+ combinedAssetCtxs.length = 0;
2189
+ for (const key of Object.keys(combinedAllMids)) {
2190
+ delete combinedAllMids[key];
2191
+ }
2192
+ const retryDelayMs = 2000;
2193
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] All DEXs returned empty, retrying in ${retryDelayMs}ms`);
2194
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
2195
+ const retryResults = await Promise.all(enabledDexs.map((dex) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex)));
2196
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mergeDexResultsInto).call(this, retryResults, combinedUniverse, combinedAssetCtxs, combinedAllMids);
2197
+ latestDexResults = retryResults;
2198
+ if (combinedUniverse.length === 0) {
2199
+ const failedDexs = retryResults
2200
+ .filter((result) => !result.success)
2201
+ .map((result) => result.dex ?? 'main');
2202
+ const succeededDexs = retryResults
2203
+ .filter((result) => result.success)
2204
+ .map((result) => result.dex ?? 'main');
2205
+ const failedDetails = retryResults
2206
+ .filter((result) => result.errorMessage)
2207
+ .map((result) => `${result.dex ?? 'main'}:${result.failedStep ?? 'unknown'}:${result.errorMessage}`);
2208
+ const staleMarketData = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getStaleMarketDataSnapshot).call(this);
2209
+ if (staleMarketData) {
2210
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] Returning stale cached market data after retry failure', {
2211
+ failedDexs,
2212
+ failedDetails,
2213
+ cachedAt: __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, "f")?.timestamp ?? Date.now(),
2214
+ });
2215
+ return staleMarketData;
2216
+ }
2217
+ const wsState = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getConnectionState();
2218
+ 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(';')}])`);
2219
+ }
2220
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] Retry succeeded', {
2221
+ marketCount: combinedUniverse.length,
2222
+ });
2223
+ }
2224
+ const partialFailures = latestDexResults.filter((result) => result.errorMessage);
2225
+ if (partialFailures.length > 0) {
2226
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Market data fetch completed with partial per-DEX failures', {
2227
+ failures: partialFailures.map((result) => `${result.dex ?? 'main'}:${result.failedStep ?? 'unknown'}:${result.errorMessage}`),
2228
+ });
2153
2229
  }
2154
2230
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Aggregated market data from all DEXs', {
2155
2231
  dexCount: enabledDexs.length,
2156
2232
  totalMarkets: combinedUniverse.length,
2157
- mainDexMarkets: dexDataResults[0]?.meta?.universe?.length ?? 0,
2233
+ mainDexMarkets: latestDexResults[0]?.meta?.universe?.length ?? 0,
2158
2234
  hip3Markets: combinedUniverse.length -
2159
- (dexDataResults[0]?.meta?.universe?.length ?? 0),
2235
+ (latestDexResults[0]?.meta?.universe?.length ?? 0),
2160
2236
  });
2161
2237
  // Debug: Log combinedAllMids to diagnose price lookup issues
2162
2238
  const hip3Keys = Object.keys(combinedAllMids).filter((key) => key.includes(':'));
@@ -2168,11 +2244,12 @@ export class HyperLiquidProvider {
2168
2244
  samplePrices: Object.fromEntries(Object.entries(combinedAllMids).slice(0, 5)),
2169
2245
  });
2170
2246
  // Transform to UI-friendly format using standalone utility
2171
- return transformMarketData({
2247
+ const transformedMarketData = transformMarketData({
2172
2248
  universe: combinedUniverse,
2173
2249
  assetCtxs: combinedAssetCtxs,
2174
2250
  allMids: combinedAllMids,
2175
2251
  }, __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").marketDataFormatters, HIP3_ASSET_MARKET_TYPES);
2252
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheFreshMarketDataSnapshot).call(this, transformedMarketData, latestDexResults);
2176
2253
  }
2177
2254
  /**
2178
2255
  * Validate deposit parameters according to HyperLiquid-specific rules
@@ -3304,6 +3381,7 @@ export class HyperLiquidProvider {
3304
3381
  __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").clear();
3305
3382
  __classPrivateFieldSet(this, _HyperLiquidProvider_cachedSpotMeta, null, "f");
3306
3383
  __classPrivateFieldSet(this, _HyperLiquidProvider_perpDexsCache, { data: null, timestamp: 0 }, "f");
3384
+ __classPrivateFieldSet(this, _HyperLiquidProvider_dexDiscoveryComplete, false, "f");
3307
3385
  // Await pending initialization before clearing to prevent the IIFE from
3308
3386
  // setting clientsInitialized = true after disconnect completes
3309
3387
  const pendingInit = __classPrivateFieldGet(this, _HyperLiquidProvider_initializationPromise, "f");
@@ -3452,6 +3530,15 @@ export class HyperLiquidProvider {
3452
3530
  throw error;
3453
3531
  }
3454
3532
  }
3533
+ async fetchHistoricalCandles(options) {
3534
+ __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").ensureInitialized();
3535
+ const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").fetchHistoricalCandles(options);
3536
+ return (result ?? {
3537
+ symbol: options.symbol,
3538
+ interval: options.interval,
3539
+ candles: [],
3540
+ });
3541
+ }
3455
3542
  /**
3456
3543
  * Get block explorer URL for an address or just the base URL
3457
3544
  *
@@ -3469,7 +3556,7 @@ export class HyperLiquidProvider {
3469
3556
  return `${baseUrl}/explorer`;
3470
3557
  }
3471
3558
  }
3472
- _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) {
3559
+ _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) {
3473
3560
  const compiled = [];
3474
3561
  for (const pattern of patterns) {
3475
3562
  try {
@@ -3665,8 +3752,8 @@ async function _HyperLiquidProvider_ensureReady() {
3665
3752
  await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureClientsInitialized).call(this);
3666
3753
  // Verify clients are properly initialized
3667
3754
  __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").ensureInitialized();
3668
- // Build asset mapping on first call only (flags are immutable)
3669
- if (__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size === 0) {
3755
+ // Build asset mapping on first call, or retry if DEX discovery previously failed
3756
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size === 0 || !__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryComplete, "f")) {
3670
3757
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Building asset mapping', {
3671
3758
  hip3Enabled: __classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"),
3672
3759
  allowlistMarkets: __classPrivateFieldGet(this, _HyperLiquidProvider_allowlistMarkets, "f"),
@@ -3679,8 +3766,15 @@ async function _HyperLiquidProvider_ensureReady() {
3679
3766
  // This prevents QR popups when just viewing the Perps section (critical for hardware wallets)
3680
3767
  })(), "f");
3681
3768
  // Await initialization - keep the promise so subsequent calls resolve immediately
3682
- // The promise is only reset in disconnect() for clean reconnection
3769
+ // The promise is only reset in disconnect() for clean reconnection,
3770
+ // or when DEX discovery was degraded so the next caller retries.
3683
3771
  await __classPrivateFieldGet(this, _HyperLiquidProvider_ensureReadyPromise, "f");
3772
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryComplete, "f")) {
3773
+ // DEX discovery failed transiently — reset so next call retries.
3774
+ // Trading still works (main DEX mapping is populated), but HIP-3 markets
3775
+ // will be re-discovered on the next #ensureReady() call.
3776
+ __classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
3777
+ }
3684
3778
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReady] Initialization complete');
3685
3779
  }, _HyperLiquidProvider_ensureReadyForTrading = async function _HyperLiquidProvider_ensureReadyForTrading() {
3686
3780
  // First ensure basic initialization is complete
@@ -3883,20 +3977,23 @@ async function _HyperLiquidProvider_fetchValidatedDexsInternal() {
3883
3977
  allDexs = await infoClient.perpDexs();
3884
3978
  }
3885
3979
  catch (error) {
3886
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(ensureError(error, 'HyperLiquidProvider.fetchValidatedDexsInternal'), __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'getValidatedDexs.perpDexs'));
3887
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, [null], "f");
3888
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedValidatedDexs, [null], "f");
3889
- return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f");
3980
+ // debugLogger not logger.error: this is a handled transient failure — the app
3981
+ // recovers to main DEX via return [null]. Sending to Sentry as error() is noise.
3982
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[fetchValidatedDexsInternal] perpDexs() call failed, falling back to main DEX', {
3983
+ error: String(error),
3984
+ ...__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'getValidatedDexs.perpDexs'),
3985
+ });
3986
+ // Do not cache — transient error, allow retry on next call
3987
+ return [null];
3890
3988
  }
3891
- // Cache for buildAssetMapping() to avoid duplicate call
3892
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, allDexs, "f");
3893
3989
  // Validate API response
3894
3990
  if (!allDexs || !Array.isArray(allDexs)) {
3895
3991
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Failed to fetch DEX list (invalid response), falling back to main DEX only', { allDexs });
3896
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, [null], "f");
3897
- __classPrivateFieldSet(this, _HyperLiquidProvider_cachedValidatedDexs, [null], "f");
3898
- return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f");
3992
+ // Do not cache — may be transient, allow retry on next call
3993
+ return [null];
3899
3994
  }
3995
+ // Cache for buildAssetMapping() to avoid duplicate call
3996
+ __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, allDexs, "f");
3900
3997
  // Extract HIP-3 DEX names (filter out null which represents main DEX)
3901
3998
  const availableHip3Dexs = [];
3902
3999
  allDexs.forEach((dex) => {
@@ -4028,19 +4125,105 @@ async function _HyperLiquidProvider_getCachedMeta(params) {
4028
4125
  }
4029
4126
  // Cache miss or skipCache=true - fetch from API
4030
4127
  const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
4031
- const meta = await infoClient.meta({ dex: dexKey });
4128
+ // Pass dex only for HIP-3 DEXs; omit for main DEX (empty string).
4129
+ // Testnet API returns null when dex="" is explicitly sent.
4130
+ const meta = await infoClient.meta(dexKey ? { dex: dexKey } : undefined);
4032
4131
  // Defensive validation before caching
4033
4132
  if (!meta?.universe || !Array.isArray(meta.universe)) {
4034
4133
  throw new Error(`[HyperLiquidProvider] Invalid meta response for DEX ${dexDisplayName}: universe is ${meta?.universe ? 'not an array' : 'missing'}`);
4035
4134
  }
4036
4135
  // Store raw meta response for reuse
4037
4136
  __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, meta);
4137
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta);
4038
4138
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedMeta] Fetched and cached meta response', {
4039
4139
  dex: dexDisplayName,
4040
4140
  universeSize: meta.universe.length,
4041
4141
  skipCache,
4042
4142
  });
4043
4143
  return meta;
4144
+ }, _HyperLiquidProvider_backfillAssetMapForDex =
4145
+ /**
4146
+ * Backfill the asset ID map for a single DEX from a fresh meta response.
4147
+ * Used to repair partial asset mapping when an individual DEX becomes available later.
4148
+ *
4149
+ * @param dex - DEX name (null for main DEX).
4150
+ * @param meta - Meta response containing the DEX universe.
4151
+ * @returns True if the mapping was rebuilt for the DEX.
4152
+ */
4153
+ async function _HyperLiquidProvider_backfillAssetMapForDex(dex, meta) {
4154
+ if (!meta?.universe || !Array.isArray(meta.universe)) {
4155
+ return false;
4156
+ }
4157
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f")) {
4158
+ try {
4159
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4160
+ }
4161
+ catch (error) {
4162
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[backfillAssetMapForDex] Unable to refresh validated DEXs before rebuilding asset map', {
4163
+ dex: dex ?? 'main',
4164
+ error: ensureError(error, 'HyperLiquidProvider.backfillAssetMapForDex').message,
4165
+ });
4166
+ }
4167
+ }
4168
+ const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f") ?? [null];
4169
+ const perpDexIndex = allPerpDexs.findIndex((entry) => {
4170
+ if (dex === null) {
4171
+ return entry === null;
4172
+ }
4173
+ return entry !== null && entry.name === dex;
4174
+ });
4175
+ if (perpDexIndex === -1) {
4176
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[backfillAssetMapForDex] Could not find perpDexIndex for DEX', { dex: dex ?? 'main' });
4177
+ return false;
4178
+ }
4179
+ const { symbolToAssetId } = buildAssetMapping({
4180
+ metaUniverse: meta.universe,
4181
+ dex,
4182
+ perpDexIndex,
4183
+ });
4184
+ symbolToAssetId.forEach((assetId, coin) => {
4185
+ __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").set(coin, assetId);
4186
+ });
4187
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[backfillAssetMapForDex] Rebuilt asset mapping for DEX', {
4188
+ dex: dex ?? 'main',
4189
+ dexAssetCount: symbolToAssetId.size,
4190
+ totalAssetCount: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
4191
+ });
4192
+ return symbolToAssetId.size > 0;
4193
+ }, _HyperLiquidProvider_getAssetIdWithRepair =
4194
+ /**
4195
+ * Resolve an asset ID, repairing the DEX-specific map when meta is available but the map is stale.
4196
+ *
4197
+ * @param params - Resolution parameters.
4198
+ * @param params.symbol - Asset symbol to resolve.
4199
+ * @param params.dexName - DEX name (null for main DEX).
4200
+ * @param params.meta - Optional pre-fetched meta for the DEX.
4201
+ * @returns The asset ID.
4202
+ */
4203
+ async function _HyperLiquidProvider_getAssetIdWithRepair(params) {
4204
+ const { symbol, dexName } = params;
4205
+ const existingAssetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
4206
+ if (existingAssetId !== undefined) {
4207
+ return existingAssetId;
4208
+ }
4209
+ const meta = params.meta ?? (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCachedMeta).call(this, { dexName: dexName ?? null }));
4210
+ const assetExistsInMeta = meta.universe.some((asset) => asset.name === symbol);
4211
+ if (assetExistsInMeta) {
4212
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta);
4213
+ const repairedAssetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
4214
+ if (repairedAssetId !== undefined) {
4215
+ return repairedAssetId;
4216
+ }
4217
+ }
4218
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Asset ID lookup failed', {
4219
+ requestedCoin: symbol,
4220
+ dexName: dexName ?? 'main',
4221
+ mapSize: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
4222
+ mapContainsAsset: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").has(symbol),
4223
+ assetExistsInMeta,
4224
+ allKeys: Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys()).slice(0, 20),
4225
+ });
4226
+ throw new Error(`Asset ID not found for ${symbol}`);
4044
4227
  }, _HyperLiquidProvider_getCachedSpotMeta =
4045
4228
  /**
4046
4229
  * Fetch spot metadata with session-based caching
@@ -4337,7 +4520,7 @@ async function _HyperLiquidProvider_swapUsdcToUsdh(amount) {
4337
4520
  if (!usdhUsdcPair) {
4338
4521
  return { success: false, error: PERPS_ERROR_CODES.SPOT_PAIR_NOT_FOUND };
4339
4522
  }
4340
- const spotAssetId = 10000 + usdhUsdcPair.index;
4523
+ const spotAssetId = SPOT_ASSET_ID_OFFSET + usdhUsdcPair.index;
4341
4524
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Found USDH/USDC spot pair', {
4342
4525
  pairIndex: usdhUsdcPair.index,
4343
4526
  pairName: usdhUsdcPair.name,
@@ -4507,12 +4690,23 @@ async function _HyperLiquidProvider_ensureUsdhCollateralForOrder(dexName, requir
4507
4690
  */
4508
4691
  async function _HyperLiquidProvider_buildAssetMapping() {
4509
4692
  // Get feature-flag-validated DEXs to map (respects hip3Enabled and enabledDexs)
4510
- const dexsToMap = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4511
- // Use cached perpDexs array (populated by getValidatedDexs)
4512
- const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f");
4513
- if (!allPerpDexs) {
4514
- throw new Error('perpDexs not cached - getValidatedDexs must be called first');
4515
- }
4693
+ let dexsToMap;
4694
+ try {
4695
+ dexsToMap = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4696
+ }
4697
+ catch (dexError) {
4698
+ // If getValidatedDexs fails, fall back to main DEX only to keep the provider
4699
+ // functional. Without this, a transient perpDexs() failure would permanently
4700
+ // brick #ensureReady via the cached rejected promise.
4701
+ // Do not set #cachedAllPerpDexs or #cachedValidatedDexs here — leave them null
4702
+ // so #getValidatedDexs retries on the next call (same as #fetchValidatedDexsInternal).
4703
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[buildAssetMapping] getValidatedDexs failed, falling back to main DEX', { error: String(dexError) });
4704
+ dexsToMap = [null];
4705
+ }
4706
+ // Local fallback only — never write [null] into #cachedAllPerpDexs here.
4707
+ // That cache is owned exclusively by #fetchValidatedDexsInternal; writing a
4708
+ // fallback here would prevent subsequent callers from retrying perpDexs().
4709
+ const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedAllPerpDexs, "f") ?? [null];
4516
4710
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Starting asset mapping rebuild', {
4517
4711
  dexs: dexsToMap,
4518
4712
  previousMapSize: __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").size,
@@ -4565,6 +4759,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4565
4759
  }));
4566
4760
  // Build mapping with DEX prefixes for HIP-3 DEXs using the utility function
4567
4761
  __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").clear();
4762
+ let dexDiscoveryComplete = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f") !== null;
4568
4763
  allMetas.forEach((result) => {
4569
4764
  if (result.status === 'fulfilled' &&
4570
4765
  result.value.success &&
@@ -4576,6 +4771,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4576
4771
  hasUniverse: Boolean(meta.universe),
4577
4772
  isArray: Array.isArray(meta.universe),
4578
4773
  });
4774
+ dexDiscoveryComplete = false;
4579
4775
  return;
4580
4776
  }
4581
4777
  // Find perpDexIndex for this DEX in the perpDexs array
@@ -4589,6 +4785,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4589
4785
  });
4590
4786
  if (perpDexIndex === -1) {
4591
4787
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`HyperLiquidProvider: Could not find perpDexIndex for DEX ${dex ?? 'main'}`);
4788
+ dexDiscoveryComplete = false;
4592
4789
  return;
4593
4790
  }
4594
4791
  // Use the utility function to build mapping for this DEX
@@ -4602,7 +4799,11 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4602
4799
  __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").set(coin, assetId);
4603
4800
  });
4604
4801
  }
4802
+ else {
4803
+ dexDiscoveryComplete = false;
4804
+ }
4605
4805
  });
4806
+ __classPrivateFieldSet(this, _HyperLiquidProvider_dexDiscoveryComplete, dexDiscoveryComplete, "f");
4606
4807
  const allKeys = Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys());
4607
4808
  const mainDexKeys = allKeys.filter((key) => !key.includes(':')).slice(0, 5);
4608
4809
  const hip3Keys = allKeys.filter((key) => key.includes(':')).slice(0, 10);
@@ -4633,14 +4834,26 @@ async function _HyperLiquidProvider_buildAssetMapping() {
4633
4834
  */
4634
4835
  async function _HyperLiquidProvider_queryUserDataAcrossDexs(baseParams, queryFn) {
4635
4836
  const enabledDexs = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getValidatedDexs).call(this);
4636
- const results = await Promise.all(enabledDexs.map(async (dex) => {
4837
+ const settledResults = await Promise.allSettled(enabledDexs.map(async (dex) => {
4637
4838
  const params = dex
4638
4839
  ? { ...baseParams, dex }
4639
4840
  : baseParams;
4640
- const data = await queryFn(params);
4641
- return { dex, data };
4841
+ return queryFn(params);
4642
4842
  }));
4643
- return results;
4843
+ const results = [];
4844
+ const failedDexs = [];
4845
+ settledResults.forEach((result, index) => {
4846
+ const dex = enabledDexs[index];
4847
+ if (result.status === 'fulfilled') {
4848
+ results.push({ dex, data: result.value });
4849
+ return;
4850
+ }
4851
+ failedDexs.push({
4852
+ dex,
4853
+ error: ensureError(result.reason, 'HyperLiquidProvider.queryUserDataAcrossDexs'),
4854
+ });
4855
+ });
4856
+ return { results, failedDexs };
4644
4857
  }, _HyperLiquidProvider_mapError = function _HyperLiquidProvider_mapError(error) {
4645
4858
  const { message } = ensureError(error, 'HyperLiquidProvider.mapError');
4646
4859
  for (const [pattern, code] of Object.entries(__classPrivateFieldGet(this, _HyperLiquidProvider_errorMappings, "f"))) {
@@ -5442,6 +5655,11 @@ async function _HyperLiquidProvider_getStandaloneValidatedDexs() {
5442
5655
  if (!allDexs || !Array.isArray(allDexs)) {
5443
5656
  return [null];
5444
5657
  }
5658
+ // Populate #cachedAllPerpDexs so buildAssetMapping can compute perpDexIndex.
5659
+ // Without this, getValidatedDexs returns from #cachedValidatedDexs (string names)
5660
+ // but #cachedAllPerpDexs (raw objects for index computation) stays null,
5661
+ // causing "Could not find perpDexIndex for DEX xyz" failures.
5662
+ __classPrivateFieldSet(this, _HyperLiquidProvider_cachedAllPerpDexs, allDexs, "f");
5445
5663
  // Extract HIP-3 DEX names (filter out null which represents main DEX)
5446
5664
  const availableHip3Dexs = [];
5447
5665
  allDexs.forEach((dex) => {
@@ -5458,6 +5676,100 @@ async function _HyperLiquidProvider_getStandaloneValidatedDexs() {
5458
5676
  const filteredDexs = availableHip3Dexs.filter((dex) => allowedDexsFromAllowlist.includes(dex));
5459
5677
  __classPrivateFieldSet(this, _HyperLiquidProvider_cachedValidatedDexs, [null, ...filteredDexs], "f");
5460
5678
  return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedValidatedDexs, "f");
5679
+ }, _HyperLiquidProvider_getAllMids =
5680
+ /**
5681
+ * Get allMids for a DEX — uses WS snapshot as primary source, REST as fallback.
5682
+ *
5683
+ * @param infoClient - The HyperLiquid info client (used only on cold start).
5684
+ * @param dexParam - Optional DEX parameter (empty string for main DEX).
5685
+ * @returns allMids record.
5686
+ */
5687
+ async function _HyperLiquidProvider_getAllMids(infoClient, dexParam) {
5688
+ const wsSnapshot = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getLastAllMidsSnapshot?.(dexParam);
5689
+ if (wsSnapshot) {
5690
+ return wsSnapshot;
5691
+ }
5692
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] No WS allMids snapshot, falling back to REST', { dexParam: dexParam ?? 'main' });
5693
+ const mids = await infoClient.allMids(dexParam ? { dex: dexParam } : undefined);
5694
+ return mids ?? {};
5695
+ }, _HyperLiquidProvider_fetchSingleDexFresh = async function _HyperLiquidProvider_fetchSingleDexFresh(infoClient, dex) {
5696
+ const dexParam = dex ?? '';
5697
+ let metaAndCtxs = null;
5698
+ try {
5699
+ metaAndCtxs = (await infoClient.metaAndAssetCtxs(dexParam ? { dex: dexParam } : undefined));
5700
+ }
5701
+ catch (error) {
5702
+ return {
5703
+ dex,
5704
+ meta: null,
5705
+ assetCtxs: [],
5706
+ allMids: {},
5707
+ success: false,
5708
+ failedStep: 'metaAndAssetCtxs',
5709
+ errorMessage: ensureError(error, 'HyperLiquidProvider.getMarketDataWithPrices.metaAndAssetCtxs').message,
5710
+ };
5711
+ }
5712
+ const meta = metaAndCtxs?.[0] ?? null;
5713
+ const assetCtxs = metaAndCtxs?.[1] ?? [];
5714
+ let dexAllMids = {};
5715
+ let allMidsErrorMessage;
5716
+ try {
5717
+ dexAllMids = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAllMids).call(this, infoClient, dexParam || undefined);
5718
+ }
5719
+ catch (error) {
5720
+ allMidsErrorMessage = ensureError(error, 'HyperLiquidProvider.getMarketDataWithPrices.allMids').message;
5721
+ }
5722
+ if (meta?.universe) {
5723
+ __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexParam, meta);
5724
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(dexParam, meta);
5725
+ __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(dexParam, assetCtxs);
5726
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dex, meta);
5727
+ }
5728
+ return {
5729
+ dex,
5730
+ meta,
5731
+ assetCtxs,
5732
+ allMids: dexAllMids,
5733
+ success: Boolean(meta?.universe),
5734
+ failedStep: allMidsErrorMessage ? 'allMids' : undefined,
5735
+ errorMessage: allMidsErrorMessage,
5736
+ };
5737
+ }, _HyperLiquidProvider_mergeDexResultsInto = function _HyperLiquidProvider_mergeDexResultsInto(results, combinedUniverse, combinedAssetCtxs, combinedAllMids) {
5738
+ results.forEach((result) => {
5739
+ if (result.success && result.meta?.universe) {
5740
+ const marketsFromDex = result.meta.universe;
5741
+ const filteredMarkets = result.dex === null
5742
+ ? marketsFromDex
5743
+ : marketsFromDex.filter((asset) => shouldIncludeMarket(asset.name, result.dex, __classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledAllowlistPatterns, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_compiledBlocklistPatterns, "f")));
5744
+ combinedUniverse.push(...filteredMarkets);
5745
+ combinedAssetCtxs.push(...result.assetCtxs);
5746
+ Object.assign(combinedAllMids, result.allMids);
5747
+ }
5748
+ });
5749
+ }, _HyperLiquidProvider_cacheFreshMarketDataSnapshot = function _HyperLiquidProvider_cacheFreshMarketDataSnapshot(marketData, results) {
5750
+ const freshMarketData = marketData.map((market) => ({
5751
+ ...market,
5752
+ isStale: false,
5753
+ }));
5754
+ __classPrivateFieldSet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, {
5755
+ data: freshMarketData.map((market) => ({ ...market })),
5756
+ timestamp: Date.now(),
5757
+ contributingDexs: results
5758
+ .filter((result) => result.success && result.meta?.universe)
5759
+ .map((result) => result.dex ?? 'main'),
5760
+ failedDexs: results
5761
+ .filter((result) => !result.success)
5762
+ .map((result) => result.dex ?? 'main'),
5763
+ }, "f");
5764
+ return freshMarketData;
5765
+ }, _HyperLiquidProvider_getStaleMarketDataSnapshot = function _HyperLiquidProvider_getStaleMarketDataSnapshot() {
5766
+ if (!__classPrivateFieldGet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, "f")) {
5767
+ return null;
5768
+ }
5769
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMarketDataWithPrices, "f").data.map((market) => ({
5770
+ ...market,
5771
+ isStale: true,
5772
+ }));
5461
5773
  }, _HyperLiquidProvider_isFeeCacheValid = function _HyperLiquidProvider_isFeeCacheValid(userAddress) {
5462
5774
  const cached = __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeCache, "f").get(userAddress);
5463
5775
  if (!cached) {
@@ -5465,9 +5777,13 @@ async function _HyperLiquidProvider_getStandaloneValidatedDexs() {
5465
5777
  }
5466
5778
  return Date.now() - cached.timestamp < cached.ttl;
5467
5779
  }, _HyperLiquidProvider_getBuilderAddress = function _HyperLiquidProvider_getBuilderAddress(isTestnet) {
5468
- return isTestnet
5469
- ? BUILDER_FEE_CONFIG.TestnetBuilder
5470
- : BUILDER_FEE_CONFIG.MainnetBuilder;
5780
+ // || intentional: env vars default to '' which must fall through to the hardcoded default
5781
+ if (isTestnet) {
5782
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
5783
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_builderAddressTestnet, "f") || BUILDER_FEE_CONFIG.TestnetBuilder;
5784
+ }
5785
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
5786
+ return __classPrivateFieldGet(this, _HyperLiquidProvider_builderAddressMainnet, "f") || BUILDER_FEE_CONFIG.MainnetBuilder;
5471
5787
  }, _HyperLiquidProvider_getReferralCode = function _HyperLiquidProvider_getReferralCode(isTestnet) {
5472
5788
  return isTestnet
5473
5789
  ? REFERRAL_CONFIG.TestnetCode