@metamask-previews/perps-controller 11.0.0-preview-9c0f91815 → 11.0.0-preview-e57e5c3dc

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 (82) hide show
  1. package/CHANGELOG.md +0 -49
  2. package/dist/PerpsController.cjs.map +1 -1
  3. package/dist/PerpsController.d.cts +1 -1
  4. package/dist/PerpsController.d.cts.map +1 -1
  5. package/dist/PerpsController.d.mts +1 -1
  6. package/dist/PerpsController.d.mts.map +1 -1
  7. package/dist/PerpsController.mjs.map +1 -1
  8. package/dist/constants/eventNames.cjs +0 -4
  9. package/dist/constants/eventNames.cjs.map +1 -1
  10. package/dist/constants/eventNames.d.cts +0 -3
  11. package/dist/constants/eventNames.d.cts.map +1 -1
  12. package/dist/constants/eventNames.d.mts +0 -3
  13. package/dist/constants/eventNames.d.mts.map +1 -1
  14. package/dist/constants/eventNames.mjs +0 -4
  15. package/dist/constants/eventNames.mjs.map +1 -1
  16. package/dist/constants/perpsConfig.cjs +1 -54
  17. package/dist/constants/perpsConfig.cjs.map +1 -1
  18. package/dist/constants/perpsConfig.d.cts +2 -71
  19. package/dist/constants/perpsConfig.d.cts.map +1 -1
  20. package/dist/constants/perpsConfig.d.mts +2 -71
  21. package/dist/constants/perpsConfig.d.mts.map +1 -1
  22. package/dist/constants/perpsConfig.mjs +0 -53
  23. package/dist/constants/perpsConfig.mjs.map +1 -1
  24. package/dist/index.cjs +3 -12
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +4 -4
  27. package/dist/index.d.cts.map +1 -1
  28. package/dist/index.d.mts +4 -4
  29. package/dist/index.d.mts.map +1 -1
  30. package/dist/index.mjs +2 -2
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/perpsErrorCodes.cjs +0 -20
  33. package/dist/perpsErrorCodes.cjs.map +1 -1
  34. package/dist/perpsErrorCodes.d.cts +0 -19
  35. package/dist/perpsErrorCodes.d.cts.map +1 -1
  36. package/dist/perpsErrorCodes.d.mts +0 -19
  37. package/dist/perpsErrorCodes.d.mts.map +1 -1
  38. package/dist/perpsErrorCodes.mjs +0 -20
  39. package/dist/perpsErrorCodes.mjs.map +1 -1
  40. package/dist/providers/HyperLiquidProvider.cjs +14 -1276
  41. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  42. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  43. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  44. package/dist/providers/HyperLiquidProvider.mjs +17 -1279
  45. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  46. package/dist/types/index.cjs.map +1 -1
  47. package/dist/types/index.d.cts +2 -40
  48. package/dist/types/index.d.cts.map +1 -1
  49. package/dist/types/index.d.mts +2 -40
  50. package/dist/types/index.d.mts.map +1 -1
  51. package/dist/types/index.mjs.map +1 -1
  52. package/dist/types/perps-types.cjs.map +1 -1
  53. package/dist/types/perps-types.d.cts +2 -33
  54. package/dist/types/perps-types.d.cts.map +1 -1
  55. package/dist/types/perps-types.d.mts +2 -33
  56. package/dist/types/perps-types.d.mts.map +1 -1
  57. package/dist/types/perps-types.mjs.map +1 -1
  58. package/dist/utils/hyperLiquidValidation.cjs +3 -192
  59. package/dist/utils/hyperLiquidValidation.cjs.map +1 -1
  60. package/dist/utils/hyperLiquidValidation.d.cts +3 -30
  61. package/dist/utils/hyperLiquidValidation.d.cts.map +1 -1
  62. package/dist/utils/hyperLiquidValidation.d.mts +3 -30
  63. package/dist/utils/hyperLiquidValidation.d.mts.map +1 -1
  64. package/dist/utils/hyperLiquidValidation.mjs +5 -194
  65. package/dist/utils/hyperLiquidValidation.mjs.map +1 -1
  66. package/dist/utils/orderCalculations.cjs +1 -131
  67. package/dist/utils/orderCalculations.cjs.map +1 -1
  68. package/dist/utils/orderCalculations.d.cts +3 -88
  69. package/dist/utils/orderCalculations.d.cts.map +1 -1
  70. package/dist/utils/orderCalculations.d.mts +3 -88
  71. package/dist/utils/orderCalculations.d.mts.map +1 -1
  72. package/dist/utils/orderCalculations.mjs +2 -128
  73. package/dist/utils/orderCalculations.mjs.map +1 -1
  74. package/dist/utils/orderTypes.cjs +4 -56
  75. package/dist/utils/orderTypes.cjs.map +1 -1
  76. package/dist/utils/orderTypes.d.cts +3 -32
  77. package/dist/utils/orderTypes.d.cts.map +1 -1
  78. package/dist/utils/orderTypes.d.mts +3 -32
  79. package/dist/utils/orderTypes.d.mts.map +1 -1
  80. package/dist/utils/orderTypes.mjs +3 -54
  81. package/dist/utils/orderTypes.mjs.map +1 -1
  82. package/package.json +2 -2
@@ -9,12 +9,12 @@ 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_cachedMarketDataWithPrices, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_dexDiscoveryCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useUnifiedAccount, _HyperLiquidProvider_dexDiscoveryComplete, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_scaleOrderGroups, _HyperLiquidProvider_chaseSessions, _HyperLiquidProvider_chasePlacementsInFlight, _HyperLiquidProvider_chaseGeneration, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_priceDeviationLimit, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_isWalletOnHyperliquid, _HyperLiquidProvider_isHyperliquidMultiSigAccount, _HyperLiquidProvider_ensureUnifiedAccountEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_backfillAssetMapForDex, _HyperLiquidProvider_getAssetIdWithRepair, _HyperLiquidProvider_getCachedSpotMeta, _HyperLiquidProvider_getCachedPerpDexs, _HyperLiquidProvider_calculateHip3FeeMultiplier, _HyperLiquidProvider_getCacheKey, _HyperLiquidProvider_fetchMarketsForDex, _HyperLiquidProvider_getUsdcTokenId, _HyperLiquidProvider_isUsdcCollateralDex, _HyperLiquidProvider_buildAssetMapping, _HyperLiquidProvider_queryUserDataAcrossDexs, _HyperLiquidProvider_mapError, _HyperLiquidProvider_getErrorContext, _HyperLiquidProvider_isMappedAccountModeExchangeError, _HyperLiquidProvider_getTradingErrorContext, _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_placeStrategyOrder, _HyperLiquidProvider_prepareStrategyPlacement, _HyperLiquidProvider_getMinimumOrderSize, _HyperLiquidProvider_buildScaleLadder, _HyperLiquidProvider_placeTwapOrder, _HyperLiquidProvider_placeScaleOrder, _HyperLiquidProvider_startChaseSession, _HyperLiquidProvider_getChaseQuotePrice, _HyperLiquidProvider_restChaseOrder, _HyperLiquidProvider_scheduleChaseTick, _HyperLiquidProvider_recoverFailedChaseTick, _HyperLiquidProvider_runChaseTick, _HyperLiquidProvider_resolveOwnRestingSizes, _HyperLiquidProvider_readOrderRemainder, _HyperLiquidProvider_cancelChaseChild, _HyperLiquidProvider_retractOrphanedChaseOrder, _HyperLiquidProvider_stopChaseSession, _HyperLiquidProvider_cancelStrategyOrder, _HyperLiquidProvider_cancelTwapOrder, _HyperLiquidProvider_cancelScaleOrder, _HyperLiquidProvider_cancelChaseOrder, _HyperLiquidProvider_readOrderIdFromStatus, _HyperLiquidProvider_getDiscountedBuilderFee, _HyperLiquidProvider_fetchOpenOrders, _HyperLiquidProvider_resolveReplacementOrderId, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_queryDexPositions, _HyperLiquidProvider_getAllMids, _HyperLiquidProvider_fetchSingleDexFresh, _HyperLiquidProvider_excludeNonUsdcCollateralResults, _HyperLiquidProvider_mergeDexResultsInto, _HyperLiquidProvider_cacheFreshMarketDataSnapshot, _HyperLiquidProvider_getStaleMarketDataSnapshot, _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_dexDiscoveryCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useUnifiedAccount, _HyperLiquidProvider_dexDiscoveryComplete, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_priceDeviationLimit, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_isWalletOnHyperliquid, _HyperLiquidProvider_isHyperliquidMultiSigAccount, _HyperLiquidProvider_ensureUnifiedAccountEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_backfillAssetMapForDex, _HyperLiquidProvider_getAssetIdWithRepair, _HyperLiquidProvider_getCachedSpotMeta, _HyperLiquidProvider_getCachedPerpDexs, _HyperLiquidProvider_calculateHip3FeeMultiplier, _HyperLiquidProvider_getCacheKey, _HyperLiquidProvider_fetchMarketsForDex, _HyperLiquidProvider_getUsdcTokenId, _HyperLiquidProvider_isUsdcCollateralDex, _HyperLiquidProvider_buildAssetMapping, _HyperLiquidProvider_queryUserDataAcrossDexs, _HyperLiquidProvider_mapError, _HyperLiquidProvider_getErrorContext, _HyperLiquidProvider_isMappedAccountModeExchangeError, _HyperLiquidProvider_getTradingErrorContext, _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_fetchOpenOrders, _HyperLiquidProvider_resolveReplacementOrderId, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_queryDexPositions, _HyperLiquidProvider_getAllMids, _HyperLiquidProvider_fetchSingleDexFresh, _HyperLiquidProvider_excludeNonUsdcCollateralResults, _HyperLiquidProvider_mergeDexResultsInto, _HyperLiquidProvider_cacheFreshMarketDataSnapshot, _HyperLiquidProvider_getStaleMarketDataSnapshot, _HyperLiquidProvider_isFeeCacheValid, _HyperLiquidProvider_getBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
13
13
  import { hasProperty } from "@metamask/utils";
14
14
  import { v4 as uuidv4 } from "uuid";
15
15
  import { PERPS_EVENT_PROPERTY, PERPS_EVENT_VALUE } from "../constants/eventNames.mjs";
16
16
  import { BASIS_POINTS_DIVISOR, BUILDER_FEE_CONFIG, FEE_RATES, getBridgeInfo, getChainId, HIP3_ASSET_MARKET_TYPES, HIP3_FEE_CONFIG, HIP3_MARGIN_CONFIG, HYPERLIQUID_ASSET_NAMES, HYPERLIQUID_CONFIG, HYPERLIQUID_WITHDRAWAL_MINUTES, REFERRAL_CONFIG, TRADING_DEFAULTS, USDC_DECIMALS, USDC_SYMBOL } from "../constants/hyperLiquidConfig.mjs";
17
- import { CHASE_ORDER_CONFIG, HYPERLIQUID_TWAP_LIMITS, ORDER_SLIPPAGE_CONFIG, PERFORMANCE_CONFIG, PERPS_CONSTANTS, TP_SL_CONFIG, WITHDRAWAL_CONSTANTS } from "../constants/perpsConfig.mjs";
17
+ import { ORDER_SLIPPAGE_CONFIG, PERFORMANCE_CONFIG, PERPS_CONSTANTS, TP_SL_CONFIG, WITHDRAWAL_CONSTANTS } from "../constants/perpsConfig.mjs";
18
18
  import { PERPS_TRANSACTIONS_HISTORY_CONSTANTS } from "../constants/transactionsHistoryConfig.mjs";
19
19
  import { PERPS_ERROR_CODES } from "../perpsErrorCodes.mjs";
20
20
  import { DexDiscoveryCacheManager } from "../services/DexDiscoveryCacheManager.mjs";
@@ -29,11 +29,10 @@ import { ensureError, isHyperLiquidMultiSigRequiredError, isHyperLiquidUserNotFo
29
29
  import { shouldDeferUnifiedAccountSetup } from "../utils/hyperLiquidAbstraction.mjs";
30
30
  import { adaptAccountStateFromSDK, adaptHyperLiquidLedgerUpdateToUserHistoryItem, adaptMarketFromSDK, adaptOrderFromSDK, adaptPositionFromSDK, adaptPositionTriggerOrderFromSDK, adaptTpslLinkageToGrouping, buildAssetMapping, formatHyperLiquidPrice, formatHyperLiquidSize, parseAssetName } from "../utils/hyperLiquidAdapter.mjs";
31
31
  import { createErrorResult, getMaxOrderValue, getSupportedPaths, validateAssetSupport, validateBalance, validateCoinExists, validateDepositParams, validateOrderParams, validateWithdrawalParams } from "../utils/hyperLiquidValidation.mjs";
32
- import { generatePerpsId } from "../utils/idUtils.mjs";
33
32
  import { transformMarketData } from "../utils/marketDataTransform.mjs";
34
33
  import { compileMarketPattern, shouldIncludeMarket } from "../utils/marketUtils.mjs";
35
- import { buildOrdersArray, calculateFinalPositionSize, calculateOrderPriceAndSize, computeChaseQuotePrice, computeScalePriceLadder, floorToSizeDecimals, formatPartialTpslSize, splitScaleSizes, validateOrderPrecision } from "../utils/orderCalculations.mjs";
36
- import { getTriggerExecution, isLimitExecutionOrderType, isStrategyOrderType, isTriggerOrderType, toSDKTimeInForce } from "../utils/orderTypes.mjs";
34
+ import { buildOrdersArray, calculateFinalPositionSize, calculateOrderPriceAndSize, floorToSizeDecimals, formatPartialTpslSize, validateOrderPrecision } from "../utils/orderCalculations.mjs";
35
+ import { getTriggerExecution, isLimitExecutionOrderType, isTriggerOrderType, toSDKTimeInForce } from "../utils/orderTypes.mjs";
37
36
  import { createStandaloneInfoClient, queryStandaloneClearinghouseStates, queryStandaloneOpenOrders } from "../utils/standaloneInfoClient.mjs";
38
37
  // getStreamManagerInstance removed: use this.#deps.streamManager instead
39
38
  /**
@@ -44,137 +43,6 @@ import { createStandaloneInfoClient, queryStandaloneClearinghouseStates, querySt
44
43
  * @returns The result of the operation.
45
44
  */
46
45
  const isStatusObject = (status) => typeof status === 'object' && status !== null;
47
- /**
48
- * Exchange messages that mean a cancel was refused because the order is not on
49
- * the book any more.
50
- *
51
- * HyperLiquid answers a cancel it cannot match with "Order was never placed,
52
- * already canceled, or filled." That is a rejection of the request but a
53
- * confirmation of what the caller wanted — nothing of that order is resting.
54
- * Every other rejection (multi-sig, a stale nonce, a rate limit) leaves the
55
- * order exactly where it was, which is a materially different outcome.
56
- */
57
- const ALREADY_GONE_CANCEL_MARKERS = [
58
- 'never placed',
59
- 'already canceled',
60
- 'already cancelled',
61
- 'order not found',
62
- ];
63
- /**
64
- * Classify one entry of a cancel response.
65
- *
66
- * @param status - A single status from the exchange's cancel response.
67
- * @returns Whether the order was cancelled, was already gone, or still rests.
68
- */
69
- const classifyCancelStatus = (status) => {
70
- if (status === 'success') {
71
- return 'cancelled';
72
- }
73
- const message = (isStatusObject(status) && typeof status.error === 'string'
74
- ? status.error
75
- : '').toLowerCase();
76
- return ALREADY_GONE_CANCEL_MARKERS.some((marker) => message.includes(marker))
77
- ? 'gone'
78
- : 'refused';
79
- };
80
- /**
81
- * Read the best price on one side of the book, discounting the chase's own
82
- * order.
83
- *
84
- * A chase rests one tick inside the spread, so its own order *is* the best
85
- * price on its side. Reading the raw book would therefore see the chase's own
86
- * quote every tick, conclude the touch has not moved, and never re-price —
87
- * masking exactly the adverse moves the strategy exists to follow. Levels this
88
- * provider occupies are netted down by what it holds there, and are skipped
89
- * entirely when nothing else is left on them.
90
- *
91
- * "Own" means *every* chase this provider is running on that side, not just the
92
- * one asking. Two chases on the same side each netting only themselves would
93
- * read the other as the external touch and improve on it, then improve on the
94
- * improvement — walking each other toward the opposite side of an unchanged
95
- * market.
96
- *
97
- * The sizes must be what the orders still have resting, not what they were
98
- * placed for: an order netted at its original size subtracts more than it
99
- * occupies, which can hide external liquidity sharing the level.
100
- *
101
- * @param levels - One side of the book, best-first.
102
- * @param ownByPrice - This provider's own resting size at each price.
103
- * @returns The best price other participants are showing, or null.
104
- */
105
- const readBestExternalPrice = (levels, ownByPrice) => {
106
- for (const level of levels ?? []) {
107
- const price = parseFloat(level.px);
108
- if (!Number.isFinite(price) || price <= 0) {
109
- continue;
110
- }
111
- const size = parseFloat(level.sz) - (ownByPrice.get(level.px) ?? 0);
112
- if (size > 0) {
113
- return price;
114
- }
115
- }
116
- return null;
117
- };
118
- /**
119
- * Narrow order params down to their strategy fields.
120
- *
121
- * Both validation entry points forward exactly this group, so a field added to
122
- * `StrategyOrderValidationParams` reaches both of them or neither.
123
- *
124
- * @param params - Order parameters.
125
- * @returns The strategy fields, as validation takes them.
126
- */
127
- const pickStrategyParams = (params) => ({
128
- twapDuration: params.twapDuration,
129
- twapRandomize: params.twapRandomize,
130
- scaleMinPrice: params.scaleMinPrice,
131
- scaleMaxPrice: params.scaleMaxPrice,
132
- scaleNumOrders: params.scaleNumOrders,
133
- chaseIntervalMs: params.chaseIntervalMs,
134
- chaseMaxDurationMs: params.chaseMaxDurationMs,
135
- chaseMaxRepricings: params.chaseMaxRepricings,
136
- });
137
- /**
138
- * Check a strategy placement's notional against the minimum the venue will
139
- * actually apply to it.
140
- *
141
- * The per-order minimum is charged against each order the venue receives, and a
142
- * strategy placement does not send one order:
143
- *
144
- * A `twap` is a single instruction the venue slices itself, so it is bounded by
145
- * the venue's own documented minimum for a TWAP rather than by the per-order
146
- * minimum that `validateOrder` has already applied.
147
- *
148
- * `scale` is deliberately absent. Its rungs are the orders the venue charges
149
- * the minimum against, and their sizes come from flooring onto the asset's size
150
- * grid with the remainder landing on the first rung — none of which is knowable
151
- * without `szDecimals`, which this check does not have. Every approximation
152
- * available here is unsound in one direction or the other, and the one that was
153
- * here rejected ladders whose submitted rungs all cleared the minimum.
154
- * `#buildScaleLadder` applies the exact per-rung check against the real grid
155
- * sizes, and it runs before anything is signed, so nothing is lost by leaving
156
- * the question to it.
157
- *
158
- * `chase` is absent too: it rests one order at a time, so the per-order minimum
159
- * the caller has already been checked against is the right bound.
160
- *
161
- * @param params - Notional parameters.
162
- * @param params.orderType - The order placement type.
163
- * @param params.orderValueUSD - Total notional of the placement, in USD.
164
- * @returns Validation result with isValid flag and optional error message.
165
- */
166
- const validateStrategyNotional = (params) => {
167
- const { orderType, orderValueUSD } = params;
168
- if (orderType === 'twap') {
169
- return orderValueUSD < HYPERLIQUID_TWAP_LIMITS.MinNotionalUsd
170
- ? {
171
- isValid: false,
172
- error: PERPS_ERROR_CODES.ORDER_TWAP_NOTIONAL_TOO_SMALL,
173
- }
174
- : { isValid: true };
175
- }
176
- return { isValid: true };
177
- };
178
46
  /**
179
47
  * Collect the order IDs of every TP/SL child carried by a parent order.
180
48
  *
@@ -335,23 +203,6 @@ export class HyperLiquidProvider {
335
203
  'multi-sig required': PERPS_ERROR_CODES.EXCHANGE_MULTI_SIG_REQUIRED,
336
204
  'invalid nonce': PERPS_ERROR_CODES.EXCHANGE_INVALID_NONCE,
337
205
  });
338
- // Scale ladders placed by this provider instance, keyed by group handle, so
339
- // one cancel can reach every rung. Cleared on disconnect; the rung IDs are
340
- // also returned to the caller as `OrderResult.childOrderIds`.
341
- _HyperLiquidProvider_scaleOrderGroups.set(this, new Map());
342
- // Chase sessions running on this provider instance, keyed by session handle.
343
- // Each owns a pending timer, so disconnect has to stop them.
344
- _HyperLiquidProvider_chaseSessions.set(this, new Map());
345
- // Chase placements that have reserved a slot against the venue's concurrency
346
- // cap but have not registered their session yet. Two round trips separate the
347
- // two, and a reservation is what keeps concurrent placements from both
348
- // passing the check.
349
- _HyperLiquidProvider_chasePlacementsInFlight.set(this, 0);
350
- // Bumped by every teardown that clears the chase registry. A placement
351
- // captures it before its round trips and refuses to register afterwards if it
352
- // has moved: a session registered after a disconnect would schedule a
353
- // background timer against a provider that has already been torn down.
354
- _HyperLiquidProvider_chaseGeneration.set(this, 0);
355
206
  // Track whether clients have been initialized (lazy initialization)
356
207
  _HyperLiquidProvider_clientsInitialized.set(this, false);
357
208
  // Promise-based lock to prevent race conditions in concurrent initialization
@@ -529,19 +380,10 @@ export class HyperLiquidProvider {
529
380
  tpslLinkage: params.tpslLinkage,
530
381
  grouping: params.grouping,
531
382
  timeInForce: params.timeInForce,
532
- clientOrderId: params.clientOrderId,
533
- ...pickStrategyParams(params),
534
383
  });
535
384
  if (!validation.isValid) {
536
385
  throw new Error(validation.error);
537
386
  }
538
- // Strategy placements expand into an execution schedule rather than a
539
- // single order, so they leave the shared path here — before the order
540
- // array, the HIP-3 transfer, and the atomic single-order submit, none of
541
- // which describe what a TWAP, a ladder, or a chase does.
542
- if (isStrategyOrderType(params.orderType)) {
543
- return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeStrategyOrder).call(this, params, params.orderType);
544
- }
545
387
  // Extract DEX name for API calls (main DEX = null)
546
388
  const { dex: dexName } = parseAssetName(params.symbol);
547
389
  // 1. Get asset info and current price before validation so price-less
@@ -708,14 +550,7 @@ export class HyperLiquidProvider {
708
550
  // close, so the retry would either be rejected as "Reduce only order would
709
551
  // increase position" or resubmit an identical order. Surfacing the
710
552
  // minimum-value error names the real problem instead.
711
- //
712
- // Strategy placements are excluded for the same reason in a different
713
- // shape: the minimum applies to each TWAP slice and each ladder rung, not
714
- // to the total, so growing the total by 1.5% does not clear it.
715
- if (isMinimumOrderError &&
716
- retryCount === 0 &&
717
- !params.reduceOnly &&
718
- !isStrategyOrderType(params.orderType)) {
553
+ if (isMinimumOrderError && retryCount === 0 && !params.reduceOnly) {
719
554
  let adjustedUsdAmount;
720
555
  let originalValue;
721
556
  if (params.usdAmount) {
@@ -791,17 +626,6 @@ export class HyperLiquidProvider {
791
626
  error: PERPS_ERROR_CODES.ORDER_EDIT_TRIGGER_UNSUPPORTED,
792
627
  };
793
628
  }
794
- // A strategy placement is not a single resting order, so there is nothing
795
- // for `modify` to rewrite: it would submit the edit as an ordinary
796
- // FrontendMarket modification and quietly drop the TWAP schedule, the
797
- // ladder, or the chase loop the caller asked for. Cancel by the strategy
798
- // handle and place again.
799
- if (isStrategyOrderType(params.newOrder.orderType)) {
800
- return {
801
- success: false,
802
- error: PERPS_ERROR_CODES.ORDER_EDIT_STRATEGY_UNSUPPORTED,
803
- };
804
- }
805
629
  // The WebSocket order cache is the cheap source for the resting order's
806
630
  // placement type, but it may be cold or stale.
807
631
  const cachedRestingOrder = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f")
@@ -972,12 +796,6 @@ export class HyperLiquidProvider {
972
796
  * @returns A promise that resolves to the result.
973
797
  */
974
798
  async cancelOrder(params) {
975
- // A strategy handle is not an exchange order ID, so it cannot go through
976
- // the single-order cancel below. Callers that omit `orderType` — every
977
- // existing one — keep the behaviour they have today.
978
- if (params.orderType && isStrategyOrderType(params.orderType)) {
979
- return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelStrategyOrder).call(this, params);
980
- }
981
799
  try {
982
800
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Canceling order:', params);
983
801
  // Hydrate the asset map before coin validation so a cold start (e.g.
@@ -3133,8 +2951,6 @@ export class HyperLiquidProvider {
3133
2951
  tpslLinkage: params.tpslLinkage,
3134
2952
  grouping: params.grouping,
3135
2953
  timeInForce: params.timeInForce,
3136
- clientOrderId: params.clientOrderId,
3137
- ...pickStrategyParams(params),
3138
2954
  });
3139
2955
  if (!basicValidation.isValid) {
3140
2956
  return basicValidation;
@@ -3207,15 +3023,6 @@ export class HyperLiquidProvider {
3207
3023
  error: PERPS_ERROR_CODES.ORDER_SIZE_MIN,
3208
3024
  };
3209
3025
  }
3210
- // A strategy placement's total clearing the per-order minimum does not
3211
- // mean the orders it expands into will.
3212
- const strategyMinimum = validateStrategyNotional({
3213
- orderType: params.orderType,
3214
- orderValueUSD,
3215
- });
3216
- if (!strategyMinimum.isValid) {
3217
- return strategyMinimum;
3218
- }
3219
3026
  }
3220
3027
  // Asset-specific leverage validation
3221
3028
  if (params.leverage && params.symbol) {
@@ -3981,17 +3788,11 @@ export class HyperLiquidProvider {
3981
3788
  */
3982
3789
  async calculateFees(params) {
3983
3790
  const { orderType, isMaker = false, amount, symbol } = params;
3984
- // Every placement is charged as its execution kind: a stop_market fills as a
3985
- // market order (taker), a stop_limit as a limit order, a scale ladder as the
3986
- // resting limit orders it fans out into, and a TWAP as the marketable
3987
- // suborders it crosses the book with.
3791
+ // Trigger placements are charged as their execution kind: a stop_market fills
3792
+ // as a market order (taker), a stop_limit as a limit order.
3988
3793
  const isMarketExecution = getTriggerExecution(orderType) === 'market';
3989
- // A chase is post-only by construction, so it can only ever fill as a maker.
3990
- // Quoting it at the taker rate would overstate the fee whatever the caller
3991
- // passes for `isMaker`.
3992
- const chargesMakerRate = orderType === 'chase' || (!isMarketExecution && isMaker);
3993
3794
  // Start with base rates from config
3994
- let feeRate = chargesMakerRate ? FEE_RATES.maker : FEE_RATES.taker;
3795
+ let feeRate = isMarketExecution || !isMaker ? FEE_RATES.taker : FEE_RATES.maker;
3995
3796
  // Parse symbol to detect HIP-3 DEX (e.g., "xyz:TSLA" → dex="xyz", parsedSymbol="TSLA")
3996
3797
  const { dex, symbol: parsedSymbol } = parseAssetName(symbol);
3997
3798
  const isHip3Asset = dex !== null;
@@ -4035,12 +3836,10 @@ export class HyperLiquidProvider {
4035
3836
  if (__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isFeeCacheValid).call(this, userAddress)) {
4036
3837
  const cached = __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeCache, "f").get(userAddress);
4037
3838
  if (cached) {
4038
- // Same maker/taker decision as the base rates above, including the
4039
- // post-only chase case — re-deriving it here would quote a chase at
4040
- // the taker rate whenever the caller passed isMaker: false.
4041
- let userFeeRate = chargesMakerRate
4042
- ? cached.perpsMakerRate
4043
- : cached.perpsTakerRate;
3839
+ // Market orders always use taker rate, limit orders check isMaker
3840
+ let userFeeRate = isMarketExecution || !isMaker
3841
+ ? cached.perpsTakerRate
3842
+ : cached.perpsMakerRate;
4044
3843
  // Apply HIP-3 dynamic multiplier to user-specific rates (includes Growth Mode)
4045
3844
  if (isHip3Asset && hip3Multiplier > 0) {
4046
3845
  userFeeRate *= hip3Multiplier;
@@ -4145,10 +3944,10 @@ export class HyperLiquidProvider {
4145
3944
  ttl: 5 * 60 * 1000, // 5 minutes
4146
3945
  };
4147
3946
  __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeCache, "f").set(userAddress, rates);
4148
- // Same maker/taker decision as the base rates above, chase included.
4149
- let userFeeRate = chargesMakerRate
4150
- ? rates.perpsMakerRate
4151
- : rates.perpsTakerRate;
3947
+ // Market orders always use taker rate, limit orders check isMaker
3948
+ let userFeeRate = isMarketExecution || !isMaker
3949
+ ? rates.perpsTakerRate
3950
+ : rates.perpsMakerRate;
4152
3951
  // Apply HIP-3 dynamic multiplier to API-fetched rates (includes Growth Mode)
4153
3952
  if (isHip3Asset && hip3Multiplier > 0) {
4154
3953
  userFeeRate *= hip3Multiplier;
@@ -4277,17 +4076,6 @@ export class HyperLiquidProvider {
4277
4076
  });
4278
4077
  // Clear subscriptions through subscription service
4279
4078
  __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").clearAll();
4280
- // Stop every chase loop: each holds a pending timer, and re-pricing after
4281
- // a disconnect would sign orders against a client that is being torn down.
4282
- // Orders already resting are deliberately left alone — disconnecting is
4283
- // not a request to cancel the user's positions or orders.
4284
- for (const sessionId of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").keys()) {
4285
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, sessionId);
4286
- }
4287
- __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").clear();
4288
- __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").clear();
4289
- // Placements still mid-flight check this before registering.
4290
- __classPrivateFieldSet(this, _HyperLiquidProvider_chaseGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f") + 1, "f");
4291
4079
  // Clear fee cache
4292
4080
  this.clearFeeCache();
4293
4081
  // Clear session caches (ensures fresh state on reconnect/account switch)
@@ -4473,7 +4261,7 @@ export class HyperLiquidProvider {
4473
4261
  return `${baseUrl}/explorer`;
4474
4262
  }
4475
4263
  }
4476
- _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_dexDiscoveryCache = 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_useUnifiedAccount = new WeakMap(), _HyperLiquidProvider_dexDiscoveryComplete = new WeakMap(), _HyperLiquidProvider_unifiedAccountSetupNeedsRetry = new WeakMap(), _HyperLiquidProvider_pendingValidatedDexsPromise = new WeakMap(), _HyperLiquidProvider_cachedUsdcTokenId = new WeakMap(), _HyperLiquidProvider_errorMappings = new WeakMap(), _HyperLiquidProvider_scaleOrderGroups = new WeakMap(), _HyperLiquidProvider_chaseSessions = new WeakMap(), _HyperLiquidProvider_chasePlacementsInFlight = new WeakMap(), _HyperLiquidProvider_chaseGeneration = new WeakMap(), _HyperLiquidProvider_clientsInitialized = new WeakMap(), _HyperLiquidProvider_initializationPromise = new WeakMap(), _HyperLiquidProvider_messenger = new WeakMap(), _HyperLiquidProvider_builderAddressTestnet = new WeakMap(), _HyperLiquidProvider_builderAddressMainnet = new WeakMap(), _HyperLiquidProvider_priceDeviationLimit = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
4264
+ _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_dexDiscoveryCache = 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_useUnifiedAccount = new WeakMap(), _HyperLiquidProvider_dexDiscoveryComplete = new WeakMap(), _HyperLiquidProvider_unifiedAccountSetupNeedsRetry = 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_priceDeviationLimit = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
4477
4265
  const compiled = [];
4478
4266
  for (const pattern of patterns) {
4479
4267
  try {
@@ -6577,1056 +6365,6 @@ async function _HyperLiquidProvider_handleOrderError(params) {
6577
6365
  }));
6578
6366
  }
6579
6367
  return createErrorResult(mappedError, { success: false });
6580
- }, _HyperLiquidProvider_placeStrategyOrder =
6581
- /**
6582
- * Dispatch a strategy placement to the handler that owns it.
6583
- *
6584
- * @param params - Order parameters, already validated.
6585
- * @param orderType - The strategy type, narrowed by the caller.
6586
- * @returns A promise that resolves to the result.
6587
- */
6588
- async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
6589
- // Captured before the shared preamble, not after it: that preamble awaits
6590
- // asset info, validation, trading readiness and a leverage update, and a
6591
- // disconnect during any of them has to be seen by the chase registration
6592
- // at the end.
6593
- const generation = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f");
6594
- if (orderType !== 'chase') {
6595
- const context = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareStrategyPlacement).call(this, params);
6596
- return orderType === 'twap'
6597
- ? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeTwapOrder).call(this, params, context)
6598
- : await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeScaleOrder).call(this, params, context);
6599
- }
6600
- // The chase slot is claimed before the preamble, not after it: the preamble
6601
- // completes the signing setup and can change the asset's leverage, and a
6602
- // request that is going to be refused for exceeding the venue's cap must
6603
- // not cost either. Reserved in the same synchronous step it is checked, so
6604
- // concurrent placements cannot both see room during the round trips that
6605
- // follow.
6606
- const activeChases = [...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").values()].filter((session) => session.active).length;
6607
- if (activeChases + __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") >=
6608
- CHASE_ORDER_CONFIG.MaxActiveSessions) {
6609
- throw new Error(PERPS_ERROR_CODES.ORDER_CHASE_LIMIT_REACHED);
6610
- }
6611
- __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementsInFlight, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") + 1, "f");
6612
- try {
6613
- const context = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareStrategyPlacement).call(this, params);
6614
- return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_startChaseSession).call(this, params, context, generation);
6615
- }
6616
- finally {
6617
- __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementsInFlight, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") - 1, "f");
6618
- }
6619
- }, _HyperLiquidProvider_prepareStrategyPlacement =
6620
- /**
6621
- * Run the shared preamble every strategy placement needs.
6622
- *
6623
- * Mirrors the single-order path's own preamble — validate against a live
6624
- * price, complete the signing setup, resolve the asset ID, apply leverage —
6625
- * so a strategy order is held to the same rules as an ordinary one.
6626
- *
6627
- * @param params - Order parameters.
6628
- * @returns The asset and sizing context the strategy handlers submit with.
6629
- */
6630
- async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
6631
- const { dex: dexName } = parseAssetName(params.symbol);
6632
- // A HIP-3 order is preceded by a margin transfer onto the builder DEX and
6633
- // followed by a rebalance, both of which are wired into the single-order
6634
- // submit path and its rollback. Rather than half-support that here, a
6635
- // strategy placement on a HIP-3 market is refused outright.
6636
- if (dexName !== null) {
6637
- throw new Error(PERPS_ERROR_CODES.ORDER_STRATEGY_MARKET_UNSUPPORTED);
6638
- }
6639
- const { assetInfo, currentPrice, meta } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
6640
- symbol: params.symbol,
6641
- dexName,
6642
- });
6643
- const effectivePrice = params.currentPrice && params.currentPrice > 0
6644
- ? params.currentPrice
6645
- : currentPrice;
6646
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_validateOrderBeforePlacement).call(this, {
6647
- ...params,
6648
- currentPrice: effectivePrice,
6649
- });
6650
- const normalizedMaxSlippageBps = params.maxSlippageBps ??
6651
- (typeof params.slippage === 'number'
6652
- ? Math.round(params.slippage * BASIS_POINTS_DIVISOR)
6653
- : undefined);
6654
- const { finalPositionSize } = calculateFinalPositionSize({
6655
- usdAmount: params.usdAmount,
6656
- size: params.size,
6657
- currentPrice: effectivePrice,
6658
- priceAtCalculation: params.priceAtCalculation,
6659
- maxSlippageBps: normalizedMaxSlippageBps,
6660
- szDecimals: assetInfo.szDecimals,
6661
- leverage: params.leverage,
6662
- reduceOnly: params.reduceOnly,
6663
- });
6664
- const formattedSize = formatHyperLiquidSize({
6665
- size: finalPositionSize,
6666
- szDecimals: assetInfo.szDecimals,
6667
- });
6668
- // Everything below is checked here, before anything is signed: it needs
6669
- // `szDecimals`, which only arrives with the asset info above, and these are
6670
- // caller mistakes that must not cost a leverage change or a signing prompt
6671
- // first.
6672
- const ladder = params.orderType === 'scale'
6673
- ? __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_buildScaleLadder).call(this, {
6674
- params,
6675
- szDecimals: assetInfo.szDecimals,
6676
- finalPositionSize,
6677
- })
6678
- : undefined;
6679
- // `validateOrder` applied the venue minimum to the notional the caller
6680
- // asked for; this applies it to the size actually being submitted. The two
6681
- // differ whenever sizing floors onto the grid rather than rounding up to
6682
- // meet the requested USD — which is exactly what a reduce-only order does,
6683
- // since the venue rejects a close larger than the position. A boundary
6684
- // amount can therefore clear the check the caller sees and still arrive
6685
- // under the minimum the venue charges against what it receives.
6686
- if (params.orderType === 'twap' || params.orderType === 'chase') {
6687
- const submittedNotional = parseFloat(formattedSize) * effectivePrice;
6688
- const minimumNotional = params.orderType === 'twap'
6689
- ? HYPERLIQUID_TWAP_LIMITS.MinNotionalUsd
6690
- : __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getMinimumOrderSize).call(this);
6691
- if (submittedNotional < minimumNotional) {
6692
- throw new Error(params.orderType === 'twap'
6693
- ? PERPS_ERROR_CODES.ORDER_TWAP_NOTIONAL_TOO_SMALL
6694
- : PERPS_ERROR_CODES.ORDER_SIZE_MIN);
6695
- }
6696
- }
6697
- // Kept after validation so an invalid strategy order never triggers the
6698
- // signature prompts in trading setup — same ordering as `placeOrder`.
6699
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
6700
- const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
6701
- symbol: params.symbol,
6702
- dexName,
6703
- meta,
6704
- });
6705
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareAssetForTrading).call(this, {
6706
- symbol: params.symbol,
6707
- assetId,
6708
- leverage: params.leverage,
6709
- });
6710
- return {
6711
- assetId,
6712
- szDecimals: assetInfo.szDecimals,
6713
- finalPositionSize,
6714
- formattedSize,
6715
- ladder,
6716
- };
6717
- }, _HyperLiquidProvider_getMinimumOrderSize = function _HyperLiquidProvider_getMinimumOrderSize() {
6718
- return __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode()
6719
- ? TRADING_DEFAULTS.amount.testnet
6720
- : TRADING_DEFAULTS.amount.mainnet;
6721
- }, _HyperLiquidProvider_buildScaleLadder = function _HyperLiquidProvider_buildScaleLadder(options) {
6722
- const { params, szDecimals, finalPositionSize } = options;
6723
- const count = params.scaleNumOrders;
6724
- const prices = computeScalePriceLadder({
6725
- minPrice: parseFloat(params.scaleMinPrice),
6726
- maxPrice: parseFloat(params.scaleMaxPrice),
6727
- count,
6728
- }).map((price) => formatHyperLiquidPrice({ price, szDecimals }));
6729
- if (new Set(prices).size !== prices.length) {
6730
- throw new Error(PERPS_ERROR_CODES.ORDER_SCALE_RANGE_INVALID);
6731
- }
6732
- // Throws ORDER_SCALE_SIZE_TOO_SMALL when a rung would round to nothing.
6733
- const sizes = splitScaleSizes({
6734
- totalSize: finalPositionSize,
6735
- count,
6736
- szDecimals,
6737
- });
6738
- const minimumOrderSize = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getMinimumOrderSize).call(this);
6739
- const cheapestRungNotional = Math.min(...sizes.map((size, index) => parseFloat(size) * parseFloat(prices[index])));
6740
- if (cheapestRungNotional < minimumOrderSize) {
6741
- throw new Error(PERPS_ERROR_CODES.ORDER_SCALE_NOTIONAL_TOO_SMALL);
6742
- }
6743
- return { prices, sizes };
6744
- }, _HyperLiquidProvider_placeTwapOrder =
6745
- /**
6746
- * Submit a TWAP through HyperLiquid's dedicated TWAP action.
6747
- *
6748
- * A TWAP is not an order on the book, so it does not go through the `order`
6749
- * action, carries no builder fee, and comes back identified by a `twapId`
6750
- * rather than an `oid`. That ID is the handle `cancelOrder` needs.
6751
- *
6752
- * @param params - Order parameters.
6753
- * @param context - Prepared asset and sizing context.
6754
- * @returns A promise that resolves to the result.
6755
- */
6756
- async function _HyperLiquidProvider_placeTwapOrder(params, context) {
6757
- const { assetId, formattedSize } = context;
6758
- const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
6759
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Submitting TWAP order', {
6760
- symbol: params.symbol,
6761
- assetId,
6762
- size: formattedSize,
6763
- durationMinutes: params.twapDuration,
6764
- randomize: params.twapRandomize ?? false,
6765
- });
6766
- const result = await exchangeClient.twapOrder({
6767
- twap: {
6768
- a: assetId,
6769
- b: params.isBuy,
6770
- s: formattedSize,
6771
- r: params.reduceOnly ?? false,
6772
- // Validation has already established this is a whole number of minutes
6773
- // inside the venue's bounds.
6774
- m: params.twapDuration,
6775
- t: params.twapRandomize ?? false,
6776
- },
6777
- });
6778
- if (result.status !== 'ok') {
6779
- throw new Error(`TWAP order failed: ${JSON.stringify(result)}`);
6780
- }
6781
- const status = result.response?.data?.status;
6782
- if (!isStatusObject(status) || !hasProperty(status, 'running')) {
6783
- const rawError = status?.error ??
6784
- 'TWAP order rejected';
6785
- throw new Error(rawError);
6786
- }
6787
- const running = status.running;
6788
- return {
6789
- success: true,
6790
- orderId: running.twapId.toString(),
6791
- submittedSize: formattedSize,
6792
- };
6793
- }, _HyperLiquidProvider_placeScaleOrder =
6794
- /**
6795
- * Fan a scale placement out into one batch of resting limit orders.
6796
- *
6797
- * The whole ladder goes in a single `order` action, which is one round trip
6798
- * and one signature rather than one per rung. It is **not** atomic: an `na`
6799
- * grouping evaluates each entry independently, so the response can report
6800
- * some rungs resting and others rejected. A partial ladder is reported as
6801
- * such — `submittedSize` covers only the rungs that actually rested — rather
6802
- * than as a full submission.
6803
- *
6804
- * @param params - Order parameters.
6805
- * @param context - Prepared asset and sizing context.
6806
- * @returns A promise that resolves to the result.
6807
- */
6808
- async function _HyperLiquidProvider_placeScaleOrder(params, context) {
6809
- const { assetId, szDecimals, formattedSize, ladder } = context;
6810
- // Built and validated in `#prepareStrategyPlacement`, before anything was
6811
- // signed, so what is submitted here is exactly what the minimums were
6812
- // applied to.
6813
- const { prices, sizes } = ladder;
6814
- const count = prices.length;
6815
- const orders = prices.map((price, index) => ({
6816
- a: assetId,
6817
- b: params.isBuy,
6818
- p: price,
6819
- s: sizes[index],
6820
- r: params.reduceOnly ?? false,
6821
- t: { limit: { tif: 'Gtc' } },
6822
- }));
6823
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Submitting scale ladder', {
6824
- symbol: params.symbol,
6825
- assetId,
6826
- count,
6827
- prices: orders.map((order) => order.p),
6828
- sizes,
6829
- });
6830
- const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
6831
- const result = await exchangeClient.order({
6832
- orders,
6833
- grouping: 'na',
6834
- builder: {
6835
- b: __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderAddress).call(this, __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode()),
6836
- f: __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getDiscountedBuilderFee).call(this),
6837
- },
6838
- });
6839
- if (result.status !== 'ok') {
6840
- throw new Error(`Scale order failed: ${JSON.stringify(result)}`);
6841
- }
6842
- const statuses = result.response?.data?.statuses ?? [];
6843
- // Which rung each ID came from matters: `submittedSize` has to add up the
6844
- // slices that actually rested, not the total that was asked for.
6845
- const restedRungs = statuses
6846
- .map((status, index) => ({
6847
- orderId: __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderIdFromStatus).call(this, status),
6848
- size: sizes[index],
6849
- }))
6850
- .filter((rung) => rung.orderId !== undefined);
6851
- // A ladder that came back with no IDs at all rested nothing; reporting it
6852
- // as a success would hand the caller a handle that cancels nothing.
6853
- if (restedRungs.length === 0) {
6854
- throw new Error(`Scale order rejected: ${JSON.stringify(result.response?.data)}`);
6855
- }
6856
- const childOrderIds = restedRungs.map((rung) => rung.orderId);
6857
- const groupId = generatePerpsId('scale');
6858
- __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").set(groupId, { assetId, orderIds: childOrderIds });
6859
- // The batch is not atomic, so a ladder can come back part-rested. Reporting
6860
- // the requested total as submitted would tell the caller they are exposed
6861
- // for more than they are.
6862
- const isPartial = restedRungs.length < count;
6863
- if (isPartial) {
6864
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Scale ladder only partly rested', {
6865
- groupId,
6866
- rested: restedRungs.length,
6867
- requested: count,
6868
- statuses,
6869
- });
6870
- }
6871
- return {
6872
- success: true,
6873
- orderId: groupId,
6874
- childOrderIds,
6875
- submittedSize: isPartial
6876
- ? formatHyperLiquidSize({
6877
- size: restedRungs.reduce((total, rung) => total + parseFloat(rung.size), 0),
6878
- szDecimals,
6879
- })
6880
- : formattedSize,
6881
- };
6882
- }, _HyperLiquidProvider_startChaseSession =
6883
- /**
6884
- * Place a chase's first order and register the session that follows it.
6885
- *
6886
- * Split from the routing above so the concurrency reservation there wraps
6887
- * every await in one `try`/`finally`.
6888
- *
6889
- * @param params - Order parameters.
6890
- * @param context - Prepared asset and sizing context.
6891
- * @param generation - Teardown generation captured before any await.
6892
- * @returns A promise that resolves to the result.
6893
- */
6894
- async function _HyperLiquidProvider_startChaseSession(params, context, generation) {
6895
- const { assetId, szDecimals, formattedSize } = context;
6896
- // The preamble is several round trips long. A disconnect during it has
6897
- // already torn down everything this session would run on, so the chase
6898
- // stops here rather than reading the book and putting a fresh order on it
6899
- // for a provider that no longer exists.
6900
- if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
6901
- throw new Error(PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
6902
- }
6903
- const quotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
6904
- symbol: params.symbol,
6905
- isBuy: params.isBuy,
6906
- szDecimals,
6907
- });
6908
- if (quotePrice === 'gone') {
6909
- // No own order to be gone on a first placement; narrows the union.
6910
- throw new Error(PERPS_ERROR_CODES.ORDER_CHASE_TOUCH_UNAVAILABLE);
6911
- }
6912
- // The book read is a round trip of its own, so the check above does not
6913
- // cover it. Re-checked here, immediately before the only statement that
6914
- // signs anything: every await on this path is now followed by a refusal
6915
- // before the next one, leaving one window that cannot be closed from here
6916
- // — a disconnect arriving while the submission itself is in flight, which
6917
- // the check after it handles.
6918
- if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
6919
- throw new Error(PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
6920
- }
6921
- // Read once, while the caller's discount context is still set.
6922
- const builderFee = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getDiscountedBuilderFee).call(this);
6923
- // Held onto rather than looked up again after the submission returns.
6924
- // `disconnect` drops the service's client reference synchronously, so a
6925
- // retraction that asked for a client after the fact would be refused one
6926
- // and leave the order resting under the account that placed it. This
6927
- // instance signed the order and can still cancel it as that account.
6928
- const placingClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
6929
- const orderId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_restChaseOrder).call(this, {
6930
- assetId,
6931
- isBuy: params.isBuy,
6932
- price: quotePrice,
6933
- size: formattedSize,
6934
- reduceOnly: params.reduceOnly ?? false,
6935
- builderFee,
6936
- exchangeClient: placingClient,
6937
- });
6938
- const intervalMs = params.chaseIntervalMs ?? CHASE_ORDER_CONFIG.DefaultIntervalMs;
6939
- const sessionId = generatePerpsId('chase');
6940
- const session = {
6941
- symbol: params.symbol,
6942
- assetId,
6943
- isBuy: params.isBuy,
6944
- size: formattedSize,
6945
- szDecimals,
6946
- reduceOnly: params.reduceOnly ?? false,
6947
- orderId,
6948
- pendingReplacement: null,
6949
- restingPrice: quotePrice,
6950
- intervalMs,
6951
- builderFee,
6952
- deadline: Date.now() +
6953
- (params.chaseMaxDurationMs ?? CHASE_ORDER_CONFIG.DefaultMaxDurationMs),
6954
- maxRepricings: params.chaseMaxRepricings ?? CHASE_ORDER_CONFIG.DefaultMaxRepricings,
6955
- repricings: 0,
6956
- timer: null,
6957
- active: true,
6958
- };
6959
- // A disconnect landed while the submission was in flight — the one window
6960
- // the checks above cannot close. The order rested, but no strategy is
6961
- // running behind it and no handle names it, so this placement is reported
6962
- // as a failure. That makes the resting order an orphan: the caller is told
6963
- // the chase failed, nothing refreshes the caches a successful placement
6964
- // would have invalidated, and the exchange id is only usable for as long as
6965
- // the provider stays pointed at the account that placed it — a disconnect
6966
- // is usually followed by an account or network switch, after which handing
6967
- // the id back is no remedy at all. So it is cancelled here, through the
6968
- // client that signed it — the account switch cannot reach that instance —
6969
- // and the failure is then true of the venue as well as of this provider.
6970
- // Best-effort still: the transport underneath that client may already be
6971
- // closing, so a cancel that does not land falls back to reporting the id.
6972
- if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
6973
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase placement outlived its provider', {
6974
- orderId,
6975
- restingPrice: quotePrice,
6976
- });
6977
- const outcome = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_retractOrphanedChaseOrder).call(this, session, placingClient);
6978
- return createErrorResult(new Error(PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED), {
6979
- success: false,
6980
- // Reported only when the retraction did not take. Naming an order
6981
- // that is no longer on the book would send the caller to cancel
6982
- // something already gone; naming one that still rests is the only
6983
- // route left to it.
6984
- ...(outcome === 'refused' ? { childOrderIds: [orderId] } : {}),
6985
- submittedSize: formattedSize,
6986
- });
6987
- }
6988
- __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").set(sessionId, session);
6989
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
6990
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase session started', {
6991
- sessionId,
6992
- symbol: params.symbol,
6993
- orderId,
6994
- restingPrice: quotePrice,
6995
- intervalMs,
6996
- });
6997
- return {
6998
- success: true,
6999
- orderId: sessionId,
7000
- childOrderIds: [orderId],
7001
- submittedSize: formattedSize,
7002
- };
7003
- }, _HyperLiquidProvider_getChaseQuotePrice =
7004
- /**
7005
- * Read the price a chase must rest at: the best bid for a buy, the best ask
7006
- * for a sell.
7007
- *
7008
- * The touch, not the mid: a post-only order priced at the mid would either
7009
- * cross or be rejected, and a chase that never rests at the front of the
7010
- * queue is not chasing anything.
7011
- *
7012
- * @param params - The lookup parameters.
7013
- * @param params.symbol - Market to read.
7014
- * @param params.isBuy - Which side the chase rests on.
7015
- * @param params.szDecimals - Asset size precision, for price formatting.
7016
- * @param params.own - The chase's own resting order, excluded from the book.
7017
- * @param params.own.orderId - Exchange ID of that order.
7018
- * @param params.own.price - Price that order rests at.
7019
- * @param params.own.size - Size it was last placed for.
7020
- * @returns The formatted price the chase should rest at, or `'gone'` when the
7021
- * order it was chasing is no longer live.
7022
- */
7023
- async function _HyperLiquidProvider_getChaseQuotePrice(params) {
7024
- const { symbol, isBuy, szDecimals, own } = params;
7025
- const book = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient().l2Book({
7026
- coin: symbol,
7027
- });
7028
- // `levels` is [bids, asks], each best-first.
7029
- const ownSide = book?.levels?.[isBuy ? 0 : 1];
7030
- const netting = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOwnRestingSizes).call(this, {
7031
- symbol,
7032
- isBuy,
7033
- callerOrderId: own?.orderId,
7034
- ownSide,
7035
- });
7036
- if (netting === 'gone') {
7037
- return 'gone';
7038
- }
7039
- const bestBid = readBestExternalPrice(book?.levels?.[0], netting);
7040
- const bestAsk = readBestExternalPrice(book?.levels?.[1], netting);
7041
- if (bestBid === null || bestAsk === null) {
7042
- throw new Error(PERPS_ERROR_CODES.ORDER_CHASE_TOUCH_UNAVAILABLE);
7043
- }
7044
- return computeChaseQuotePrice({ bestBid, bestAsk, isBuy, szDecimals });
7045
- }, _HyperLiquidProvider_restChaseOrder =
7046
- /**
7047
- * Rest one post-only order for a chase and return its exchange ID.
7048
- *
7049
- * @param params - The placement parameters.
7050
- * @param params.assetId - Resolved asset ID.
7051
- * @param params.isBuy - Order side.
7052
- * @param params.price - Formatted limit price.
7053
- * @param params.size - Formatted size.
7054
- * @param params.reduceOnly - Whether the order may only reduce a position.
7055
- * @param params.builderFee - Builder fee, in tenths of a basis point, captured
7056
- * when the session started so replacements keep the rate they were quoted at.
7057
- * @param params.exchangeClient - Client to submit through. Passed in rather
7058
- * than looked up here so a first placement can keep the instance it signed
7059
- * with, which is the only one that can take the order back once `disconnect`
7060
- * has dropped the service's reference.
7061
- * @returns The resting order's exchange ID.
7062
- */
7063
- async function _HyperLiquidProvider_restChaseOrder(params) {
7064
- const result = await params.exchangeClient.order({
7065
- orders: [
7066
- {
7067
- a: params.assetId,
7068
- b: params.isBuy,
7069
- p: params.price,
7070
- s: params.size,
7071
- r: params.reduceOnly,
7072
- // Post-only: a chase adds liquidity at the touch. Crossing would end
7073
- // the chase on its first tick at a worse price than resting does.
7074
- t: { limit: { tif: 'Alo' } },
7075
- },
7076
- ],
7077
- grouping: 'na',
7078
- builder: {
7079
- b: __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderAddress).call(this, __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode()),
7080
- f: params.builderFee,
7081
- },
7082
- });
7083
- if (result.status !== 'ok') {
7084
- throw new Error(`Chase order failed: ${JSON.stringify(result)}`);
7085
- }
7086
- const orderId = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderIdFromStatus).call(this, result.response?.data?.statuses?.[0]);
7087
- if (!orderId) {
7088
- throw new Error(`Chase order rejected: ${JSON.stringify(result.response?.data)}`);
7089
- }
7090
- return orderId;
7091
- }, _HyperLiquidProvider_scheduleChaseTick = function _HyperLiquidProvider_scheduleChaseTick(sessionId) {
7092
- const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
7093
- if (!session?.active) {
7094
- return;
7095
- }
7096
- const timer = setTimeout(() => {
7097
- // A rejected tick must not stop the session from being cancellable, and
7098
- // must not surface as an unhandled rejection either.
7099
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_runChaseTick).call(this, sessionId).catch((error) => {
7100
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase tick failed', {
7101
- sessionId,
7102
- error: ensureError(error, 'HyperLiquidProvider.chaseTick').message,
7103
- });
7104
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_recoverFailedChaseTick).call(this, sessionId);
7105
- });
7106
- }, session.intervalMs);
7107
- // Node keeps the process alive for a pending timer; a background chase is
7108
- // not a reason to hold an exiting process open. React Native's timers have
7109
- // no `unref`, hence the guard.
7110
- timer.unref?.();
7111
- session.timer = timer;
7112
- }, _HyperLiquidProvider_recoverFailedChaseTick = function _HyperLiquidProvider_recoverFailedChaseTick(sessionId) {
7113
- const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
7114
- if (!session?.active) {
7115
- return;
7116
- }
7117
- if (session.orderId === null) {
7118
- session.active = false;
7119
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase ended with nothing resting', {
7120
- sessionId,
7121
- });
7122
- return;
7123
- }
7124
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
7125
- }, _HyperLiquidProvider_runChaseTick =
7126
- /**
7127
- * Advance one chase session: re-price if the touch has moved, stop if the
7128
- * window has closed.
7129
- *
7130
- * @param sessionId - Session to advance.
7131
- */
7132
- async function _HyperLiquidProvider_runChaseTick(sessionId) {
7133
- const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
7134
- if (!session?.active) {
7135
- return;
7136
- }
7137
- if (Date.now() >= session.deadline) {
7138
- // The window closed. The last order stays resting as an ordinary limit
7139
- // order and the session stays registered, so cancelling by its handle
7140
- // still reaches that order.
7141
- session.active = false;
7142
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase session window closed', { sessionId });
7143
- return;
7144
- }
7145
- const quotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
7146
- symbol: session.symbol,
7147
- isBuy: session.isBuy,
7148
- szDecimals: session.szDecimals,
7149
- own: session.orderId
7150
- ? {
7151
- orderId: session.orderId,
7152
- price: session.restingPrice,
7153
- size: session.size,
7154
- }
7155
- : undefined,
7156
- });
7157
- if (quotePrice === 'gone') {
7158
- // The order left the book without the loop seeing it — it filled. Ending
7159
- // here releases its slot against the venue's concurrency cap instead of
7160
- // holding one until the window closes.
7161
- session.orderId = null;
7162
- session.active = false;
7163
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order filled between ticks', {
7164
- sessionId,
7165
- });
7166
- return;
7167
- }
7168
- // The book read is a round trip, and a cancel arriving during it stops the
7169
- // session. Without this re-check the tick would cancel and re-place the very
7170
- // order the caller just asked to be rid of.
7171
- if (!session.active) {
7172
- return;
7173
- }
7174
- if (quotePrice !== session.restingPrice && session.orderId) {
7175
- const outcome = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseChild).call(this, session);
7176
- // The cancel is a second round trip, and this is the window where a
7177
- // caller's `cancelOrder` does the most damage: it would cancel the order
7178
- // this tick has already cancelled, report the cancel incomplete, and then
7179
- // this tick would rest a replacement the caller has no idea exists.
7180
- // Stopping here leaves nothing on the book.
7181
- if (!session.active) {
7182
- // A refused cancel leaves the child resting. Preserve its ID so the
7183
- // caller that stopped this session can report an incomplete cancel and
7184
- // retry it instead of orphaning the order.
7185
- if (outcome !== 'refused') {
7186
- session.orderId = null;
7187
- }
7188
- return;
7189
- }
7190
- if (outcome === 'refused') {
7191
- // The exchange kept the order, so it is still resting at the old price.
7192
- // Placing the replacement anyway would double the position. Leave it
7193
- // alone and try again on the next tick, which is why this falls through
7194
- // to the reschedule below rather than ending the session.
7195
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase reprice cancel refused', {
7196
- sessionId,
7197
- orderId: session.orderId,
7198
- });
7199
- }
7200
- else if (outcome === 'gone') {
7201
- // The order left the book between ticks: it filled, or something else
7202
- // cancelled it. There is nothing left to chase.
7203
- session.orderId = null;
7204
- session.active = false;
7205
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order no longer resting', {
7206
- sessionId,
7207
- });
7208
- return;
7209
- }
7210
- else {
7211
- // The cancel is confirmed, so the session owns nothing from here on.
7212
- // Recorded before the read rather than after it: a read that rejects
7213
- // would otherwise leave the session naming an order that is already off
7214
- // the book, and recovery would reschedule a chase with nothing resting.
7215
- const cancelledOrderId = session.orderId;
7216
- session.orderId = null;
7217
- // No further fills can reach a cancelled order, so what it did not fill
7218
- // is now fixed. Sampling before the cancel would have left a window in
7219
- // which a fill lands and is then re-placed.
7220
- const remaining = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, cancelledOrderId);
7221
- // Another round trip, another window for a cancel to land. By now the
7222
- // old order is already off the book, so a cancel that arrived during it
7223
- // found nothing to cancel and reported success — resting a replacement
7224
- // after that would put an order on the book the caller believes is gone
7225
- // and has no handle for.
7226
- if (!session.active || !__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").has(sessionId)) {
7227
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase cancelled mid-reprice', {
7228
- sessionId,
7229
- });
7230
- return;
7231
- }
7232
- if (remaining === null) {
7233
- // It filled completely between ticks; there is nothing left to chase.
7234
- session.active = false;
7235
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order fully filled', { sessionId });
7236
- return;
7237
- }
7238
- // Published *before* the placement starts, not from the promise it
7239
- // returns: the window opens the moment `#restChaseOrder` is entered, so
7240
- // deriving the marker from its return value would leave the synchronous
7241
- // prefix of that call unguarded. A cancel arriving anywhere inside the
7242
- // round trip now waits for the replacement to land instead of reading
7243
- // the null `orderId` as "nothing rests", reporting success, and dropping
7244
- // the handle while this call is still putting an order on the book.
7245
- let settleReplacement;
7246
- session.pendingReplacement = new Promise((resolve) => {
7247
- settleReplacement = resolve;
7248
- });
7249
- try {
7250
- session.orderId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_restChaseOrder).call(this, {
7251
- assetId: session.assetId,
7252
- isBuy: session.isBuy,
7253
- price: quotePrice,
7254
- size: remaining,
7255
- reduceOnly: session.reduceOnly,
7256
- builderFee: session.builderFee,
7257
- // A running session is on a live provider, so the current client is
7258
- // the right one; only the first placement has a teardown to survive.
7259
- exchangeClient: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient(),
7260
- });
7261
- session.size = remaining;
7262
- }
7263
- finally {
7264
- // Cleared before the waiters wake, so they see the settled session.
7265
- session.pendingReplacement = null;
7266
- settleReplacement?.();
7267
- }
7268
- session.restingPrice = quotePrice;
7269
- session.repricings += 1;
7270
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase re-priced', {
7271
- sessionId,
7272
- orderId: session.orderId,
7273
- restingPrice: quotePrice,
7274
- size: session.size,
7275
- repricings: session.repricings,
7276
- });
7277
- // A cancel that arrived during the round trip is now waiting on this
7278
- // session; it cancels the order just recorded above. A `disconnect`
7279
- // deregisters the session instead, and deliberately leaves resting
7280
- // orders alone — logged with its ID so it stays traceable.
7281
- if (!__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").has(sessionId)) {
7282
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase replacement outlived its session', {
7283
- sessionId,
7284
- orderId: session.orderId,
7285
- });
7286
- return;
7287
- }
7288
- if (!session.active) {
7289
- return;
7290
- }
7291
- }
7292
- }
7293
- if (session.repricings >= session.maxRepricings) {
7294
- session.active = false;
7295
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase repricing cap reached', { sessionId });
7296
- return;
7297
- }
7298
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
7299
- }, _HyperLiquidProvider_resolveOwnRestingSizes =
7300
- /**
7301
- * Resolve how much of the chase's own order is really sitting on its level.
7302
- *
7303
- * The session tracks what its order was last *placed* for, which overstates
7304
- * the order once it partially fills. Over-subtracting only matters when it
7305
- * would net the level away entirely — while the level still shows more size
7306
- * than the order could possibly hold, the level has external liquidity either
7307
- * way and the stale figure is good enough.
7308
- *
7309
- * So the live size is fetched only in the ambiguous case, which keeps the
7310
- * common tick to a single book read rather than doubling the request rate
7311
- * against the venue for every chase on every interval.
7312
- *
7313
- * @param params - Netting parameters.
7314
- * @param params.symbol - Market being quoted.
7315
- * @param params.isBuy - Side being quoted.
7316
- * @param params.callerOrderId - The asking session's order, if it has one.
7317
- * @param params.ownSide - The side of the book those orders rest on.
7318
- * @returns Our resting size at each price, or `'gone'` when the asking
7319
- * session's own order is no longer live.
7320
- */
7321
- async function _HyperLiquidProvider_resolveOwnRestingSizes(params) {
7322
- const { symbol, isBuy, callerOrderId, ownSide } = params;
7323
- // Every chase this provider is running on this side, the caller included.
7324
- const ourOrders = [...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").values()]
7325
- .filter((session) => session.orderId !== null &&
7326
- session.symbol === symbol &&
7327
- session.isBuy === isBuy)
7328
- .map((session) => ({
7329
- orderId: session.orderId,
7330
- price: session.restingPrice,
7331
- size: session.size,
7332
- }));
7333
- if (ourOrders.length === 0) {
7334
- return new Map();
7335
- }
7336
- const recorded = new Map();
7337
- for (const order of ourOrders) {
7338
- recorded.set(order.price, (recorded.get(order.price) ?? 0) + parseFloat(order.size));
7339
- }
7340
- // A level holding more than we possibly could has external size regardless,
7341
- // so the recorded figures cannot change the answer there and are left as
7342
- // they are. Elsewhere the recorded sizes may overstate what is really
7343
- // resting — an order partially fills without the loop seeing it — and only
7344
- // then is a lookup worth a round trip.
7345
- const ambiguous = ourOrders.filter((order) => {
7346
- const level = ownSide?.find((entry) => entry.px === order.price);
7347
- return !level || parseFloat(level.sz) <= (recorded.get(order.price) ?? 0);
7348
- });
7349
- let callerIsGone = false;
7350
- for (const order of ambiguous) {
7351
- try {
7352
- const live = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, order.orderId);
7353
- const delta = (live === null ? 0 : parseFloat(live)) - parseFloat(order.size);
7354
- recorded.set(order.price, Math.max(0, (recorded.get(order.price) ?? 0) + delta));
7355
- if (live === null && order.orderId === callerOrderId) {
7356
- callerIsGone = true;
7357
- }
7358
- }
7359
- catch (error) {
7360
- // A failed lookup must not stop the chase. Keeping the recorded size can
7361
- // only over-subtract, which quotes a level deeper rather than leaving
7362
- // the order stranded at a stale price.
7363
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase own-size lookup failed', {
7364
- orderId: order.orderId,
7365
- error: ensureError(error, 'HyperLiquidProvider.chaseOwnSize').message,
7366
- });
7367
- }
7368
- }
7369
- return callerIsGone ? 'gone' : recorded;
7370
- }, _HyperLiquidProvider_readOrderRemainder =
7371
- /**
7372
- * Read what a chase's just-cancelled order left unfilled.
7373
- *
7374
- * A chase re-prices by cancelling and re-placing, and the order it cancels
7375
- * may have partially filled first; re-placing the session's original size
7376
- * would execute more than the caller asked for.
7377
- *
7378
- * Read *after* the cancel on purpose. The order's status endpoint answers for
7379
- * an order that is no longer on the book, and once the cancel has landed no
7380
- * further fills can reach it — so the unfilled size it reports is final.
7381
- * Sampling the open-order book beforehand would instead leave a one-round-trip
7382
- * window in which a fill lands and is then re-placed on top.
7383
- *
7384
- * @param orderId - Exchange ID of the order that was just cancelled.
7385
- * @returns The unfilled size, or null when nothing is left to chase.
7386
- */
7387
- async function _HyperLiquidProvider_readOrderRemainder(orderId) {
7388
- const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
7389
- const status = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient().orderStatus({
7390
- user: userAddress,
7391
- oid: parseInt(orderId, 10),
7392
- });
7393
- if (status.status !== 'order') {
7394
- return null;
7395
- }
7396
- const remaining = String(status.order.order.sz);
7397
- return parseFloat(remaining) > 0 ? remaining : null;
7398
- }, _HyperLiquidProvider_cancelChaseChild =
7399
- /**
7400
- * Cancel the order a chase session currently has resting.
7401
- *
7402
- * @param session - The session whose child to cancel.
7403
- * @param placingClient - Client to cancel through. Omitted by every cancel on
7404
- * a live provider, which wants the current one; an abandoned placement passes
7405
- * the client it signed with, the only one still able to reach its order.
7406
- * @returns Whether the order was cancelled, was already gone, or still rests.
7407
- */
7408
- async function _HyperLiquidProvider_cancelChaseChild(session, placingClient) {
7409
- if (!session.orderId) {
7410
- return 'gone';
7411
- }
7412
- // Looked up only once there is something to cancel, so a session with
7413
- // nothing resting still answers on a provider whose client is already gone.
7414
- const exchangeClient = placingClient ?? __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
7415
- const result = await exchangeClient.cancel({
7416
- cancels: [{ a: session.assetId, o: parseInt(session.orderId, 10) }],
7417
- });
7418
- return classifyCancelStatus(result.response?.data?.statuses?.[0]);
7419
- }, _HyperLiquidProvider_retractOrphanedChaseOrder =
7420
- /**
7421
- * Take back the order of a chase that was abandoned before it registered.
7422
- *
7423
- * Best-effort by construction: the provider is already being torn down, so a
7424
- * cancel that fails outright is reported rather than retried or thrown. The
7425
- * caller reports the placement as a failure either way — the outcome only
7426
- * decides whether an exchange id is worth handing back with it.
7427
- *
7428
- * @param session - The unregistered session holding the resting order.
7429
- * @param placingClient - The client the order was signed with. The service's
7430
- * own reference is already cleared by the time this runs, so asking it for a
7431
- * client here would fail before a cancel was ever sent.
7432
- * @returns Whether the order was cancelled, was already gone, or still rests.
7433
- */
7434
- async function _HyperLiquidProvider_retractOrphanedChaseOrder(session, placingClient) {
7435
- try {
7436
- const outcome = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseChild).call(this, session, placingClient);
7437
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Retracted abandoned chase order', {
7438
- orderId: session.orderId,
7439
- outcome,
7440
- });
7441
- return outcome;
7442
- }
7443
- catch (error) {
7444
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Could not retract abandoned chase order', {
7445
- orderId: session.orderId,
7446
- error: ensureError(error, 'HyperLiquidProvider.startChaseSession')
7447
- .message,
7448
- });
7449
- return 'refused';
7450
- }
7451
- }, _HyperLiquidProvider_stopChaseSession = function _HyperLiquidProvider_stopChaseSession(sessionId) {
7452
- const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
7453
- if (!session) {
7454
- return;
7455
- }
7456
- session.active = false;
7457
- if (session.timer) {
7458
- clearTimeout(session.timer);
7459
- session.timer = null;
7460
- }
7461
- }, _HyperLiquidProvider_cancelStrategyOrder =
7462
- /**
7463
- * Cancel a strategy placement by its handle.
7464
- *
7465
- * @param params - Cancellation parameters.
7466
- * @returns A promise that resolves to the result.
7467
- */
7468
- async function _HyperLiquidProvider_cancelStrategyOrder(params) {
7469
- try {
7470
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Canceling strategy order:', params);
7471
- if (params.orderType === 'twap') {
7472
- return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelTwapOrder).call(this, params);
7473
- }
7474
- if (params.orderType === 'scale') {
7475
- return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelScaleOrder).call(this, params);
7476
- }
7477
- return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseOrder).call(this, params);
7478
- }
7479
- catch (error) {
7480
- const mappedError = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, error);
7481
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(mappedError, await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getTradingErrorContext).call(this, 'cancelOrder', mappedError, {
7482
- orderId: params.orderId,
7483
- coin: params.symbol,
7484
- orderType: params.orderType,
7485
- }));
7486
- return createErrorResult(mappedError, {
7487
- success: false,
7488
- orderId: params.orderId,
7489
- });
7490
- }
7491
- }, _HyperLiquidProvider_cancelTwapOrder =
7492
- /**
7493
- * Cancel a running TWAP through the venue's TWAP cancel action.
7494
- *
7495
- * A TWAP never rested on the book, so the ordinary `cancel` action has no
7496
- * order ID to match and would reject it.
7497
- *
7498
- * @param params - Cancellation parameters, with `orderId` carrying the TWAP ID.
7499
- * @returns A promise that resolves to the result.
7500
- */
7501
- async function _HyperLiquidProvider_cancelTwapOrder(params) {
7502
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReady).call(this);
7503
- const coinValidation = validateCoinExists(params.symbol, __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f"));
7504
- if (!coinValidation.isValid) {
7505
- throw new Error(coinValidation.error);
7506
- }
7507
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
7508
- const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
7509
- symbol: params.symbol,
7510
- dexName: parseAssetName(params.symbol).dex,
7511
- });
7512
- const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient().twapCancel({
7513
- a: assetId,
7514
- t: parseInt(params.orderId, 10),
7515
- });
7516
- const status = result.response?.data?.status;
7517
- if (status === 'success') {
7518
- return { success: true, orderId: params.orderId };
7519
- }
7520
- const rawError = status?.error ??
7521
- 'TWAP cancellation failed';
7522
- return createErrorResult(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, new Error(rawError)), {
7523
- success: false,
7524
- orderId: params.orderId,
7525
- });
7526
- }, _HyperLiquidProvider_cancelScaleOrder =
7527
- /**
7528
- * Cancel every child of a scale ladder in one batch.
7529
- *
7530
- * @param params - Cancellation parameters, with `orderId` carrying the group handle.
7531
- * @returns A promise that resolves to the result.
7532
- */
7533
- async function _HyperLiquidProvider_cancelScaleOrder(params) {
7534
- const group = __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").get(params.orderId);
7535
- if (!group) {
7536
- throw new Error(PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
7537
- }
7538
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
7539
- const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient().cancel({
7540
- cancels: group.orderIds.map((orderId) => ({
7541
- a: group.assetId,
7542
- o: parseInt(orderId, 10),
7543
- })),
7544
- });
7545
- const statuses = result.response?.data?.statuses ?? [];
7546
- // A rung that filled or was cancelled individually comes back as a
7547
- // rejection, but nothing of it is resting — counting it as still live would
7548
- // pin the handle open for a ladder that is entirely off the book.
7549
- const remaining = group.orderIds.filter((_unused, index) => classifyCancelStatus(statuses[index]) === 'refused');
7550
- if (remaining.length === 0) {
7551
- __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").delete(params.orderId);
7552
- return { success: true, orderId: params.orderId };
7553
- }
7554
- // A rung the exchange refused to cancel may still be resting. Keeping the
7555
- // handle registered against what is left means the caller can retry the
7556
- // same cancel rather than being told the ladder is gone when it is not.
7557
- __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").set(params.orderId, {
7558
- assetId: group.assetId,
7559
- orderIds: remaining,
7560
- });
7561
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Scale group cancel left children resting', {
7562
- groupId: params.orderId,
7563
- remaining: remaining.length,
7564
- total: group.orderIds.length,
7565
- });
7566
- return createErrorResult(new Error(PERPS_ERROR_CODES.ORDER_STRATEGY_CANCEL_INCOMPLETE), { success: false, orderId: params.orderId });
7567
- }, _HyperLiquidProvider_cancelChaseOrder =
7568
- /**
7569
- * Stop a chase session and cancel whatever it still has resting.
7570
- *
7571
- * @param params - Cancellation parameters, with `orderId` carrying the session handle.
7572
- * @returns A promise that resolves to the result.
7573
- */
7574
- async function _HyperLiquidProvider_cancelChaseOrder(params) {
7575
- const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(params.orderId);
7576
- if (!session) {
7577
- throw new Error(PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
7578
- }
7579
- // Stopped first: a tick that fired between here and the cancel below would
7580
- // otherwise re-place the very order being cancelled.
7581
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, params.orderId);
7582
- // A replacement already in flight cannot be called off, so the cancel waits
7583
- // for it and then cancels whatever it rested. Deciding without waiting would
7584
- // read the session's null `orderId` as "nothing rests" and report a clean
7585
- // cancellation over an order that was about to appear on the book.
7586
- if (session.pendingReplacement) {
7587
- await session.pendingReplacement;
7588
- }
7589
- // Nothing rests: the order filled, something else cancelled it, or a
7590
- // replacement failed to go up. Either way the session ends cleanly.
7591
- if (session.orderId === null) {
7592
- __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").delete(params.orderId);
7593
- return { success: true, orderId: params.orderId };
7594
- }
7595
- await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
7596
- // Only a refusal leaves an order behind. A child that had already filled or
7597
- // been cancelled is reported as a rejection too, but nothing of it is
7598
- // resting — treating that as a failure would pin the handle open forever on
7599
- // a chase that is entirely finished.
7600
- if ((await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseChild).call(this, session)) === 'refused') {
7601
- // The order is still resting. The session stays registered — stopped, but
7602
- // still cancellable — so the caller can retry with the same handle.
7603
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase cancel left its order resting', {
7604
- sessionId: params.orderId,
7605
- orderId: session.orderId,
7606
- });
7607
- return createErrorResult(new Error(PERPS_ERROR_CODES.ORDER_STRATEGY_CANCEL_INCOMPLETE), { success: false, orderId: params.orderId });
7608
- }
7609
- __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").delete(params.orderId);
7610
- return { success: true, orderId: params.orderId };
7611
- }, _HyperLiquidProvider_readOrderIdFromStatus = function _HyperLiquidProvider_readOrderIdFromStatus(status) {
7612
- if (!isStatusObject(status)) {
7613
- return undefined;
7614
- }
7615
- // `hasProperty` types the property as `unknown`, so each branch is cast to
7616
- // the only shape the exchange puts there.
7617
- const restingOrder = hasProperty(status, 'resting')
7618
- ? status.resting
7619
- : undefined;
7620
- const filledOrder = hasProperty(status, 'filled')
7621
- ? status.filled
7622
- : undefined;
7623
- return (restingOrder?.oid?.toString() ?? filledOrder?.oid?.toString() ?? undefined);
7624
- }, _HyperLiquidProvider_getDiscountedBuilderFee = function _HyperLiquidProvider_getDiscountedBuilderFee() {
7625
- if (__classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") === undefined) {
7626
- return BUILDER_FEE_CONFIG.MaxFeeTenthsBps;
7627
- }
7628
- return Math.floor(BUILDER_FEE_CONFIG.MaxFeeTenthsBps *
7629
- (1 - __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") / BASIS_POINTS_DIVISOR));
7630
6368
  }, _HyperLiquidProvider_fetchOpenOrders =
7631
6369
  /**
7632
6370
  * Read the account's currently resting orders.