@metamask-previews/perps-controller 12.2.0-preview-d23deb68f → 12.2.0-preview-4165cebcf

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 (79) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +13 -2
  3. package/dist/PerpsController-method-action-types.cjs.map +1 -1
  4. package/dist/PerpsController-method-action-types.d.cts +23 -1
  5. package/dist/PerpsController-method-action-types.d.cts.map +1 -1
  6. package/dist/PerpsController-method-action-types.d.mts +23 -1
  7. package/dist/PerpsController-method-action-types.d.mts.map +1 -1
  8. package/dist/PerpsController-method-action-types.mjs.map +1 -1
  9. package/dist/PerpsController.cjs +26 -0
  10. package/dist/PerpsController.cjs.map +1 -1
  11. package/dist/PerpsController.d.cts +17 -1
  12. package/dist/PerpsController.d.cts.map +1 -1
  13. package/dist/PerpsController.d.mts +17 -1
  14. package/dist/PerpsController.d.mts.map +1 -1
  15. package/dist/PerpsController.mjs +26 -0
  16. package/dist/PerpsController.mjs.map +1 -1
  17. package/dist/constants/eventNames.cjs +5 -0
  18. package/dist/constants/eventNames.cjs.map +1 -1
  19. package/dist/constants/eventNames.d.cts +3 -0
  20. package/dist/constants/eventNames.d.cts.map +1 -1
  21. package/dist/constants/eventNames.d.mts +3 -0
  22. package/dist/constants/eventNames.d.mts.map +1 -1
  23. package/dist/constants/eventNames.mjs +5 -0
  24. package/dist/constants/eventNames.mjs.map +1 -1
  25. package/dist/constants/perpsConfig.cjs +22 -9
  26. package/dist/constants/perpsConfig.cjs.map +1 -1
  27. package/dist/constants/perpsConfig.d.cts +21 -8
  28. package/dist/constants/perpsConfig.d.cts.map +1 -1
  29. package/dist/constants/perpsConfig.d.mts +21 -8
  30. package/dist/constants/perpsConfig.d.mts.map +1 -1
  31. package/dist/constants/perpsConfig.mjs +21 -8
  32. package/dist/constants/perpsConfig.mjs.map +1 -1
  33. package/dist/index.cjs +5 -4
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +3 -3
  36. package/dist/index.d.cts.map +1 -1
  37. package/dist/index.d.mts +3 -3
  38. package/dist/index.d.mts.map +1 -1
  39. package/dist/index.mjs +1 -1
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/perpsErrorCodes.cjs +1 -0
  42. package/dist/perpsErrorCodes.cjs.map +1 -1
  43. package/dist/perpsErrorCodes.d.cts +1 -0
  44. package/dist/perpsErrorCodes.d.cts.map +1 -1
  45. package/dist/perpsErrorCodes.d.mts +1 -0
  46. package/dist/perpsErrorCodes.d.mts.map +1 -1
  47. package/dist/perpsErrorCodes.mjs +1 -0
  48. package/dist/perpsErrorCodes.mjs.map +1 -1
  49. package/dist/providers/AggregatedPerpsProvider.cjs +41 -0
  50. package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
  51. package/dist/providers/AggregatedPerpsProvider.d.cts +16 -1
  52. package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
  53. package/dist/providers/AggregatedPerpsProvider.d.mts +16 -1
  54. package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
  55. package/dist/providers/AggregatedPerpsProvider.mjs +41 -0
  56. package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
  57. package/dist/providers/HyperLiquidProvider.cjs +374 -33
  58. package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
  59. package/dist/providers/HyperLiquidProvider.d.cts +16 -1
  60. package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
  61. package/dist/providers/HyperLiquidProvider.d.mts +16 -1
  62. package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
  63. package/dist/providers/HyperLiquidProvider.mjs +376 -35
  64. package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
  65. package/dist/types/index.cjs.map +1 -1
  66. package/dist/types/index.d.cts +34 -0
  67. package/dist/types/index.d.cts.map +1 -1
  68. package/dist/types/index.d.mts +34 -0
  69. package/dist/types/index.d.mts.map +1 -1
  70. package/dist/types/index.mjs.map +1 -1
  71. package/dist/utils/hyperLiquidValidation.cjs +16 -4
  72. package/dist/utils/hyperLiquidValidation.cjs.map +1 -1
  73. package/dist/utils/hyperLiquidValidation.d.cts +1 -0
  74. package/dist/utils/hyperLiquidValidation.d.cts.map +1 -1
  75. package/dist/utils/hyperLiquidValidation.d.mts +1 -0
  76. package/dist/utils/hyperLiquidValidation.d.mts.map +1 -1
  77. package/dist/utils/hyperLiquidValidation.mjs +17 -5
  78. package/dist/utils/hyperLiquidValidation.mjs.map +1 -1
  79. package/package.json +2 -2
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _HyperLiquidProvider_instances, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_cachedMarketDataWithPrices, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_dexDiscoveryCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_subscriptionBuilderApprovalEpoch, _HyperLiquidProvider_approvedBuilderAddresses, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_userFeeResolution, _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_subscriptionBuilderAddressTestnet, _HyperLiquidProvider_subscriptionBuilderAddressMainnet, _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_getApprovedBuilderKey, _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_getBuilderOrderContext, _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_getSubscriptionBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
13
+ var _HyperLiquidProvider_instances, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_cachedMarketDataWithPrices, _HyperLiquidProvider_cachedSpotMeta, _HyperLiquidProvider_dexDiscoveryCache, _HyperLiquidProvider_referralCheckCache, _HyperLiquidProvider_builderFeeCheckCache, _HyperLiquidProvider_ensureReadyPromise, _HyperLiquidProvider_pendingBuilderFeeApprovals, _HyperLiquidProvider_subscriptionBuilderApprovalEpoch, _HyperLiquidProvider_approvedBuilderAddresses, _HyperLiquidProvider_compiledAllowlistPatterns, _HyperLiquidProvider_compiledBlocklistPatterns, _HyperLiquidProvider_userFeeDiscountBips, _HyperLiquidProvider_userFeeResolution, _HyperLiquidProvider_hip3Enabled, _HyperLiquidProvider_allowlistMarkets, _HyperLiquidProvider_blocklistMarkets, _HyperLiquidProvider_useUnifiedAccount, _HyperLiquidProvider_dexDiscoveryComplete, _HyperLiquidProvider_unifiedAccountSetupNeedsRetry, _HyperLiquidProvider_pendingValidatedDexsPromise, _HyperLiquidProvider_cachedUsdcTokenId, _HyperLiquidProvider_errorMappings, _HyperLiquidProvider_scaleOrderGroups, _HyperLiquidProvider_chaseSessions, _HyperLiquidProvider_chaseTerminations, _HyperLiquidProvider_terminatedChaseHandles, _HyperLiquidProvider_chasePlacementsInFlight, _HyperLiquidProvider_chasePlacementWaiters, _HyperLiquidProvider_chaseTickQueue, _HyperLiquidProvider_chaseGeneration, _HyperLiquidProvider_chasePlacementBlockers, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_subscriptionBuilderAddressTestnet, _HyperLiquidProvider_subscriptionBuilderAddressMainnet, _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_getApprovedBuilderKey, _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_pauseChaseTicksForPlacement, _HyperLiquidProvider_resumeChaseTicksAfterPlacement, _HyperLiquidProvider_recoverFailedChaseTick, _HyperLiquidProvider_runChaseTick, _HyperLiquidProvider_resolveOwnRestingSizes, _HyperLiquidProvider_readOrderRemainder, _HyperLiquidProvider_cancelChaseChild, _HyperLiquidProvider_retractOrphanedChaseOrder, _HyperLiquidProvider_stopChaseSession, _HyperLiquidProvider_cancelStrategyOrder, _HyperLiquidProvider_cancelTwapOrder, _HyperLiquidProvider_cancelScaleOrder, _HyperLiquidProvider_cancelChaseOrder, _HyperLiquidProvider_performChaseTermination, _HyperLiquidProvider_readOrderIdFromStatus, _HyperLiquidProvider_getDiscountedBuilderFee, _HyperLiquidProvider_getBuilderOrderContext, _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_getSubscriptionBuilderAddress, _HyperLiquidProvider_getReferralCode, _HyperLiquidProvider_ensureReferralSet, _HyperLiquidProvider_isReferralCodeReady, _HyperLiquidProvider_checkReferralSet, _HyperLiquidProvider_setReferralCode;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.HyperLiquidProvider = void 0;
16
16
  const utils_1 = require("@metamask/utils");
@@ -63,6 +63,14 @@ const ALREADY_GONE_CANCEL_MARKERS = [
63
63
  'already cancelled',
64
64
  'order not found',
65
65
  ];
66
+ const RETRYABLE_CHASE_PLACEMENT_MARKERS = [
67
+ 'post only order would have immediately matched',
68
+ 'price too far from oracle',
69
+ ];
70
+ const isRetryableChasePlacementError = (error) => {
71
+ const message = (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.startChaseSession').message.toLowerCase();
72
+ return RETRYABLE_CHASE_PLACEMENT_MARKERS.some((marker) => message.includes(marker));
73
+ };
66
74
  /**
67
75
  * Classify one entry of a cancel response.
68
76
  *
@@ -137,6 +145,7 @@ const pickStrategyParams = (params) => ({
137
145
  chaseIntervalMs: params.chaseIntervalMs,
138
146
  chaseMaxDurationMs: params.chaseMaxDurationMs,
139
147
  chaseMaxRepricings: params.chaseMaxRepricings,
148
+ chaseMaxDistanceBps: params.chaseMaxDistanceBps,
140
149
  });
141
150
  /**
142
151
  * Check a strategy placement's notional against the minimum the venue will
@@ -387,16 +396,34 @@ class HyperLiquidProvider {
387
396
  // Chase sessions running on this provider instance, keyed by session handle.
388
397
  // Each owns a pending timer, so disconnect has to stop them.
389
398
  _HyperLiquidProvider_chaseSessions.set(this, new Map());
399
+ // In-flight termination is keyed by stable strategy handle so retries share
400
+ // one venue mutation. Completed handles remain idempotent for this provider
401
+ // lifecycle and are cleared on disconnect.
402
+ _HyperLiquidProvider_chaseTerminations.set(this, new Map());
403
+ // Provider-lifetime tombstones make every later retry idempotent. Disconnect
404
+ // clears them with the rest of the account-scoped Chase registry.
405
+ _HyperLiquidProvider_terminatedChaseHandles.set(this, new Set());
390
406
  // Chase placements that have reserved a slot against the venue's concurrency
391
407
  // cap but have not registered their session yet. Two round trips separate the
392
408
  // two, and a reservation is what keeps concurrent placements from both
393
409
  // passing the check.
394
410
  _HyperLiquidProvider_chasePlacementsInFlight.set(this, 0);
411
+ // Allows lifecycle teardown to wait until every placement has either
412
+ // registered a session or retracted its newly-rested child.
413
+ _HyperLiquidProvider_chasePlacementWaiters.set(this, new Set());
414
+ // Serialize background Chase mutations. Several sessions share one signer and
415
+ // transport, so simultaneous cancel/replace ticks would create avoidable
416
+ // signed traffic and can starve a foreground placement.
417
+ _HyperLiquidProvider_chaseTickQueue.set(this, Promise.resolve());
395
418
  // Bumped by every teardown that clears the chase registry. A placement
396
419
  // captures it before its round trips and refuses to register afterwards if it
397
420
  // has moved: a session registered after a disconnect would schedule a
398
421
  // background timer against a provider that has already been torn down.
399
422
  _HyperLiquidProvider_chaseGeneration.set(this, 0);
423
+ // Reference-counted because suspension and disconnect may overlap. One
424
+ // lifecycle owner finishing must not reopen placement while another still
425
+ // drains or tears down the provider.
426
+ _HyperLiquidProvider_chasePlacementBlockers.set(this, 0);
400
427
  // Track whether clients have been initialized (lazy initialization)
401
428
  _HyperLiquidProvider_clientsInitialized.set(this, false);
402
429
  // Promise-based lock to prevent race conditions in concurrent initialization
@@ -906,6 +933,101 @@ class HyperLiquidProvider {
906
933
  });
907
934
  }
908
935
  }
936
+ /**
937
+ * Return stable client-facing snapshots for every Chase session retained by
938
+ * this provider instance. A read may refresh the current child order's
939
+ * remaining size from the venue, throttled to the Chase interval.
940
+ *
941
+ * @returns Current Chase session snapshots.
942
+ */
943
+ async getChaseOrders() {
944
+ return await Promise.all([...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").entries()].map(async ([handle, session]) => {
945
+ const now = Date.now();
946
+ let snapshotRemainingSize = session.size;
947
+ if (session.orderId !== null &&
948
+ session.pendingReplacement === null &&
949
+ now - session.lastSnapshotSizeRefreshAt >= session.intervalMs) {
950
+ session.lastSnapshotSizeRefreshAt = now;
951
+ const snapshotOrderId = session.orderId;
952
+ try {
953
+ const liveRemainder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, snapshotOrderId);
954
+ if (liveRemainder !== null &&
955
+ session.orderId === snapshotOrderId &&
956
+ session.pendingReplacement === null) {
957
+ Object.assign(session, { size: liveRemainder });
958
+ snapshotRemainingSize = liveRemainder;
959
+ }
960
+ }
961
+ catch (error) {
962
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase snapshot size refresh failed', {
963
+ orderId: snapshotOrderId,
964
+ error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.getChaseOrders')
965
+ .message,
966
+ });
967
+ }
968
+ }
969
+ const arrival = Number.parseFloat(session.arrivalPrice);
970
+ const resting = Number.parseFloat(session.restingPrice);
971
+ const adverseDistance = session.isBuy
972
+ ? resting - arrival
973
+ : arrival - resting;
974
+ const measuredDistance = Number.isFinite(arrival) &&
975
+ arrival > 0 &&
976
+ Number.isFinite(adverseDistance)
977
+ ? Math.round((Math.max(0, adverseDistance) / arrival) * hyperLiquidConfig_js_1.BASIS_POINTS_DIVISOR)
978
+ : 0;
979
+ return {
980
+ handle,
981
+ symbol: session.symbol,
982
+ side: session.isBuy ? 'buy' : 'sell',
983
+ originalSize: session.originalSize,
984
+ remainingSize: snapshotRemainingSize,
985
+ arrivalPrice: session.arrivalPrice,
986
+ restingPrice: session.restingPrice,
987
+ restingOrderId: session.orderId,
988
+ distanceChasedBps: measuredDistance,
989
+ ...(session.maxDistanceBps === undefined
990
+ ? {}
991
+ : { maxDistanceBps: session.maxDistanceBps }),
992
+ repricings: session.repricings,
993
+ startedAt: session.startedAt,
994
+ status: session.status,
995
+ };
996
+ }));
997
+ }
998
+ /**
999
+ * Stop all active Chase loops while deliberately leaving their current
1000
+ * post-only children resting. Used when a client moves to the background.
1001
+ *
1002
+ * @returns Snapshots after every in-flight replacement has settled.
1003
+ */
1004
+ async suspendChaseOrders() {
1005
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementBlockers, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") + 1, "f");
1006
+ // Abort a placement that passed the blocker check but has not completed
1007
+ // its final generation check; the waiter below then drains its cleanup.
1008
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chaseGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f") + 1, "f");
1009
+ try {
1010
+ await Promise.all([...__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementWaiters, "f")]);
1011
+ // Clear timers without deactivating sessions, then let any tick already
1012
+ // admitted to the shared queue finish its cancel/replace. Stopping first
1013
+ // can strand a session between children: the old order is cancelled, the
1014
+ // tick observes `active === false`, and suspension reports a resting
1015
+ // Chase that no longer owns an exchange order.
1016
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_pauseChaseTicksForPlacement).call(this);
1017
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
1018
+ for (const [sessionId, session] of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").entries()) {
1019
+ if (!session.active) {
1020
+ continue;
1021
+ }
1022
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, sessionId);
1023
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.Backgrounded;
1024
+ }
1025
+ return await this.getChaseOrders();
1026
+ }
1027
+ finally {
1028
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementBlockers, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") - 1, "f");
1029
+ }
1030
+ }
909
1031
  /**
910
1032
  * Edit an existing order (pending/unfilled order)
911
1033
  *
@@ -1124,7 +1246,22 @@ class HyperLiquidProvider {
1124
1246
  if (params.orderType && (0, orderTypes_js_1.isStrategyOrderType)(params.orderType)) {
1125
1247
  return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelStrategyOrder).call(this, params);
1126
1248
  }
1249
+ // Resolve ownership before the first await. A reprice can change the child
1250
+ // ID while an ordinary cancel is in flight; cancelling through the stable
1251
+ // session handle stops the loop, joins any replacement, and removes the
1252
+ // current child instead of leaving a replacement chasing behind the user.
1253
+ const owningChase = [...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").entries()].find(([, session]) => session.orderId === params.orderId ||
1254
+ session.replacingOrderId === params.orderId);
1127
1255
  try {
1256
+ if (owningChase) {
1257
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, owningChase[0]);
1258
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
1259
+ return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseOrder).call(this, {
1260
+ ...params,
1261
+ orderId: owningChase[0],
1262
+ orderType: 'chase',
1263
+ });
1264
+ }
1128
1265
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Canceling order:', params);
1129
1266
  // Hydrate the asset map before coin validation so a cold start (e.g.
1130
1267
  // service-worker restart with an empty prefetch map) can self-heal
@@ -4519,6 +4656,8 @@ class HyperLiquidProvider {
4519
4656
  * @returns A promise that resolves to the result.
4520
4657
  */
4521
4658
  async disconnect() {
4659
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementBlockers, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") + 1, "f");
4660
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chaseGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f") + 1, "f");
4522
4661
  try {
4523
4662
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Disconnecting provider', {
4524
4663
  isTestnet: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode(),
@@ -4530,13 +4669,20 @@ class HyperLiquidProvider {
4530
4669
  // a disconnect would sign orders against a client that is being torn down.
4531
4670
  // Orders already resting are deliberately left alone — disconnecting is
4532
4671
  // not a request to cancel the user's positions or orders.
4533
- for (const sessionId of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").keys()) {
4534
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, sessionId);
4672
+ // Invalidate placements first, then drain every mutation before clearing
4673
+ // the registry and tearing down the clients they use.
4674
+ for (const [sessionId, session] of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").entries()) {
4675
+ if (session.active) {
4676
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, sessionId);
4677
+ }
4535
4678
  }
4679
+ await Promise.all([...__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementWaiters, "f")]);
4680
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
4681
+ await Promise.allSettled([...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").values()]);
4536
4682
  __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").clear();
4683
+ __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").clear();
4684
+ __classPrivateFieldGet(this, _HyperLiquidProvider_terminatedChaseHandles, "f").clear();
4537
4685
  __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").clear();
4538
- // Placements still mid-flight check this before registering.
4539
- __classPrivateFieldSet(this, _HyperLiquidProvider_chaseGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f") + 1, "f");
4540
4686
  // Clear fee cache
4541
4687
  this.clearFeeCache();
4542
4688
  // Clear session caches (ensures fresh state on reconnect/account switch)
@@ -4602,6 +4748,9 @@ class HyperLiquidProvider {
4602
4748
  catch (error) {
4603
4749
  return (0, hyperLiquidValidation_js_1.createErrorResult)(error, { success: false });
4604
4750
  }
4751
+ finally {
4752
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementBlockers, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") - 1, "f");
4753
+ }
4605
4754
  }
4606
4755
  /**
4607
4756
  * Lightweight WebSocket health check using SDK's built-in ready() method
@@ -4727,7 +4876,7 @@ class HyperLiquidProvider {
4727
4876
  }
4728
4877
  }
4729
4878
  exports.HyperLiquidProvider = HyperLiquidProvider;
4730
- _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_subscriptionBuilderApprovalEpoch = new WeakMap(), _HyperLiquidProvider_approvedBuilderAddresses = new WeakMap(), _HyperLiquidProvider_compiledAllowlistPatterns = new WeakMap(), _HyperLiquidProvider_compiledBlocklistPatterns = new WeakMap(), _HyperLiquidProvider_userFeeDiscountBips = new WeakMap(), _HyperLiquidProvider_userFeeResolution = 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_subscriptionBuilderAddressTestnet = new WeakMap(), _HyperLiquidProvider_subscriptionBuilderAddressMainnet = 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) {
4879
+ _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_subscriptionBuilderApprovalEpoch = new WeakMap(), _HyperLiquidProvider_approvedBuilderAddresses = new WeakMap(), _HyperLiquidProvider_compiledAllowlistPatterns = new WeakMap(), _HyperLiquidProvider_compiledBlocklistPatterns = new WeakMap(), _HyperLiquidProvider_userFeeDiscountBips = new WeakMap(), _HyperLiquidProvider_userFeeResolution = 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_chaseTerminations = new WeakMap(), _HyperLiquidProvider_terminatedChaseHandles = new WeakMap(), _HyperLiquidProvider_chasePlacementsInFlight = new WeakMap(), _HyperLiquidProvider_chasePlacementWaiters = new WeakMap(), _HyperLiquidProvider_chaseTickQueue = new WeakMap(), _HyperLiquidProvider_chaseGeneration = new WeakMap(), _HyperLiquidProvider_chasePlacementBlockers = new WeakMap(), _HyperLiquidProvider_clientsInitialized = new WeakMap(), _HyperLiquidProvider_initializationPromise = new WeakMap(), _HyperLiquidProvider_messenger = new WeakMap(), _HyperLiquidProvider_builderAddressTestnet = new WeakMap(), _HyperLiquidProvider_builderAddressMainnet = new WeakMap(), _HyperLiquidProvider_subscriptionBuilderAddressTestnet = new WeakMap(), _HyperLiquidProvider_subscriptionBuilderAddressMainnet = 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) {
4731
4880
  const compiled = [];
4732
4881
  for (const pattern of patterns) {
4733
4882
  try {
@@ -6847,13 +6996,16 @@ async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
6847
6996
  // asset info, validation, trading readiness and a leverage update, and a
6848
6997
  // disconnect during any of them has to be seen by the chase registration
6849
6998
  // at the end.
6850
- const generation = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f");
6851
6999
  if (orderType !== 'chase') {
6852
7000
  const context = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareStrategyPlacement).call(this, params);
6853
7001
  return orderType === 'twap'
6854
7002
  ? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeTwapOrder).call(this, params, context)
6855
7003
  : await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeScaleOrder).call(this, params, context);
6856
7004
  }
7005
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") > 0) {
7006
+ throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
7007
+ }
7008
+ const generation = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f");
6857
7009
  // The chase slot is claimed before the preamble, not after it: the preamble
6858
7010
  // completes the signing setup and can change the asset's leverage, and a
6859
7011
  // request that is going to be refused for exceeding the venue's cap must
@@ -6866,12 +7018,24 @@ async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
6866
7018
  throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_LIMIT_REACHED);
6867
7019
  }
6868
7020
  __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementsInFlight, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") + 1, "f");
7021
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_pauseChaseTicksForPlacement).call(this);
7022
+ let settlePlacement;
7023
+ const placementWaiter = new Promise((resolve) => {
7024
+ settlePlacement = resolve;
7025
+ });
7026
+ __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementWaiters, "f").add(placementWaiter);
6869
7027
  try {
7028
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
6870
7029
  const context = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareStrategyPlacement).call(this, params);
6871
7030
  return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_startChaseSession).call(this, params, context, generation);
6872
7031
  }
6873
7032
  finally {
7033
+ settlePlacement?.();
7034
+ __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementWaiters, "f").delete(placementWaiter);
6874
7035
  __classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementsInFlight, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") - 1, "f");
7036
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") === 0) {
7037
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resumeChaseTicksAfterPlacement).call(this);
7038
+ }
6875
7039
  }
6876
7040
  }, _HyperLiquidProvider_prepareStrategyPlacement =
6877
7041
  /**
@@ -7156,7 +7320,7 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
7156
7320
  if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
7157
7321
  throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
7158
7322
  }
7159
- const quotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
7323
+ let quotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
7160
7324
  symbol: params.symbol,
7161
7325
  isBuy: params.isBuy,
7162
7326
  szDecimals,
@@ -7176,22 +7340,55 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
7176
7340
  }
7177
7341
  // Read once, while the caller's fee-source context is still set.
7178
7342
  const builder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderOrderContext).call(this);
7343
+ if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
7344
+ throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
7345
+ }
7179
7346
  // Held onto rather than looked up again after the submission returns.
7180
7347
  // `disconnect` drops the service's client reference synchronously, so a
7181
7348
  // retraction that asked for a client after the fact would be refused one
7182
7349
  // and leave the order resting under the account that placed it. This
7183
7350
  // instance signed the order and can still cancel it as that account.
7184
7351
  const placingClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
7185
- const orderId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_restChaseOrder).call(this, {
7186
- assetId,
7187
- isBuy: params.isBuy,
7188
- price: quotePrice,
7189
- size: formattedSize,
7190
- reduceOnly: params.reduceOnly ?? false,
7191
- builderFee: builder.f,
7192
- builderAddress: builder.b,
7193
- exchangeClient: placingClient,
7194
- });
7352
+ let orderId;
7353
+ for (let attempt = 1; attempt <= perpsConfig_js_1.CHASE_ORDER_CONFIG.InitialPlacementAttempts; attempt += 1) {
7354
+ try {
7355
+ orderId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_restChaseOrder).call(this, {
7356
+ assetId,
7357
+ isBuy: params.isBuy,
7358
+ price: quotePrice,
7359
+ size: formattedSize,
7360
+ reduceOnly: params.reduceOnly ?? false,
7361
+ builderFee: builder.f,
7362
+ builderAddress: builder.b,
7363
+ exchangeClient: placingClient,
7364
+ });
7365
+ break;
7366
+ }
7367
+ catch (error) {
7368
+ if (attempt === perpsConfig_js_1.CHASE_ORDER_CONFIG.InitialPlacementAttempts ||
7369
+ !isRetryableChasePlacementError(error)) {
7370
+ throw error;
7371
+ }
7372
+ if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
7373
+ throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
7374
+ }
7375
+ const refreshedQuote = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
7376
+ symbol: params.symbol,
7377
+ isBuy: params.isBuy,
7378
+ szDecimals,
7379
+ });
7380
+ if (refreshedQuote === 'gone') {
7381
+ throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_TOUCH_UNAVAILABLE);
7382
+ }
7383
+ if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
7384
+ throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
7385
+ }
7386
+ quotePrice = refreshedQuote;
7387
+ }
7388
+ }
7389
+ if (!orderId) {
7390
+ throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_TOUCH_UNAVAILABLE);
7391
+ }
7195
7392
  const intervalMs = params.chaseIntervalMs ?? perpsConfig_js_1.CHASE_ORDER_CONFIG.DefaultIntervalMs;
7196
7393
  const sessionId = (0, idUtils_js_1.generatePerpsId)('chase');
7197
7394
  const session = {
@@ -7199,12 +7396,18 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
7199
7396
  assetId,
7200
7397
  isBuy: params.isBuy,
7201
7398
  size: formattedSize,
7399
+ originalSize: formattedSize,
7202
7400
  szDecimals,
7203
7401
  reduceOnly: params.reduceOnly ?? false,
7204
7402
  orderId,
7403
+ replacingOrderId: null,
7205
7404
  pendingReplacement: null,
7206
7405
  restingPrice: quotePrice,
7406
+ arrivalPrice: quotePrice,
7407
+ startedAt: Date.now(),
7408
+ maxDistanceBps: params.chaseMaxDistanceBps,
7207
7409
  intervalMs,
7410
+ lastSnapshotSizeRefreshAt: 0,
7208
7411
  builderFee: builder.f,
7209
7412
  builderAddress: builder.b,
7210
7413
  deadline: Date.now() +
@@ -7213,6 +7416,7 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
7213
7416
  repricings: 0,
7214
7417
  timer: null,
7215
7418
  active: true,
7419
+ status: perpsConfig_js_1.CHASE_ORDER_STATUS.Active,
7216
7420
  };
7217
7421
  // A disconnect landed while the submission was in flight — the one window
7218
7422
  // the checks above cannot close. The order rested, but no strategy is
@@ -7353,21 +7557,41 @@ async function _HyperLiquidProvider_restChaseOrder(params) {
7353
7557
  return;
7354
7558
  }
7355
7559
  const timer = setTimeout(() => {
7356
- // A rejected tick must not stop the session from being cancellable, and
7357
- // must not surface as an unhandled rejection either.
7358
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_runChaseTick).call(this, sessionId).catch((error) => {
7359
- __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase tick failed', {
7360
- sessionId,
7361
- error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.chaseTick').message,
7362
- });
7363
- __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_recoverFailedChaseTick).call(this, sessionId);
7364
- });
7560
+ session.timer = null;
7561
+ __classPrivateFieldSet(this, _HyperLiquidProvider_chaseTickQueue, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f").then(async () => {
7562
+ // A rejected tick must not stop the session from being cancellable, and
7563
+ // must not surface as an unhandled rejection either.
7564
+ try {
7565
+ await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_runChaseTick).call(this, sessionId);
7566
+ }
7567
+ catch (error) {
7568
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase tick failed', {
7569
+ sessionId,
7570
+ error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.chaseTick').message,
7571
+ });
7572
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_recoverFailedChaseTick).call(this, sessionId);
7573
+ }
7574
+ return undefined;
7575
+ }), "f");
7365
7576
  }, session.intervalMs);
7366
7577
  // Node keeps the process alive for a pending timer; a background chase is
7367
7578
  // not a reason to hold an exiting process open. React Native's timers have
7368
7579
  // no `unref`, hence the guard.
7369
7580
  timer.unref?.();
7370
7581
  session.timer = timer;
7582
+ }, _HyperLiquidProvider_pauseChaseTicksForPlacement = function _HyperLiquidProvider_pauseChaseTicksForPlacement() {
7583
+ for (const session of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").values()) {
7584
+ if (session.timer) {
7585
+ clearTimeout(session.timer);
7586
+ session.timer = null;
7587
+ }
7588
+ }
7589
+ }, _HyperLiquidProvider_resumeChaseTicksAfterPlacement = function _HyperLiquidProvider_resumeChaseTicksAfterPlacement() {
7590
+ for (const [sessionId, session] of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f")) {
7591
+ if (session.active && !session.timer) {
7592
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
7593
+ }
7594
+ }
7371
7595
  }, _HyperLiquidProvider_recoverFailedChaseTick = function _HyperLiquidProvider_recoverFailedChaseTick(sessionId) {
7372
7596
  const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
7373
7597
  if (!session?.active) {
@@ -7375,6 +7599,7 @@ async function _HyperLiquidProvider_restChaseOrder(params) {
7375
7599
  }
7376
7600
  if (session.orderId === null) {
7377
7601
  session.active = false;
7602
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.Failed;
7378
7603
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase ended with nothing resting', {
7379
7604
  sessionId,
7380
7605
  });
@@ -7393,15 +7618,27 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7393
7618
  if (!session?.active) {
7394
7619
  return;
7395
7620
  }
7621
+ // Give a new Chase placement priority over background cancel/replace
7622
+ // traffic. With several active sessions, their signed mutations can
7623
+ // otherwise overlap the placement preamble and trip the SDK transport's
7624
+ // circuit breaker before the new order reaches the venue. Deferring one
7625
+ // polling interval leaves every existing child resting as a valid ALO and
7626
+ // preserves the venue's five-session limit without increasing request
7627
+ // churn.
7628
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementsInFlight, "f") > 0) {
7629
+ __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
7630
+ return;
7631
+ }
7396
7632
  if (Date.now() >= session.deadline) {
7397
7633
  // The window closed. The last order stays resting as an ordinary limit
7398
7634
  // order and the session stays registered, so cancelling by its handle
7399
7635
  // still reaches that order.
7400
7636
  session.active = false;
7637
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.DurationReached;
7401
7638
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase session window closed', { sessionId });
7402
7639
  return;
7403
7640
  }
7404
- const quotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
7641
+ const rawQuotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
7405
7642
  symbol: session.symbol,
7406
7643
  isBuy: session.isBuy,
7407
7644
  szDecimals: session.szDecimals,
@@ -7413,17 +7650,56 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7413
7650
  }
7414
7651
  : undefined,
7415
7652
  });
7416
- if (quotePrice === 'gone') {
7653
+ if (rawQuotePrice === 'gone') {
7417
7654
  // The order left the book without the loop seeing it — it filled. Ending
7418
7655
  // here releases its slot against the venue's concurrency cap instead of
7419
7656
  // holding one until the window closes.
7420
7657
  session.orderId = null;
7421
7658
  session.active = false;
7659
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.Filled;
7422
7660
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order filled between ticks', {
7423
7661
  sessionId,
7424
7662
  });
7425
7663
  return;
7426
7664
  }
7665
+ const arrivalPrice = Number.parseFloat(session.arrivalPrice);
7666
+ const rawQuote = Number.parseFloat(rawQuotePrice);
7667
+ const adverseDistanceFromArrival = session.isBuy
7668
+ ? (rawQuote - arrivalPrice) / arrivalPrice
7669
+ : (arrivalPrice - rawQuote) / arrivalPrice;
7670
+ const boundaryDirection = session.isBuy ? 1 : -1;
7671
+ const maxDistanceRatio = session.maxDistanceBps === undefined
7672
+ ? undefined
7673
+ : session.maxDistanceBps / hyperLiquidConfig_js_1.BASIS_POINTS_DIVISOR;
7674
+ const boundaryPrice = maxDistanceRatio === undefined
7675
+ ? undefined
7676
+ : arrivalPrice * (1 + boundaryDirection * maxDistanceRatio);
7677
+ let reachedMaxDistance = boundaryPrice !== undefined &&
7678
+ maxDistanceRatio !== undefined &&
7679
+ adverseDistanceFromArrival >= maxDistanceRatio;
7680
+ let quotePrice = rawQuotePrice;
7681
+ if (reachedMaxDistance && boundaryPrice !== undefined) {
7682
+ quotePrice = (0, hyperLiquidAdapter_js_1.formatHyperLiquidPrice)({
7683
+ price: boundaryPrice,
7684
+ szDecimals: session.szDecimals,
7685
+ });
7686
+ const formattedBoundary = Number.parseFloat(quotePrice);
7687
+ const overshootsBoundary = session.isBuy
7688
+ ? formattedBoundary > boundaryPrice
7689
+ : formattedBoundary < boundaryPrice;
7690
+ if (overshootsBoundary) {
7691
+ const tick = (0, orderCalculations_js_1.getPriceTick)({
7692
+ price: boundaryPrice,
7693
+ szDecimals: session.szDecimals,
7694
+ });
7695
+ quotePrice = (0, hyperLiquidAdapter_js_1.formatHyperLiquidPrice)({
7696
+ price: session.isBuy
7697
+ ? formattedBoundary - tick
7698
+ : formattedBoundary + tick,
7699
+ szDecimals: session.szDecimals,
7700
+ });
7701
+ }
7702
+ }
7427
7703
  // The book read is a round trip, and a cancel arriving during it stops the
7428
7704
  // session. Without this re-check the tick would cancel and re-place the very
7429
7705
  // order the caller just asked to be rid of.
@@ -7455,14 +7731,26 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7455
7731
  sessionId,
7456
7732
  orderId: session.orderId,
7457
7733
  });
7734
+ reachedMaxDistance = false;
7458
7735
  }
7459
7736
  else if (outcome === 'gone') {
7460
7737
  // The order left the book between ticks: it filled, or something else
7461
7738
  // cancelled it. There is nothing left to chase.
7739
+ const goneOrderId = session.orderId;
7740
+ const remaining = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, goneOrderId);
7462
7741
  session.orderId = null;
7463
7742
  session.active = false;
7743
+ session.status =
7744
+ remaining === null
7745
+ ? perpsConfig_js_1.CHASE_ORDER_STATUS.Filled
7746
+ : perpsConfig_js_1.CHASE_ORDER_STATUS.Failed;
7747
+ if (remaining !== null) {
7748
+ session.size = remaining;
7749
+ }
7464
7750
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order no longer resting', {
7465
7751
  sessionId,
7752
+ status: session.status,
7753
+ remainingSize: session.size,
7466
7754
  });
7467
7755
  return;
7468
7756
  }
@@ -7472,6 +7760,7 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7472
7760
  // would otherwise leave the session naming an order that is already off
7473
7761
  // the book, and recovery would reschedule a chase with nothing resting.
7474
7762
  const cancelledOrderId = session.orderId;
7763
+ session.replacingOrderId = cancelledOrderId;
7475
7764
  session.orderId = null;
7476
7765
  // No further fills can reach a cancelled order, so what it did not fill
7477
7766
  // is now fixed. Sampling before the cancel would have left a window in
@@ -7491,6 +7780,7 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7491
7780
  if (remaining === null) {
7492
7781
  // It filled completely between ticks; there is nothing left to chase.
7493
7782
  session.active = false;
7783
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.Filled;
7494
7784
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order fully filled', { sessionId });
7495
7785
  return;
7496
7786
  }
@@ -7522,6 +7812,7 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7522
7812
  }
7523
7813
  finally {
7524
7814
  // Cleared before the waiters wake, so they see the settled session.
7815
+ session.replacingOrderId = null;
7525
7816
  session.pendingReplacement = null;
7526
7817
  settleReplacement?.();
7527
7818
  }
@@ -7550,8 +7841,19 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
7550
7841
  }
7551
7842
  }
7552
7843
  }
7844
+ if (reachedMaxDistance) {
7845
+ session.active = false;
7846
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.MaxDistanceReached;
7847
+ __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase max distance reached', {
7848
+ sessionId,
7849
+ restingPrice: session.restingPrice,
7850
+ maxDistanceBps: session.maxDistanceBps,
7851
+ });
7852
+ return;
7853
+ }
7553
7854
  if (session.repricings >= session.maxRepricings) {
7554
7855
  session.active = false;
7856
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.RepricingLimitReached;
7555
7857
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase repricing cap reached', { sessionId });
7556
7858
  return;
7557
7859
  }
@@ -7672,9 +7974,19 @@ async function _HyperLiquidProvider_cancelChaseChild(session, placingClient) {
7672
7974
  // Looked up only once there is something to cancel, so a session with
7673
7975
  // nothing resting still answers on a provider whose client is already gone.
7674
7976
  const exchangeClient = placingClient ?? __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
7675
- const result = await exchangeClient.cancel({
7676
- cancels: [{ a: session.assetId, o: parseInt(session.orderId, 10) }],
7677
- });
7977
+ let result;
7978
+ try {
7979
+ result = await exchangeClient.cancel({
7980
+ cancels: [{ a: session.assetId, o: parseInt(session.orderId, 10) }],
7981
+ });
7982
+ }
7983
+ catch (error) {
7984
+ const message = (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.cancelChaseChild').message.toLowerCase();
7985
+ if (ALREADY_GONE_CANCEL_MARKERS.some((marker) => message.includes(marker))) {
7986
+ return 'gone';
7987
+ }
7988
+ throw error;
7989
+ }
7678
7990
  return classifyCancelStatus(result.response?.data?.statuses?.[0]);
7679
7991
  }, _HyperLiquidProvider_retractOrphanedChaseOrder =
7680
7992
  /**
@@ -7714,6 +8026,7 @@ async function _HyperLiquidProvider_retractOrphanedChaseOrder(session, placingCl
7714
8026
  return;
7715
8027
  }
7716
8028
  session.active = false;
8029
+ session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.TerminationPending;
7717
8030
  if (session.timer) {
7718
8031
  clearTimeout(session.timer);
7719
8032
  session.timer = null;
@@ -7832,6 +8145,33 @@ async function _HyperLiquidProvider_cancelScaleOrder(params) {
7832
8145
  * @returns A promise that resolves to the result.
7833
8146
  */
7834
8147
  async function _HyperLiquidProvider_cancelChaseOrder(params) {
8148
+ if (__classPrivateFieldGet(this, _HyperLiquidProvider_terminatedChaseHandles, "f").has(params.orderId)) {
8149
+ return { success: true, orderId: params.orderId };
8150
+ }
8151
+ const existingTermination = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").get(params.orderId);
8152
+ if (existingTermination) {
8153
+ return await existingTermination;
8154
+ }
8155
+ const termination = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_performChaseTermination).call(this, params);
8156
+ __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").set(params.orderId, termination);
8157
+ try {
8158
+ const result = await termination;
8159
+ if (result.success) {
8160
+ __classPrivateFieldGet(this, _HyperLiquidProvider_terminatedChaseHandles, "f").add(params.orderId);
8161
+ }
8162
+ return result;
8163
+ }
8164
+ finally {
8165
+ __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").delete(params.orderId);
8166
+ }
8167
+ }, _HyperLiquidProvider_performChaseTermination =
8168
+ /**
8169
+ * Own one Chase termination after concurrent callers have been deduplicated.
8170
+ *
8171
+ * @param params - Cancellation parameters with a stable Chase handle.
8172
+ * @returns The single underlying termination result.
8173
+ */
8174
+ async function _HyperLiquidProvider_performChaseTermination(params) {
7835
8175
  const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(params.orderId);
7836
8176
  if (!session) {
7837
8177
  throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
@@ -7857,7 +8197,8 @@ async function _HyperLiquidProvider_cancelChaseOrder(params) {
7857
8197
  // been cancelled is reported as a rejection too, but nothing of it is
7858
8198
  // resting — treating that as a failure would pin the handle open forever on
7859
8199
  // a chase that is entirely finished.
7860
- if ((await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseChild).call(this, session)) === 'refused') {
8200
+ const cancelOutcome = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseChild).call(this, session);
8201
+ if (cancelOutcome === 'refused') {
7861
8202
  // The order is still resting. The session stays registered — stopped, but
7862
8203
  // still cancellable — so the caller can retry with the same handle.
7863
8204
  __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase cancel left its order resting', {