@metamask-previews/perps-controller 12.2.0-preview-e68ab1498 → 13.0.0-preview-4b37525
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.
- package/CHANGELOG.md +15 -6
- package/dist/PerpsController-method-action-types.cjs.map +1 -1
- package/dist/PerpsController-method-action-types.d.cts +26 -3
- package/dist/PerpsController-method-action-types.d.cts.map +1 -1
- package/dist/PerpsController-method-action-types.d.mts +26 -3
- package/dist/PerpsController-method-action-types.d.mts.map +1 -1
- package/dist/PerpsController-method-action-types.mjs.map +1 -1
- package/dist/PerpsController.cjs +392 -102
- package/dist/PerpsController.cjs.map +1 -1
- package/dist/PerpsController.d.cts +26 -7
- package/dist/PerpsController.d.cts.map +1 -1
- package/dist/PerpsController.d.mts +26 -7
- package/dist/PerpsController.d.mts.map +1 -1
- package/dist/PerpsController.mjs +392 -102
- package/dist/PerpsController.mjs.map +1 -1
- package/dist/constants/eventNames.cjs +1 -1
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +1 -1
- package/dist/constants/eventNames.d.mts +1 -1
- package/dist/constants/eventNames.mjs +1 -1
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.cjs +14 -2
- package/dist/constants/hyperLiquidConfig.cjs.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.cts +10 -0
- package/dist/constants/hyperLiquidConfig.d.cts.map +1 -1
- package/dist/constants/hyperLiquidConfig.d.mts +10 -0
- package/dist/constants/hyperLiquidConfig.d.mts.map +1 -1
- package/dist/constants/hyperLiquidConfig.mjs +12 -0
- package/dist/constants/hyperLiquidConfig.mjs.map +1 -1
- package/dist/constants/perpsConfig.cjs +3 -4
- package/dist/constants/perpsConfig.cjs.map +1 -1
- package/dist/constants/perpsConfig.d.cts +2 -4
- package/dist/constants/perpsConfig.d.cts.map +1 -1
- package/dist/constants/perpsConfig.d.mts +2 -4
- package/dist/constants/perpsConfig.d.mts.map +1 -1
- package/dist/constants/perpsConfig.mjs +3 -4
- package/dist/constants/perpsConfig.mjs.map +1 -1
- package/dist/index.cjs +8 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/perpsErrorCodes.cjs +5 -1
- package/dist/perpsErrorCodes.cjs.map +1 -1
- package/dist/perpsErrorCodes.d.cts +4 -0
- package/dist/perpsErrorCodes.d.cts.map +1 -1
- package/dist/perpsErrorCodes.d.mts +4 -0
- package/dist/perpsErrorCodes.d.mts.map +1 -1
- package/dist/perpsErrorCodes.mjs +5 -1
- package/dist/perpsErrorCodes.mjs.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.cjs +104 -14
- package/dist/providers/AggregatedPerpsProvider.cjs.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.d.cts +34 -2
- package/dist/providers/AggregatedPerpsProvider.d.cts.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.d.mts +34 -2
- package/dist/providers/AggregatedPerpsProvider.d.mts.map +1 -1
- package/dist/providers/AggregatedPerpsProvider.mjs +102 -13
- package/dist/providers/AggregatedPerpsProvider.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +2141 -637
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +37 -17
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +37 -17
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +2146 -642
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +96 -3
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +96 -3
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/utils/capabilitySymbols.cjs +25 -0
- package/dist/utils/capabilitySymbols.cjs.map +1 -0
- package/dist/utils/capabilitySymbols.d.cts +15 -0
- package/dist/utils/capabilitySymbols.d.cts.map +1 -0
- package/dist/utils/capabilitySymbols.d.mts +15 -0
- package/dist/utils/capabilitySymbols.d.mts.map +1 -0
- package/dist/utils/capabilitySymbols.mjs +21 -0
- package/dist/utils/capabilitySymbols.mjs.map +1 -0
- package/dist/utils/hyperLiquidAdapter.cjs +20 -1
- package/dist/utils/hyperLiquidAdapter.cjs.map +1 -1
- package/dist/utils/hyperLiquidAdapter.d.cts +1 -0
- package/dist/utils/hyperLiquidAdapter.d.cts.map +1 -1
- package/dist/utils/hyperLiquidAdapter.d.mts +1 -0
- package/dist/utils/hyperLiquidAdapter.d.mts.map +1 -1
- package/dist/utils/hyperLiquidAdapter.mjs +19 -0
- package/dist/utils/hyperLiquidAdapter.mjs.map +1 -1
- package/dist/utils/hyperLiquidValidation.cjs +1 -1
- package/dist/utils/hyperLiquidValidation.cjs.map +1 -1
- package/dist/utils/hyperLiquidValidation.d.cts +1 -1
- package/dist/utils/hyperLiquidValidation.d.mts +1 -1
- package/dist/utils/hyperLiquidValidation.mjs +1 -1
- package/dist/utils/hyperLiquidValidation.mjs.map +1 -1
- package/dist/utils/stringParseUtils.cjs +17 -1
- package/dist/utils/stringParseUtils.cjs.map +1 -1
- package/dist/utils/stringParseUtils.d.cts +8 -0
- package/dist/utils/stringParseUtils.d.cts.map +1 -1
- package/dist/utils/stringParseUtils.d.mts +8 -0
- package/dist/utils/stringParseUtils.d.mts.map +1 -1
- package/dist/utils/stringParseUtils.mjs +15 -0
- package/dist/utils/stringParseUtils.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -10,10 +10,11 @@ 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_chaseTerminations, _HyperLiquidProvider_terminatedChaseHandles, _HyperLiquidProvider_chasePlacementsInFlight, _HyperLiquidProvider_chasePlacementWaiters, _HyperLiquidProvider_chaseTickQueue,
|
|
13
|
+
var _HyperLiquidProvider_instances, _a, _HyperLiquidProvider_deps, _HyperLiquidProvider_clientService, _HyperLiquidProvider_walletService, _HyperLiquidProvider_subscriptionService, _HyperLiquidProvider_symbolToAssetId, _HyperLiquidProvider_userFeeCache, _HyperLiquidProvider_maxLeverageCache, _HyperLiquidProvider_cachedMetaByDex, _HyperLiquidProvider_orderCapabilitiesMarketsByDex, _HyperLiquidProvider_orderCapabilitiesRefreshByDex, _HyperLiquidProvider_isDisconnected, _HyperLiquidProvider_disconnectOperationsInFlight, _HyperLiquidProvider_disconnectOperationPromise, _HyperLiquidProvider_lifecycleGeneration, _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_cancelledScaleOrderGroups, _HyperLiquidProvider_trackedTwapOrdersByMessenger, _HyperLiquidProvider_trackedTwapOrders, _HyperLiquidProvider_chaseSessions, _HyperLiquidProvider_chaseTerminations, _HyperLiquidProvider_terminatedChaseHandles, _HyperLiquidProvider_chasePlacementsInFlight, _HyperLiquidProvider_chasePlacementWaiters, _HyperLiquidProvider_chaseTickQueue, _HyperLiquidProvider_strategyGeneration, _HyperLiquidProvider_chasePlacementBlockers, _HyperLiquidProvider_clientsInitialized, _HyperLiquidProvider_initializationPromise, _HyperLiquidProvider_messenger, _HyperLiquidProvider_builderAddressTestnet, _HyperLiquidProvider_builderAddressMainnet, _HyperLiquidProvider_subscriptionBuilderAddressTestnet, _HyperLiquidProvider_subscriptionBuilderAddressMainnet, _HyperLiquidProvider_priceDeviationLimit, _HyperLiquidProvider_onChaseOrderMaxDistanceReached, _HyperLiquidProvider_resolveOrderFeePolicy, _HyperLiquidProvider_assertProviderLifecycleCurrent, _HyperLiquidProvider_assertCacheWriteLifecycleCurrent, _HyperLiquidProvider_isCacheWriteLifecycleCurrent, _HyperLiquidProvider_getFreshOrderCapabilityMarkets, _HyperLiquidProvider_compilePatternsSafely, _HyperLiquidProvider_ensureClientsInitialized, _HyperLiquidProvider_isWalletOnHyperliquid, _HyperLiquidProvider_isHyperliquidMultiSigAccount, _HyperLiquidProvider_ensureUnifiedAccountEnabled, _HyperLiquidProvider_ensureReady, _HyperLiquidProvider_tradingSetupPromise, _HyperLiquidProvider_tradingSetupComplete, _HyperLiquidProvider_builderFeeSetupPromises, _HyperLiquidProvider_ensureBuilderFeeSetup, _HyperLiquidProvider_ensureReadyForTrading, _HyperLiquidProvider_getOrFetchPrice, _HyperLiquidProvider_filterFills, _HyperLiquidProvider_getAllAvailableDexs, _HyperLiquidProvider_getValidatedDexs, _HyperLiquidProvider_fetchValidatedDexsInternal, _HyperLiquidProvider_getCachedMeta, _HyperLiquidProvider_fetchMeta, _HyperLiquidProvider_cacheDexMetadata, _HyperLiquidProvider_cacheDexMetadataFromRead, _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_submitPreparedStrategy, _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_rebalanceChaseSession, _HyperLiquidProvider_adaptTwapOrder, _HyperLiquidProvider_rebalanceTrackedTwapOrder, _HyperLiquidProvider_rebalanceTerminalHip3Twaps, _HyperLiquidProvider_cancelStrategyOrder, _HyperLiquidProvider_cancelTwapOrder, _HyperLiquidProvider_cancelScaleOrder, _HyperLiquidProvider_cancelChaseOrder, _HyperLiquidProvider_performChaseTermination, _HyperLiquidProvider_cancelOrderRequests, _HyperLiquidProvider_cancelOrderRequestBatch, _HyperLiquidProvider_readOrderPlacementOutcome, _HyperLiquidProvider_readOrderIdFromStatus, _HyperLiquidProvider_getDiscountedBuilderFee, _HyperLiquidProvider_getBuilderOrderContext, _HyperLiquidProvider_fetchOpenOrders, _HyperLiquidProvider_resolveReplacementOrderId, _HyperLiquidProvider_getStandaloneValidatedDexs, _HyperLiquidProvider_queryDexPositions, _HyperLiquidProvider_restoreScaleOrderGroups, _HyperLiquidProvider_getAllMids, _HyperLiquidProvider_fetchSingleDexFresh, _HyperLiquidProvider_excludeNonUsdcCollateralResults, _HyperLiquidProvider_mergeDexResultsInto, _HyperLiquidProvider_cacheFreshMarketDataSnapshot, _HyperLiquidProvider_getStaleMarketDataSnapshot, _HyperLiquidProvider_isFeeCacheValid, _HyperLiquidProvider_performDisconnect, _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");
|
|
17
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
17
18
|
const uuid_1 = require("uuid");
|
|
18
19
|
const eventNames_js_1 = require("../constants/eventNames.cjs");
|
|
19
20
|
const hyperLiquidConfig_js_1 = require("../constants/hyperLiquidConfig.cjs");
|
|
@@ -28,6 +29,7 @@ const TradingReadinessCache_js_1 = require("../services/TradingReadinessCache.cj
|
|
|
28
29
|
const hyperliquid_types_js_1 = require("../types/hyperliquid-types.cjs");
|
|
29
30
|
const index_js_1 = require("../types/index.cjs");
|
|
30
31
|
const accountUtils_js_1 = require("../utils/accountUtils.cjs");
|
|
32
|
+
const capabilitySymbols_js_1 = require("../utils/capabilitySymbols.cjs");
|
|
31
33
|
const errorUtils_js_1 = require("../utils/errorUtils.cjs");
|
|
32
34
|
const hyperLiquidAbstraction_js_1 = require("../utils/hyperLiquidAbstraction.cjs");
|
|
33
35
|
const hyperLiquidAdapter_js_1 = require("../utils/hyperLiquidAdapter.cjs");
|
|
@@ -38,6 +40,7 @@ const marketUtils_js_1 = require("../utils/marketUtils.cjs");
|
|
|
38
40
|
const orderCalculations_js_1 = require("../utils/orderCalculations.cjs");
|
|
39
41
|
const orderTypes_js_1 = require("../utils/orderTypes.cjs");
|
|
40
42
|
const standaloneInfoClient_js_1 = require("../utils/standaloneInfoClient.cjs");
|
|
43
|
+
const stringParseUtils_js_1 = require("../utils/stringParseUtils.cjs");
|
|
41
44
|
// getStreamManagerInstance removed: use this.#deps.streamManager instead
|
|
42
45
|
/**
|
|
43
46
|
* Type guard to check if a status is an object (not a string literal like "waitingForFill")
|
|
@@ -62,15 +65,54 @@ const ALREADY_GONE_CANCEL_MARKERS = [
|
|
|
62
65
|
'already canceled',
|
|
63
66
|
'already cancelled',
|
|
64
67
|
'order not found',
|
|
68
|
+
'twap not found',
|
|
65
69
|
];
|
|
66
70
|
const RETRYABLE_CHASE_PLACEMENT_MARKERS = [
|
|
67
71
|
'post only order would have immediately matched',
|
|
68
72
|
'price too far from oracle',
|
|
69
73
|
];
|
|
74
|
+
const CHASE_ORDER_STATUS_RETRY_COUNT = 2;
|
|
75
|
+
const CHASE_ORDER_STATUS_RETRY_DELAY_MS = 100;
|
|
76
|
+
const CHASE_ORDER_STATUS_UNAVAILABLE = 'status_unavailable';
|
|
77
|
+
class ChaseOrderStatusUnavailableError extends Error {
|
|
78
|
+
constructor() {
|
|
79
|
+
super('Chase order status unavailable');
|
|
80
|
+
this.name = 'ChaseOrderStatusUnavailableError';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
70
83
|
const isRetryableChasePlacementError = (error) => {
|
|
71
84
|
const message = (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.startChaseSession').message.toLowerCase();
|
|
72
85
|
return RETRYABLE_CHASE_PLACEMENT_MARKERS.some((marker) => message.includes(marker));
|
|
73
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* What happened to one order a cancel was asked to remove.
|
|
89
|
+
*
|
|
90
|
+
* `Cancelled` and `Gone` both mean nothing of it is resting, which is all a
|
|
91
|
+
* caller asked for; only `Refused` leaves an order behind.
|
|
92
|
+
*/
|
|
93
|
+
var CancelChildOutcome;
|
|
94
|
+
(function (CancelChildOutcome) {
|
|
95
|
+
CancelChildOutcome["Cancelled"] = "cancelled";
|
|
96
|
+
CancelChildOutcome["Gone"] = "gone";
|
|
97
|
+
CancelChildOutcome["Refused"] = "refused";
|
|
98
|
+
})(CancelChildOutcome || (CancelChildOutcome = {}));
|
|
99
|
+
var HyperLiquidTwapLifecycleStatus;
|
|
100
|
+
(function (HyperLiquidTwapLifecycleStatus) {
|
|
101
|
+
HyperLiquidTwapLifecycleStatus["Activated"] = "activated";
|
|
102
|
+
HyperLiquidTwapLifecycleStatus["Failed"] = "error";
|
|
103
|
+
HyperLiquidTwapLifecycleStatus["Finished"] = "finished";
|
|
104
|
+
HyperLiquidTwapLifecycleStatus["Stopped"] = "stopped";
|
|
105
|
+
HyperLiquidTwapLifecycleStatus["Terminated"] = "terminated";
|
|
106
|
+
HyperLiquidTwapLifecycleStatus["WaitingForTrigger"] = "waitingForTrigger";
|
|
107
|
+
})(HyperLiquidTwapLifecycleStatus || (HyperLiquidTwapLifecycleStatus = {}));
|
|
108
|
+
var PerpsTwapLifecycleStatus;
|
|
109
|
+
(function (PerpsTwapLifecycleStatus) {
|
|
110
|
+
PerpsTwapLifecycleStatus["Active"] = "active";
|
|
111
|
+
PerpsTwapLifecycleStatus["Canceled"] = "canceled";
|
|
112
|
+
PerpsTwapLifecycleStatus["Completed"] = "completed";
|
|
113
|
+
PerpsTwapLifecycleStatus["CompletedUnderfilled"] = "completed_underfilled";
|
|
114
|
+
PerpsTwapLifecycleStatus["Failed"] = "failed";
|
|
115
|
+
})(PerpsTwapLifecycleStatus || (PerpsTwapLifecycleStatus = {}));
|
|
74
116
|
/**
|
|
75
117
|
* Classify one entry of a cancel response.
|
|
76
118
|
*
|
|
@@ -79,14 +121,14 @@ const isRetryableChasePlacementError = (error) => {
|
|
|
79
121
|
*/
|
|
80
122
|
const classifyCancelStatus = (status) => {
|
|
81
123
|
if (status === 'success') {
|
|
82
|
-
return
|
|
124
|
+
return CancelChildOutcome.Cancelled;
|
|
83
125
|
}
|
|
84
126
|
const message = (isStatusObject(status) && typeof status.error === 'string'
|
|
85
127
|
? status.error
|
|
86
128
|
: '').toLowerCase();
|
|
87
129
|
return ALREADY_GONE_CANCEL_MARKERS.some((marker) => message.includes(marker))
|
|
88
|
-
?
|
|
89
|
-
:
|
|
130
|
+
? CancelChildOutcome.Gone
|
|
131
|
+
: CancelChildOutcome.Refused;
|
|
90
132
|
};
|
|
91
133
|
/**
|
|
92
134
|
* Read the best price on one side of the book, discounting the chase's own
|
|
@@ -188,6 +230,29 @@ const validateStrategyNotional = (params) => {
|
|
|
188
230
|
}
|
|
189
231
|
return { isValid: true };
|
|
190
232
|
};
|
|
233
|
+
/**
|
|
234
|
+
* Create one recoverable identity for a Scale ladder and one venue CLOID per
|
|
235
|
+
* rung. HyperLiquid requires every CLOID to be unique, so the last byte holds
|
|
236
|
+
* the rung index while the preceding 15 bytes identify the shared group.
|
|
237
|
+
*
|
|
238
|
+
* @param count - Number of ladder rungs.
|
|
239
|
+
* @returns The public group handle and venue client order IDs.
|
|
240
|
+
*/
|
|
241
|
+
const createScaleOrderIdentity = (count) => {
|
|
242
|
+
const groupKey = `${hyperLiquidAdapter_js_1.HYPERLIQUID_SCALE_CLOID_MARKER}${(0, uuid_1.v4)()
|
|
243
|
+
.replace(/-/gu, '')
|
|
244
|
+
.slice(0, 22)}`;
|
|
245
|
+
const clientOrderIds = Array.from({ length: count }, (_, index) => {
|
|
246
|
+
const clientOrderId = `0x${groupKey}${index
|
|
247
|
+
.toString(16)
|
|
248
|
+
.padStart(2, '0')}`;
|
|
249
|
+
if (!(0, utils_1.isHexString)(clientOrderId)) {
|
|
250
|
+
throw new Error('Failed to create Scale client order ID');
|
|
251
|
+
}
|
|
252
|
+
return clientOrderId;
|
|
253
|
+
});
|
|
254
|
+
return { groupId: `scale:${groupKey}`, clientOrderIds };
|
|
255
|
+
};
|
|
191
256
|
/**
|
|
192
257
|
* Collect the order IDs of every TP/SL child carried by a parent order.
|
|
193
258
|
*
|
|
@@ -299,6 +364,76 @@ function collectPositionTriggerOrders(params) {
|
|
|
299
364
|
...(stopLossSummaryPrice && { stopLossPrice: stopLossSummaryPrice }),
|
|
300
365
|
};
|
|
301
366
|
}
|
|
367
|
+
const MAX_API_FEE_RATE = 1;
|
|
368
|
+
const MAX_API_FEE_DISCOUNT = 1;
|
|
369
|
+
/**
|
|
370
|
+
* Fee applicability by canonical order type.
|
|
371
|
+
*
|
|
372
|
+
* The configuration type makes this map exhaustive, so a new order type cannot
|
|
373
|
+
* inherit a builder-fee policy accidentally. HyperLiquid's dedicated TWAP
|
|
374
|
+
* action has no builder field. Every other standalone placement uses an order
|
|
375
|
+
* action that can carry one builder context. This policy is deliberately not a
|
|
376
|
+
* constructor or order input. A future backend policy must be resolved inside
|
|
377
|
+
* the provider from its trusted source rather than accepted from a client.
|
|
378
|
+
*/
|
|
379
|
+
const HYPERLIQUID_ORDER_FEE_CONFIG = {
|
|
380
|
+
market: { chargesMetamaskBuilderFee: true },
|
|
381
|
+
limit: { chargesMetamaskBuilderFee: true },
|
|
382
|
+
stop_market: { chargesMetamaskBuilderFee: true },
|
|
383
|
+
stop_limit: { chargesMetamaskBuilderFee: true },
|
|
384
|
+
take_profit_market: { chargesMetamaskBuilderFee: true },
|
|
385
|
+
take_profit_limit: { chargesMetamaskBuilderFee: true },
|
|
386
|
+
twap: { chargesMetamaskBuilderFee: false },
|
|
387
|
+
scale: { chargesMetamaskBuilderFee: true },
|
|
388
|
+
chase: { chargesMetamaskBuilderFee: true },
|
|
389
|
+
};
|
|
390
|
+
const MILLISECONDS_PER_MINUTE = 60000;
|
|
391
|
+
const MILLISECONDS_PER_SECOND = 1000;
|
|
392
|
+
/**
|
|
393
|
+
* Normalize the TWAP history timestamp documented in seconds while tolerating
|
|
394
|
+
* an already-millisecond value from a future SDK response.
|
|
395
|
+
*
|
|
396
|
+
* @param timestamp - Venue timestamp in seconds or milliseconds.
|
|
397
|
+
* @returns Timestamp in milliseconds.
|
|
398
|
+
*/
|
|
399
|
+
const normalizeTwapHistoryTimestamp = (timestamp) => timestamp < 1000000000000
|
|
400
|
+
? timestamp * MILLISECONDS_PER_SECOND
|
|
401
|
+
: timestamp;
|
|
402
|
+
const getTwapOrderScopeKey = (params) => `${params.network}:${params.userAddress.toLowerCase()}:${params.orderId}`;
|
|
403
|
+
const resolveTwapOrderStatus = (historyEntry, executedSize, totalSize) => {
|
|
404
|
+
switch (historyEntry.status.status) {
|
|
405
|
+
case HyperLiquidTwapLifecycleStatus.Activated:
|
|
406
|
+
case HyperLiquidTwapLifecycleStatus.WaitingForTrigger:
|
|
407
|
+
return PerpsTwapLifecycleStatus.Active;
|
|
408
|
+
case HyperLiquidTwapLifecycleStatus.Finished:
|
|
409
|
+
return executedSize.isLessThan(totalSize)
|
|
410
|
+
? PerpsTwapLifecycleStatus.CompletedUnderfilled
|
|
411
|
+
: PerpsTwapLifecycleStatus.Completed;
|
|
412
|
+
case HyperLiquidTwapLifecycleStatus.Terminated:
|
|
413
|
+
case HyperLiquidTwapLifecycleStatus.Stopped:
|
|
414
|
+
return PerpsTwapLifecycleStatus.Canceled;
|
|
415
|
+
case HyperLiquidTwapLifecycleStatus.Failed:
|
|
416
|
+
return PerpsTwapLifecycleStatus.Failed;
|
|
417
|
+
default:
|
|
418
|
+
// A new venue status is not proof that a schedule stopped. Keep it
|
|
419
|
+
// non-terminal so collateral cannot be reclaimed from a live TWAP.
|
|
420
|
+
return PerpsTwapLifecycleStatus.Active;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
const adaptTwapOrderFill = (entry) => ({
|
|
424
|
+
fillId: entry.fill.tid.toString(),
|
|
425
|
+
orderId: entry.fill.oid.toString(),
|
|
426
|
+
side: entry.fill.side === 'B' ? 'buy' : 'sell',
|
|
427
|
+
price: entry.fill.px,
|
|
428
|
+
size: entry.fill.sz,
|
|
429
|
+
fee: entry.fill.fee,
|
|
430
|
+
feeToken: entry.fill.feeToken,
|
|
431
|
+
...(entry.fill.builderFee === undefined
|
|
432
|
+
? {}
|
|
433
|
+
: { builderFee: entry.fill.builderFee }),
|
|
434
|
+
timestamp: entry.fill.time,
|
|
435
|
+
transactionHash: entry.fill.hash,
|
|
436
|
+
});
|
|
302
437
|
/**
|
|
303
438
|
* HyperLiquid provider implementation
|
|
304
439
|
*
|
|
@@ -313,7 +448,7 @@ function collectPositionTriggerOrders(params) {
|
|
|
313
448
|
class HyperLiquidProvider {
|
|
314
449
|
constructor(options) {
|
|
315
450
|
_HyperLiquidProvider_instances.add(this);
|
|
316
|
-
this.protocolId =
|
|
451
|
+
this.protocolId = perpsConfig_js_1.PROVIDER_CONFIG.DefaultProvider;
|
|
317
452
|
// Platform dependencies for logging and debugging
|
|
318
453
|
_HyperLiquidProvider_deps.set(this, void 0);
|
|
319
454
|
// Service instances
|
|
@@ -329,6 +464,16 @@ class HyperLiquidProvider {
|
|
|
329
464
|
// Cache for raw meta responses (shared across methods to avoid redundant API calls)
|
|
330
465
|
// Filtering is applied on-demand (cheap array operations) - no need for separate processed cache
|
|
331
466
|
_HyperLiquidProvider_cachedMetaByDex.set(this, new Map());
|
|
467
|
+
// Fresh filtered markets used only for capability discovery. Each routed
|
|
468
|
+
// DEX owns its freshness window and coalesced refresh.
|
|
469
|
+
_HyperLiquidProvider_orderCapabilitiesMarketsByDex.set(this, new Map());
|
|
470
|
+
_HyperLiquidProvider_orderCapabilitiesRefreshByDex.set(this, new Map());
|
|
471
|
+
// Sticky for this instance. PerpsController discards disconnected providers
|
|
472
|
+
// during initialization; direct callers must call initialize() before reuse.
|
|
473
|
+
_HyperLiquidProvider_isDisconnected.set(this, false);
|
|
474
|
+
_HyperLiquidProvider_disconnectOperationsInFlight.set(this, 0);
|
|
475
|
+
_HyperLiquidProvider_disconnectOperationPromise.set(this, null);
|
|
476
|
+
_HyperLiquidProvider_lifecycleGeneration.set(this, 0);
|
|
332
477
|
// Last known-good market list for stale fallback when every enabled DEX fails in one fetch window.
|
|
333
478
|
_HyperLiquidProvider_cachedMarketDataWithPrices.set(this, null);
|
|
334
479
|
// Session cache for spot metadata (contains token info for HIP-3 collateral checks)
|
|
@@ -361,12 +506,9 @@ class HyperLiquidProvider {
|
|
|
361
506
|
_HyperLiquidProvider_hip3Enabled.set(this, void 0);
|
|
362
507
|
_HyperLiquidProvider_allowlistMarkets.set(this, void 0);
|
|
363
508
|
_HyperLiquidProvider_blocklistMarkets.set(this, void 0);
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
// disable the migration via a hot-fix release if a regression surfaces
|
|
368
|
-
// in the wild — flipping this to false reverts to the legacy programmatic
|
|
369
|
-
// HIP-3 transfer path that already lives in the codebase.
|
|
509
|
+
// Legacy rollback switch. MetaMask production supports unified account and
|
|
510
|
+
// portfolio margin. The false branch and its manual HIP-3 transfers remain
|
|
511
|
+
// temporarily for rollback compatibility and will be removed separately.
|
|
370
512
|
_HyperLiquidProvider_useUnifiedAccount.set(this, void 0);
|
|
371
513
|
// True once DEX discovery has succeeded with real data (not a fallback).
|
|
372
514
|
// When false, #ensureReadyPromise is reset after each init so the next
|
|
@@ -393,6 +535,10 @@ class HyperLiquidProvider {
|
|
|
393
535
|
// one cancel can reach every rung. Cleared on disconnect; the rung IDs are
|
|
394
536
|
// also returned to the caller as `OrderResult.childOrderIds`.
|
|
395
537
|
_HyperLiquidProvider_scaleOrderGroups.set(this, new Map());
|
|
538
|
+
// Prevent a stale open-order cache from recreating a group that this
|
|
539
|
+
// provider lifecycle already canceled successfully.
|
|
540
|
+
_HyperLiquidProvider_cancelledScaleOrderGroups.set(this, new Set());
|
|
541
|
+
_HyperLiquidProvider_trackedTwapOrders.set(this, void 0);
|
|
396
542
|
// Chase sessions running on this provider instance, keyed by session handle.
|
|
397
543
|
// Each owns a pending timer, so disconnect has to stop them.
|
|
398
544
|
_HyperLiquidProvider_chaseSessions.set(this, new Map());
|
|
@@ -415,11 +561,9 @@ class HyperLiquidProvider {
|
|
|
415
561
|
// transport, so simultaneous cancel/replace ticks would create avoidable
|
|
416
562
|
// signed traffic and can starve a foreground placement.
|
|
417
563
|
_HyperLiquidProvider_chaseTickQueue.set(this, Promise.resolve());
|
|
418
|
-
//
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
// background timer against a provider that has already been torn down.
|
|
422
|
-
_HyperLiquidProvider_chaseGeneration.set(this, 0);
|
|
564
|
+
// Every strategy captures this before its round trips. A changed generation
|
|
565
|
+
// prevents a late response from registering handles after disconnect.
|
|
566
|
+
_HyperLiquidProvider_strategyGeneration.set(this, 0);
|
|
423
567
|
// Reference-counted because suspension and disconnect may overlap. One
|
|
424
568
|
// lifecycle owner finishing must not reopen placement while another still
|
|
425
569
|
// drains or tears down the provider.
|
|
@@ -434,27 +578,35 @@ class HyperLiquidProvider {
|
|
|
434
578
|
_HyperLiquidProvider_subscriptionBuilderAddressTestnet.set(this, void 0);
|
|
435
579
|
_HyperLiquidProvider_subscriptionBuilderAddressMainnet.set(this, void 0);
|
|
436
580
|
_HyperLiquidProvider_priceDeviationLimit.set(this, void 0);
|
|
581
|
+
_HyperLiquidProvider_onChaseOrderMaxDistanceReached.set(this, void 0);
|
|
437
582
|
/**
|
|
438
583
|
* Ensure provider is ready for TRADING operations (signing required)
|
|
439
584
|
*
|
|
440
|
-
* This method performs
|
|
585
|
+
* This method performs shared setup that may require user signatures:
|
|
441
586
|
* - DEX abstraction enablement (for HIP-3 auto-transfers)
|
|
442
|
-
* - Builder fee approval (required for orders)
|
|
443
587
|
* - Referral code setup (attribution)
|
|
588
|
+
* - Builder fee approval when the whole action carries a builder context
|
|
444
589
|
*
|
|
445
590
|
* These operations are DEFERRED from ensureReady() to avoid hardware wallet prompt spam
|
|
446
591
|
* when users are just viewing the Perps section (critical for hardware wallets).
|
|
447
592
|
*
|
|
448
|
-
*
|
|
593
|
+
* General trading readiness is independent of builder approval. Native TWAP
|
|
594
|
+
* and cancellations call this with `requiresBuilderFee: false`.
|
|
449
595
|
*/
|
|
450
596
|
_HyperLiquidProvider_tradingSetupPromise.set(this, null);
|
|
451
597
|
_HyperLiquidProvider_tradingSetupComplete.set(this, false);
|
|
598
|
+
_HyperLiquidProvider_builderFeeSetupPromises.set(this, new Map());
|
|
452
599
|
__classPrivateFieldSet(this, _HyperLiquidProvider_deps, options.platformDependencies, "f");
|
|
453
600
|
__classPrivateFieldSet(this, _HyperLiquidProvider_messenger, options.messenger, "f");
|
|
601
|
+
const trackedTwapOrders = __classPrivateFieldGet(_a, _a, "f", _HyperLiquidProvider_trackedTwapOrdersByMessenger).get(__classPrivateFieldGet(this, _HyperLiquidProvider_messenger, "f")) ??
|
|
602
|
+
new Map();
|
|
603
|
+
__classPrivateFieldGet(_a, _a, "f", _HyperLiquidProvider_trackedTwapOrdersByMessenger).set(__classPrivateFieldGet(this, _HyperLiquidProvider_messenger, "f"), trackedTwapOrders);
|
|
604
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_trackedTwapOrders, trackedTwapOrders, "f");
|
|
454
605
|
__classPrivateFieldSet(this, _HyperLiquidProvider_builderAddressTestnet, options.builderAddressTestnet, "f");
|
|
455
606
|
__classPrivateFieldSet(this, _HyperLiquidProvider_builderAddressMainnet, options.builderAddressMainnet, "f");
|
|
456
607
|
__classPrivateFieldSet(this, _HyperLiquidProvider_subscriptionBuilderAddressTestnet, options.subscriptionBuilderAddressTestnet, "f");
|
|
457
608
|
__classPrivateFieldSet(this, _HyperLiquidProvider_subscriptionBuilderAddressMainnet, options.subscriptionBuilderAddressMainnet, "f");
|
|
609
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_onChaseOrderMaxDistanceReached, options.onChaseOrderMaxDistanceReached, "f");
|
|
458
610
|
__classPrivateFieldSet(this, _HyperLiquidProvider_priceDeviationLimit, options.priceDeviationLimit ??
|
|
459
611
|
hyperLiquidConfig_js_1.HYPERLIQUID_CONFIG.OraclePriceDeviationLimit, "f");
|
|
460
612
|
const isTestnet = options.isTestnet ?? false;
|
|
@@ -504,6 +656,56 @@ class HyperLiquidProvider {
|
|
|
504
656
|
isTestnet,
|
|
505
657
|
});
|
|
506
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* Return provider-owned strategy support for a routed market.
|
|
661
|
+
* HyperLiquid metadata has no per-market strategy flags. This provider
|
|
662
|
+
* advertises its implemented strategies uniformly after confirming the
|
|
663
|
+
* routed market exists.
|
|
664
|
+
*
|
|
665
|
+
* @param params - Required market route context.
|
|
666
|
+
* @returns Supported strategy order types.
|
|
667
|
+
*/
|
|
668
|
+
async getOrderCapabilities(params) {
|
|
669
|
+
if (!(0, capabilitySymbols_js_1.isValidCapabilitySymbol)(params.symbol, { allowProviderRoute: true })) {
|
|
670
|
+
return {
|
|
671
|
+
status: 'unavailable',
|
|
672
|
+
providerId: this.protocolId,
|
|
673
|
+
reason: 'invalid_symbol',
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
const { dex } = (0, hyperLiquidAdapter_js_1.parseAssetName)(params.symbol);
|
|
677
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_isDisconnected, "f")) {
|
|
678
|
+
return {
|
|
679
|
+
status: 'unavailable',
|
|
680
|
+
providerId: this.protocolId,
|
|
681
|
+
reason: 'provider_unavailable',
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
685
|
+
try {
|
|
686
|
+
const marketExists = (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getFreshOrderCapabilityMarkets).call(this, dex)).some((market) => market.name === params.symbol);
|
|
687
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Order capability read');
|
|
688
|
+
return marketExists
|
|
689
|
+
? hyperLiquidConfig_js_1.HYPERLIQUID_ORDER_CAPABILITIES
|
|
690
|
+
: {
|
|
691
|
+
status: 'unavailable',
|
|
692
|
+
providerId: this.protocolId,
|
|
693
|
+
reason: 'market_not_found',
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
catch (error) {
|
|
697
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Order capabilities unavailable', {
|
|
698
|
+
symbol: params.symbol,
|
|
699
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.getOrderCapabilities')
|
|
700
|
+
.message,
|
|
701
|
+
});
|
|
702
|
+
return {
|
|
703
|
+
status: 'unavailable',
|
|
704
|
+
providerId: this.protocolId,
|
|
705
|
+
reason: 'provider_unavailable',
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
507
709
|
/**
|
|
508
710
|
* Get fills using WebSocket cache first, falling back to REST API
|
|
509
711
|
* OPTIMIZATION: Uses cached fills when available (0 API weight), only calls REST on cache miss
|
|
@@ -762,7 +964,10 @@ class HyperLiquidProvider {
|
|
|
762
964
|
// Ensure provider is ready for trading (includes signing operations).
|
|
763
965
|
// Kept after validation so invalid orders never trigger signature prompts
|
|
764
966
|
// (builder-fee approval, DEX abstraction enablement, etc.).
|
|
765
|
-
|
|
967
|
+
const { chargesMetamaskBuilderFee } = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOrderFeePolicy).call(this, params);
|
|
968
|
+
const builderFeeSetupContext = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, {
|
|
969
|
+
requiresBuilderFee: chargesMetamaskBuilderFee,
|
|
970
|
+
});
|
|
766
971
|
// Debug: Log asset map state before order placement
|
|
767
972
|
const allMapKeys = Array.from(__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").keys());
|
|
768
973
|
const hip3Keys = allMapKeys.filter((key) => key.includes(':'));
|
|
@@ -867,6 +1072,8 @@ class HyperLiquidProvider {
|
|
|
867
1072
|
transferInfo,
|
|
868
1073
|
symbol: params.symbol,
|
|
869
1074
|
assetId,
|
|
1075
|
+
chargesMetamaskBuilderFee,
|
|
1076
|
+
builderFeeSetupContext,
|
|
870
1077
|
});
|
|
871
1078
|
}
|
|
872
1079
|
catch (error) {
|
|
@@ -933,6 +1140,54 @@ class HyperLiquidProvider {
|
|
|
933
1140
|
});
|
|
934
1141
|
}
|
|
935
1142
|
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Read native TWAP schedules and their slice fills from the venue.
|
|
1145
|
+
*
|
|
1146
|
+
* @returns Current and terminal TWAP lifecycle records, newest first.
|
|
1147
|
+
*/
|
|
1148
|
+
async getTwapOrders() {
|
|
1149
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureClientsInitialized).call(this);
|
|
1150
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").ensureInitialized();
|
|
1151
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
1152
|
+
const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
|
|
1153
|
+
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
1154
|
+
const [history, sliceFills] = await Promise.all([
|
|
1155
|
+
infoClient.twapHistory({ user: userAddress }),
|
|
1156
|
+
infoClient.userTwapSliceFills({ user: userAddress }),
|
|
1157
|
+
]);
|
|
1158
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'TWAP lifecycle read');
|
|
1159
|
+
const fillsByTwapId = new Map();
|
|
1160
|
+
for (const sliceFill of sliceFills) {
|
|
1161
|
+
const existing = fillsByTwapId.get(sliceFill.twapId) ?? [];
|
|
1162
|
+
existing.push(sliceFill);
|
|
1163
|
+
fillsByTwapId.set(sliceFill.twapId, existing);
|
|
1164
|
+
}
|
|
1165
|
+
const now = Date.now();
|
|
1166
|
+
const ordersById = new Map();
|
|
1167
|
+
for (const historyEntry of history) {
|
|
1168
|
+
const order = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_adaptTwapOrder).call(this, {
|
|
1169
|
+
historyEntry,
|
|
1170
|
+
sliceFills: historyEntry.twapId === undefined
|
|
1171
|
+
? []
|
|
1172
|
+
: (fillsByTwapId.get(historyEntry.twapId) ?? []),
|
|
1173
|
+
now,
|
|
1174
|
+
});
|
|
1175
|
+
if (!order) {
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
const existing = ordersById.get(order.orderId);
|
|
1179
|
+
if (!existing || order.lastUpdated >= existing.lastUpdated) {
|
|
1180
|
+
ordersById.set(order.orderId, order);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
const orders = [...ordersById.values()].sort((left, right) => right.startedAt - left.startedAt);
|
|
1184
|
+
const network = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'testnet' : 'mainnet';
|
|
1185
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceTerminalHip3Twaps).call(this, orders, {
|
|
1186
|
+
network,
|
|
1187
|
+
userAddress,
|
|
1188
|
+
});
|
|
1189
|
+
return orders;
|
|
1190
|
+
}
|
|
936
1191
|
/**
|
|
937
1192
|
* Return stable client-facing snapshots for every Chase session retained by
|
|
938
1193
|
* this provider instance. A read may refresh the current child order's
|
|
@@ -950,12 +1205,26 @@ class HyperLiquidProvider {
|
|
|
950
1205
|
session.lastSnapshotSizeRefreshAt = now;
|
|
951
1206
|
const snapshotOrderId = session.orderId;
|
|
952
1207
|
try {
|
|
953
|
-
const liveRemainder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, snapshotOrderId);
|
|
954
|
-
if (
|
|
955
|
-
session.orderId === snapshotOrderId &&
|
|
1208
|
+
const liveRemainder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, snapshotOrderId, CHASE_ORDER_STATUS_RETRY_COUNT);
|
|
1209
|
+
if (session.orderId === snapshotOrderId &&
|
|
956
1210
|
session.pendingReplacement === null) {
|
|
957
|
-
|
|
958
|
-
|
|
1211
|
+
if (liveRemainder.terminalStatus === null) {
|
|
1212
|
+
if (liveRemainder.remainingSize !== null) {
|
|
1213
|
+
session.size = liveRemainder.remainingSize;
|
|
1214
|
+
snapshotRemainingSize = liveRemainder.remainingSize;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
session.orderId = null;
|
|
1219
|
+
session.size = liveRemainder.remainingSize ?? '0';
|
|
1220
|
+
session.active = false;
|
|
1221
|
+
if (session.timer) {
|
|
1222
|
+
clearTimeout(session.timer);
|
|
1223
|
+
session.timer = null;
|
|
1224
|
+
}
|
|
1225
|
+
session.status = liveRemainder.terminalStatus;
|
|
1226
|
+
snapshotRemainingSize = session.size;
|
|
1227
|
+
}
|
|
959
1228
|
}
|
|
960
1229
|
}
|
|
961
1230
|
catch (error) {
|
|
@@ -966,6 +1235,12 @@ class HyperLiquidProvider {
|
|
|
966
1235
|
});
|
|
967
1236
|
}
|
|
968
1237
|
}
|
|
1238
|
+
if (!session.active && session.hip3Transfer) {
|
|
1239
|
+
const rebalanced = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
1240
|
+
if (rebalanced && session.removeAfterRebalance) {
|
|
1241
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").delete(handle);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
969
1244
|
const arrival = Number.parseFloat(session.arrivalPrice);
|
|
970
1245
|
const resting = Number.parseFloat(session.restingPrice);
|
|
971
1246
|
const adverseDistance = session.isBuy
|
|
@@ -1003,9 +1278,6 @@ class HyperLiquidProvider {
|
|
|
1003
1278
|
*/
|
|
1004
1279
|
async suspendChaseOrders() {
|
|
1005
1280
|
__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
1281
|
try {
|
|
1010
1282
|
await Promise.all([...__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementWaiters, "f")]);
|
|
1011
1283
|
// Clear timers without deactivating sessions, then let any tick already
|
|
@@ -1188,10 +1460,10 @@ class HyperLiquidProvider {
|
|
|
1188
1460
|
? params.newOrder.clientOrderId
|
|
1189
1461
|
: undefined,
|
|
1190
1462
|
};
|
|
1191
|
-
// Every refusal is behind us, so
|
|
1192
|
-
//
|
|
1193
|
-
//
|
|
1194
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
|
|
1463
|
+
// Every refusal is behind us, so shared trading readiness can run now.
|
|
1464
|
+
// HyperLiquid's modify action has no builder field and must not request a
|
|
1465
|
+
// builder-fee approval.
|
|
1466
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
1195
1467
|
// Submit modification via SDK
|
|
1196
1468
|
const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
|
|
1197
1469
|
const result = await exchangeClient.modify({
|
|
@@ -1256,24 +1528,25 @@ class HyperLiquidProvider {
|
|
|
1256
1528
|
if (owningChase) {
|
|
1257
1529
|
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, owningChase[0]);
|
|
1258
1530
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
|
|
1259
|
-
|
|
1531
|
+
const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseOrder).call(this, {
|
|
1260
1532
|
...params,
|
|
1261
1533
|
orderId: owningChase[0],
|
|
1262
1534
|
orderType: 'chase',
|
|
1263
1535
|
});
|
|
1536
|
+
return { ...result, orderId: params.orderId };
|
|
1264
1537
|
}
|
|
1265
1538
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Canceling order:', params);
|
|
1266
1539
|
// Hydrate the asset map before coin validation so a cold start (e.g.
|
|
1267
1540
|
// service-worker restart with an empty prefetch map) can self-heal
|
|
1268
1541
|
// without signature prompts on invalid cancels. Trading setup (builder
|
|
1269
|
-
//
|
|
1270
|
-
// matching placeOrder / editOrder.
|
|
1542
|
+
// referral and unified-account setup runs only after validation passes,
|
|
1543
|
+
// matching placeOrder / editOrder. Cancel has no builder field.
|
|
1271
1544
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReady).call(this);
|
|
1272
1545
|
const coinValidation = (0, hyperLiquidValidation_js_1.validateCoinExists)(params.symbol, __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f"));
|
|
1273
1546
|
if (!coinValidation.isValid) {
|
|
1274
1547
|
throw new Error(coinValidation.error);
|
|
1275
1548
|
}
|
|
1276
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
|
|
1549
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
1277
1550
|
const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
|
|
1278
1551
|
const asset = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
|
|
1279
1552
|
symbol: params.symbol,
|
|
@@ -1297,10 +1570,10 @@ class HyperLiquidProvider {
|
|
|
1297
1570
|
// HyperLiquid usually rejects a cancel without throwing: the status entry
|
|
1298
1571
|
// carries the raw exchange string (e.g. "multi-sig required"). Map it the
|
|
1299
1572
|
// same way as a thrown rejection so callers get a standardized code
|
|
1300
|
-
// instead of a generic message.
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
'Order cancellation failed';
|
|
1573
|
+
// instead of a generic message.
|
|
1574
|
+
const rawError = isStatusObject(status) && typeof status.error === 'string'
|
|
1575
|
+
? status.error
|
|
1576
|
+
: 'Order cancellation failed';
|
|
1304
1577
|
return (0, hyperLiquidValidation_js_1.createErrorResult)(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, new Error(rawError)), {
|
|
1305
1578
|
success: false,
|
|
1306
1579
|
orderId: params.orderId,
|
|
@@ -1312,7 +1585,10 @@ class HyperLiquidProvider {
|
|
|
1312
1585
|
orderId: params.orderId,
|
|
1313
1586
|
coin: params.symbol,
|
|
1314
1587
|
}));
|
|
1315
|
-
return (0, hyperLiquidValidation_js_1.createErrorResult)(mappedError, {
|
|
1588
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(mappedError, {
|
|
1589
|
+
success: false,
|
|
1590
|
+
orderId: params.orderId,
|
|
1591
|
+
});
|
|
1316
1592
|
}
|
|
1317
1593
|
}
|
|
1318
1594
|
/**
|
|
@@ -1323,87 +1599,126 @@ class HyperLiquidProvider {
|
|
|
1323
1599
|
* @returns A promise that resolves to the result.
|
|
1324
1600
|
*/
|
|
1325
1601
|
async cancelOrders(params) {
|
|
1602
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Batch canceling orders:', {
|
|
1603
|
+
count: params.length,
|
|
1604
|
+
});
|
|
1605
|
+
if (params.length === 0) {
|
|
1606
|
+
return {
|
|
1607
|
+
success: false,
|
|
1608
|
+
successCount: 0,
|
|
1609
|
+
failureCount: 0,
|
|
1610
|
+
results: [],
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
const results = params.map((order) => ({
|
|
1614
|
+
orderId: order.orderId,
|
|
1615
|
+
symbol: order.symbol,
|
|
1616
|
+
success: false,
|
|
1617
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.BATCH_CANCEL_FAILED,
|
|
1618
|
+
}));
|
|
1619
|
+
// Resolve Chase ownership before the first await. A queued reprice may
|
|
1620
|
+
// replace the child ID, but the stable session handle still reaches it.
|
|
1621
|
+
const chaseSessions = [...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").entries()];
|
|
1622
|
+
const chaseRoutes = params.flatMap((order, index) => {
|
|
1623
|
+
const owner = chaseSessions.find(([, session]) => session.orderId === order.orderId ||
|
|
1624
|
+
session.replacingOrderId === order.orderId);
|
|
1625
|
+
return owner ? [{ handle: owner[0], index, order }] : [];
|
|
1626
|
+
});
|
|
1627
|
+
const chaseIndexes = new Set(chaseRoutes.map(({ index }) => index));
|
|
1326
1628
|
try {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
});
|
|
1330
|
-
if (params.length === 0) {
|
|
1331
|
-
return {
|
|
1332
|
-
success: false,
|
|
1333
|
-
successCount: 0,
|
|
1334
|
-
failureCount: 0,
|
|
1335
|
-
results: [],
|
|
1336
|
-
};
|
|
1629
|
+
for (const handle of new Set(chaseRoutes.map((route) => route.handle))) {
|
|
1630
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, handle);
|
|
1337
1631
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1632
|
+
if (chaseRoutes.length > 0) {
|
|
1633
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
|
|
1634
|
+
}
|
|
1635
|
+
for (const { handle, index, order } of chaseRoutes) {
|
|
1636
|
+
const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelStrategyOrder).call(this, {
|
|
1637
|
+
orderId: handle,
|
|
1344
1638
|
symbol: order.symbol,
|
|
1345
|
-
|
|
1639
|
+
orderType: 'chase',
|
|
1346
1640
|
});
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1641
|
+
results[index] = {
|
|
1642
|
+
orderId: order.orderId,
|
|
1643
|
+
symbol: order.symbol,
|
|
1644
|
+
success: result.success,
|
|
1645
|
+
...(result.error === undefined ? {} : { error: result.error }),
|
|
1350
1646
|
};
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
failureCount,
|
|
1364
|
-
results: statuses.map((status, index) => {
|
|
1365
|
-
// Map each per-status rejection the same way cancelOrder does, so a
|
|
1366
|
-
// batch cancel reports standardized codes rather than raw exchange
|
|
1367
|
-
// strings for the rejections this provider recognizes.
|
|
1368
|
-
const statusError = status?.error;
|
|
1647
|
+
}
|
|
1648
|
+
const ordinaryOrders = params.flatMap((order, index) => chaseIndexes.has(index) ? [] : [{ index, order }]);
|
|
1649
|
+
if (ordinaryOrders.length > 0) {
|
|
1650
|
+
// Cancellation carries no builder context, so it must not prompt for a
|
|
1651
|
+
// fee approval that the action cannot use.
|
|
1652
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
1653
|
+
const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
|
|
1654
|
+
const cancelRequests = await Promise.all(ordinaryOrders.map(async ({ order }) => {
|
|
1655
|
+
const asset = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
|
|
1656
|
+
symbol: order.symbol,
|
|
1657
|
+
dexName: (0, hyperLiquidAdapter_js_1.parseAssetName)(order.symbol).dex,
|
|
1658
|
+
});
|
|
1369
1659
|
return {
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
success: status === 'success',
|
|
1373
|
-
error: statusError
|
|
1374
|
-
? __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, new Error(statusError)).message
|
|
1375
|
-
: undefined,
|
|
1660
|
+
a: asset,
|
|
1661
|
+
o: parseInt(order.orderId, 10),
|
|
1376
1662
|
};
|
|
1377
|
-
})
|
|
1378
|
-
|
|
1663
|
+
}));
|
|
1664
|
+
const result = await exchangeClient.cancel({
|
|
1665
|
+
cancels: cancelRequests,
|
|
1666
|
+
});
|
|
1667
|
+
const statuses = result.response?.data?.statuses ?? [];
|
|
1668
|
+
if (result.status === 'ok' &&
|
|
1669
|
+
statuses.length === ordinaryOrders.length) {
|
|
1670
|
+
ordinaryOrders.forEach(({ index, order }, statusIndex) => {
|
|
1671
|
+
const status = statuses[statusIndex];
|
|
1672
|
+
const success = status === 'success';
|
|
1673
|
+
const statusError = isStatusObject(status) && typeof status.error === 'string'
|
|
1674
|
+
? status.error
|
|
1675
|
+
: undefined;
|
|
1676
|
+
results[index] = {
|
|
1677
|
+
orderId: order.orderId,
|
|
1678
|
+
symbol: order.symbol,
|
|
1679
|
+
success,
|
|
1680
|
+
...(success
|
|
1681
|
+
? {}
|
|
1682
|
+
: {
|
|
1683
|
+
error: statusError === undefined
|
|
1684
|
+
? perpsErrorCodes_js_1.PERPS_ERROR_CODES.BATCH_CANCEL_FAILED
|
|
1685
|
+
: __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, new Error(statusError)).message,
|
|
1686
|
+
}),
|
|
1687
|
+
};
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1379
1691
|
}
|
|
1380
1692
|
catch (error) {
|
|
1381
1693
|
const mappedError = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, error);
|
|
1382
1694
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(mappedError, await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getTradingErrorContext).call(this, 'cancelOrders', mappedError, {
|
|
1383
1695
|
orderCount: params.length,
|
|
1384
1696
|
}));
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
error: error instanceof Error
|
|
1395
|
-
? mappedError.message
|
|
1396
|
-
: perpsErrorCodes_js_1.PERPS_ERROR_CODES.BATCH_CANCEL_FAILED,
|
|
1397
|
-
})),
|
|
1398
|
-
};
|
|
1697
|
+
for (const result of results) {
|
|
1698
|
+
if (!result.success &&
|
|
1699
|
+
result.error === perpsErrorCodes_js_1.PERPS_ERROR_CODES.BATCH_CANCEL_FAILED) {
|
|
1700
|
+
result.error =
|
|
1701
|
+
error instanceof Error
|
|
1702
|
+
? mappedError.message
|
|
1703
|
+
: perpsErrorCodes_js_1.PERPS_ERROR_CODES.BATCH_CANCEL_FAILED;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1399
1706
|
}
|
|
1707
|
+
const successCount = results.filter(({ success }) => success).length;
|
|
1708
|
+
return {
|
|
1709
|
+
success: successCount > 0,
|
|
1710
|
+
successCount,
|
|
1711
|
+
failureCount: results.length - successCount,
|
|
1712
|
+
results,
|
|
1713
|
+
};
|
|
1400
1714
|
}
|
|
1401
1715
|
async closePositions(params) {
|
|
1402
1716
|
// Declare outside try block so it's accessible in catch block
|
|
1403
1717
|
let positionsToClose = [];
|
|
1404
1718
|
try {
|
|
1405
|
-
//
|
|
1406
|
-
|
|
1719
|
+
// Batch preparation needs trading readiness but not builder approval yet.
|
|
1720
|
+
// The provider-owned market policy is resolved from the positions below.
|
|
1721
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
1407
1722
|
// Get all current positions from cache (avoids 429 rate limiting)
|
|
1408
1723
|
const positions = await this.getPositions();
|
|
1409
1724
|
// Filter positions based on params
|
|
@@ -1441,6 +1756,7 @@ class HyperLiquidProvider {
|
|
|
1441
1756
|
// Build orders array, plus the positions each order closes so response
|
|
1442
1757
|
// statuses stay index-aligned when a position is skipped below
|
|
1443
1758
|
const orders = [];
|
|
1759
|
+
const feePolicyContexts = [];
|
|
1444
1760
|
const orderedPositions = [];
|
|
1445
1761
|
// Positions no order could be built for. Reported as failures so a caller
|
|
1446
1762
|
// cannot read "closed everything" from a result that left one open.
|
|
@@ -1515,6 +1831,13 @@ class HyperLiquidProvider {
|
|
|
1515
1831
|
r: true, // reduceOnly
|
|
1516
1832
|
t: { limit: { tif: 'Ioc' } }, // Immediate or cancel for market-like execution
|
|
1517
1833
|
});
|
|
1834
|
+
feePolicyContexts.push({
|
|
1835
|
+
symbol: position.symbol,
|
|
1836
|
+
isBuy,
|
|
1837
|
+
size: formattedSize,
|
|
1838
|
+
orderType: 'market',
|
|
1839
|
+
reduceOnly: true,
|
|
1840
|
+
});
|
|
1518
1841
|
orderedPositions.push(position);
|
|
1519
1842
|
orderedHip3Transfers.push(hip3Transfer);
|
|
1520
1843
|
}
|
|
@@ -1529,11 +1852,19 @@ class HyperLiquidProvider {
|
|
|
1529
1852
|
results: skippedResults,
|
|
1530
1853
|
};
|
|
1531
1854
|
}
|
|
1855
|
+
// HyperLiquid accepts one builder context for the whole close batch.
|
|
1856
|
+
// Resolve every position context and charge the batch when any included
|
|
1857
|
+
// policy charges, preserving deterministic behavior for future policies
|
|
1858
|
+
// that vary by market or route.
|
|
1859
|
+
const chargesMetamaskBuilderFee = feePolicyContexts.some((context) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOrderFeePolicy).call(this, context).chargesMetamaskBuilderFee);
|
|
1860
|
+
const builder = chargesMetamaskBuilderFee
|
|
1861
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderOrderContext).call(this, await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: true }))
|
|
1862
|
+
: undefined;
|
|
1532
1863
|
// Single batch API call
|
|
1533
1864
|
const result = await exchangeClient.order({
|
|
1534
1865
|
orders,
|
|
1535
1866
|
grouping: 'na',
|
|
1536
|
-
builder
|
|
1867
|
+
...(builder && { builder }),
|
|
1537
1868
|
});
|
|
1538
1869
|
// Parse response statuses (one per order)
|
|
1539
1870
|
const { statuses } = result.response.data;
|
|
@@ -1647,11 +1978,11 @@ class HyperLiquidProvider {
|
|
|
1647
1978
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReady).call(this);
|
|
1648
1979
|
// Use live position (from WebSocket) if available, otherwise fetch via REST
|
|
1649
1980
|
// Preferring WebSocket data avoids rate limiting issues with the REST API
|
|
1650
|
-
let
|
|
1651
|
-
if (
|
|
1981
|
+
let fetchedPosition;
|
|
1982
|
+
if (livePosition) {
|
|
1652
1983
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using live position from WebSocket', {
|
|
1653
|
-
symbol:
|
|
1654
|
-
size:
|
|
1984
|
+
symbol: livePosition.symbol,
|
|
1985
|
+
size: livePosition.size,
|
|
1655
1986
|
});
|
|
1656
1987
|
}
|
|
1657
1988
|
else {
|
|
@@ -1667,8 +1998,9 @@ class HyperLiquidProvider {
|
|
|
1667
1998
|
}));
|
|
1668
1999
|
throw error;
|
|
1669
2000
|
}
|
|
1670
|
-
|
|
2001
|
+
fetchedPosition = positions.find((pos) => pos.symbol === symbol);
|
|
1671
2002
|
}
|
|
2003
|
+
const position = livePosition ?? fetchedPosition;
|
|
1672
2004
|
if (!position) {
|
|
1673
2005
|
throw new Error(`No position found for ${symbol}`);
|
|
1674
2006
|
}
|
|
@@ -1732,17 +2064,117 @@ class HyperLiquidProvider {
|
|
|
1732
2064
|
error: precision.error,
|
|
1733
2065
|
};
|
|
1734
2066
|
}
|
|
1735
|
-
// Everything is validated: only now run the trading setup that can prompt
|
|
1736
|
-
// for signatures and write the referral / builder-fee approvals.
|
|
1737
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
|
|
1738
|
-
// Cancel existing TP/SL orders for this position
|
|
1739
|
-
// OPTIMIZATION: Use WebSocket cache first (0 weight), fall back to single-DEX REST (20 weight)
|
|
1740
|
-
// Previously: queryUserDataAcrossDexs queried ALL DEXs (20 weight × N DEXs = 40+ weight)
|
|
1741
2067
|
const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
|
|
1742
2068
|
symbol,
|
|
1743
2069
|
dexName,
|
|
1744
2070
|
});
|
|
2071
|
+
const fullSize = perpsConfig_js_1.TP_SL_CONFIG.UsePositionBoundTpsl && !isPartialTpsl
|
|
2072
|
+
? '0'
|
|
2073
|
+
: (0, hyperLiquidAdapter_js_1.formatHyperLiquidSize)({
|
|
2074
|
+
size: positionSize,
|
|
2075
|
+
szDecimals: assetInfo.szDecimals,
|
|
2076
|
+
});
|
|
2077
|
+
// Partial TP/SL orders carry their own size; the rest cover the position.
|
|
2078
|
+
// A partial size that rounds away at the asset precision is rejected
|
|
2079
|
+
// rather than sent as '0', which the exchange reads as whole-position.
|
|
2080
|
+
const resolveTpslSize = (tpslSize) => tpslSize === undefined
|
|
2081
|
+
? fullSize
|
|
2082
|
+
: (0, orderCalculations_js_1.formatPartialTpslSize)({
|
|
2083
|
+
size: parseFloat(tpslSize),
|
|
2084
|
+
szDecimals: assetInfo.szDecimals,
|
|
2085
|
+
});
|
|
2086
|
+
// HyperLiquid accepts one builder context for the whole TP/SL action.
|
|
2087
|
+
// Position TP/SL has no parent policy to inherit, so resolve every
|
|
2088
|
+
// included trigger and charge the batch when any child policy charges.
|
|
2089
|
+
const feePolicyContexts = [
|
|
2090
|
+
...(takeProfitPrice
|
|
2091
|
+
? [
|
|
2092
|
+
{
|
|
2093
|
+
symbol,
|
|
2094
|
+
isBuy: !isLong,
|
|
2095
|
+
size: resolveTpslSize(takeProfitSize),
|
|
2096
|
+
orderType: 'take_profit_limit',
|
|
2097
|
+
price: takeProfitPrice,
|
|
2098
|
+
triggerPrice: takeProfitPrice,
|
|
2099
|
+
reduceOnly: true,
|
|
2100
|
+
},
|
|
2101
|
+
]
|
|
2102
|
+
: []),
|
|
2103
|
+
...(stopLossPrice
|
|
2104
|
+
? [
|
|
2105
|
+
{
|
|
2106
|
+
symbol,
|
|
2107
|
+
isBuy: !isLong,
|
|
2108
|
+
size: resolveTpslSize(stopLossSize),
|
|
2109
|
+
orderType: 'stop_market',
|
|
2110
|
+
triggerPrice: stopLossPrice,
|
|
2111
|
+
reduceOnly: true,
|
|
2112
|
+
},
|
|
2113
|
+
]
|
|
2114
|
+
: []),
|
|
2115
|
+
];
|
|
2116
|
+
const replacementChargesMetamaskBuilderFee = feePolicyContexts.some((feePolicyContext) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOrderFeePolicy).call(this, feePolicyContext)
|
|
2117
|
+
.chargesMetamaskBuilderFee);
|
|
2118
|
+
// Cancel existing TP/SL orders for this position
|
|
2119
|
+
// OPTIMIZATION: Use WebSocket cache first (0 weight), fall back to single-DEX REST (20 weight)
|
|
2120
|
+
// Previously: queryUserDataAcrossDexs queried ALL DEXs (20 weight × N DEXs = 40+ weight)
|
|
1745
2121
|
let cancelRequests = [];
|
|
2122
|
+
const restorablePositionTpslOrders = [];
|
|
2123
|
+
const restorableStandaloneTpslOrders = [];
|
|
2124
|
+
// Every replacement must cancel first so old and new reduce-only triggers
|
|
2125
|
+
// cannot execute together. Retain the exact trigger definitions so a
|
|
2126
|
+
// definitively failed replacement can restore confirmed cancellations.
|
|
2127
|
+
const captureRestorableTpslOrders = (tpslOrders) => {
|
|
2128
|
+
if (!takeProfitPrice && !stopLossPrice) {
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
tpslOrders.forEach((order) => {
|
|
2132
|
+
const orderId = Number(order.orderId);
|
|
2133
|
+
const orderType = order.triggerOrderType;
|
|
2134
|
+
const triggerPrice = order.triggerPrice ?? order.price;
|
|
2135
|
+
if (!Number.isSafeInteger(orderId) || !orderType || !triggerPrice) {
|
|
2136
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED);
|
|
2137
|
+
}
|
|
2138
|
+
const size = order.isPositionTpsl ? '0' : order.remainingSize;
|
|
2139
|
+
const isBuy = order.side === 'buy';
|
|
2140
|
+
const feePolicyContext = {
|
|
2141
|
+
symbol,
|
|
2142
|
+
isBuy,
|
|
2143
|
+
size,
|
|
2144
|
+
orderType,
|
|
2145
|
+
triggerPrice,
|
|
2146
|
+
reduceOnly: true,
|
|
2147
|
+
...((0, orderTypes_js_1.isLimitExecutionOrderType)(orderType) && {
|
|
2148
|
+
price: order.price,
|
|
2149
|
+
}),
|
|
2150
|
+
};
|
|
2151
|
+
const restorableOrder = {
|
|
2152
|
+
orderId,
|
|
2153
|
+
order: {
|
|
2154
|
+
a: assetId,
|
|
2155
|
+
b: isBuy,
|
|
2156
|
+
p: order.price,
|
|
2157
|
+
s: size,
|
|
2158
|
+
r: true,
|
|
2159
|
+
t: {
|
|
2160
|
+
trigger: {
|
|
2161
|
+
isMarket: !(0, orderTypes_js_1.isLimitExecutionOrderType)(orderType),
|
|
2162
|
+
triggerPx: triggerPrice,
|
|
2163
|
+
tpsl: (0, orderTypes_js_1.getTriggerDirection)(orderType) === 'stop' ? 'sl' : 'tp',
|
|
2164
|
+
},
|
|
2165
|
+
},
|
|
2166
|
+
},
|
|
2167
|
+
chargesMetamaskBuilderFee: __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOrderFeePolicy).call(this, feePolicyContext)
|
|
2168
|
+
.chargesMetamaskBuilderFee,
|
|
2169
|
+
};
|
|
2170
|
+
if (order.isPositionTpsl) {
|
|
2171
|
+
restorablePositionTpslOrders.push(restorableOrder);
|
|
2172
|
+
}
|
|
2173
|
+
else {
|
|
2174
|
+
restorableStandaloneTpslOrders.push(restorableOrder);
|
|
2175
|
+
}
|
|
2176
|
+
});
|
|
2177
|
+
};
|
|
1746
2178
|
// Use atomic getter to prevent race condition between check and get
|
|
1747
2179
|
const cachedOrders = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getOrdersCacheIfInitialized();
|
|
1748
2180
|
// Replacing TP/SL has to consider standalone ('na' grouping) triggers —
|
|
@@ -1769,16 +2201,16 @@ class HyperLiquidProvider {
|
|
|
1769
2201
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(cachedOrders === null
|
|
1770
2202
|
? 'WebSocket cache not initialized, falling back to single-DEX REST query'
|
|
1771
2203
|
: 'TP/SL update needs parent/child order context: using single-DEX REST query', { dex: dexName ?? 'main', isPartialTpsl });
|
|
1772
|
-
const
|
|
2204
|
+
const openOrders = await infoClient.frontendOpenOrders({
|
|
1773
2205
|
user: userAddress,
|
|
1774
2206
|
dex: dexName ?? undefined,
|
|
1775
2207
|
});
|
|
1776
2208
|
// Orders that belong to a pending parent order (normalTpsl children) are
|
|
1777
2209
|
// also listed at the top level, so collect their IDs to exclude them:
|
|
1778
2210
|
// they protect that pending order, not this position.
|
|
1779
|
-
const childOrderIds = collectChildOrderIds(
|
|
2211
|
+
const childOrderIds = collectChildOrderIds(openOrders);
|
|
1780
2212
|
// Filter using raw SDK response properties
|
|
1781
|
-
const tpslOrders =
|
|
2213
|
+
const tpslOrders = openOrders.filter((order) => order.coin === symbol &&
|
|
1782
2214
|
order.reduceOnly &&
|
|
1783
2215
|
// Position-bound TP/SL always qualifies, and so do standalone
|
|
1784
2216
|
// triggers on this market (they belong to the position too, whether
|
|
@@ -1790,6 +2222,7 @@ class HyperLiquidProvider {
|
|
|
1790
2222
|
order.isTrigger &&
|
|
1791
2223
|
(order.orderType.includes('Take Profit') ||
|
|
1792
2224
|
order.orderType.includes('Stop')));
|
|
2225
|
+
captureRestorableTpslOrders(tpslOrders.map((order) => (0, hyperLiquidAdapter_js_1.adaptOrderFromSDK)(order, position)));
|
|
1793
2226
|
cancelRequests = tpslOrders.map((order) => ({
|
|
1794
2227
|
a: assetId,
|
|
1795
2228
|
o: order.oid,
|
|
@@ -1813,36 +2246,14 @@ class HyperLiquidProvider {
|
|
|
1813
2246
|
order.detailedOrderType &&
|
|
1814
2247
|
(order.detailedOrderType.includes('Take Profit') ||
|
|
1815
2248
|
order.detailedOrderType.includes('Stop')));
|
|
2249
|
+
captureRestorableTpslOrders(tpslOrders);
|
|
1816
2250
|
cancelRequests = tpslOrders.map((order) => ({
|
|
1817
2251
|
a: assetId,
|
|
1818
2252
|
o: parseInt(order.orderId, 10),
|
|
1819
2253
|
}));
|
|
1820
2254
|
}
|
|
1821
|
-
if (cancelRequests.length > 0) {
|
|
1822
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`Canceling ${cancelRequests.length} existing TP/SL orders for ${symbol}`);
|
|
1823
|
-
const cancelResult = await exchangeClient.cancel({
|
|
1824
|
-
cancels: cancelRequests,
|
|
1825
|
-
});
|
|
1826
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Cancel result:', cancelResult);
|
|
1827
|
-
}
|
|
1828
|
-
// assetId already validated above when building cancelRequests
|
|
1829
2255
|
// Build orders array for TP/SL
|
|
1830
2256
|
const orders = [];
|
|
1831
|
-
const fullSize = perpsConfig_js_1.TP_SL_CONFIG.UsePositionBoundTpsl && !isPartialTpsl
|
|
1832
|
-
? '0'
|
|
1833
|
-
: (0, hyperLiquidAdapter_js_1.formatHyperLiquidSize)({
|
|
1834
|
-
size: positionSize,
|
|
1835
|
-
szDecimals: assetInfo.szDecimals,
|
|
1836
|
-
});
|
|
1837
|
-
// Partial TP/SL orders carry their own size; the rest cover the position.
|
|
1838
|
-
// A partial size that rounds away at the asset precision is rejected
|
|
1839
|
-
// rather than sent as '0', which the exchange reads as whole-position.
|
|
1840
|
-
const resolveTpslSize = (tpslSize) => tpslSize === undefined
|
|
1841
|
-
? fullSize
|
|
1842
|
-
: (0, orderCalculations_js_1.formatPartialTpslSize)({
|
|
1843
|
-
size: parseFloat(tpslSize),
|
|
1844
|
-
szDecimals: assetInfo.szDecimals,
|
|
1845
|
-
});
|
|
1846
2257
|
// Take Profit order
|
|
1847
2258
|
if (takeProfitPrice) {
|
|
1848
2259
|
const tpOrder = {
|
|
@@ -1891,24 +2302,184 @@ class HyperLiquidProvider {
|
|
|
1891
2302
|
};
|
|
1892
2303
|
orders.push(slOrder);
|
|
1893
2304
|
}
|
|
1894
|
-
|
|
2305
|
+
const rollbackRequiresBuilderFee = [
|
|
2306
|
+
...restorablePositionTpslOrders,
|
|
2307
|
+
...restorableStandaloneTpslOrders,
|
|
2308
|
+
].some((order) => order.chargesMetamaskBuilderFee);
|
|
2309
|
+
const requiresBuilderFee = replacementChargesMetamaskBuilderFee || rollbackRequiresBuilderFee;
|
|
2310
|
+
// Approval and builder-context resolution both finish before the
|
|
2311
|
+
// pre-cancel. A failure here therefore leaves the old protection intact.
|
|
2312
|
+
const builderFeeSetupContext = requiresBuilderFee
|
|
2313
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, {
|
|
2314
|
+
requiresBuilderFee: true,
|
|
2315
|
+
builderFeeApprovalFailureCode: perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED,
|
|
2316
|
+
})
|
|
2317
|
+
: await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
2318
|
+
const builderOrderContext = builderFeeSetupContext
|
|
2319
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderOrderContext).call(this, builderFeeSetupContext)
|
|
2320
|
+
: undefined;
|
|
2321
|
+
const restoreCancelledProtection = async (cancelledOrderIds) => {
|
|
2322
|
+
const restoredOrderIds = [];
|
|
2323
|
+
let success = true;
|
|
2324
|
+
const protectionGroups = [
|
|
2325
|
+
{
|
|
2326
|
+
grouping: 'positionTpsl',
|
|
2327
|
+
entries: restorablePositionTpslOrders,
|
|
2328
|
+
},
|
|
2329
|
+
{
|
|
2330
|
+
grouping: 'na',
|
|
2331
|
+
entries: restorableStandaloneTpslOrders,
|
|
2332
|
+
},
|
|
2333
|
+
];
|
|
2334
|
+
for (const protection of protectionGroups) {
|
|
2335
|
+
const entries = protection.entries.filter((entry) => cancelledOrderIds.has(entry.orderId));
|
|
2336
|
+
if (entries.length === 0) {
|
|
2337
|
+
continue;
|
|
2338
|
+
}
|
|
2339
|
+
try {
|
|
2340
|
+
const result = await exchangeClient.order({
|
|
2341
|
+
orders: entries.map((entry) => entry.order),
|
|
2342
|
+
grouping: protection.grouping,
|
|
2343
|
+
...(entries.some((entry) => entry.chargesMetamaskBuilderFee) &&
|
|
2344
|
+
builderOrderContext && { builder: builderOrderContext }),
|
|
2345
|
+
});
|
|
2346
|
+
const statuses = result.response?.data?.statuses ?? [];
|
|
2347
|
+
const outcomes = statuses
|
|
2348
|
+
.slice(0, entries.length)
|
|
2349
|
+
.map((status) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderPlacementOutcome).call(this, status));
|
|
2350
|
+
restoredOrderIds.push(...outcomes.flatMap((outcome) => outcome ? [outcome.orderId] : []));
|
|
2351
|
+
if (result.status !== 'ok' ||
|
|
2352
|
+
statuses.length !== entries.length ||
|
|
2353
|
+
outcomes.some((outcome) => outcome === undefined)) {
|
|
2354
|
+
success = false;
|
|
2355
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED), __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'updatePositionTPSL > restoreCancelledProtection', { symbol, grouping: protection.grouping, statuses }));
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
catch (error) {
|
|
2359
|
+
success = false;
|
|
2360
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error((0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.updatePositionTPSL.restoreCancelledProtection'), __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'updatePositionTPSL > restoreCancelledProtection', { symbol, grouping: protection.grouping }));
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
return { restoredOrderIds, success };
|
|
2364
|
+
};
|
|
2365
|
+
const createProtectionLostResult = (survivingOrderIds) => (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_PROTECTION_LOST), {
|
|
2366
|
+
success: false,
|
|
2367
|
+
childOrderIds: [...new Set(survivingOrderIds)],
|
|
2368
|
+
});
|
|
2369
|
+
// Clearing has no replacement batch to preserve. A partial cancellation
|
|
2370
|
+
// is reported so the caller can retry the same clear operation.
|
|
1895
2371
|
if (orders.length === 0) {
|
|
2372
|
+
const remainingOrderIds = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequests).call(this, exchangeClient, cancelRequests);
|
|
2373
|
+
if (remainingOrderIds.length > 0) {
|
|
2374
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED);
|
|
2375
|
+
}
|
|
1896
2376
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('No new TP/SL orders to place - existing ones cancelled');
|
|
1897
2377
|
return {
|
|
1898
2378
|
success: true,
|
|
1899
2379
|
// No orderId since we only cancelled orders, didn't place new ones
|
|
1900
2380
|
};
|
|
1901
2381
|
}
|
|
1902
|
-
//
|
|
1903
|
-
//
|
|
1904
|
-
//
|
|
1905
|
-
const
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2382
|
+
// Cancel before placing for both position-bound and standalone partial
|
|
2383
|
+
// triggers. A place-first partial update leaves both trigger sets live
|
|
2384
|
+
// during the cancellation round trip and can reduce more than requested.
|
|
2385
|
+
const confirmedCancelledOldOrderIds = new Set();
|
|
2386
|
+
const oldCancellation = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequestBatch).call(this, exchangeClient, cancelRequests);
|
|
2387
|
+
if (!oldCancellation.responseComplete) {
|
|
2388
|
+
const requestedOrderIds = new Set(cancelRequests.map((request) => request.o));
|
|
2389
|
+
let possiblyLiveOrderIds = Array.from(requestedOrderIds, String);
|
|
2390
|
+
try {
|
|
2391
|
+
const liveOrders = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchOpenOrders).call(this, { dexName });
|
|
2392
|
+
possiblyLiveOrderIds = liveOrders
|
|
2393
|
+
.filter((order) => requestedOrderIds.has(order.oid))
|
|
2394
|
+
.map((order) => String(order.oid));
|
|
2395
|
+
}
|
|
2396
|
+
catch (error) {
|
|
2397
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Could not reconcile TP/SL protection after an incomplete cancel', {
|
|
2398
|
+
symbol,
|
|
2399
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.updatePositionTPSL.reconcileProtection').message,
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
return createProtectionLostResult(possiblyLiveOrderIds);
|
|
2403
|
+
}
|
|
2404
|
+
oldCancellation.cancelledOrderIds.forEach((orderId) => confirmedCancelledOldOrderIds.add(orderId));
|
|
2405
|
+
if (oldCancellation.remainingOrderIds.length > 0) {
|
|
2406
|
+
const restoration = await restoreCancelledProtection(confirmedCancelledOldOrderIds);
|
|
2407
|
+
if (!restoration.success) {
|
|
2408
|
+
return createProtectionLostResult([
|
|
2409
|
+
...oldCancellation.remainingOrderIds.map(String),
|
|
2410
|
+
...restoration.restoredOrderIds,
|
|
2411
|
+
]);
|
|
2412
|
+
}
|
|
2413
|
+
const updateError = new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED);
|
|
2414
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").logger.error(updateError, __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getErrorContext).call(this, 'updatePositionTPSL', {
|
|
2415
|
+
symbol: params.symbol,
|
|
2416
|
+
hasTakeProfit: params.takeProfitPrice !== undefined,
|
|
2417
|
+
hasStopLoss: params.stopLossPrice !== undefined,
|
|
2418
|
+
}));
|
|
2419
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(updateError, {
|
|
2420
|
+
success: false,
|
|
2421
|
+
childOrderIds: [
|
|
2422
|
+
...new Set([
|
|
2423
|
+
...oldCancellation.remainingOrderIds.map(String),
|
|
2424
|
+
...restoration.restoredOrderIds,
|
|
2425
|
+
]),
|
|
2426
|
+
],
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2429
|
+
let result;
|
|
2430
|
+
try {
|
|
2431
|
+
result = await exchangeClient.order({
|
|
2432
|
+
orders,
|
|
2433
|
+
grouping: isPartialTpsl ? 'na' : 'positionTpsl',
|
|
2434
|
+
...(replacementChargesMetamaskBuilderFee &&
|
|
2435
|
+
builderOrderContext && { builder: builderOrderContext }),
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
catch (error) {
|
|
2439
|
+
const restoration = await restoreCancelledProtection(confirmedCancelledOldOrderIds);
|
|
2440
|
+
if (!restoration.success) {
|
|
2441
|
+
return createProtectionLostResult(restoration.restoredOrderIds);
|
|
2442
|
+
}
|
|
2443
|
+
throw error;
|
|
2444
|
+
}
|
|
2445
|
+
const placementStatuses = result.response?.data?.statuses ?? [];
|
|
2446
|
+
const placementOutcomes = placementStatuses
|
|
2447
|
+
.slice(0, orders.length)
|
|
2448
|
+
.map((status) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderPlacementOutcome).call(this, status));
|
|
2449
|
+
const replacementOrderIds = placementOutcomes.flatMap((outcome) => outcome ? [outcome.orderId] : []);
|
|
2450
|
+
const restingReplacementOrderIds = placementOutcomes.flatMap((outcome) => outcome?.state === 'resting' ? [outcome.orderId] : []);
|
|
2451
|
+
const filledReplacementOrderIds = placementOutcomes.flatMap((outcome) => outcome?.state === 'filled' ? [outcome.orderId] : []);
|
|
2452
|
+
if (result.status !== 'ok' ||
|
|
2453
|
+
placementStatuses.length !== orders.length ||
|
|
2454
|
+
replacementOrderIds.length !== orders.length) {
|
|
2455
|
+
const remainingReplacementIds = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequests).call(this, exchangeClient, restingReplacementOrderIds.map((orderId) => ({
|
|
2456
|
+
a: assetId,
|
|
2457
|
+
o: Number(orderId),
|
|
2458
|
+
})));
|
|
2459
|
+
const recoverableOrderIds = [
|
|
2460
|
+
...filledReplacementOrderIds,
|
|
2461
|
+
...remainingReplacementIds.map(String),
|
|
2462
|
+
];
|
|
2463
|
+
if (recoverableOrderIds.length === 0) {
|
|
2464
|
+
const restoration = await restoreCancelledProtection(confirmedCancelledOldOrderIds);
|
|
2465
|
+
if (!restoration.success) {
|
|
2466
|
+
return createProtectionLostResult(restoration.restoredOrderIds);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
// A filled replacement may have changed or closed the position, while
|
|
2470
|
+
// an uncancelled replacement may still protect it. Restoring the old
|
|
2471
|
+
// whole-position triggers in either case risks stale or duplicate
|
|
2472
|
+
// protection, so return those IDs for caller reconciliation instead.
|
|
2473
|
+
if (recoverableOrderIds.length > 0) {
|
|
2474
|
+
if (!isPartialTpsl) {
|
|
2475
|
+
return createProtectionLostResult(recoverableOrderIds);
|
|
2476
|
+
}
|
|
2477
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED), {
|
|
2478
|
+
success: false,
|
|
2479
|
+
childOrderIds: recoverableOrderIds,
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.TPSL_UPDATE_FAILED);
|
|
1912
2483
|
}
|
|
1913
2484
|
return {
|
|
1914
2485
|
success: true,
|
|
@@ -1936,8 +2507,9 @@ class HyperLiquidProvider {
|
|
|
1936
2507
|
async closePosition(params) {
|
|
1937
2508
|
try {
|
|
1938
2509
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Closing position:', params);
|
|
1939
|
-
//
|
|
1940
|
-
|
|
2510
|
+
// The delegated placeOrder call resolves the builder-fee policy for the
|
|
2511
|
+
// concrete close order after validation.
|
|
2512
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
1941
2513
|
// Use provided position (from WebSocket) or fetch from cache
|
|
1942
2514
|
// This avoids unnecessary API calls and prevents 429 rate limiting
|
|
1943
2515
|
let { position } = params;
|
|
@@ -2737,6 +3309,7 @@ class HyperLiquidProvider {
|
|
|
2737
3309
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Using cached open orders from WebSocket', {
|
|
2738
3310
|
count: cachedOrders.length,
|
|
2739
3311
|
});
|
|
3312
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_restoreScaleOrderGroups).call(this, cachedOrders);
|
|
2740
3313
|
return cachedOrders;
|
|
2741
3314
|
}
|
|
2742
3315
|
}
|
|
@@ -2767,6 +3340,7 @@ class HyperLiquidProvider {
|
|
|
2767
3340
|
const position = positions.find((pos) => pos.symbol === order.coin);
|
|
2768
3341
|
return (0, hyperLiquidAdapter_js_1.adaptOrderFromSDK)(order, position);
|
|
2769
3342
|
});
|
|
3343
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_restoreScaleOrderGroups).call(this, orders);
|
|
2770
3344
|
return orders;
|
|
2771
3345
|
}
|
|
2772
3346
|
catch (error) {
|
|
@@ -3320,6 +3894,7 @@ class HyperLiquidProvider {
|
|
|
3320
3894
|
* @returns A promise that resolves to the combined market data from all enabled DEXs.
|
|
3321
3895
|
*/
|
|
3322
3896
|
async getMarketDataWithPrices() {
|
|
3897
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
3323
3898
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Getting market data with prices via HyperLiquid SDK');
|
|
3324
3899
|
// Ensure asset mapping is built first (populates meta cache)
|
|
3325
3900
|
// This guarantees buildAssetMapping has run before we check cache,
|
|
@@ -3335,16 +3910,15 @@ class HyperLiquidProvider {
|
|
|
3335
3910
|
// Check the meta cache first to avoid redundant API calls when buildAssetMapping
|
|
3336
3911
|
// has already populated it; on cache miss, delegate to #fetchSingleDexFresh.
|
|
3337
3912
|
const dexDataResults = await Promise.all(enabledDexs.map(async (dex) => {
|
|
3338
|
-
const dexKey = dex ?? '';
|
|
3339
3913
|
const dexParam = dex ?? '';
|
|
3340
|
-
const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(
|
|
3914
|
+
const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dex);
|
|
3341
3915
|
if (!cachedMeta) {
|
|
3342
3916
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Cache miss for ${dex ?? 'main'}, fetching`);
|
|
3343
|
-
return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex);
|
|
3917
|
+
return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex, lifecycleGeneration);
|
|
3344
3918
|
}
|
|
3345
3919
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] Using cached meta for ${dex ?? 'main'}`, { universeSize: cachedMeta.universe.length });
|
|
3346
3920
|
let metaForDex = cachedMeta;
|
|
3347
|
-
let assetCtxs = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getDexAssetCtxsCache(
|
|
3921
|
+
let assetCtxs = __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").getDexAssetCtxsCache(dexParam) ?? [];
|
|
3348
3922
|
let failedStep;
|
|
3349
3923
|
let errorMessage;
|
|
3350
3924
|
if (assetCtxs.length !== metaForDex.universe.length) {
|
|
@@ -3365,10 +3939,12 @@ class HyperLiquidProvider {
|
|
|
3365
3939
|
}
|
|
3366
3940
|
metaForDex = freshMeta;
|
|
3367
3941
|
assetCtxs = freshAssetCtxs;
|
|
3368
|
-
__classPrivateFieldGet(this,
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3942
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheDexMetadataFromRead).call(this, {
|
|
3943
|
+
dex,
|
|
3944
|
+
meta: freshMeta,
|
|
3945
|
+
assetCtxs,
|
|
3946
|
+
lifecycleGeneration,
|
|
3947
|
+
});
|
|
3372
3948
|
}
|
|
3373
3949
|
catch (error) {
|
|
3374
3950
|
return {
|
|
@@ -3420,7 +3996,7 @@ class HyperLiquidProvider {
|
|
|
3420
3996
|
const retryDelayMs = 2000;
|
|
3421
3997
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[getMarketDataWithPrices] All DEXs returned empty, retrying in ${retryDelayMs}ms`);
|
|
3422
3998
|
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
3423
|
-
const retryResults = await Promise.all(enabledDexs.map((dex) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex)));
|
|
3999
|
+
const retryResults = await Promise.all(enabledDexs.map((dex) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchSingleDexFresh).call(this, infoClient, dex, lifecycleGeneration)));
|
|
3424
4000
|
const usdcFilteredRetryResults = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_excludeNonUsdcCollateralResults).call(this, retryResults);
|
|
3425
4001
|
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mergeDexResultsInto).call(this, usdcFilteredRetryResults, combinedUniverse, combinedAssetCtxs, combinedAllMids);
|
|
3426
4002
|
latestDexResults = usdcFilteredRetryResults;
|
|
@@ -3480,6 +4056,9 @@ class HyperLiquidProvider {
|
|
|
3480
4056
|
assetCtxs: combinedAssetCtxs,
|
|
3481
4057
|
allMids: combinedAllMids,
|
|
3482
4058
|
}, __classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").marketDataFormatters, hyperLiquidConfig_js_1.HIP3_ASSET_MARKET_TYPES, hyperLiquidConfig_js_1.HYPERLIQUID_ASSET_NAMES);
|
|
4059
|
+
if (!__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Market data cache write')) {
|
|
4060
|
+
return transformedMarketData;
|
|
4061
|
+
}
|
|
3483
4062
|
return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheFreshMarketDataSnapshot).call(this, transformedMarketData, latestDexResults);
|
|
3484
4063
|
}
|
|
3485
4064
|
/**
|
|
@@ -4134,23 +4713,28 @@ class HyperLiquidProvider {
|
|
|
4134
4713
|
async toggleTestnet() {
|
|
4135
4714
|
try {
|
|
4136
4715
|
const newIsTestnet = !__classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode();
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
}
|
|
4145
|
-
catch {
|
|
4146
|
-
// Ignore - we're switching networks anyway
|
|
4147
|
-
}
|
|
4716
|
+
const disconnectResult = await this.disconnect();
|
|
4717
|
+
if (!disconnectResult.success) {
|
|
4718
|
+
// The network did not change. Keep the provider eligible for lazy
|
|
4719
|
+
// recovery instead of leaving this aborted toggle permanently sticky.
|
|
4720
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_isDisconnected, false, "f");
|
|
4721
|
+
throw new Error(disconnectResult.error ??
|
|
4722
|
+
'Failed to disconnect before network toggle');
|
|
4148
4723
|
}
|
|
4149
4724
|
// Update all services
|
|
4150
4725
|
__classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").setTestnetMode(newIsTestnet);
|
|
4726
|
+
// Invalidate reads that started after disconnect completed but before
|
|
4727
|
+
// the clients switched networks.
|
|
4728
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_lifecycleGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f") + 1, "f");
|
|
4151
4729
|
__classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").setTestnetMode(newIsTestnet);
|
|
4152
|
-
|
|
4153
|
-
|
|
4730
|
+
const initializeResult = await this.initialize();
|
|
4731
|
+
if (!initializeResult.success) {
|
|
4732
|
+
// The network switch is already committed. Leave the provider eligible
|
|
4733
|
+
// for lazy initialization so the next operation can retry the failed
|
|
4734
|
+
// client setup instead of remaining permanently disconnected.
|
|
4735
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_isDisconnected, false, "f");
|
|
4736
|
+
throw new Error(initializeResult.error ?? 'Failed to initialize after network toggle');
|
|
4737
|
+
}
|
|
4154
4738
|
return {
|
|
4155
4739
|
success: true,
|
|
4156
4740
|
isTestnet: newIsTestnet,
|
|
@@ -4169,9 +4753,18 @@ class HyperLiquidProvider {
|
|
|
4169
4753
|
* @returns A promise that resolves to the result.
|
|
4170
4754
|
*/
|
|
4171
4755
|
async initialize() {
|
|
4756
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
4172
4757
|
try {
|
|
4758
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0) {
|
|
4759
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
4760
|
+
}
|
|
4173
4761
|
// Ensure clients are initialized (lazy initialization)
|
|
4174
4762
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureClientsInitialized).call(this);
|
|
4763
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0 ||
|
|
4764
|
+
lifecycleGeneration !== __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f")) {
|
|
4765
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
4766
|
+
}
|
|
4767
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_isDisconnected, false, "f");
|
|
4175
4768
|
return {
|
|
4176
4769
|
success: true,
|
|
4177
4770
|
chainId: (0, hyperLiquidConfig_js_1.getChainId)(__classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode()),
|
|
@@ -4309,6 +4902,7 @@ class HyperLiquidProvider {
|
|
|
4309
4902
|
* @returns A promise that resolves to the numeric result.
|
|
4310
4903
|
*/
|
|
4311
4904
|
async getMaxLeverage(asset) {
|
|
4905
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
4312
4906
|
try {
|
|
4313
4907
|
// Check cache first
|
|
4314
4908
|
const cached = __classPrivateFieldGet(this, _HyperLiquidProvider_maxLeverageCache, "f").get(asset);
|
|
@@ -4341,11 +4935,12 @@ class HyperLiquidProvider {
|
|
|
4341
4935
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`Asset ${asset} not found in universe, using default max leverage`);
|
|
4342
4936
|
return perpsConfig_js_1.PERPS_CONSTANTS.DefaultMaxLeverage;
|
|
4343
4937
|
}
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4938
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Maximum leverage cache write')) {
|
|
4939
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_maxLeverageCache, "f").set(asset, {
|
|
4940
|
+
value: assetInfo.maxLeverage,
|
|
4941
|
+
timestamp: now,
|
|
4942
|
+
});
|
|
4943
|
+
}
|
|
4349
4944
|
return assetInfo.maxLeverage;
|
|
4350
4945
|
}
|
|
4351
4946
|
catch (error) {
|
|
@@ -4366,7 +4961,13 @@ class HyperLiquidProvider {
|
|
|
4366
4961
|
* @returns A promise that resolves to the result.
|
|
4367
4962
|
*/
|
|
4368
4963
|
async calculateFees(params) {
|
|
4964
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
4369
4965
|
const { orderType, isMaker = false, amount, symbol } = params;
|
|
4966
|
+
const numericAmount = amount === undefined ? undefined : Number.parseFloat(amount);
|
|
4967
|
+
const parsedAmount = numericAmount === undefined ||
|
|
4968
|
+
(Number.isFinite(numericAmount) && numericAmount >= 0)
|
|
4969
|
+
? numericAmount
|
|
4970
|
+
: 0;
|
|
4370
4971
|
// Every placement is charged as its execution kind: a stop_market fills as a
|
|
4371
4972
|
// market order (taker), a stop_limit as a limit order, a scale ladder as the
|
|
4372
4973
|
// resting limit orders it fans out into, and a TWAP as the marketable
|
|
@@ -4413,6 +5014,7 @@ class HyperLiquidProvider {
|
|
|
4413
5014
|
// Try to get user-specific rates if wallet is connected
|
|
4414
5015
|
try {
|
|
4415
5016
|
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
5017
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'User fee cache read');
|
|
4416
5018
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('User Address Retrieved', {
|
|
4417
5019
|
userAddress,
|
|
4418
5020
|
network: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'testnet' : 'mainnet',
|
|
@@ -4453,7 +5055,9 @@ class HyperLiquidProvider {
|
|
|
4453
5055
|
});
|
|
4454
5056
|
// Fetch fresh rates from SDK
|
|
4455
5057
|
// Read-only operation: only need client initialization
|
|
5058
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'User fee fetch');
|
|
4456
5059
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureClientsInitialized).call(this);
|
|
5060
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'User fee fetch');
|
|
4457
5061
|
__classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").ensureInitialized();
|
|
4458
5062
|
const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
|
|
4459
5063
|
const userFees = await infoClient.userFees({
|
|
@@ -4466,13 +5070,21 @@ class HyperLiquidProvider {
|
|
|
4466
5070
|
activeStakingDiscount: userFees.activeStakingDiscount,
|
|
4467
5071
|
});
|
|
4468
5072
|
// Parse base user rates (these don't include discounts as expected)
|
|
4469
|
-
const baseUserTakerRate =
|
|
4470
|
-
const baseUserMakerRate =
|
|
4471
|
-
const baseUserSpotTakerRate =
|
|
4472
|
-
const baseUserSpotMakerRate =
|
|
5073
|
+
const baseUserTakerRate = (0, stringParseUtils_js_1.parseBoundedNonNegativeDecimal)(userFees.userCrossRate, MAX_API_FEE_RATE);
|
|
5074
|
+
const baseUserMakerRate = (0, stringParseUtils_js_1.parseBoundedNonNegativeDecimal)(userFees.userAddRate, MAX_API_FEE_RATE);
|
|
5075
|
+
const baseUserSpotTakerRate = (0, stringParseUtils_js_1.parseBoundedNonNegativeDecimal)(userFees.userSpotCrossRate, MAX_API_FEE_RATE);
|
|
5076
|
+
const baseUserSpotMakerRate = (0, stringParseUtils_js_1.parseBoundedNonNegativeDecimal)(userFees.userSpotAddRate, MAX_API_FEE_RATE);
|
|
4473
5077
|
// Apply discounts manually since HyperLiquid API doesn't apply them
|
|
4474
|
-
const referralDiscount =
|
|
4475
|
-
const stakingDiscount =
|
|
5078
|
+
const referralDiscount = (0, stringParseUtils_js_1.parseBoundedNonNegativeDecimal)(userFees.activeReferralDiscount || '0', MAX_API_FEE_DISCOUNT);
|
|
5079
|
+
const stakingDiscount = (0, stringParseUtils_js_1.parseBoundedNonNegativeDecimal)(userFees.activeStakingDiscount?.discount || '0', MAX_API_FEE_DISCOUNT);
|
|
5080
|
+
if (baseUserTakerRate === null ||
|
|
5081
|
+
baseUserMakerRate === null ||
|
|
5082
|
+
baseUserSpotTakerRate === null ||
|
|
5083
|
+
baseUserSpotMakerRate === null ||
|
|
5084
|
+
referralDiscount === null ||
|
|
5085
|
+
stakingDiscount === null) {
|
|
5086
|
+
throw new Error('Invalid fee rates received from API');
|
|
5087
|
+
}
|
|
4476
5088
|
// Calculate total discount (referral + staking, but not compounding)
|
|
4477
5089
|
const totalDiscount = Math.min(referralDiscount + stakingDiscount, 0.4); // Cap at 40%
|
|
4478
5090
|
// Apply discount to rates
|
|
@@ -4498,20 +5110,20 @@ class HyperLiquidProvider {
|
|
|
4498
5110
|
},
|
|
4499
5111
|
});
|
|
4500
5112
|
// Validate all rates are valid numbers before caching
|
|
4501
|
-
if (
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
5113
|
+
if (!Number.isFinite(perpsTakerRate) ||
|
|
5114
|
+
!Number.isFinite(perpsMakerRate) ||
|
|
5115
|
+
!Number.isFinite(spotTakerRate) ||
|
|
5116
|
+
!Number.isFinite(spotMakerRate) ||
|
|
4505
5117
|
perpsTakerRate < 0 ||
|
|
4506
5118
|
perpsMakerRate < 0 ||
|
|
4507
5119
|
spotTakerRate < 0 ||
|
|
4508
5120
|
spotMakerRate < 0) {
|
|
4509
5121
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Fee Rate Validation Failed', {
|
|
4510
5122
|
validation: {
|
|
4511
|
-
perpsTakerValid:
|
|
4512
|
-
perpsMakerValid:
|
|
4513
|
-
spotTakerValid:
|
|
4514
|
-
spotMakerValid:
|
|
5123
|
+
perpsTakerValid: Number.isFinite(perpsTakerRate) && perpsTakerRate >= 0,
|
|
5124
|
+
perpsMakerValid: Number.isFinite(perpsMakerRate) && perpsMakerRate >= 0,
|
|
5125
|
+
spotTakerValid: Number.isFinite(spotTakerRate) && spotTakerRate >= 0,
|
|
5126
|
+
spotMakerValid: Number.isFinite(spotMakerRate) && spotMakerRate >= 0,
|
|
4515
5127
|
},
|
|
4516
5128
|
rawValues: {
|
|
4517
5129
|
perpsTakerRate,
|
|
@@ -4530,6 +5142,7 @@ class HyperLiquidProvider {
|
|
|
4530
5142
|
timestamp: Date.now(),
|
|
4531
5143
|
ttl: 5 * 60 * 1000, // 5 minutes
|
|
4532
5144
|
};
|
|
5145
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'User fee cache write');
|
|
4533
5146
|
__classPrivateFieldGet(this, _HyperLiquidProvider_userFeeCache, "f").set(userAddress, rates);
|
|
4534
5147
|
// Same maker/taker decision as the base rates above, chase included.
|
|
4535
5148
|
let userFeeRate = chargesMakerRate
|
|
@@ -4553,6 +5166,9 @@ class HyperLiquidProvider {
|
|
|
4553
5166
|
catch (error) {
|
|
4554
5167
|
// Silently fall back to base rates
|
|
4555
5168
|
const safeError = (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.getFeeSchedule');
|
|
5169
|
+
if (safeError.message === perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE) {
|
|
5170
|
+
throw safeError;
|
|
5171
|
+
}
|
|
4556
5172
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Fee API Call Failed - Falling Back to Base Rates', {
|
|
4557
5173
|
error: safeError.message,
|
|
4558
5174
|
errorType: safeError.name,
|
|
@@ -4561,43 +5177,46 @@ class HyperLiquidProvider {
|
|
|
4561
5177
|
userAddress: 'unknown',
|
|
4562
5178
|
});
|
|
4563
5179
|
}
|
|
4564
|
-
|
|
5180
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Fee calculation');
|
|
4565
5181
|
// Protocol base fee (HyperLiquid's fee)
|
|
4566
5182
|
const protocolFeeRate = feeRate;
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
}
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
// Apply MetaMask reward discount if active
|
|
4580
|
-
if (__classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") !== undefined) {
|
|
4581
|
-
const discount = __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") / hyperLiquidConfig_js_1.BASIS_POINTS_DIVISOR; // Convert basis points to decimal
|
|
4582
|
-
metamaskFeeRate = hyperLiquidConfig_js_1.BUILDER_FEE_CONFIG.MaxFeeDecimal * (1 - discount);
|
|
5183
|
+
const protocolFeeAmount = parsedAmount === undefined ? undefined : parsedAmount * protocolFeeRate;
|
|
5184
|
+
// The provider policy, not the client, owns whether this placement can
|
|
5185
|
+
// carry a builder fee. The dedicated TWAP action has no builder field.
|
|
5186
|
+
const { chargesMetamaskBuilderFee } = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOrderFeePolicy).call(this, params);
|
|
5187
|
+
const baseMetamaskFeeRate = chargesMetamaskBuilderFee
|
|
5188
|
+
? hyperLiquidConfig_js_1.BUILDER_FEE_CONFIG.MaxFeeDecimal
|
|
5189
|
+
: 0;
|
|
5190
|
+
const metamaskFeeDiscount = __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") === undefined
|
|
5191
|
+
? 0
|
|
5192
|
+
: __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") / hyperLiquidConfig_js_1.BASIS_POINTS_DIVISOR;
|
|
5193
|
+
const metamaskFeeRate = baseMetamaskFeeRate * (1 - metamaskFeeDiscount);
|
|
5194
|
+
if (chargesMetamaskBuilderFee && __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") !== undefined) {
|
|
4583
5195
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Applied MetaMask fee discount', {
|
|
4584
|
-
originalRate:
|
|
5196
|
+
originalRate: baseMetamaskFeeRate,
|
|
4585
5197
|
discountBips: __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f"),
|
|
4586
5198
|
discountPercentage: __classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") / 100,
|
|
4587
5199
|
adjustedRate: metamaskFeeRate,
|
|
4588
|
-
discountAmount:
|
|
5200
|
+
discountAmount: baseMetamaskFeeRate * metamaskFeeDiscount,
|
|
4589
5201
|
});
|
|
4590
5202
|
}
|
|
4591
|
-
const
|
|
4592
|
-
? 0
|
|
4593
|
-
: parsedAmount * metamaskFeeRate;
|
|
4594
|
-
const metamaskFeeAmount = amount === undefined ? undefined : validAmountForMetamaskFee;
|
|
5203
|
+
const metamaskFeeAmount = parsedAmount === undefined ? undefined : parsedAmount * metamaskFeeRate;
|
|
4595
5204
|
// Total fees
|
|
4596
5205
|
const totalFeeRate = protocolFeeRate + metamaskFeeRate;
|
|
4597
|
-
const
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
5206
|
+
const totalFeeAmount = parsedAmount === undefined ? undefined : parsedAmount * totalFeeRate;
|
|
5207
|
+
if (!Number.isFinite(protocolFeeRate) ||
|
|
5208
|
+
protocolFeeRate < 0 ||
|
|
5209
|
+
!Number.isFinite(metamaskFeeRate) ||
|
|
5210
|
+
metamaskFeeRate < 0 ||
|
|
5211
|
+
!Number.isFinite(totalFeeRate) ||
|
|
5212
|
+
totalFeeRate < 0 ||
|
|
5213
|
+
(protocolFeeAmount !== undefined &&
|
|
5214
|
+
!Number.isFinite(protocolFeeAmount)) ||
|
|
5215
|
+
(metamaskFeeAmount !== undefined &&
|
|
5216
|
+
!Number.isFinite(metamaskFeeAmount)) ||
|
|
5217
|
+
(totalFeeAmount !== undefined && !Number.isFinite(totalFeeAmount))) {
|
|
5218
|
+
throw new Error('Invalid fee calculation result');
|
|
5219
|
+
}
|
|
4601
5220
|
const result = {
|
|
4602
5221
|
// Total fees
|
|
4603
5222
|
feeRate: totalFeeRate,
|
|
@@ -4656,100 +5275,18 @@ class HyperLiquidProvider {
|
|
|
4656
5275
|
* @returns A promise that resolves to the result.
|
|
4657
5276
|
*/
|
|
4658
5277
|
async disconnect() {
|
|
4659
|
-
|
|
4660
|
-
|
|
5278
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationPromise, "f")) {
|
|
5279
|
+
return __classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationPromise, "f");
|
|
5280
|
+
}
|
|
5281
|
+
const operation = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_performDisconnect).call(this);
|
|
5282
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_disconnectOperationPromise, operation, "f");
|
|
4661
5283
|
try {
|
|
4662
|
-
|
|
4663
|
-
isTestnet: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode(),
|
|
4664
|
-
timestamp: new Date().toISOString(),
|
|
4665
|
-
});
|
|
4666
|
-
// Clear subscriptions through subscription service
|
|
4667
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").clearAll();
|
|
4668
|
-
// Stop every chase loop: each holds a pending timer, and re-pricing after
|
|
4669
|
-
// a disconnect would sign orders against a client that is being torn down.
|
|
4670
|
-
// Orders already resting are deliberately left alone — disconnecting is
|
|
4671
|
-
// not a request to cancel the user's positions or orders.
|
|
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
|
-
}
|
|
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()]);
|
|
4682
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").clear();
|
|
4683
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").clear();
|
|
4684
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_terminatedChaseHandles, "f").clear();
|
|
4685
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").clear();
|
|
4686
|
-
// Clear fee cache
|
|
4687
|
-
this.clearFeeCache();
|
|
4688
|
-
// Clear session caches (ensures fresh state on reconnect/account switch)
|
|
4689
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_referralCheckCache, "f").clear();
|
|
4690
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").clear();
|
|
4691
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_subscriptionBuilderApprovalEpoch, __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionBuilderApprovalEpoch, "f") + 1, "f");
|
|
4692
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_approvedBuilderAddresses, "f").clear();
|
|
4693
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_userFeeResolution, undefined, "f");
|
|
4694
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_userFeeDiscountBips, undefined, "f");
|
|
4695
|
-
// NOTE: UnifiedAccountCache is global and NOT cleared on disconnect
|
|
4696
|
-
// to prevent repeated signing requests across reconnections
|
|
4697
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").clear();
|
|
4698
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_cachedSpotMeta, null, "f");
|
|
4699
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").reset();
|
|
4700
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_dexDiscoveryComplete, false, "f");
|
|
4701
|
-
// Await pending initialization before clearing to prevent the IIFE from
|
|
4702
|
-
// setting clientsInitialized = true after disconnect completes
|
|
4703
|
-
const pendingInit = __classPrivateFieldGet(this, _HyperLiquidProvider_initializationPromise, "f");
|
|
4704
|
-
const pendingReady = __classPrivateFieldGet(this, _HyperLiquidProvider_ensureReadyPromise, "f");
|
|
4705
|
-
const pendingTradingSetup = __classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f");
|
|
4706
|
-
// Clear references first to prevent new callers from reusing
|
|
4707
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_initializationPromise, null, "f");
|
|
4708
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
|
|
4709
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupPromise, null, "f");
|
|
4710
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupComplete, false, "f");
|
|
4711
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_pendingBuilderFeeApprovals, "f").clear();
|
|
4712
|
-
// Wait for pending operations to complete (ignore errors)
|
|
4713
|
-
// This prevents IIFEs from setting state after disconnect completes
|
|
4714
|
-
if (pendingInit) {
|
|
4715
|
-
try {
|
|
4716
|
-
await pendingInit;
|
|
4717
|
-
}
|
|
4718
|
-
catch {
|
|
4719
|
-
// Ignore - we're disconnecting anyway
|
|
4720
|
-
}
|
|
4721
|
-
}
|
|
4722
|
-
if (pendingReady) {
|
|
4723
|
-
try {
|
|
4724
|
-
await pendingReady;
|
|
4725
|
-
}
|
|
4726
|
-
catch {
|
|
4727
|
-
// Ignore - we're disconnecting anyway
|
|
4728
|
-
}
|
|
4729
|
-
}
|
|
4730
|
-
if (pendingTradingSetup) {
|
|
4731
|
-
try {
|
|
4732
|
-
await pendingTradingSetup;
|
|
4733
|
-
}
|
|
4734
|
-
catch {
|
|
4735
|
-
// Ignore - we're disconnecting anyway
|
|
4736
|
-
}
|
|
4737
|
-
}
|
|
4738
|
-
// Reset client initialization flag so wallet adapter will be recreated with new account
|
|
4739
|
-
// This fixes account synchronization issue where old account's address persists in wallet adapter
|
|
4740
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_clientsInitialized, false, "f");
|
|
4741
|
-
// Disconnect client service
|
|
4742
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").disconnect();
|
|
4743
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Provider fully disconnected', {
|
|
4744
|
-
timestamp: new Date().toISOString(),
|
|
4745
|
-
});
|
|
4746
|
-
return { success: true };
|
|
4747
|
-
}
|
|
4748
|
-
catch (error) {
|
|
4749
|
-
return (0, hyperLiquidValidation_js_1.createErrorResult)(error, { success: false });
|
|
5284
|
+
return await operation;
|
|
4750
5285
|
}
|
|
4751
5286
|
finally {
|
|
4752
|
-
|
|
5287
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationPromise, "f") === operation) {
|
|
5288
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_disconnectOperationPromise, null, "f");
|
|
5289
|
+
}
|
|
4753
5290
|
}
|
|
4754
5291
|
}
|
|
4755
5292
|
/**
|
|
@@ -4876,7 +5413,75 @@ class HyperLiquidProvider {
|
|
|
4876
5413
|
}
|
|
4877
5414
|
}
|
|
4878
5415
|
exports.HyperLiquidProvider = HyperLiquidProvider;
|
|
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(),
|
|
5416
|
+
_a = HyperLiquidProvider, _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_orderCapabilitiesMarketsByDex = new WeakMap(), _HyperLiquidProvider_orderCapabilitiesRefreshByDex = new WeakMap(), _HyperLiquidProvider_isDisconnected = new WeakMap(), _HyperLiquidProvider_disconnectOperationsInFlight = new WeakMap(), _HyperLiquidProvider_disconnectOperationPromise = new WeakMap(), _HyperLiquidProvider_lifecycleGeneration = 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_cancelledScaleOrderGroups = new WeakMap(), _HyperLiquidProvider_trackedTwapOrders = 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_strategyGeneration = 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_onChaseOrderMaxDistanceReached = new WeakMap(), _HyperLiquidProvider_tradingSetupPromise = new WeakMap(), _HyperLiquidProvider_tradingSetupComplete = new WeakMap(), _HyperLiquidProvider_builderFeeSetupPromises = new WeakMap(), _HyperLiquidProvider_instances = new WeakSet(), _HyperLiquidProvider_resolveOrderFeePolicy = function _HyperLiquidProvider_resolveOrderFeePolicy(params) {
|
|
5417
|
+
const fallbackPolicy = Object.prototype.hasOwnProperty.call(HYPERLIQUID_ORDER_FEE_CONFIG, params.orderType)
|
|
5418
|
+
? HYPERLIQUID_ORDER_FEE_CONFIG[params.orderType]
|
|
5419
|
+
: undefined;
|
|
5420
|
+
if (fallbackPolicy) {
|
|
5421
|
+
return fallbackPolicy;
|
|
5422
|
+
}
|
|
5423
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Unknown order type used the safe builder-fee policy', { orderType: params.orderType });
|
|
5424
|
+
return HYPERLIQUID_ORDER_FEE_CONFIG.market;
|
|
5425
|
+
}, _HyperLiquidProvider_assertProviderLifecycleCurrent = function _HyperLiquidProvider_assertProviderLifecycleCurrent(generation, operation) {
|
|
5426
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_isDisconnected, "f") || generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f")) {
|
|
5427
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Provider operation became stale during disconnect', { operation });
|
|
5428
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
5429
|
+
}
|
|
5430
|
+
}, _HyperLiquidProvider_assertCacheWriteLifecycleCurrent = function _HyperLiquidProvider_assertCacheWriteLifecycleCurrent(generation, operation) {
|
|
5431
|
+
if (!__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isCacheWriteLifecycleCurrent).call(this, generation, operation)) {
|
|
5432
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
5433
|
+
}
|
|
5434
|
+
}, _HyperLiquidProvider_isCacheWriteLifecycleCurrent = function _HyperLiquidProvider_isCacheWriteLifecycleCurrent(generation, operation) {
|
|
5435
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0 ||
|
|
5436
|
+
generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f")) {
|
|
5437
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Cache write became stale during disconnect', { operation });
|
|
5438
|
+
return false;
|
|
5439
|
+
}
|
|
5440
|
+
return true;
|
|
5441
|
+
}, _HyperLiquidProvider_getFreshOrderCapabilityMarkets =
|
|
5442
|
+
/**
|
|
5443
|
+
* Return filtered market metadata fresh enough for a capability query.
|
|
5444
|
+
* Each DEX shares one refresh across concurrent callers, and a failed
|
|
5445
|
+
* refresh remains immediately retryable.
|
|
5446
|
+
*
|
|
5447
|
+
* @param dex - Routed DEX, or null for the main DEX.
|
|
5448
|
+
* @returns Fresh filtered markets for that route.
|
|
5449
|
+
*/
|
|
5450
|
+
async function _HyperLiquidProvider_getFreshOrderCapabilityMarkets(dex) {
|
|
5451
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5452
|
+
const cachedMarkets = __classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesMarketsByDex, "f").get(dex);
|
|
5453
|
+
if (cachedMarkets &&
|
|
5454
|
+
Date.now() - cachedMarkets.freshAt <
|
|
5455
|
+
perpsConfig_js_1.PERFORMANCE_CONFIG.OrderCapabilitiesMetaFreshnessMs) {
|
|
5456
|
+
return cachedMarkets.markets;
|
|
5457
|
+
}
|
|
5458
|
+
let refreshPromise = __classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesRefreshByDex, "f").get(dex);
|
|
5459
|
+
if (!refreshPromise) {
|
|
5460
|
+
refreshPromise = (async () => {
|
|
5461
|
+
const markets = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchMarketsForDex).call(this, {
|
|
5462
|
+
dex,
|
|
5463
|
+
skipCache: true,
|
|
5464
|
+
});
|
|
5465
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Order capability metadata refresh');
|
|
5466
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesMarketsByDex, "f").set(dex, {
|
|
5467
|
+
markets,
|
|
5468
|
+
freshAt: Date.now(),
|
|
5469
|
+
});
|
|
5470
|
+
return markets;
|
|
5471
|
+
})();
|
|
5472
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesRefreshByDex, "f").set(dex, refreshPromise);
|
|
5473
|
+
}
|
|
5474
|
+
try {
|
|
5475
|
+
const markets = await refreshPromise;
|
|
5476
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Order capability read');
|
|
5477
|
+
return markets;
|
|
5478
|
+
}
|
|
5479
|
+
finally {
|
|
5480
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesRefreshByDex, "f").get(dex) === refreshPromise) {
|
|
5481
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesRefreshByDex, "f").delete(dex);
|
|
5482
|
+
}
|
|
5483
|
+
}
|
|
5484
|
+
}, _HyperLiquidProvider_compilePatternsSafely = function _HyperLiquidProvider_compilePatternsSafely(patterns, listName) {
|
|
4880
5485
|
const compiled = [];
|
|
4881
5486
|
for (const pattern of patterns) {
|
|
4882
5487
|
try {
|
|
@@ -4899,6 +5504,9 @@ _HyperLiquidProvider_deps = new WeakMap(), _HyperLiquidProvider_clientService =
|
|
|
4899
5504
|
* the connection is fully established before marking initialization complete.
|
|
4900
5505
|
*/
|
|
4901
5506
|
async function _HyperLiquidProvider_ensureClientsInitialized() {
|
|
5507
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0) {
|
|
5508
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
5509
|
+
}
|
|
4902
5510
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_clientsInitialized, "f")) {
|
|
4903
5511
|
return; // Already initialized
|
|
4904
5512
|
}
|
|
@@ -4906,6 +5514,9 @@ async function _HyperLiquidProvider_ensureClientsInitialized() {
|
|
|
4906
5514
|
// This prevents race conditions when multiple methods call concurrently
|
|
4907
5515
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_initializationPromise, "f")) {
|
|
4908
5516
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_initializationPromise, "f");
|
|
5517
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0) {
|
|
5518
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
5519
|
+
}
|
|
4909
5520
|
return;
|
|
4910
5521
|
}
|
|
4911
5522
|
// Create and cache the initialization promise
|
|
@@ -4914,8 +5525,14 @@ async function _HyperLiquidProvider_ensureClientsInitialized() {
|
|
|
4914
5525
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_clientsInitialized, "f")) {
|
|
4915
5526
|
return;
|
|
4916
5527
|
}
|
|
5528
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0) {
|
|
5529
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
5530
|
+
}
|
|
4917
5531
|
const wallet = __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").createWalletAdapter();
|
|
4918
5532
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").initialize(wallet);
|
|
5533
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") > 0) {
|
|
5534
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
5535
|
+
}
|
|
4919
5536
|
// Set termination callback for logging when WebSocket terminates
|
|
4920
5537
|
// Note: Do NOT restore subscriptions here - termination means connection failed permanently
|
|
4921
5538
|
__classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").setOnTerminateCallback((error) => {
|
|
@@ -5386,7 +6003,13 @@ async function _HyperLiquidProvider_ensureReady() {
|
|
|
5386
6003
|
// Await initialization - keep the promise so subsequent calls resolve immediately
|
|
5387
6004
|
// The promise is only reset in disconnect() for clean reconnection,
|
|
5388
6005
|
// or when DEX discovery was degraded so the next caller retries.
|
|
5389
|
-
|
|
6006
|
+
try {
|
|
6007
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_ensureReadyPromise, "f");
|
|
6008
|
+
}
|
|
6009
|
+
catch (error) {
|
|
6010
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
|
|
6011
|
+
throw error;
|
|
6012
|
+
}
|
|
5390
6013
|
if (!__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryComplete, "f")) {
|
|
5391
6014
|
// DEX discovery failed transiently — reset so next call retries.
|
|
5392
6015
|
// Trading still works (main DEX mapping is populated), but HIP-3 markets
|
|
@@ -5401,72 +6024,102 @@ async function _HyperLiquidProvider_ensureReady() {
|
|
|
5401
6024
|
__classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
|
|
5402
6025
|
}
|
|
5403
6026
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReady] Initialization complete');
|
|
5404
|
-
},
|
|
6027
|
+
}, _HyperLiquidProvider_ensureBuilderFeeSetup =
|
|
6028
|
+
/**
|
|
6029
|
+
* Approve the standard builder fee once for the current account and network.
|
|
6030
|
+
* TWAP never calls this because its native action has no builder field.
|
|
6031
|
+
* Without an approval failure code, approval remains non-blocking and the
|
|
6032
|
+
* returned context describes attribution only; it does not prove approval.
|
|
6033
|
+
*
|
|
6034
|
+
* @param approvalFailureCode - Operation-specific error to throw when
|
|
6035
|
+
* approval is unavailable or fails.
|
|
6036
|
+
* @returns The account, network, and configured builder for the action.
|
|
6037
|
+
*/
|
|
6038
|
+
async function _HyperLiquidProvider_ensureBuilderFeeSetup(approvalFailureCode) {
|
|
6039
|
+
const isTestnet = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode();
|
|
6040
|
+
const network = isTestnet ? 'testnet' : 'mainnet';
|
|
6041
|
+
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
6042
|
+
const cacheKey = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCacheKey).call(this, network, userAddress);
|
|
6043
|
+
const builderAddress = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderAddress).call(this, isTestnet);
|
|
6044
|
+
const context = {
|
|
6045
|
+
network,
|
|
6046
|
+
userAddress,
|
|
6047
|
+
builderAddress,
|
|
6048
|
+
};
|
|
6049
|
+
const setupKey = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getApprovedBuilderKey).call(this, network, userAddress, builderAddress);
|
|
6050
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").has(cacheKey)) {
|
|
6051
|
+
return context;
|
|
6052
|
+
}
|
|
6053
|
+
let pendingApproval = __classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeSetupPromises, "f").get(setupKey);
|
|
6054
|
+
if (!pendingApproval) {
|
|
6055
|
+
pendingApproval = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureBuilderFeeApproval).call(this, context);
|
|
6056
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeSetupPromises, "f").set(setupKey, pendingApproval);
|
|
6057
|
+
}
|
|
6058
|
+
try {
|
|
6059
|
+
await pendingApproval;
|
|
6060
|
+
}
|
|
6061
|
+
catch (error) {
|
|
6062
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureBuilderFeeSetup] Builder fee approval failed', error);
|
|
6063
|
+
if (approvalFailureCode) {
|
|
6064
|
+
throw new Error(approvalFailureCode);
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
6067
|
+
finally {
|
|
6068
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeSetupPromises, "f").get(setupKey) === pendingApproval) {
|
|
6069
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeSetupPromises, "f").delete(setupKey);
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
if (approvalFailureCode && !__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").has(cacheKey)) {
|
|
6073
|
+
throw new Error(approvalFailureCode);
|
|
6074
|
+
}
|
|
6075
|
+
return context;
|
|
6076
|
+
}, _HyperLiquidProvider_ensureReadyForTrading = async function _HyperLiquidProvider_ensureReadyForTrading(options) {
|
|
5405
6077
|
// First ensure basic initialization is complete
|
|
5406
6078
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReady).call(this);
|
|
5407
6079
|
// dexAbstraction users were deferred during init to avoid an EIP-712 prompt
|
|
5408
6080
|
// on Perps section open. Drive the migration here, gated by its own cache so
|
|
5409
6081
|
// already-migrated or already-rejected users are not re-prompted.
|
|
5410
6082
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureUnifiedAccountEnabled).call(this, { allowUserSigning: true });
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
6083
|
+
if (!__classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupComplete, "f") && !__classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f")) {
|
|
6084
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
6085
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReadyForTrading] Starting shared trading setup');
|
|
6086
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupPromise, (async () => {
|
|
6087
|
+
// Pre-fetch spotMeta for HIP-3 operations (non-blocking if it fails)
|
|
6088
|
+
// This ensures token info (e.g. USDC token index) is available during order placement
|
|
6089
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f")) {
|
|
6090
|
+
try {
|
|
6091
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCachedSpotMeta).call(this);
|
|
6092
|
+
}
|
|
6093
|
+
catch (error) {
|
|
6094
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReadyForTrading] spotMeta pre-fetch failed, will retry when needed', error);
|
|
6095
|
+
// Don't throw - spotMeta will be fetched on-demand if needed
|
|
6096
|
+
}
|
|
5421
6097
|
}
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
6098
|
+
// Set up referral code independently from builder-fee applicability.
|
|
6099
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReferralSet).call(this);
|
|
6100
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Trading setup completion');
|
|
6101
|
+
// Only mark complete if keyring was unlocked (signing could actually happen)
|
|
6102
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").isKeyringUnlocked()) {
|
|
6103
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupComplete, true, "f");
|
|
5425
6104
|
}
|
|
5426
|
-
}
|
|
5427
|
-
return;
|
|
5428
|
-
}
|
|
5429
|
-
// If trading setup is in progress, wait for it
|
|
5430
|
-
if (__classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f")) {
|
|
5431
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReadyForTrading] Waiting for in-progress trading setup');
|
|
5432
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f");
|
|
5433
|
-
return;
|
|
6105
|
+
})(), "f");
|
|
5434
6106
|
}
|
|
5435
|
-
__classPrivateFieldGet(this,
|
|
5436
|
-
|
|
5437
|
-
// Pre-fetch spotMeta for HIP-3 operations (non-blocking if it fails)
|
|
5438
|
-
// This ensures token info (e.g. USDC token index) is available during order placement
|
|
5439
|
-
if (__classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f")) {
|
|
5440
|
-
try {
|
|
5441
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCachedSpotMeta).call(this);
|
|
5442
|
-
}
|
|
5443
|
-
catch (error) {
|
|
5444
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReadyForTrading] spotMeta pre-fetch failed, will retry when needed', error);
|
|
5445
|
-
// Don't throw - spotMeta will be fetched on-demand if needed
|
|
5446
|
-
}
|
|
5447
|
-
}
|
|
5448
|
-
// Set up builder fee approval
|
|
6107
|
+
const pendingSetup = __classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f");
|
|
6108
|
+
if (pendingSetup) {
|
|
5449
6109
|
try {
|
|
5450
|
-
await
|
|
5451
|
-
}
|
|
5452
|
-
catch (error) {
|
|
5453
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Builder fee approval failed', error);
|
|
5454
|
-
// Don't throw - let trading continue, will fail with clear error if needed
|
|
6110
|
+
await pendingSetup;
|
|
5455
6111
|
}
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupComplete, true, "f");
|
|
6112
|
+
finally {
|
|
6113
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f") === pendingSetup) {
|
|
6114
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupPromise, null, "f");
|
|
6115
|
+
}
|
|
5461
6116
|
}
|
|
5462
|
-
})(), "f");
|
|
5463
|
-
try {
|
|
5464
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f");
|
|
5465
|
-
}
|
|
5466
|
-
finally {
|
|
5467
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupPromise, null, "f");
|
|
5468
6117
|
}
|
|
6118
|
+
const builderFeeSetupContext = options.requiresBuilderFee
|
|
6119
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureBuilderFeeSetup).call(this, options.builderFeeApprovalFailureCode)
|
|
6120
|
+
: undefined;
|
|
5469
6121
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureReadyForTrading] Trading setup complete');
|
|
6122
|
+
return builderFeeSetupContext;
|
|
5470
6123
|
}, _HyperLiquidProvider_getOrFetchPrice =
|
|
5471
6124
|
/**
|
|
5472
6125
|
* Get current price for a symbol using WebSocket cache first, REST API fallback
|
|
@@ -5529,6 +6182,7 @@ async function _HyperLiquidProvider_getOrFetchPrice(params) {
|
|
|
5529
6182
|
* @returns Array of all DEX names (null for main DEX, strings for HIP-3 DEXs)
|
|
5530
6183
|
*/
|
|
5531
6184
|
async function _HyperLiquidProvider_getAllAvailableDexs() {
|
|
6185
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5532
6186
|
// Use unified state if available
|
|
5533
6187
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").state) {
|
|
5534
6188
|
const availableHip3Dexs = [];
|
|
@@ -5546,6 +6200,7 @@ async function _HyperLiquidProvider_getAllAvailableDexs() {
|
|
|
5546
6200
|
if (!allDexs || !Array.isArray(allDexs)) {
|
|
5547
6201
|
return [null]; // Fallback to main DEX only
|
|
5548
6202
|
}
|
|
6203
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'DEX discovery cache write');
|
|
5549
6204
|
const state = __classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").update(allDexs);
|
|
5550
6205
|
const availableHip3Dexs = [];
|
|
5551
6206
|
state.raw.forEach((dex) => {
|
|
@@ -5592,14 +6247,17 @@ async function _HyperLiquidProvider_getValidatedDexs() {
|
|
|
5592
6247
|
return __classPrivateFieldGet(this, _HyperLiquidProvider_pendingValidatedDexsPromise, "f");
|
|
5593
6248
|
}
|
|
5594
6249
|
// Create and cache the pending promise for deduplication
|
|
5595
|
-
|
|
6250
|
+
const pendingPromise = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchValidatedDexsInternal).call(this);
|
|
6251
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_pendingValidatedDexsPromise, pendingPromise, "f");
|
|
5596
6252
|
try {
|
|
5597
|
-
const result = await
|
|
6253
|
+
const result = await pendingPromise;
|
|
5598
6254
|
return result;
|
|
5599
6255
|
}
|
|
5600
6256
|
finally {
|
|
5601
|
-
//
|
|
5602
|
-
|
|
6257
|
+
// A stale request must not clear a newer lifecycle's pending request.
|
|
6258
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_pendingValidatedDexsPromise, "f") === pendingPromise) {
|
|
6259
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_pendingValidatedDexsPromise, null, "f");
|
|
6260
|
+
}
|
|
5603
6261
|
}
|
|
5604
6262
|
}, _HyperLiquidProvider_fetchValidatedDexsInternal =
|
|
5605
6263
|
/**
|
|
@@ -5609,6 +6267,7 @@ async function _HyperLiquidProvider_getValidatedDexs() {
|
|
|
5609
6267
|
* @returns A promise that resolves to the result.
|
|
5610
6268
|
*/
|
|
5611
6269
|
async function _HyperLiquidProvider_fetchValidatedDexsInternal() {
|
|
6270
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5612
6271
|
// Kill switch: HIP-3 disabled, return main DEX only
|
|
5613
6272
|
if (!__classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f")) {
|
|
5614
6273
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: HIP-3 disabled via hip3Enabled flag');
|
|
@@ -5638,6 +6297,7 @@ async function _HyperLiquidProvider_fetchValidatedDexsInternal() {
|
|
|
5638
6297
|
return [null];
|
|
5639
6298
|
}
|
|
5640
6299
|
// Atomically update unified state (raw + validated + timestamp)
|
|
6300
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'DEX discovery cache write');
|
|
5641
6301
|
const state = __classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").update(allDexs);
|
|
5642
6302
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquidProvider: Available DEXs (market filtering applied at data layer)', {
|
|
5643
6303
|
count: state.validated.filter((dex) => dex !== null).length,
|
|
@@ -5656,13 +6316,12 @@ async function _HyperLiquidProvider_fetchValidatedDexsInternal() {
|
|
|
5656
6316
|
* @throws Error if API returns invalid data
|
|
5657
6317
|
*/
|
|
5658
6318
|
async function _HyperLiquidProvider_getCachedMeta(params) {
|
|
6319
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5659
6320
|
const { dexName, skipCache } = params;
|
|
5660
|
-
|
|
5661
|
-
const dexKey = dexName ?? '';
|
|
5662
|
-
const dexDisplayName = dexKey || 'main';
|
|
6321
|
+
const dexDisplayName = dexName ?? 'main';
|
|
5663
6322
|
// Skip cache if requested (forces fresh fetch)
|
|
5664
6323
|
if (!skipCache) {
|
|
5665
|
-
const cached = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(
|
|
6324
|
+
const cached = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dexName);
|
|
5666
6325
|
if (cached) {
|
|
5667
6326
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedMeta] Using cached meta response', {
|
|
5668
6327
|
dex: dexDisplayName,
|
|
@@ -5672,6 +6331,29 @@ async function _HyperLiquidProvider_getCachedMeta(params) {
|
|
|
5672
6331
|
}
|
|
5673
6332
|
}
|
|
5674
6333
|
// Cache miss or skipCache=true - fetch from API.
|
|
6334
|
+
const meta = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_fetchMeta).call(this, dexName);
|
|
6335
|
+
const cached = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheDexMetadataFromRead).call(this, {
|
|
6336
|
+
dex: dexName,
|
|
6337
|
+
meta,
|
|
6338
|
+
lifecycleGeneration,
|
|
6339
|
+
});
|
|
6340
|
+
if (cached) {
|
|
6341
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedMeta] Fetched and cached meta response', {
|
|
6342
|
+
dex: dexDisplayName,
|
|
6343
|
+
universeSize: meta.universe.length,
|
|
6344
|
+
skipCache,
|
|
6345
|
+
});
|
|
6346
|
+
}
|
|
6347
|
+
return meta;
|
|
6348
|
+
}, _HyperLiquidProvider_fetchMeta =
|
|
6349
|
+
/**
|
|
6350
|
+
* Fetch and validate metadata without mutating provider caches.
|
|
6351
|
+
*
|
|
6352
|
+
* @param dexName - DEX name, or null for the main DEX.
|
|
6353
|
+
* @returns Validated metadata for the requested DEX.
|
|
6354
|
+
*/
|
|
6355
|
+
async function _HyperLiquidProvider_fetchMeta(dexName) {
|
|
6356
|
+
const dexDisplayName = dexName ?? 'main';
|
|
5675
6357
|
// Bring the SDK clients up first. This is the first client touch on the
|
|
5676
6358
|
// write path — placeOrder resolves asset info before it ensures trading
|
|
5677
6359
|
// readiness — so without it a cold start or a post-disconnect action fails
|
|
@@ -5683,20 +6365,54 @@ async function _HyperLiquidProvider_getCachedMeta(params) {
|
|
|
5683
6365
|
const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient({ useHttp: true });
|
|
5684
6366
|
// Pass dex only for HIP-3 DEXs; omit for main DEX (empty string).
|
|
5685
6367
|
// Testnet API returns null when dex="" is explicitly sent.
|
|
5686
|
-
const meta = await infoClient.meta(
|
|
6368
|
+
const meta = await infoClient.meta(dexName ? { dex: dexName } : undefined);
|
|
5687
6369
|
// Defensive validation before caching
|
|
5688
6370
|
if (!meta?.universe || !Array.isArray(meta.universe)) {
|
|
5689
6371
|
throw new Error(`[HyperLiquidProvider] Invalid meta response for DEX ${dexDisplayName}: universe is ${meta?.universe ? 'not an array' : 'missing'}`);
|
|
5690
6372
|
}
|
|
5691
|
-
// Store raw meta response for reuse
|
|
5692
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dexKey, meta);
|
|
5693
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta);
|
|
5694
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedMeta] Fetched and cached meta response', {
|
|
5695
|
-
dex: dexDisplayName,
|
|
5696
|
-
universeSize: meta.universe.length,
|
|
5697
|
-
skipCache,
|
|
5698
|
-
});
|
|
5699
6373
|
return meta;
|
|
6374
|
+
}, _HyperLiquidProvider_cacheDexMetadata = function _HyperLiquidProvider_cacheDexMetadata(params) {
|
|
6375
|
+
const { dex, meta, assetCtxs, lifecycleGeneration } = params;
|
|
6376
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'DEX metadata cache write');
|
|
6377
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").set(dex, meta);
|
|
6378
|
+
if (assetCtxs) {
|
|
6379
|
+
const subscriptionDexKey = dex ?? '';
|
|
6380
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexMetaCache(subscriptionDexKey, meta);
|
|
6381
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").setDexAssetCtxsCache(subscriptionDexKey, assetCtxs);
|
|
6382
|
+
}
|
|
6383
|
+
}, _HyperLiquidProvider_cacheDexMetadataFromRead =
|
|
6384
|
+
/**
|
|
6385
|
+
* Cache metadata fetched for a read without discarding a valid response.
|
|
6386
|
+
*
|
|
6387
|
+
* @param params - Metadata and lifecycle context.
|
|
6388
|
+
* @param params.dex - DEX name, or null for the main DEX.
|
|
6389
|
+
* @param params.meta - Validated DEX metadata.
|
|
6390
|
+
* @param params.assetCtxs - Asset contexts shared with subscriptions, if any.
|
|
6391
|
+
* @param params.lifecycleGeneration - Lifecycle that produced the metadata.
|
|
6392
|
+
* @returns Whether the fetched metadata was cached.
|
|
6393
|
+
*/
|
|
6394
|
+
async function _HyperLiquidProvider_cacheDexMetadataFromRead(params) {
|
|
6395
|
+
const { dex, meta, assetCtxs, lifecycleGeneration } = params;
|
|
6396
|
+
if (!__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'DEX metadata read cache write')) {
|
|
6397
|
+
return false;
|
|
6398
|
+
}
|
|
6399
|
+
try {
|
|
6400
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheDexMetadata).call(this, {
|
|
6401
|
+
dex,
|
|
6402
|
+
meta,
|
|
6403
|
+
assetCtxs,
|
|
6404
|
+
lifecycleGeneration,
|
|
6405
|
+
});
|
|
6406
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dex, meta, lifecycleGeneration);
|
|
6407
|
+
return true;
|
|
6408
|
+
}
|
|
6409
|
+
catch (error) {
|
|
6410
|
+
if ((0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.cacheDexMetadataFromRead')
|
|
6411
|
+
.message === perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE) {
|
|
6412
|
+
return false;
|
|
6413
|
+
}
|
|
6414
|
+
throw error;
|
|
6415
|
+
}
|
|
5700
6416
|
}, _HyperLiquidProvider_backfillAssetMapForDex =
|
|
5701
6417
|
/**
|
|
5702
6418
|
* Backfill the asset ID map for a single DEX from a fresh meta response.
|
|
@@ -5704,9 +6420,11 @@ async function _HyperLiquidProvider_getCachedMeta(params) {
|
|
|
5704
6420
|
*
|
|
5705
6421
|
* @param dex - DEX name (null for main DEX).
|
|
5706
6422
|
* @param meta - Meta response containing the DEX universe.
|
|
6423
|
+
* @param lifecycleGeneration - Lifecycle that produced the metadata.
|
|
5707
6424
|
* @returns True if the mapping was rebuilt for the DEX.
|
|
5708
6425
|
*/
|
|
5709
|
-
async function _HyperLiquidProvider_backfillAssetMapForDex(dex, meta) {
|
|
6426
|
+
async function _HyperLiquidProvider_backfillAssetMapForDex(dex, meta, lifecycleGeneration) {
|
|
6427
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Asset map backfill');
|
|
5710
6428
|
if (!meta?.universe || !Array.isArray(meta.universe)) {
|
|
5711
6429
|
return false;
|
|
5712
6430
|
}
|
|
@@ -5721,6 +6439,7 @@ async function _HyperLiquidProvider_backfillAssetMapForDex(dex, meta) {
|
|
|
5721
6439
|
});
|
|
5722
6440
|
}
|
|
5723
6441
|
}
|
|
6442
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Asset map backfill');
|
|
5724
6443
|
const allPerpDexs = __classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").state?.raw ?? [null];
|
|
5725
6444
|
const perpDexIndex = allPerpDexs.findIndex((entry) => {
|
|
5726
6445
|
if (dex === null) {
|
|
@@ -5757,6 +6476,7 @@ async function _HyperLiquidProvider_backfillAssetMapForDex(dex, meta) {
|
|
|
5757
6476
|
* @returns The asset ID.
|
|
5758
6477
|
*/
|
|
5759
6478
|
async function _HyperLiquidProvider_getAssetIdWithRepair(params) {
|
|
6479
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5760
6480
|
const { symbol, dexName } = params;
|
|
5761
6481
|
const existingAssetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
|
|
5762
6482
|
if (existingAssetId !== undefined) {
|
|
@@ -5765,7 +6485,7 @@ async function _HyperLiquidProvider_getAssetIdWithRepair(params) {
|
|
|
5765
6485
|
const meta = params.meta ?? (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCachedMeta).call(this, { dexName: dexName ?? null }));
|
|
5766
6486
|
const assetExistsInMeta = meta.universe.some((asset) => asset.name === symbol);
|
|
5767
6487
|
if (assetExistsInMeta) {
|
|
5768
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta);
|
|
6488
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_backfillAssetMapForDex).call(this, dexName, meta, lifecycleGeneration);
|
|
5769
6489
|
const repairedAssetId = __classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").get(symbol);
|
|
5770
6490
|
if (repairedAssetId !== undefined) {
|
|
5771
6491
|
return repairedAssetId;
|
|
@@ -5796,13 +6516,16 @@ async function _HyperLiquidProvider_getCachedSpotMeta() {
|
|
|
5796
6516
|
});
|
|
5797
6517
|
return __classPrivateFieldGet(this, _HyperLiquidProvider_cachedSpotMeta, "f");
|
|
5798
6518
|
}
|
|
6519
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5799
6520
|
const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
|
|
5800
6521
|
const spotMeta = await infoClient.spotMeta();
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
6522
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Spot metadata cache write')) {
|
|
6523
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_cachedSpotMeta, spotMeta, "f");
|
|
6524
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedSpotMeta] Fetched and cached spotMeta', {
|
|
6525
|
+
tokensCount: spotMeta.tokens.length,
|
|
6526
|
+
universeCount: spotMeta.universe.length,
|
|
6527
|
+
});
|
|
6528
|
+
}
|
|
5806
6529
|
return spotMeta;
|
|
5807
6530
|
}, _HyperLiquidProvider_getCachedPerpDexs =
|
|
5808
6531
|
/**
|
|
@@ -5812,6 +6535,7 @@ async function _HyperLiquidProvider_getCachedSpotMeta() {
|
|
|
5812
6535
|
* @returns Array of ExtendedPerpDex objects (null entries represent main DEX)
|
|
5813
6536
|
*/
|
|
5814
6537
|
async function _HyperLiquidProvider_getCachedPerpDexs() {
|
|
6538
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
5815
6539
|
const now = Date.now();
|
|
5816
6540
|
// Return cached data if still valid (uses unified state timestamp for TTL)
|
|
5817
6541
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").state &&
|
|
@@ -5829,17 +6553,19 @@ async function _HyperLiquidProvider_getCachedPerpDexs() {
|
|
|
5829
6553
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureClientsInitialized).call(this);
|
|
5830
6554
|
const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
|
|
5831
6555
|
const perpDexs = (await infoClient.perpDexs());
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
6556
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_isCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Perp DEX cache write')) {
|
|
6557
|
+
// Atomically update unified state (raw + validated + timestamp)
|
|
6558
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").update(perpDexs);
|
|
6559
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getCachedPerpDexs] Fetched and cached perpDexs data', {
|
|
6560
|
+
count: perpDexs.length,
|
|
6561
|
+
dexes: perpDexs
|
|
6562
|
+
.filter((dex) => dex !== null)
|
|
6563
|
+
.map((dex) => ({
|
|
6564
|
+
name: dex.name,
|
|
6565
|
+
deployerFeeScale: dex.deployerFeeScale,
|
|
6566
|
+
})),
|
|
6567
|
+
});
|
|
6568
|
+
}
|
|
5843
6569
|
return perpDexs;
|
|
5844
6570
|
}, _HyperLiquidProvider_calculateHip3FeeMultiplier =
|
|
5845
6571
|
/**
|
|
@@ -6011,6 +6737,7 @@ async function _HyperLiquidProvider_isUsdcCollateralDex(dexName) {
|
|
|
6011
6737
|
* the asset ID lookup succeeds and the order routes to the correct DEX.
|
|
6012
6738
|
*/
|
|
6013
6739
|
async function _HyperLiquidProvider_buildAssetMapping() {
|
|
6740
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
6014
6741
|
// Get feature-flag-validated DEXs to map (respects hip3Enabled and enabledDexs)
|
|
6015
6742
|
let dexsToMap;
|
|
6016
6743
|
try {
|
|
@@ -6041,14 +6768,14 @@ async function _HyperLiquidProvider_buildAssetMapping() {
|
|
|
6041
6768
|
// Extract HIP-3 DEX names (filter out null which represents main DEX)
|
|
6042
6769
|
const enabledDexs = dexsToMap.filter((dex) => dex !== null);
|
|
6043
6770
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").updateFeatureFlags(__classPrivateFieldGet(this, _HyperLiquidProvider_hip3Enabled, "f"), enabledDexs, __classPrivateFieldGet(this, _HyperLiquidProvider_allowlistMarkets, "f"), __classPrivateFieldGet(this, _HyperLiquidProvider_blocklistMarkets, "f"));
|
|
6771
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Asset mapping rebuild');
|
|
6044
6772
|
// Fetch metadata for each DEX in parallel using metaAndAssetCtxs
|
|
6045
6773
|
// Optimization: Check cache first - getMarketDataWithPrices may have already fetched
|
|
6046
6774
|
// If not cached, fetch via metaAndAssetCtxs and populate cache for other methods
|
|
6047
6775
|
const infoClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient();
|
|
6048
6776
|
const allMetas = await Promise.allSettled(dexsToMap.map((dex) => {
|
|
6049
|
-
const dexKey = dex ?? '';
|
|
6050
6777
|
// Check if already cached (e.g., by getMarketDataWithPrices running in parallel)
|
|
6051
|
-
const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(
|
|
6778
|
+
const cachedMeta = __classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").get(dex);
|
|
6052
6779
|
if (cachedMeta) {
|
|
6053
6780
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log(`[buildAssetMapping] Using cached meta for ${dex ?? 'main'}`, { universeSize: cachedMeta.universe.length });
|
|
6054
6781
|
return Promise.resolve({
|
|
@@ -6066,11 +6793,12 @@ async function _HyperLiquidProvider_buildAssetMapping() {
|
|
|
6066
6793
|
const assetCtxs = result?.[1] || [];
|
|
6067
6794
|
// Cache meta for later use by getCachedMeta
|
|
6068
6795
|
if (meta?.universe) {
|
|
6069
|
-
__classPrivateFieldGet(this,
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6796
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheDexMetadata).call(this, {
|
|
6797
|
+
dex,
|
|
6798
|
+
meta,
|
|
6799
|
+
assetCtxs,
|
|
6800
|
+
lifecycleGeneration,
|
|
6801
|
+
});
|
|
6074
6802
|
}
|
|
6075
6803
|
return { dex, meta, success: true };
|
|
6076
6804
|
})
|
|
@@ -6079,6 +6807,7 @@ async function _HyperLiquidProvider_buildAssetMapping() {
|
|
|
6079
6807
|
return { dex, meta: null, success: false };
|
|
6080
6808
|
});
|
|
6081
6809
|
}));
|
|
6810
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertCacheWriteLifecycleCurrent).call(this, lifecycleGeneration, 'Asset mapping rebuild');
|
|
6082
6811
|
// Build mapping with DEX prefixes for HIP-3 DEXs using the utility function
|
|
6083
6812
|
__classPrivateFieldGet(this, _HyperLiquidProvider_symbolToAssetId, "f").clear();
|
|
6084
6813
|
let dexDiscoveryComplete = __classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").state !== null;
|
|
@@ -6250,12 +6979,16 @@ async function _HyperLiquidProvider_checkBuilderFeeApproval(builder, userAddress
|
|
|
6250
6979
|
* This prevents repeated signing requests for hardware wallets.
|
|
6251
6980
|
*
|
|
6252
6981
|
* Note: This is network-specific - testnet and mainnet have separate builder fee states
|
|
6982
|
+
*
|
|
6983
|
+
* @param params - Builder fee setup context.
|
|
6984
|
+
* @param params.network - HyperLiquid network for the approval.
|
|
6985
|
+
* @param params.userAddress - Account that owns the approval.
|
|
6986
|
+
* @param params.builderAddress - Builder address being approved.
|
|
6253
6987
|
*/
|
|
6254
|
-
async function _HyperLiquidProvider_ensureBuilderFeeApproval() {
|
|
6255
|
-
const
|
|
6256
|
-
const network
|
|
6257
|
-
|
|
6258
|
-
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
6988
|
+
async function _HyperLiquidProvider_ensureBuilderFeeApproval(params) {
|
|
6989
|
+
const lifecycleGeneration = __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f");
|
|
6990
|
+
const { network, userAddress, builderAddress } = params;
|
|
6991
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Builder fee approval');
|
|
6259
6992
|
const cacheKey = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getCacheKey).call(this, network, userAddress);
|
|
6260
6993
|
// Check GLOBAL cache first to avoid repeated signing requests across reconnections
|
|
6261
6994
|
// This is CRITICAL for hardware wallets to prevent repeated signing prompts
|
|
@@ -6272,6 +7005,11 @@ async function _HyperLiquidProvider_ensureBuilderFeeApproval() {
|
|
|
6272
7005
|
if (inFlightPromise) {
|
|
6273
7006
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureBuilderFeeApproval] Global in-flight, waiting...', { network });
|
|
6274
7007
|
await inFlightPromise;
|
|
7008
|
+
const completedApproval = TradingReadinessCache_js_1.PerpsSigningCache.getBuilderFee(network, userAddress);
|
|
7009
|
+
if (completedApproval?.attempted && completedApproval.success) {
|
|
7010
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").set(cacheKey, true);
|
|
7011
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_approvedBuilderAddresses, "f").add(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getApprovedBuilderKey).call(this, network, userAddress, builderAddress));
|
|
7012
|
+
}
|
|
6275
7013
|
return;
|
|
6276
7014
|
}
|
|
6277
7015
|
// Set global in-flight lock
|
|
@@ -6281,10 +7019,13 @@ async function _HyperLiquidProvider_ensureBuilderFeeApproval() {
|
|
|
6281
7019
|
const recheckCache = TradingReadinessCache_js_1.PerpsSigningCache.getBuilderFee(network, userAddress);
|
|
6282
7020
|
if (recheckCache?.attempted && recheckCache?.success) {
|
|
6283
7021
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureBuilderFeeApproval] Completed by another provider', { network });
|
|
7022
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").set(cacheKey, true);
|
|
7023
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_approvedBuilderAddresses, "f").add(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getApprovedBuilderKey).call(this, network, userAddress, builderAddress));
|
|
6284
7024
|
completeInFlight();
|
|
6285
7025
|
return;
|
|
6286
7026
|
}
|
|
6287
7027
|
const { isApproved, requiredDecimal } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_checkBuilderFeeStatus).call(this, builderAddress, userAddress);
|
|
7028
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Builder fee approval');
|
|
6288
7029
|
if (isApproved) {
|
|
6289
7030
|
// User already has approval on-chain
|
|
6290
7031
|
TradingReadinessCache_js_1.PerpsSigningCache.setBuilderFee(network, userAddress, {
|
|
@@ -6309,11 +7050,15 @@ async function _HyperLiquidProvider_ensureBuilderFeeApproval() {
|
|
|
6309
7050
|
afterApprovalDecimal < requiredDecimal) {
|
|
6310
7051
|
throw new Error('[HyperLiquidProvider] Builder fee approval verification failed');
|
|
6311
7052
|
}
|
|
6312
|
-
//
|
|
7053
|
+
// The approval is already confirmed on-chain. Preserve that fact for
|
|
7054
|
+
// the next provider lifecycle even if this instance became stale while
|
|
7055
|
+
// the approval request was in flight.
|
|
6313
7056
|
TradingReadinessCache_js_1.PerpsSigningCache.setBuilderFee(network, userAddress, {
|
|
6314
7057
|
attempted: true,
|
|
6315
7058
|
success: true,
|
|
6316
7059
|
});
|
|
7060
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_assertProviderLifecycleCurrent).call(this, lifecycleGeneration, 'Builder fee approval');
|
|
7061
|
+
// Cache success in the current instance after the lifecycle check.
|
|
6317
7062
|
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").set(cacheKey, true);
|
|
6318
7063
|
__classPrivateFieldGet(this, _HyperLiquidProvider_approvedBuilderAddresses, "f").add(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getApprovedBuilderKey).call(this, network, userAddress, builderAddress));
|
|
6319
7064
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[ensureBuilderFeeApproval] Approval successful', {
|
|
@@ -6324,6 +7069,11 @@ async function _HyperLiquidProvider_ensureBuilderFeeApproval() {
|
|
|
6324
7069
|
completeInFlight();
|
|
6325
7070
|
}
|
|
6326
7071
|
catch (error) {
|
|
7072
|
+
if ((0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.ensureBuilderFeeApproval')
|
|
7073
|
+
.message === perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE) {
|
|
7074
|
+
completeInFlight();
|
|
7075
|
+
return;
|
|
7076
|
+
}
|
|
6327
7077
|
// HyperLiquid wraps wallet signing failures and preserves KEYRING_LOCKED
|
|
6328
7078
|
// in `cause`, so classify the full chain and leave retry caches empty.
|
|
6329
7079
|
if ((0, errorUtils_js_1.isKeyringLockedError)(error)) {
|
|
@@ -6661,6 +7411,7 @@ async function _HyperLiquidProvider_calculateHip3RequiredMargin(params) {
|
|
|
6661
7411
|
* @param params.transferInfo - The transfer information.
|
|
6662
7412
|
* @param params.transferInfo.amount - The amount value.
|
|
6663
7413
|
* @param params.transferInfo.sourceDex - The source DEX for the transfer.
|
|
7414
|
+
* @returns Whether the balance check and any required transfer succeeded.
|
|
6664
7415
|
* @private
|
|
6665
7416
|
*/
|
|
6666
7417
|
async function _HyperLiquidProvider_handleHip3PostOrderRebalance(params) {
|
|
@@ -6689,16 +7440,20 @@ async function _HyperLiquidProvider_handleHip3PostOrderRebalance(params) {
|
|
|
6689
7440
|
excessAmount: excessAmount.toFixed(2),
|
|
6690
7441
|
destinationDex: transferInfo.sourceDex,
|
|
6691
7442
|
});
|
|
6692
|
-
await this.transferBetweenDexs({
|
|
7443
|
+
const transferResult = await this.transferBetweenDexs({
|
|
6693
7444
|
sourceDex: dexName,
|
|
6694
7445
|
destinationDex: transferInfo.sourceDex,
|
|
6695
7446
|
amount: excessAmount.toFixed(hyperLiquidConfig_js_1.USDC_DECIMALS),
|
|
6696
7447
|
});
|
|
7448
|
+
if (!transferResult.success) {
|
|
7449
|
+
throw new Error(transferResult.error ?? perpsErrorCodes_js_1.PERPS_ERROR_CODES.TRANSFER_FAILED);
|
|
7450
|
+
}
|
|
6697
7451
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('✅ HyperLiquidProvider: Auto-rebalance completed', {
|
|
6698
7452
|
transferredBack: excessAmount.toFixed(2),
|
|
6699
7453
|
from: dexName,
|
|
6700
7454
|
to: transferInfo.sourceDex,
|
|
6701
7455
|
});
|
|
7456
|
+
return true;
|
|
6702
7457
|
}
|
|
6703
7458
|
catch (rebalanceError) {
|
|
6704
7459
|
// Don't fail the order if rebalance fails (order already succeeded)
|
|
@@ -6707,6 +7462,7 @@ async function _HyperLiquidProvider_handleHip3PostOrderRebalance(params) {
|
|
|
6707
7462
|
excessAmount: excessAmount.toFixed(2),
|
|
6708
7463
|
note: 'Auto-rebalance failed - funds remain on HIP-3 DEX',
|
|
6709
7464
|
}));
|
|
7465
|
+
return false;
|
|
6710
7466
|
}
|
|
6711
7467
|
}
|
|
6712
7468
|
else {
|
|
@@ -6715,6 +7471,7 @@ async function _HyperLiquidProvider_handleHip3PostOrderRebalance(params) {
|
|
|
6715
7471
|
threshold: minimumTransferThreshold.toFixed(2),
|
|
6716
7472
|
note: 'Excess below minimum transfer threshold',
|
|
6717
7473
|
});
|
|
7474
|
+
return true;
|
|
6718
7475
|
}
|
|
6719
7476
|
}
|
|
6720
7477
|
catch (balanceCheckError) {
|
|
@@ -6723,6 +7480,7 @@ async function _HyperLiquidProvider_handleHip3PostOrderRebalance(params) {
|
|
|
6723
7480
|
dex: dexName,
|
|
6724
7481
|
note: 'Failed to verify post-order balance for auto-rebalance',
|
|
6725
7482
|
}));
|
|
7483
|
+
return false;
|
|
6726
7484
|
}
|
|
6727
7485
|
}, _HyperLiquidProvider_handleHip3OrderRollback =
|
|
6728
7486
|
/**
|
|
@@ -6906,7 +7664,10 @@ async function _HyperLiquidProvider_handleHip3PreOrder(params) {
|
|
|
6906
7664
|
async function _HyperLiquidProvider_submitOrderWithRollback(params) {
|
|
6907
7665
|
const { orders, grouping, isHip3Order, dexName, transferInfo, symbol } = params;
|
|
6908
7666
|
const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
|
|
6909
|
-
const builder =
|
|
7667
|
+
const builder = params.chargesMetamaskBuilderFee
|
|
7668
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderOrderContext).call(this, params.builderFeeSetupContext ??
|
|
7669
|
+
(await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureBuilderFeeSetup).call(this)))
|
|
7670
|
+
: undefined;
|
|
6910
7671
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Submitting order via asset ID routing', {
|
|
6911
7672
|
symbol,
|
|
6912
7673
|
assetId: orders[0].a,
|
|
@@ -6919,7 +7680,7 @@ async function _HyperLiquidProvider_submitOrderWithRollback(params) {
|
|
|
6919
7680
|
const result = await exchangeClient.order({
|
|
6920
7681
|
orders,
|
|
6921
7682
|
grouping,
|
|
6922
|
-
builder,
|
|
7683
|
+
...(builder && { builder }),
|
|
6923
7684
|
});
|
|
6924
7685
|
if (result.status !== 'ok') {
|
|
6925
7686
|
throw new Error(`Order failed: ${JSON.stringify(result)}`);
|
|
@@ -6994,18 +7755,22 @@ async function _HyperLiquidProvider_handleOrderError(params) {
|
|
|
6994
7755
|
async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
|
|
6995
7756
|
// Captured before the shared preamble, not after it: that preamble awaits
|
|
6996
7757
|
// asset info, validation, trading readiness and a leverage update, and a
|
|
6997
|
-
// disconnect during any of them has to be seen
|
|
6998
|
-
|
|
7758
|
+
// disconnect during any of them has to be seen before or after submission.
|
|
7759
|
+
const generation = __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f");
|
|
6999
7760
|
if (orderType !== 'chase') {
|
|
7000
7761
|
const context = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareStrategyPlacement).call(this, params);
|
|
7001
|
-
return
|
|
7002
|
-
|
|
7003
|
-
|
|
7762
|
+
return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_submitPreparedStrategy).call(this, params, context, async () => {
|
|
7763
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
7764
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE);
|
|
7765
|
+
}
|
|
7766
|
+
return orderType === 'twap'
|
|
7767
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeTwapOrder).call(this, params, context, generation)
|
|
7768
|
+
: await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_placeScaleOrder).call(this, params, context, generation);
|
|
7769
|
+
});
|
|
7004
7770
|
}
|
|
7005
7771
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") > 0) {
|
|
7006
7772
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
|
|
7007
7773
|
}
|
|
7008
|
-
const generation = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f");
|
|
7009
7774
|
// The chase slot is claimed before the preamble, not after it: the preamble
|
|
7010
7775
|
// completes the signing setup and can change the asset's leverage, and a
|
|
7011
7776
|
// request that is going to be refused for exceeding the venue's cap must
|
|
@@ -7027,7 +7792,7 @@ async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
|
|
|
7027
7792
|
try {
|
|
7028
7793
|
await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
|
|
7029
7794
|
const context = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_prepareStrategyPlacement).call(this, params);
|
|
7030
|
-
return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_startChaseSession).call(this, params, context, generation);
|
|
7795
|
+
return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_submitPreparedStrategy).call(this, params, context, async () => await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_startChaseSession).call(this, params, context, generation));
|
|
7031
7796
|
}
|
|
7032
7797
|
finally {
|
|
7033
7798
|
settlePlacement?.();
|
|
@@ -7037,6 +7802,74 @@ async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
|
|
|
7037
7802
|
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resumeChaseTicksAfterPlacement).call(this);
|
|
7038
7803
|
}
|
|
7039
7804
|
}
|
|
7805
|
+
}, _HyperLiquidProvider_submitPreparedStrategy =
|
|
7806
|
+
/**
|
|
7807
|
+
* Submit a prepared strategy and settle any manual HIP-3 collateral move.
|
|
7808
|
+
*
|
|
7809
|
+
* Scale and Chase leave regular orders or fills on the venue, so the normal
|
|
7810
|
+
* HIP-3 post-order balance check can return any unreserved excess. Native
|
|
7811
|
+
* TWAP executes future slices, so its transferred collateral stays on the
|
|
7812
|
+
* routed DEX until cancellation confirms the schedule has stopped.
|
|
7813
|
+
*
|
|
7814
|
+
* @param params - Strategy order parameters.
|
|
7815
|
+
* @param context - Prepared placement and HIP-3 transfer context.
|
|
7816
|
+
* @param submit - Venue submission.
|
|
7817
|
+
* @returns The strategy placement result.
|
|
7818
|
+
*/
|
|
7819
|
+
async function _HyperLiquidProvider_submitPreparedStrategy(params, context, submit) {
|
|
7820
|
+
const { dexName, network, transferInfo, userAddress } = context;
|
|
7821
|
+
let result;
|
|
7822
|
+
try {
|
|
7823
|
+
result = await submit();
|
|
7824
|
+
}
|
|
7825
|
+
catch (error) {
|
|
7826
|
+
if (dexName && transferInfo) {
|
|
7827
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_handleHip3OrderRollback).call(this, { dexName, transferInfo });
|
|
7828
|
+
}
|
|
7829
|
+
throw error;
|
|
7830
|
+
}
|
|
7831
|
+
const hasVenueExposure = result.success === true ||
|
|
7832
|
+
result.orderId !== undefined ||
|
|
7833
|
+
(result.childOrderIds?.length ?? 0) > 0;
|
|
7834
|
+
if (dexName && transferInfo && !hasVenueExposure) {
|
|
7835
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_handleHip3OrderRollback).call(this, { dexName, transferInfo });
|
|
7836
|
+
return result;
|
|
7837
|
+
}
|
|
7838
|
+
if (params.orderType === 'twap' && result.orderId) {
|
|
7839
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").set(getTwapOrderScopeKey({
|
|
7840
|
+
network,
|
|
7841
|
+
userAddress,
|
|
7842
|
+
orderId: result.orderId,
|
|
7843
|
+
}), {
|
|
7844
|
+
symbol: params.symbol,
|
|
7845
|
+
...(dexName && transferInfo
|
|
7846
|
+
? { hip3Transfer: { dexName, transferInfo } }
|
|
7847
|
+
: {}),
|
|
7848
|
+
});
|
|
7849
|
+
return result;
|
|
7850
|
+
}
|
|
7851
|
+
if (params.orderType === 'chase' &&
|
|
7852
|
+
result.success &&
|
|
7853
|
+
result.orderId &&
|
|
7854
|
+
dexName &&
|
|
7855
|
+
transferInfo) {
|
|
7856
|
+
const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(result.orderId);
|
|
7857
|
+
if (session) {
|
|
7858
|
+
session.hip3Transfer = { dexName, transferInfo };
|
|
7859
|
+
return result;
|
|
7860
|
+
}
|
|
7861
|
+
}
|
|
7862
|
+
if (params.orderType === 'chase' && hasVenueExposure) {
|
|
7863
|
+
// A stale placement can fail after its child rests and the best-effort
|
|
7864
|
+
// retraction is refused. With no session left to own that child, keep
|
|
7865
|
+
// manual HIP-3 collateral on its DEX until the caller cancels the
|
|
7866
|
+
// reported exchange ID.
|
|
7867
|
+
return result;
|
|
7868
|
+
}
|
|
7869
|
+
if (dexName && transferInfo) {
|
|
7870
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_handleHip3PostOrderRebalance).call(this, { dexName, transferInfo });
|
|
7871
|
+
}
|
|
7872
|
+
return result;
|
|
7040
7873
|
}, _HyperLiquidProvider_prepareStrategyPlacement =
|
|
7041
7874
|
/**
|
|
7042
7875
|
* Run the shared preamble every strategy placement needs.
|
|
@@ -7050,13 +7883,6 @@ async function _HyperLiquidProvider_placeStrategyOrder(params, orderType) {
|
|
|
7050
7883
|
*/
|
|
7051
7884
|
async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
|
|
7052
7885
|
const { dex: dexName } = (0, hyperLiquidAdapter_js_1.parseAssetName)(params.symbol);
|
|
7053
|
-
// A HIP-3 order is preceded by a margin transfer onto the builder DEX and
|
|
7054
|
-
// followed by a rebalance, both of which are wired into the single-order
|
|
7055
|
-
// submit path and its rollback. Rather than half-support that here, a
|
|
7056
|
-
// strategy placement on a HIP-3 market is refused outright.
|
|
7057
|
-
if (dexName !== null) {
|
|
7058
|
-
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_MARKET_UNSUPPORTED);
|
|
7059
|
-
}
|
|
7060
7886
|
const { assetInfo, currentPrice, meta } = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetInfo).call(this, {
|
|
7061
7887
|
symbol: params.symbol,
|
|
7062
7888
|
dexName,
|
|
@@ -7117,7 +7943,10 @@ async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
|
|
|
7117
7943
|
}
|
|
7118
7944
|
// Kept after validation so an invalid strategy order never triggers the
|
|
7119
7945
|
// signature prompts in trading setup — same ordering as `placeOrder`.
|
|
7120
|
-
|
|
7946
|
+
const { chargesMetamaskBuilderFee } = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_resolveOrderFeePolicy).call(this, params);
|
|
7947
|
+
const builderFeeSetupContext = chargesMetamaskBuilderFee
|
|
7948
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: true })
|
|
7949
|
+
: await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
7121
7950
|
const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
|
|
7122
7951
|
symbol: params.symbol,
|
|
7123
7952
|
dexName,
|
|
@@ -7128,12 +7957,38 @@ async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
|
|
|
7128
7957
|
assetId,
|
|
7129
7958
|
leverage: params.leverage,
|
|
7130
7959
|
});
|
|
7960
|
+
const builder = builderFeeSetupContext
|
|
7961
|
+
? await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderOrderContext).call(this, builderFeeSetupContext)
|
|
7962
|
+
: undefined;
|
|
7963
|
+
const network = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'testnet' : 'mainnet';
|
|
7964
|
+
const userAddress = builderFeeSetupContext?.userAddress ??
|
|
7965
|
+
(await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault());
|
|
7966
|
+
let transferInfo = null;
|
|
7967
|
+
if (dexName) {
|
|
7968
|
+
const orderPrice = ladder === undefined
|
|
7969
|
+
? effectivePrice
|
|
7970
|
+
: Math.max(...ladder.prices.map(Number.parseFloat));
|
|
7971
|
+
const hip3Result = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_handleHip3PreOrder).call(this, {
|
|
7972
|
+
dexName,
|
|
7973
|
+
symbol: params.symbol,
|
|
7974
|
+
orderPrice,
|
|
7975
|
+
positionSize: parseFloat(formattedSize),
|
|
7976
|
+
leverage: params.leverage ?? assetInfo.maxLeverage ?? 1,
|
|
7977
|
+
isBuy: params.isBuy,
|
|
7978
|
+
maxLeverage: assetInfo.maxLeverage,
|
|
7979
|
+
});
|
|
7980
|
+
transferInfo = hip3Result.transferInfo;
|
|
7981
|
+
}
|
|
7131
7982
|
return {
|
|
7132
7983
|
assetId,
|
|
7133
7984
|
szDecimals: assetInfo.szDecimals,
|
|
7134
|
-
finalPositionSize,
|
|
7135
7985
|
formattedSize,
|
|
7136
7986
|
ladder,
|
|
7987
|
+
builder,
|
|
7988
|
+
dexName,
|
|
7989
|
+
network,
|
|
7990
|
+
transferInfo,
|
|
7991
|
+
userAddress,
|
|
7137
7992
|
};
|
|
7138
7993
|
}, _HyperLiquidProvider_getMinimumOrderSize = function _HyperLiquidProvider_getMinimumOrderSize() {
|
|
7139
7994
|
return __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode()
|
|
@@ -7141,11 +7996,17 @@ async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
|
|
|
7141
7996
|
: hyperLiquidConfig_js_1.TRADING_DEFAULTS.amount.mainnet;
|
|
7142
7997
|
}, _HyperLiquidProvider_buildScaleLadder = function _HyperLiquidProvider_buildScaleLadder(options) {
|
|
7143
7998
|
const { params, szDecimals, finalPositionSize } = options;
|
|
7144
|
-
const
|
|
7999
|
+
const { scaleMinPrice, scaleMaxPrice, scaleNumOrders } = params;
|
|
8000
|
+
if (scaleMinPrice === undefined || scaleMaxPrice === undefined) {
|
|
8001
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_SCALE_RANGE_REQUIRED);
|
|
8002
|
+
}
|
|
8003
|
+
if (scaleNumOrders === undefined) {
|
|
8004
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_SCALE_COUNT_INVALID);
|
|
8005
|
+
}
|
|
7145
8006
|
const prices = (0, orderCalculations_js_1.computeScalePriceLadder)({
|
|
7146
|
-
minPrice: parseFloat(
|
|
7147
|
-
maxPrice: parseFloat(
|
|
7148
|
-
count,
|
|
8007
|
+
minPrice: parseFloat(scaleMinPrice),
|
|
8008
|
+
maxPrice: parseFloat(scaleMaxPrice),
|
|
8009
|
+
count: scaleNumOrders,
|
|
7149
8010
|
}).map((price) => (0, hyperLiquidAdapter_js_1.formatHyperLiquidPrice)({ price, szDecimals }));
|
|
7150
8011
|
if (new Set(prices).size !== prices.length) {
|
|
7151
8012
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_SCALE_RANGE_INVALID);
|
|
@@ -7154,7 +8015,7 @@ async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
|
|
|
7154
8015
|
// which a skew weighted far enough from even can do on its own.
|
|
7155
8016
|
const sizes = (0, orderCalculations_js_1.splitScaleSizes)({
|
|
7156
8017
|
totalSize: finalPositionSize,
|
|
7157
|
-
count,
|
|
8018
|
+
count: scaleNumOrders,
|
|
7158
8019
|
szDecimals,
|
|
7159
8020
|
skew: params.scaleSkew,
|
|
7160
8021
|
});
|
|
@@ -7174,16 +8035,26 @@ async function _HyperLiquidProvider_prepareStrategyPlacement(params) {
|
|
|
7174
8035
|
*
|
|
7175
8036
|
* @param params - Order parameters.
|
|
7176
8037
|
* @param context - Prepared asset and sizing context.
|
|
8038
|
+
* @param generation - Teardown generation captured before preparation.
|
|
7177
8039
|
* @returns A promise that resolves to the result.
|
|
7178
8040
|
*/
|
|
7179
|
-
async function _HyperLiquidProvider_placeTwapOrder(params, context) {
|
|
8041
|
+
async function _HyperLiquidProvider_placeTwapOrder(params, context, generation) {
|
|
7180
8042
|
const { assetId, formattedSize } = context;
|
|
8043
|
+
const durationMinutes = params.twapDuration;
|
|
8044
|
+
if (durationMinutes === undefined) {
|
|
8045
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TWAP_DURATION_REQUIRED);
|
|
8046
|
+
}
|
|
8047
|
+
if (!Number.isSafeInteger(durationMinutes) ||
|
|
8048
|
+
durationMinutes < perpsConfig_js_1.HYPERLIQUID_TWAP_LIMITS.MinDurationMinutes ||
|
|
8049
|
+
durationMinutes > perpsConfig_js_1.HYPERLIQUID_TWAP_LIMITS.MaxDurationMinutes) {
|
|
8050
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TWAP_DURATION_INVALID);
|
|
8051
|
+
}
|
|
7181
8052
|
const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
|
|
7182
8053
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Submitting TWAP order', {
|
|
7183
8054
|
symbol: params.symbol,
|
|
7184
8055
|
assetId,
|
|
7185
8056
|
size: formattedSize,
|
|
7186
|
-
durationMinutes
|
|
8057
|
+
durationMinutes,
|
|
7187
8058
|
randomize: params.twapRandomize ?? false,
|
|
7188
8059
|
});
|
|
7189
8060
|
const result = await exchangeClient.twapOrder({
|
|
@@ -7192,9 +8063,7 @@ async function _HyperLiquidProvider_placeTwapOrder(params, context) {
|
|
|
7192
8063
|
b: params.isBuy,
|
|
7193
8064
|
s: formattedSize,
|
|
7194
8065
|
r: params.reduceOnly ?? false,
|
|
7195
|
-
|
|
7196
|
-
// inside the venue's bounds.
|
|
7197
|
-
m: params.twapDuration,
|
|
8066
|
+
m: durationMinutes,
|
|
7198
8067
|
t: params.twapRandomize ?? false,
|
|
7199
8068
|
},
|
|
7200
8069
|
});
|
|
@@ -7202,15 +8071,44 @@ async function _HyperLiquidProvider_placeTwapOrder(params, context) {
|
|
|
7202
8071
|
throw new Error(`TWAP order failed: ${JSON.stringify(result)}`);
|
|
7203
8072
|
}
|
|
7204
8073
|
const status = result.response?.data?.status;
|
|
7205
|
-
if (!isStatusObject(status)
|
|
7206
|
-
|
|
7207
|
-
|
|
8074
|
+
if (!isStatusObject(status)) {
|
|
8075
|
+
throw new Error('TWAP order rejected');
|
|
8076
|
+
}
|
|
8077
|
+
const rawError = typeof status.error === 'string' ? status.error : 'TWAP order rejected';
|
|
8078
|
+
const { running } = status;
|
|
8079
|
+
if (!isStatusObject(running) ||
|
|
8080
|
+
typeof running.twapId !== 'number' ||
|
|
8081
|
+
!Number.isSafeInteger(running.twapId) ||
|
|
8082
|
+
running.twapId < 0) {
|
|
7208
8083
|
throw new Error(rawError);
|
|
7209
8084
|
}
|
|
7210
|
-
const
|
|
8085
|
+
const orderId = running.twapId.toString();
|
|
8086
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
8087
|
+
let remainsLive = true;
|
|
8088
|
+
try {
|
|
8089
|
+
const cancelResult = await exchangeClient.twapCancel({
|
|
8090
|
+
a: assetId,
|
|
8091
|
+
t: running.twapId,
|
|
8092
|
+
});
|
|
8093
|
+
remainsLive =
|
|
8094
|
+
classifyCancelStatus(cancelResult.response?.data?.status) ===
|
|
8095
|
+
CancelChildOutcome.Refused;
|
|
8096
|
+
}
|
|
8097
|
+
catch (error) {
|
|
8098
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Stale TWAP placement could not be retracted', {
|
|
8099
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.placeTwapOrder.retract').message,
|
|
8100
|
+
orderId,
|
|
8101
|
+
});
|
|
8102
|
+
}
|
|
8103
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE), {
|
|
8104
|
+
success: false,
|
|
8105
|
+
submittedSize: formattedSize,
|
|
8106
|
+
...(remainsLive && { orderId }),
|
|
8107
|
+
});
|
|
8108
|
+
}
|
|
7211
8109
|
return {
|
|
7212
8110
|
success: true,
|
|
7213
|
-
orderId
|
|
8111
|
+
orderId,
|
|
7214
8112
|
submittedSize: formattedSize,
|
|
7215
8113
|
};
|
|
7216
8114
|
}, _HyperLiquidProvider_placeScaleOrder =
|
|
@@ -7219,22 +8117,25 @@ async function _HyperLiquidProvider_placeTwapOrder(params, context) {
|
|
|
7219
8117
|
*
|
|
7220
8118
|
* The whole ladder goes in a single `order` action, which is one round trip
|
|
7221
8119
|
* and one signature rather than one per rung. It is **not** atomic: an `na`
|
|
7222
|
-
* grouping evaluates each entry independently
|
|
7223
|
-
*
|
|
7224
|
-
* such — `submittedSize` covers only the rungs that actually rested — rather
|
|
7225
|
-
* than as a full submission.
|
|
8120
|
+
* grouping evaluates each entry independently. Every rung must either rest
|
|
8121
|
+
* or fill; otherwise all known resting rungs are retracted before failure.
|
|
7226
8122
|
*
|
|
7227
8123
|
* @param params - Order parameters.
|
|
7228
8124
|
* @param context - Prepared asset and sizing context.
|
|
8125
|
+
* @param generation - Teardown generation captured before preparation.
|
|
7229
8126
|
* @returns A promise that resolves to the result.
|
|
7230
8127
|
*/
|
|
7231
|
-
async function _HyperLiquidProvider_placeScaleOrder(params, context) {
|
|
7232
|
-
const { assetId,
|
|
8128
|
+
async function _HyperLiquidProvider_placeScaleOrder(params, context, generation) {
|
|
8129
|
+
const { assetId, formattedSize, ladder, builder } = context;
|
|
7233
8130
|
// Built and validated in `#prepareStrategyPlacement`, before anything was
|
|
7234
8131
|
// signed, so what is submitted here is exactly what the minimums were
|
|
7235
8132
|
// applied to.
|
|
8133
|
+
if (!ladder) {
|
|
8134
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_SCALE_RANGE_REQUIRED);
|
|
8135
|
+
}
|
|
7236
8136
|
const { prices, sizes } = ladder;
|
|
7237
8137
|
const count = prices.length;
|
|
8138
|
+
const { groupId, clientOrderIds } = createScaleOrderIdentity(count);
|
|
7238
8139
|
const orders = prices.map((price, index) => ({
|
|
7239
8140
|
a: assetId,
|
|
7240
8141
|
b: params.isBuy,
|
|
@@ -7242,6 +8143,7 @@ async function _HyperLiquidProvider_placeScaleOrder(params, context) {
|
|
|
7242
8143
|
s: sizes[index],
|
|
7243
8144
|
r: params.reduceOnly ?? false,
|
|
7244
8145
|
t: { limit: { tif: 'Gtc' } },
|
|
8146
|
+
c: clientOrderIds[index],
|
|
7245
8147
|
}));
|
|
7246
8148
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Submitting scale ladder', {
|
|
7247
8149
|
symbol: params.symbol,
|
|
@@ -7254,50 +8156,81 @@ async function _HyperLiquidProvider_placeScaleOrder(params, context) {
|
|
|
7254
8156
|
const result = await exchangeClient.order({
|
|
7255
8157
|
orders,
|
|
7256
8158
|
grouping: 'na',
|
|
7257
|
-
builder
|
|
8159
|
+
...(builder && { builder }),
|
|
7258
8160
|
});
|
|
7259
|
-
if (result.status !== 'ok') {
|
|
7260
|
-
throw new Error(`Scale order failed: ${JSON.stringify(result)}`);
|
|
7261
|
-
}
|
|
7262
8161
|
const statuses = result.response?.data?.statuses ?? [];
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
.
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
8162
|
+
const outcomes = statuses
|
|
8163
|
+
.slice(0, count)
|
|
8164
|
+
.map((status) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderPlacementOutcome).call(this, status));
|
|
8165
|
+
const acceptedCount = outcomes.filter((outcome) => outcome !== undefined).length;
|
|
8166
|
+
const restingChildOrderIds = outcomes.flatMap((outcome) => outcome?.state === 'resting' ? [outcome.orderId] : []);
|
|
8167
|
+
const filledChildOrderIds = outcomes.flatMap((outcome) => outcome?.state === 'filled' ? [outcome.orderId] : []);
|
|
8168
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
8169
|
+
const remainingOrderIds = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequests).call(this, exchangeClient, restingChildOrderIds.map((orderId) => ({
|
|
8170
|
+
a: assetId,
|
|
8171
|
+
o: Number(orderId),
|
|
8172
|
+
})));
|
|
8173
|
+
const recoverableOrderIds = [
|
|
8174
|
+
...filledChildOrderIds,
|
|
8175
|
+
...remainingOrderIds.map(String),
|
|
8176
|
+
];
|
|
8177
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.PROVIDER_LIFECYCLE_STALE), {
|
|
8178
|
+
success: false,
|
|
8179
|
+
submittedSize: formattedSize,
|
|
8180
|
+
...(recoverableOrderIds.length > 0 && {
|
|
8181
|
+
childOrderIds: recoverableOrderIds,
|
|
8182
|
+
}),
|
|
8183
|
+
});
|
|
8184
|
+
}
|
|
8185
|
+
if (result.status !== 'ok' ||
|
|
8186
|
+
statuses.length !== count ||
|
|
8187
|
+
acceptedCount !== count) {
|
|
8188
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Scale ladder was not fully accepted', {
|
|
8189
|
+
accepted: acceptedCount,
|
|
8190
|
+
filled: filledChildOrderIds.length,
|
|
8191
|
+
resting: restingChildOrderIds.length,
|
|
7287
8192
|
requested: count,
|
|
7288
8193
|
statuses,
|
|
7289
8194
|
});
|
|
8195
|
+
const remainingOrderIds = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequests).call(this, exchangeClient, restingChildOrderIds.map((orderId) => ({
|
|
8196
|
+
a: assetId,
|
|
8197
|
+
o: Number(orderId),
|
|
8198
|
+
})));
|
|
8199
|
+
const recoverableOrderIds = [
|
|
8200
|
+
...filledChildOrderIds,
|
|
8201
|
+
...remainingOrderIds.map(String),
|
|
8202
|
+
];
|
|
8203
|
+
if (remainingOrderIds.length > 0) {
|
|
8204
|
+
const remainingRestingOrderIds = remainingOrderIds.map(String);
|
|
8205
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").set(groupId, {
|
|
8206
|
+
symbol: params.symbol,
|
|
8207
|
+
orderIds: remainingRestingOrderIds,
|
|
8208
|
+
});
|
|
8209
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_CANCEL_INCOMPLETE), {
|
|
8210
|
+
success: false,
|
|
8211
|
+
orderId: groupId,
|
|
8212
|
+
childOrderIds: recoverableOrderIds,
|
|
8213
|
+
submittedSize: formattedSize,
|
|
8214
|
+
});
|
|
8215
|
+
}
|
|
8216
|
+
if (recoverableOrderIds.length > 0) {
|
|
8217
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_REJECTED), {
|
|
8218
|
+
success: false,
|
|
8219
|
+
childOrderIds: recoverableOrderIds,
|
|
8220
|
+
submittedSize: formattedSize,
|
|
8221
|
+
});
|
|
8222
|
+
}
|
|
8223
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_REJECTED);
|
|
7290
8224
|
}
|
|
8225
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").set(groupId, {
|
|
8226
|
+
symbol: params.symbol,
|
|
8227
|
+
orderIds: restingChildOrderIds,
|
|
8228
|
+
});
|
|
7291
8229
|
return {
|
|
7292
8230
|
success: true,
|
|
7293
8231
|
orderId: groupId,
|
|
7294
|
-
childOrderIds,
|
|
7295
|
-
submittedSize:
|
|
7296
|
-
? (0, hyperLiquidAdapter_js_1.formatHyperLiquidSize)({
|
|
7297
|
-
size: restedRungs.reduce((total, rung) => total + parseFloat(rung.size), 0),
|
|
7298
|
-
szDecimals,
|
|
7299
|
-
})
|
|
7300
|
-
: formattedSize,
|
|
8232
|
+
childOrderIds: restingChildOrderIds,
|
|
8233
|
+
submittedSize: formattedSize,
|
|
7301
8234
|
};
|
|
7302
8235
|
}, _HyperLiquidProvider_startChaseSession =
|
|
7303
8236
|
/**
|
|
@@ -7312,12 +8245,12 @@ async function _HyperLiquidProvider_placeScaleOrder(params, context) {
|
|
|
7312
8245
|
* @returns A promise that resolves to the result.
|
|
7313
8246
|
*/
|
|
7314
8247
|
async function _HyperLiquidProvider_startChaseSession(params, context, generation) {
|
|
7315
|
-
const { assetId, szDecimals, formattedSize } = context;
|
|
8248
|
+
const { assetId, szDecimals, formattedSize, builder } = context;
|
|
7316
8249
|
// The preamble is several round trips long. A disconnect during it has
|
|
7317
8250
|
// already torn down everything this session would run on, so the chase
|
|
7318
8251
|
// stops here rather than reading the book and putting a fresh order on it
|
|
7319
8252
|
// for a provider that no longer exists.
|
|
7320
|
-
if (generation !== __classPrivateFieldGet(this,
|
|
8253
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
7321
8254
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
|
|
7322
8255
|
}
|
|
7323
8256
|
let quotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
|
|
@@ -7325,8 +8258,9 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7325
8258
|
isBuy: params.isBuy,
|
|
7326
8259
|
szDecimals,
|
|
7327
8260
|
});
|
|
7328
|
-
if (quotePrice ===
|
|
7329
|
-
|
|
8261
|
+
if (quotePrice === CHASE_ORDER_STATUS_UNAVAILABLE ||
|
|
8262
|
+
typeof quotePrice !== 'string') {
|
|
8263
|
+
// A first placement has no child whose terminal state could be read.
|
|
7330
8264
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_TOUCH_UNAVAILABLE);
|
|
7331
8265
|
}
|
|
7332
8266
|
// The book read is a round trip of its own, so the check above does not
|
|
@@ -7335,12 +8269,7 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7335
8269
|
// before the next one, leaving one window that cannot be closed from here
|
|
7336
8270
|
// — a disconnect arriving while the submission itself is in flight, which
|
|
7337
8271
|
// the check after it handles.
|
|
7338
|
-
if (generation !== __classPrivateFieldGet(this,
|
|
7339
|
-
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
|
|
7340
|
-
}
|
|
7341
|
-
// Read once, while the caller's fee-source context is still set.
|
|
7342
|
-
const builder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderOrderContext).call(this);
|
|
7343
|
-
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_chaseGeneration, "f")) {
|
|
8272
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
7344
8273
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
|
|
7345
8274
|
}
|
|
7346
8275
|
// Held onto rather than looked up again after the submission returns.
|
|
@@ -7358,8 +8287,7 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7358
8287
|
price: quotePrice,
|
|
7359
8288
|
size: formattedSize,
|
|
7360
8289
|
reduceOnly: params.reduceOnly ?? false,
|
|
7361
|
-
|
|
7362
|
-
builderAddress: builder.b,
|
|
8290
|
+
builder,
|
|
7363
8291
|
exchangeClient: placingClient,
|
|
7364
8292
|
});
|
|
7365
8293
|
break;
|
|
@@ -7369,7 +8297,7 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7369
8297
|
!isRetryableChasePlacementError(error)) {
|
|
7370
8298
|
throw error;
|
|
7371
8299
|
}
|
|
7372
|
-
if (generation !== __classPrivateFieldGet(this,
|
|
8300
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
7373
8301
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
|
|
7374
8302
|
}
|
|
7375
8303
|
const refreshedQuote = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
|
|
@@ -7377,10 +8305,11 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7377
8305
|
isBuy: params.isBuy,
|
|
7378
8306
|
szDecimals,
|
|
7379
8307
|
});
|
|
7380
|
-
if (refreshedQuote ===
|
|
8308
|
+
if (refreshedQuote === CHASE_ORDER_STATUS_UNAVAILABLE ||
|
|
8309
|
+
typeof refreshedQuote !== 'string') {
|
|
7381
8310
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_TOUCH_UNAVAILABLE);
|
|
7382
8311
|
}
|
|
7383
|
-
if (generation !== __classPrivateFieldGet(this,
|
|
8312
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
7384
8313
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_CHASE_ABANDONED);
|
|
7385
8314
|
}
|
|
7386
8315
|
quotePrice = refreshedQuote;
|
|
@@ -7408,11 +8337,11 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7408
8337
|
maxDistanceBps: params.chaseMaxDistanceBps,
|
|
7409
8338
|
intervalMs,
|
|
7410
8339
|
lastSnapshotSizeRefreshAt: 0,
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
(params.chaseMaxDurationMs
|
|
7415
|
-
maxRepricings: params.chaseMaxRepricings ??
|
|
8340
|
+
builder,
|
|
8341
|
+
deadline: params.chaseMaxDurationMs === undefined
|
|
8342
|
+
? Number.POSITIVE_INFINITY
|
|
8343
|
+
: Date.now() + params.chaseMaxDurationMs,
|
|
8344
|
+
maxRepricings: params.chaseMaxRepricings ?? Number.POSITIVE_INFINITY,
|
|
7416
8345
|
repricings: 0,
|
|
7417
8346
|
timer: null,
|
|
7418
8347
|
active: true,
|
|
@@ -7431,7 +8360,7 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7431
8360
|
// and the failure is then true of the venue as well as of this provider.
|
|
7432
8361
|
// Best-effort still: the transport underneath that client may already be
|
|
7433
8362
|
// closing, so a cancel that does not land falls back to reporting the id.
|
|
7434
|
-
if (generation !== __classPrivateFieldGet(this,
|
|
8363
|
+
if (generation !== __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f")) {
|
|
7435
8364
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase placement outlived its provider', {
|
|
7436
8365
|
orderId,
|
|
7437
8366
|
restingPrice: quotePrice,
|
|
@@ -7443,7 +8372,9 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7443
8372
|
// that is no longer on the book would send the caller to cancel
|
|
7444
8373
|
// something already gone; naming one that still rests is the only
|
|
7445
8374
|
// route left to it.
|
|
7446
|
-
...(outcome ===
|
|
8375
|
+
...(outcome === CancelChildOutcome.Refused
|
|
8376
|
+
? { childOrderIds: [orderId] }
|
|
8377
|
+
: {}),
|
|
7447
8378
|
submittedSize: formattedSize,
|
|
7448
8379
|
});
|
|
7449
8380
|
}
|
|
@@ -7479,8 +8410,8 @@ async function _HyperLiquidProvider_startChaseSession(params, context, generatio
|
|
|
7479
8410
|
* @param params.own.orderId - Exchange ID of that order.
|
|
7480
8411
|
* @param params.own.price - Price that order rests at.
|
|
7481
8412
|
* @param params.own.size - Size it was last placed for.
|
|
7482
|
-
* @returns The formatted price
|
|
7483
|
-
*
|
|
8413
|
+
* @returns The formatted price, a terminal child result, or the status
|
|
8414
|
+
* unavailable sentinel when the child may still be live.
|
|
7484
8415
|
*/
|
|
7485
8416
|
async function _HyperLiquidProvider_getChaseQuotePrice(params) {
|
|
7486
8417
|
const { symbol, isBuy, szDecimals, own } = params;
|
|
@@ -7495,8 +8426,9 @@ async function _HyperLiquidProvider_getChaseQuotePrice(params) {
|
|
|
7495
8426
|
callerOrderId: own?.orderId,
|
|
7496
8427
|
ownSide,
|
|
7497
8428
|
});
|
|
7498
|
-
if (netting ===
|
|
7499
|
-
|
|
8429
|
+
if (netting === CHASE_ORDER_STATUS_UNAVAILABLE ||
|
|
8430
|
+
!(netting instanceof Map)) {
|
|
8431
|
+
return netting;
|
|
7500
8432
|
}
|
|
7501
8433
|
const bestBid = readBestExternalPrice(book?.levels?.[0], netting);
|
|
7502
8434
|
const bestAsk = readBestExternalPrice(book?.levels?.[1], netting);
|
|
@@ -7514,9 +8446,7 @@ async function _HyperLiquidProvider_getChaseQuotePrice(params) {
|
|
|
7514
8446
|
* @param params.price - Formatted limit price.
|
|
7515
8447
|
* @param params.size - Formatted size.
|
|
7516
8448
|
* @param params.reduceOnly - Whether the order may only reduce a position.
|
|
7517
|
-
* @param params.
|
|
7518
|
-
* when the session started so replacements keep the rate they were quoted at.
|
|
7519
|
-
* @param params.builderAddress - Builder address captured with the fee.
|
|
8449
|
+
* @param params.builder - Builder context captured when the session started.
|
|
7520
8450
|
* @param params.exchangeClient - Client to submit through. Passed in rather
|
|
7521
8451
|
* than looked up here so a first placement can keep the instance it signed
|
|
7522
8452
|
* with, which is the only one that can take the order back once `disconnect`
|
|
@@ -7538,10 +8468,7 @@ async function _HyperLiquidProvider_restChaseOrder(params) {
|
|
|
7538
8468
|
},
|
|
7539
8469
|
],
|
|
7540
8470
|
grouping: 'na',
|
|
7541
|
-
builder:
|
|
7542
|
-
b: params.builderAddress,
|
|
7543
|
-
f: params.builderFee,
|
|
7544
|
-
},
|
|
8471
|
+
...(params.builder && { builder: params.builder }),
|
|
7545
8472
|
});
|
|
7546
8473
|
if (result.status !== 'ok') {
|
|
7547
8474
|
throw new Error(`Chase order failed: ${JSON.stringify(result)}`);
|
|
@@ -7553,25 +8480,21 @@ async function _HyperLiquidProvider_restChaseOrder(params) {
|
|
|
7553
8480
|
return orderId;
|
|
7554
8481
|
}, _HyperLiquidProvider_scheduleChaseTick = function _HyperLiquidProvider_scheduleChaseTick(sessionId) {
|
|
7555
8482
|
const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
|
|
7556
|
-
if (!session?.active) {
|
|
8483
|
+
if (!session?.active || session.timer !== null) {
|
|
7557
8484
|
return;
|
|
7558
8485
|
}
|
|
7559
8486
|
const timer = setTimeout(() => {
|
|
7560
8487
|
session.timer = null;
|
|
7561
|
-
__classPrivateFieldSet(this, _HyperLiquidProvider_chaseTickQueue, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f")
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
});
|
|
7572
|
-
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_recoverFailedChaseTick).call(this, sessionId);
|
|
7573
|
-
}
|
|
7574
|
-
return undefined;
|
|
8488
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_chaseTickQueue, __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f")
|
|
8489
|
+
.then(() => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_runChaseTick).call(this, sessionId))
|
|
8490
|
+
.catch((error) => {
|
|
8491
|
+
// Resolve the shared queue after every failure. Otherwise one
|
|
8492
|
+
// rejected tick prevents all later ticks and teardown from running.
|
|
8493
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase tick failed', {
|
|
8494
|
+
sessionId,
|
|
8495
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.chaseTick').message,
|
|
8496
|
+
});
|
|
8497
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_recoverFailedChaseTick).call(this, sessionId);
|
|
7575
8498
|
}), "f");
|
|
7576
8499
|
}, session.intervalMs);
|
|
7577
8500
|
// Node keeps the process alive for a pending timer; a background chase is
|
|
@@ -7603,6 +8526,12 @@ async function _HyperLiquidProvider_restChaseOrder(params) {
|
|
|
7603
8526
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase ended with nothing resting', {
|
|
7604
8527
|
sessionId,
|
|
7605
8528
|
});
|
|
8529
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session).catch((error) => {
|
|
8530
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase collateral cleanup failed', {
|
|
8531
|
+
sessionId,
|
|
8532
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.recoverFailedChaseTick').message,
|
|
8533
|
+
});
|
|
8534
|
+
});
|
|
7606
8535
|
return;
|
|
7607
8536
|
}
|
|
7608
8537
|
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
|
|
@@ -7636,6 +8565,7 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7636
8565
|
session.active = false;
|
|
7637
8566
|
session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.DurationReached;
|
|
7638
8567
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase session window closed', { sessionId });
|
|
8568
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
7639
8569
|
return;
|
|
7640
8570
|
}
|
|
7641
8571
|
const rawQuotePrice = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getChaseQuotePrice).call(this, {
|
|
@@ -7650,16 +8580,29 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7650
8580
|
}
|
|
7651
8581
|
: undefined,
|
|
7652
8582
|
});
|
|
7653
|
-
if (rawQuotePrice
|
|
7654
|
-
// The order left the book without the loop seeing it
|
|
7655
|
-
//
|
|
7656
|
-
// holding one until the window closes.
|
|
8583
|
+
if (typeof rawQuotePrice !== 'string') {
|
|
8584
|
+
// The order left the book without the loop seeing it. Preserve the venue
|
|
8585
|
+
// status so an external cancellation is not reported as a fill.
|
|
7657
8586
|
session.orderId = null;
|
|
7658
8587
|
session.active = false;
|
|
7659
|
-
session.status =
|
|
7660
|
-
|
|
8588
|
+
session.status = rawQuotePrice.status;
|
|
8589
|
+
session.size = rawQuotePrice.remainingSize ?? '0';
|
|
8590
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order ended between ticks', {
|
|
8591
|
+
sessionId,
|
|
8592
|
+
status: session.status,
|
|
8593
|
+
});
|
|
8594
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
8595
|
+
return;
|
|
8596
|
+
}
|
|
8597
|
+
if (rawQuotePrice === CHASE_ORDER_STATUS_UNAVAILABLE) {
|
|
8598
|
+
// The child may still be live. Leave it untouched and retry on the next
|
|
8599
|
+
// normal interval instead of permanently stranding the Chase after one
|
|
8600
|
+
// short status outage.
|
|
8601
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order status unavailable', {
|
|
7661
8602
|
sessionId,
|
|
8603
|
+
orderId: session.orderId,
|
|
7662
8604
|
});
|
|
8605
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
|
|
7663
8606
|
return;
|
|
7664
8607
|
}
|
|
7665
8608
|
const arrivalPrice = Number.parseFloat(session.arrivalPrice);
|
|
@@ -7717,12 +8660,12 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7717
8660
|
// A refused cancel leaves the child resting. Preserve its ID so the
|
|
7718
8661
|
// caller that stopped this session can report an incomplete cancel and
|
|
7719
8662
|
// retry it instead of orphaning the order.
|
|
7720
|
-
if (outcome !==
|
|
8663
|
+
if (outcome !== CancelChildOutcome.Refused) {
|
|
7721
8664
|
session.orderId = null;
|
|
7722
8665
|
}
|
|
7723
8666
|
return;
|
|
7724
8667
|
}
|
|
7725
|
-
if (outcome ===
|
|
8668
|
+
if (outcome === CancelChildOutcome.Refused) {
|
|
7726
8669
|
// The exchange kept the order, so it is still resting at the old price.
|
|
7727
8670
|
// Placing the replacement anyway would double the position. Leave it
|
|
7728
8671
|
// alone and try again on the next tick, which is why this falls through
|
|
@@ -7733,25 +8676,36 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7733
8676
|
});
|
|
7734
8677
|
reachedMaxDistance = false;
|
|
7735
8678
|
}
|
|
7736
|
-
else if (outcome ===
|
|
8679
|
+
else if (outcome === CancelChildOutcome.Gone) {
|
|
7737
8680
|
// The order left the book between ticks: it filled, or something else
|
|
7738
8681
|
// cancelled it. There is nothing left to chase.
|
|
7739
8682
|
const goneOrderId = session.orderId;
|
|
7740
|
-
const remaining = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, goneOrderId);
|
|
7741
8683
|
session.orderId = null;
|
|
7742
8684
|
session.active = false;
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
session.
|
|
8685
|
+
let remainder;
|
|
8686
|
+
try {
|
|
8687
|
+
remainder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, goneOrderId, CHASE_ORDER_STATUS_RETRY_COUNT);
|
|
8688
|
+
}
|
|
8689
|
+
catch (error) {
|
|
8690
|
+
session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.Failed;
|
|
8691
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order status unavailable', {
|
|
8692
|
+
sessionId,
|
|
8693
|
+
orderId: goneOrderId,
|
|
8694
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.chaseGoneOrderStatus').message,
|
|
8695
|
+
});
|
|
8696
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
8697
|
+
return;
|
|
8698
|
+
}
|
|
8699
|
+
session.status = remainder.terminalStatus ?? perpsConfig_js_1.CHASE_ORDER_STATUS.Failed;
|
|
8700
|
+
if (remainder.remainingSize !== null) {
|
|
8701
|
+
session.size = remainder.remainingSize;
|
|
7749
8702
|
}
|
|
7750
8703
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order no longer resting', {
|
|
7751
8704
|
sessionId,
|
|
7752
8705
|
status: session.status,
|
|
7753
8706
|
remainingSize: session.size,
|
|
7754
8707
|
});
|
|
8708
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
7755
8709
|
return;
|
|
7756
8710
|
}
|
|
7757
8711
|
else {
|
|
@@ -7765,25 +8719,44 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7765
8719
|
// No further fills can reach a cancelled order, so what it did not fill
|
|
7766
8720
|
// is now fixed. Sampling before the cancel would have left a window in
|
|
7767
8721
|
// which a fill lands and is then re-placed.
|
|
7768
|
-
|
|
8722
|
+
let remainder;
|
|
8723
|
+
try {
|
|
8724
|
+
remainder = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, cancelledOrderId, CHASE_ORDER_STATUS_RETRY_COUNT);
|
|
8725
|
+
}
|
|
8726
|
+
catch (error) {
|
|
8727
|
+
session.replacingOrderId = null;
|
|
8728
|
+
throw error;
|
|
8729
|
+
}
|
|
7769
8730
|
// Another round trip, another window for a cancel to land. By now the
|
|
7770
8731
|
// old order is already off the book, so a cancel that arrived during it
|
|
7771
8732
|
// found nothing to cancel and reported success — resting a replacement
|
|
7772
8733
|
// after that would put an order on the book the caller believes is gone
|
|
7773
8734
|
// and has no handle for.
|
|
7774
8735
|
if (!session.active || !__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").has(sessionId)) {
|
|
8736
|
+
session.replacingOrderId = null;
|
|
7775
8737
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase cancelled mid-reprice', {
|
|
7776
8738
|
sessionId,
|
|
7777
8739
|
});
|
|
7778
8740
|
return;
|
|
7779
8741
|
}
|
|
7780
|
-
if (
|
|
7781
|
-
|
|
8742
|
+
if (remainder.remainingSize === null ||
|
|
8743
|
+
(remainder.terminalStatus !== null &&
|
|
8744
|
+
remainder.terminalStatus !== perpsConfig_js_1.CHASE_ORDER_STATUS.Canceled)) {
|
|
8745
|
+
// Nothing is left to chase. Preserve whether the venue actually
|
|
8746
|
+
// confirmed a fill rather than labelling every zero remainder filled.
|
|
8747
|
+
session.replacingOrderId = null;
|
|
7782
8748
|
session.active = false;
|
|
7783
|
-
session.
|
|
7784
|
-
|
|
8749
|
+
session.size = remainder.remainingSize ?? '0';
|
|
8750
|
+
session.status =
|
|
8751
|
+
remainder.terminalStatus ?? perpsConfig_js_1.CHASE_ORDER_STATUS.Failed;
|
|
8752
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase order has no remainder', {
|
|
8753
|
+
sessionId,
|
|
8754
|
+
status: session.status,
|
|
8755
|
+
});
|
|
8756
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
7785
8757
|
return;
|
|
7786
8758
|
}
|
|
8759
|
+
const remaining = remainder.remainingSize;
|
|
7787
8760
|
// Published *before* the placement starts, not from the promise it
|
|
7788
8761
|
// returns: the window opens the moment `#restChaseOrder` is entered, so
|
|
7789
8762
|
// deriving the marker from its return value would leave the synchronous
|
|
@@ -7802,8 +8775,7 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7802
8775
|
price: quotePrice,
|
|
7803
8776
|
size: remaining,
|
|
7804
8777
|
reduceOnly: session.reduceOnly,
|
|
7805
|
-
|
|
7806
|
-
builderAddress: session.builderAddress,
|
|
8778
|
+
builder: session.builder,
|
|
7807
8779
|
// A running session is on a live provider, so the current client is
|
|
7808
8780
|
// the right one; only the first placement has a teardown to survive.
|
|
7809
8781
|
exchangeClient: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient(),
|
|
@@ -7841,7 +8813,7 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7841
8813
|
}
|
|
7842
8814
|
}
|
|
7843
8815
|
}
|
|
7844
|
-
if (reachedMaxDistance) {
|
|
8816
|
+
if (reachedMaxDistance && session.maxDistanceBps !== undefined) {
|
|
7845
8817
|
session.active = false;
|
|
7846
8818
|
session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.MaxDistanceReached;
|
|
7847
8819
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase max distance reached', {
|
|
@@ -7849,12 +8821,24 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7849
8821
|
restingPrice: session.restingPrice,
|
|
7850
8822
|
maxDistanceBps: session.maxDistanceBps,
|
|
7851
8823
|
});
|
|
8824
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_onChaseOrderMaxDistanceReached, "f")?.call(this, {
|
|
8825
|
+
handle: sessionId,
|
|
8826
|
+
symbol: session.symbol,
|
|
8827
|
+
side: session.isBuy ? 'buy' : 'sell',
|
|
8828
|
+
restingOrderId: session.orderId,
|
|
8829
|
+
restingPrice: session.restingPrice,
|
|
8830
|
+
maxDistanceBps: session.maxDistanceBps,
|
|
8831
|
+
timestamp: Date.now(),
|
|
8832
|
+
providerId: perpsConfig_js_1.PROVIDER_CONFIG.DefaultProvider,
|
|
8833
|
+
});
|
|
8834
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
7852
8835
|
return;
|
|
7853
8836
|
}
|
|
7854
8837
|
if (session.repricings >= session.maxRepricings) {
|
|
7855
8838
|
session.active = false;
|
|
7856
8839
|
session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.RepricingLimitReached;
|
|
7857
8840
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase repricing cap reached', { sessionId });
|
|
8841
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
7858
8842
|
return;
|
|
7859
8843
|
}
|
|
7860
8844
|
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_scheduleChaseTick).call(this, sessionId);
|
|
@@ -7877,21 +8861,24 @@ async function _HyperLiquidProvider_runChaseTick(sessionId) {
|
|
|
7877
8861
|
* @param params.isBuy - Side being quoted.
|
|
7878
8862
|
* @param params.callerOrderId - The asking session's order, if it has one.
|
|
7879
8863
|
* @param params.ownSide - The side of the book those orders rest on.
|
|
7880
|
-
* @returns Our resting size at each price,
|
|
7881
|
-
*
|
|
8864
|
+
* @returns Our resting size at each price, the asking child's terminal
|
|
8865
|
+
* result, or the unavailable sentinel.
|
|
7882
8866
|
*/
|
|
7883
8867
|
async function _HyperLiquidProvider_resolveOwnRestingSizes(params) {
|
|
7884
8868
|
const { symbol, isBuy, callerOrderId, ownSide } = params;
|
|
7885
8869
|
// Every chase this provider is running on this side, the caller included.
|
|
7886
|
-
const ourOrders = [
|
|
7887
|
-
|
|
7888
|
-
session.
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
8870
|
+
const ourOrders = [];
|
|
8871
|
+
for (const session of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").values()) {
|
|
8872
|
+
if (session.orderId !== null &&
|
|
8873
|
+
session.symbol === symbol &&
|
|
8874
|
+
session.isBuy === isBuy) {
|
|
8875
|
+
ourOrders.push({
|
|
8876
|
+
orderId: session.orderId,
|
|
8877
|
+
price: session.restingPrice,
|
|
8878
|
+
size: session.size,
|
|
8879
|
+
});
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
7895
8882
|
if (ourOrders.length === 0) {
|
|
7896
8883
|
return new Map();
|
|
7897
8884
|
}
|
|
@@ -7908,27 +8895,44 @@ async function _HyperLiquidProvider_resolveOwnRestingSizes(params) {
|
|
|
7908
8895
|
const level = ownSide?.find((entry) => entry.px === order.price);
|
|
7909
8896
|
return !level || parseFloat(level.sz) <= (recorded.get(order.price) ?? 0);
|
|
7910
8897
|
});
|
|
7911
|
-
let
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
8898
|
+
let callerTerminalResult = null;
|
|
8899
|
+
let callerStatusUnavailable = false;
|
|
8900
|
+
const resolutions = await Promise.allSettled(ambiguous.map((order) => __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, order.orderId, CHASE_ORDER_STATUS_RETRY_COUNT)));
|
|
8901
|
+
resolutions.forEach((resolution, index) => {
|
|
8902
|
+
const order = ambiguous[index];
|
|
8903
|
+
if (resolution.status === 'fulfilled') {
|
|
8904
|
+
const { remainingSize: live, terminalStatus } = resolution.value;
|
|
7915
8905
|
const delta = (live === null ? 0 : parseFloat(live)) - parseFloat(order.size);
|
|
7916
8906
|
recorded.set(order.price, Math.max(0, (recorded.get(order.price) ?? 0) + delta));
|
|
7917
|
-
if (
|
|
7918
|
-
|
|
8907
|
+
if (terminalStatus !== null && order.orderId === callerOrderId) {
|
|
8908
|
+
callerTerminalResult = {
|
|
8909
|
+
remainingSize: live,
|
|
8910
|
+
status: terminalStatus,
|
|
8911
|
+
};
|
|
7919
8912
|
}
|
|
7920
8913
|
}
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
|
|
8914
|
+
else {
|
|
8915
|
+
const { reason: error } = resolution;
|
|
8916
|
+
if (error instanceof ChaseOrderStatusUnavailableError &&
|
|
8917
|
+
order.orderId === callerOrderId) {
|
|
8918
|
+
callerStatusUnavailable = true;
|
|
8919
|
+
}
|
|
8920
|
+
else {
|
|
8921
|
+
// A failed lookup must not stop the chase. Keeping the recorded size
|
|
8922
|
+
// can only over-subtract, which quotes a level deeper rather than
|
|
8923
|
+
// leaving the order stranded at a stale price.
|
|
8924
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase own-size lookup failed', {
|
|
8925
|
+
orderId: order.orderId,
|
|
8926
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.chaseOwnSize')
|
|
8927
|
+
.message,
|
|
8928
|
+
});
|
|
8929
|
+
}
|
|
7929
8930
|
}
|
|
8931
|
+
});
|
|
8932
|
+
if (callerStatusUnavailable) {
|
|
8933
|
+
return CHASE_ORDER_STATUS_UNAVAILABLE;
|
|
7930
8934
|
}
|
|
7931
|
-
return
|
|
8935
|
+
return callerTerminalResult ?? recorded;
|
|
7932
8936
|
}, _HyperLiquidProvider_readOrderRemainder =
|
|
7933
8937
|
/**
|
|
7934
8938
|
* Read what a chase's just-cancelled order left unfilled.
|
|
@@ -7944,19 +8948,51 @@ async function _HyperLiquidProvider_resolveOwnRestingSizes(params) {
|
|
|
7944
8948
|
* window in which a fill lands and is then re-placed on top.
|
|
7945
8949
|
*
|
|
7946
8950
|
* @param orderId - Exchange ID of the order that was just cancelled.
|
|
7947
|
-
* @
|
|
8951
|
+
* @param unknownStatusRetries - Remaining retries for a transient unknown ID.
|
|
8952
|
+
* @returns The unfilled size and exact terminal status, when present.
|
|
7948
8953
|
*/
|
|
7949
|
-
async function _HyperLiquidProvider_readOrderRemainder(orderId) {
|
|
8954
|
+
async function _HyperLiquidProvider_readOrderRemainder(orderId, unknownStatusRetries = 0) {
|
|
7950
8955
|
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
7951
8956
|
const status = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getInfoClient().orderStatus({
|
|
7952
8957
|
user: userAddress,
|
|
7953
8958
|
oid: parseInt(orderId, 10),
|
|
7954
8959
|
});
|
|
7955
8960
|
if (status.status !== 'order') {
|
|
7956
|
-
|
|
8961
|
+
// unknownOid can be transient while the order-status index catches up.
|
|
8962
|
+
// Treating it as a fill would drop the only handle to a live order.
|
|
8963
|
+
if (unknownStatusRetries > 0) {
|
|
8964
|
+
await new Promise((resolve) => setTimeout(resolve, CHASE_ORDER_STATUS_RETRY_DELAY_MS));
|
|
8965
|
+
return await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderRemainder).call(this, orderId, unknownStatusRetries - 1);
|
|
8966
|
+
}
|
|
8967
|
+
throw new ChaseOrderStatusUnavailableError();
|
|
7957
8968
|
}
|
|
7958
8969
|
const remaining = String(status.order.order.sz);
|
|
7959
|
-
|
|
8970
|
+
const remainingSize = parseFloat(remaining) > 0 ? remaining : null;
|
|
8971
|
+
switch (status.order.status) {
|
|
8972
|
+
case 'open':
|
|
8973
|
+
case 'triggered':
|
|
8974
|
+
return { remainingSize, terminalStatus: null };
|
|
8975
|
+
case 'filled':
|
|
8976
|
+
return {
|
|
8977
|
+
remainingSize: null,
|
|
8978
|
+
terminalStatus: perpsConfig_js_1.CHASE_ORDER_STATUS.Filled,
|
|
8979
|
+
};
|
|
8980
|
+
case 'canceled':
|
|
8981
|
+
return remainingSize === null
|
|
8982
|
+
? {
|
|
8983
|
+
remainingSize: null,
|
|
8984
|
+
terminalStatus: perpsConfig_js_1.CHASE_ORDER_STATUS.Filled,
|
|
8985
|
+
}
|
|
8986
|
+
: {
|
|
8987
|
+
remainingSize,
|
|
8988
|
+
terminalStatus: perpsConfig_js_1.CHASE_ORDER_STATUS.Canceled,
|
|
8989
|
+
};
|
|
8990
|
+
default:
|
|
8991
|
+
return {
|
|
8992
|
+
remainingSize,
|
|
8993
|
+
terminalStatus: perpsConfig_js_1.CHASE_ORDER_STATUS.Failed,
|
|
8994
|
+
};
|
|
8995
|
+
}
|
|
7960
8996
|
}, _HyperLiquidProvider_cancelChaseChild =
|
|
7961
8997
|
/**
|
|
7962
8998
|
* Cancel the order a chase session currently has resting.
|
|
@@ -7969,7 +9005,7 @@ async function _HyperLiquidProvider_readOrderRemainder(orderId) {
|
|
|
7969
9005
|
*/
|
|
7970
9006
|
async function _HyperLiquidProvider_cancelChaseChild(session, placingClient) {
|
|
7971
9007
|
if (!session.orderId) {
|
|
7972
|
-
return
|
|
9008
|
+
return CancelChildOutcome.Gone;
|
|
7973
9009
|
}
|
|
7974
9010
|
// Looked up only once there is something to cancel, so a session with
|
|
7975
9011
|
// nothing resting still answers on a provider whose client is already gone.
|
|
@@ -7983,7 +9019,7 @@ async function _HyperLiquidProvider_cancelChaseChild(session, placingClient) {
|
|
|
7983
9019
|
catch (error) {
|
|
7984
9020
|
const message = (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.cancelChaseChild').message.toLowerCase();
|
|
7985
9021
|
if (ALREADY_GONE_CANCEL_MARKERS.some((marker) => message.includes(marker))) {
|
|
7986
|
-
return
|
|
9022
|
+
return CancelChildOutcome.Gone;
|
|
7987
9023
|
}
|
|
7988
9024
|
throw error;
|
|
7989
9025
|
}
|
|
@@ -8018,19 +9054,194 @@ async function _HyperLiquidProvider_retractOrphanedChaseOrder(session, placingCl
|
|
|
8018
9054
|
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.startChaseSession')
|
|
8019
9055
|
.message,
|
|
8020
9056
|
});
|
|
8021
|
-
return
|
|
9057
|
+
return CancelChildOutcome.Refused;
|
|
8022
9058
|
}
|
|
8023
9059
|
}, _HyperLiquidProvider_stopChaseSession = function _HyperLiquidProvider_stopChaseSession(sessionId) {
|
|
8024
9060
|
const session = __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").get(sessionId);
|
|
8025
9061
|
if (!session) {
|
|
8026
9062
|
return;
|
|
8027
9063
|
}
|
|
9064
|
+
const wasActive = session.active;
|
|
8028
9065
|
session.active = false;
|
|
8029
|
-
|
|
9066
|
+
if (wasActive) {
|
|
9067
|
+
session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.TerminationPending;
|
|
9068
|
+
}
|
|
8030
9069
|
if (session.timer) {
|
|
8031
9070
|
clearTimeout(session.timer);
|
|
8032
9071
|
session.timer = null;
|
|
8033
9072
|
}
|
|
9073
|
+
}, _HyperLiquidProvider_rebalanceChaseSession =
|
|
9074
|
+
/**
|
|
9075
|
+
* Rebalance one Chase session at most once at a time. Failed cleanup keeps
|
|
9076
|
+
* the transfer context so a later lifecycle read or cancel can retry it.
|
|
9077
|
+
*
|
|
9078
|
+
* @param session - Chase session whose manual HIP-3 transfer is complete.
|
|
9079
|
+
* @returns Whether no collateral cleanup remains for the session.
|
|
9080
|
+
*/
|
|
9081
|
+
async function _HyperLiquidProvider_rebalanceChaseSession(session) {
|
|
9082
|
+
const { hip3Transfer } = session;
|
|
9083
|
+
if (!hip3Transfer) {
|
|
9084
|
+
return true;
|
|
9085
|
+
}
|
|
9086
|
+
if (session.orderId !== null ||
|
|
9087
|
+
session.replacingOrderId !== null ||
|
|
9088
|
+
session.pendingReplacement !== null) {
|
|
9089
|
+
return false;
|
|
9090
|
+
}
|
|
9091
|
+
let rebalancePromise = session.hip3RebalancePromise;
|
|
9092
|
+
if (!rebalancePromise) {
|
|
9093
|
+
rebalancePromise = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_handleHip3PostOrderRebalance).call(this, hip3Transfer);
|
|
9094
|
+
session.hip3RebalancePromise = rebalancePromise;
|
|
9095
|
+
}
|
|
9096
|
+
try {
|
|
9097
|
+
const success = await rebalancePromise;
|
|
9098
|
+
if (success && session.hip3Transfer === hip3Transfer) {
|
|
9099
|
+
delete session.hip3Transfer;
|
|
9100
|
+
}
|
|
9101
|
+
return success;
|
|
9102
|
+
}
|
|
9103
|
+
finally {
|
|
9104
|
+
if (session.hip3RebalancePromise === rebalancePromise) {
|
|
9105
|
+
delete session.hip3RebalancePromise;
|
|
9106
|
+
}
|
|
9107
|
+
}
|
|
9108
|
+
}, _HyperLiquidProvider_adaptTwapOrder = function _HyperLiquidProvider_adaptTwapOrder(params) {
|
|
9109
|
+
const { historyEntry, now } = params;
|
|
9110
|
+
const { state, twapId } = historyEntry;
|
|
9111
|
+
if (twapId === undefined || !Number.isSafeInteger(twapId) || twapId < 0) {
|
|
9112
|
+
return null;
|
|
9113
|
+
}
|
|
9114
|
+
const totalSize = new bignumber_js_1.BigNumber(state.sz);
|
|
9115
|
+
const executedSize = new bignumber_js_1.BigNumber(state.executedSz);
|
|
9116
|
+
const executedNotional = new bignumber_js_1.BigNumber(state.executedNtl);
|
|
9117
|
+
if (!totalSize.isFinite() ||
|
|
9118
|
+
!executedSize.isFinite() ||
|
|
9119
|
+
!executedNotional.isFinite() ||
|
|
9120
|
+
!Number.isFinite(state.timestamp) ||
|
|
9121
|
+
!Number.isFinite(historyEntry.time) ||
|
|
9122
|
+
!Number.isFinite(state.minutes)) {
|
|
9123
|
+
return null;
|
|
9124
|
+
}
|
|
9125
|
+
let boundedExecutedSize = executedSize;
|
|
9126
|
+
if (executedSize.isLessThan(0)) {
|
|
9127
|
+
boundedExecutedSize = new bignumber_js_1.BigNumber(0);
|
|
9128
|
+
}
|
|
9129
|
+
else if (executedSize.isGreaterThan(totalSize)) {
|
|
9130
|
+
boundedExecutedSize = totalSize;
|
|
9131
|
+
}
|
|
9132
|
+
const rawRemainingSize = totalSize.minus(boundedExecutedSize);
|
|
9133
|
+
const remainingSize = rawRemainingSize.isGreaterThan(0)
|
|
9134
|
+
? rawRemainingSize
|
|
9135
|
+
: new bignumber_js_1.BigNumber(0);
|
|
9136
|
+
const status = resolveTwapOrderStatus(historyEntry, boundedExecutedSize, totalSize);
|
|
9137
|
+
const fills = params.sliceFills
|
|
9138
|
+
.map(adaptTwapOrderFill)
|
|
9139
|
+
.sort((left, right) => left.timestamp - right.timestamp);
|
|
9140
|
+
const startedAt = state.timestamp;
|
|
9141
|
+
const historyUpdatedAt = normalizeTwapHistoryTimestamp(historyEntry.time);
|
|
9142
|
+
const lastUpdated = Math.max(startedAt, historyUpdatedAt, ...fills.map((fill) => fill.timestamp));
|
|
9143
|
+
const durationMilliseconds = state.minutes * MILLISECONDS_PER_MINUTE;
|
|
9144
|
+
const elapsedTimeMilliseconds = Math.min(durationMilliseconds, Math.max(0, (status === PerpsTwapLifecycleStatus.Active ? now : lastUpdated) -
|
|
9145
|
+
startedAt));
|
|
9146
|
+
const fillProgressBps = totalSize.isGreaterThan(0)
|
|
9147
|
+
? boundedExecutedSize
|
|
9148
|
+
.dividedBy(totalSize)
|
|
9149
|
+
.multipliedBy(hyperLiquidConfig_js_1.BASIS_POINTS_DIVISOR)
|
|
9150
|
+
.integerValue(bignumber_js_1.BigNumber.ROUND_FLOOR)
|
|
9151
|
+
.toNumber()
|
|
9152
|
+
: 0;
|
|
9153
|
+
const timeProgressBps = durationMilliseconds > 0
|
|
9154
|
+
? Math.floor((elapsedTimeMilliseconds / durationMilliseconds) *
|
|
9155
|
+
hyperLiquidConfig_js_1.BASIS_POINTS_DIVISOR)
|
|
9156
|
+
: 0;
|
|
9157
|
+
return {
|
|
9158
|
+
orderId: twapId.toString(),
|
|
9159
|
+
symbol: state.coin,
|
|
9160
|
+
side: state.side === 'B' ? 'buy' : 'sell',
|
|
9161
|
+
size: state.sz,
|
|
9162
|
+
executedSize: boundedExecutedSize.toString(),
|
|
9163
|
+
remainingSize: remainingSize.toFixed(),
|
|
9164
|
+
executedNotional: state.executedNtl,
|
|
9165
|
+
...(executedSize.isGreaterThan(0) && {
|
|
9166
|
+
averagePrice: executedNotional.dividedBy(executedSize).toFixed(),
|
|
9167
|
+
}),
|
|
9168
|
+
fillProgressBps,
|
|
9169
|
+
timeProgressBps,
|
|
9170
|
+
elapsedTimeMilliseconds,
|
|
9171
|
+
durationMinutes: state.minutes,
|
|
9172
|
+
randomize: state.randomize,
|
|
9173
|
+
reduceOnly: state.reduceOnly,
|
|
9174
|
+
status,
|
|
9175
|
+
startedAt,
|
|
9176
|
+
lastUpdated,
|
|
9177
|
+
...(historyEntry.status.status ===
|
|
9178
|
+
HyperLiquidTwapLifecycleStatus.Failed && {
|
|
9179
|
+
error: historyEntry.status.description,
|
|
9180
|
+
}),
|
|
9181
|
+
fills,
|
|
9182
|
+
};
|
|
9183
|
+
}, _HyperLiquidProvider_rebalanceTrackedTwapOrder =
|
|
9184
|
+
/**
|
|
9185
|
+
* Rebalance one tracked TWAP at most once at a time. A failed transfer keeps
|
|
9186
|
+
* the tracking entry so the next lifecycle read or cancel can retry it.
|
|
9187
|
+
*
|
|
9188
|
+
* @param trackingKey - Account-scoped TWAP tracking key.
|
|
9189
|
+
* @returns Whether no cleanup remains for the entry.
|
|
9190
|
+
*/
|
|
9191
|
+
async function _HyperLiquidProvider_rebalanceTrackedTwapOrder(trackingKey) {
|
|
9192
|
+
const trackedOrder = __classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").get(trackingKey);
|
|
9193
|
+
if (!trackedOrder) {
|
|
9194
|
+
return true;
|
|
9195
|
+
}
|
|
9196
|
+
if (!trackedOrder.hip3Transfer) {
|
|
9197
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").get(trackingKey) === trackedOrder) {
|
|
9198
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").delete(trackingKey);
|
|
9199
|
+
}
|
|
9200
|
+
return true;
|
|
9201
|
+
}
|
|
9202
|
+
let { rebalancePromise } = trackedOrder;
|
|
9203
|
+
if (!rebalancePromise) {
|
|
9204
|
+
rebalancePromise = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_handleHip3PostOrderRebalance).call(this, trackedOrder.hip3Transfer);
|
|
9205
|
+
trackedOrder.rebalancePromise = rebalancePromise;
|
|
9206
|
+
}
|
|
9207
|
+
try {
|
|
9208
|
+
const success = await rebalancePromise;
|
|
9209
|
+
if (success &&
|
|
9210
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").get(trackingKey) === trackedOrder) {
|
|
9211
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").delete(trackingKey);
|
|
9212
|
+
}
|
|
9213
|
+
return success;
|
|
9214
|
+
}
|
|
9215
|
+
finally {
|
|
9216
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").get(trackingKey) === trackedOrder &&
|
|
9217
|
+
trackedOrder.rebalancePromise === rebalancePromise) {
|
|
9218
|
+
delete trackedOrder.rebalancePromise;
|
|
9219
|
+
}
|
|
9220
|
+
}
|
|
9221
|
+
}, _HyperLiquidProvider_rebalanceTerminalHip3Twaps =
|
|
9222
|
+
/**
|
|
9223
|
+
* Return manually moved HIP-3 collateral after a TWAP reaches a terminal
|
|
9224
|
+
* venue state. The scoped registry survives reconnects so an active schedule
|
|
9225
|
+
* cannot lose its eventual cleanup path.
|
|
9226
|
+
*
|
|
9227
|
+
* @param orders - Current and historical TWAP lifecycle records.
|
|
9228
|
+
* @param scope - Current account and network identity.
|
|
9229
|
+
*/
|
|
9230
|
+
async function _HyperLiquidProvider_rebalanceTerminalHip3Twaps(orders, scope) {
|
|
9231
|
+
for (const order of orders) {
|
|
9232
|
+
if (order.status === PerpsTwapLifecycleStatus.Active) {
|
|
9233
|
+
continue;
|
|
9234
|
+
}
|
|
9235
|
+
const trackingKey = getTwapOrderScopeKey({
|
|
9236
|
+
...scope,
|
|
9237
|
+
orderId: order.orderId,
|
|
9238
|
+
});
|
|
9239
|
+
const trackedOrder = __classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").get(trackingKey);
|
|
9240
|
+
if (trackedOrder?.symbol !== order.symbol) {
|
|
9241
|
+
continue;
|
|
9242
|
+
}
|
|
9243
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceTrackedTwapOrder).call(this, trackingKey);
|
|
9244
|
+
}
|
|
8034
9245
|
}, _HyperLiquidProvider_cancelStrategyOrder =
|
|
8035
9246
|
/**
|
|
8036
9247
|
* Cancel a strategy placement by its handle.
|
|
@@ -8077,21 +9288,64 @@ async function _HyperLiquidProvider_cancelTwapOrder(params) {
|
|
|
8077
9288
|
if (!coinValidation.isValid) {
|
|
8078
9289
|
throw new Error(coinValidation.error);
|
|
8079
9290
|
}
|
|
8080
|
-
|
|
9291
|
+
const twapId = Number(params.orderId);
|
|
9292
|
+
if (!/^\d+$/u.test(params.orderId) || !Number.isSafeInteger(twapId)) {
|
|
9293
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
|
|
9294
|
+
}
|
|
9295
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
9296
|
+
const network = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode() ? 'testnet' : 'mainnet';
|
|
9297
|
+
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
9298
|
+
const trackingKey = getTwapOrderScopeKey({
|
|
9299
|
+
network,
|
|
9300
|
+
userAddress,
|
|
9301
|
+
orderId: params.orderId,
|
|
9302
|
+
});
|
|
9303
|
+
const trackedOrder = __classPrivateFieldGet(this, _HyperLiquidProvider_trackedTwapOrders, "f").get(trackingKey);
|
|
9304
|
+
let ownershipAuthenticated = trackedOrder !== undefined;
|
|
9305
|
+
if (trackedOrder) {
|
|
9306
|
+
if (trackedOrder.symbol !== params.symbol) {
|
|
9307
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
|
|
9308
|
+
}
|
|
9309
|
+
}
|
|
9310
|
+
else {
|
|
9311
|
+
let venueOrders = null;
|
|
9312
|
+
try {
|
|
9313
|
+
venueOrders = await this.getTwapOrders();
|
|
9314
|
+
}
|
|
9315
|
+
catch (error) {
|
|
9316
|
+
// History is an ownership check, not the cancellation transport. A
|
|
9317
|
+
// transient read failure must not make a live TWAP impossible to stop.
|
|
9318
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('TWAP history unavailable before cancellation', {
|
|
9319
|
+
orderId: params.orderId,
|
|
9320
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.cancelTwapOrderHistory').message,
|
|
9321
|
+
});
|
|
9322
|
+
}
|
|
9323
|
+
const venueOrder = venueOrders?.find((order) => order.orderId === params.orderId);
|
|
9324
|
+
if (venueOrders !== null && venueOrder?.symbol !== params.symbol) {
|
|
9325
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
|
|
9326
|
+
}
|
|
9327
|
+
ownershipAuthenticated = venueOrder !== undefined;
|
|
9328
|
+
}
|
|
8081
9329
|
const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
|
|
8082
9330
|
symbol: params.symbol,
|
|
8083
9331
|
dexName: (0, hyperLiquidAdapter_js_1.parseAssetName)(params.symbol).dex,
|
|
8084
9332
|
});
|
|
8085
9333
|
const result = await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient().twapCancel({
|
|
8086
9334
|
a: assetId,
|
|
8087
|
-
t:
|
|
9335
|
+
t: twapId,
|
|
8088
9336
|
});
|
|
8089
9337
|
const status = result.response?.data?.status;
|
|
8090
|
-
|
|
9338
|
+
const cancelOutcome = classifyCancelStatus(status);
|
|
9339
|
+
if (cancelOutcome === CancelChildOutcome.Gone && !ownershipAuthenticated) {
|
|
9340
|
+
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
|
|
9341
|
+
}
|
|
9342
|
+
if (cancelOutcome !== CancelChildOutcome.Refused) {
|
|
9343
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceTrackedTwapOrder).call(this, trackingKey);
|
|
8091
9344
|
return { success: true, orderId: params.orderId };
|
|
8092
9345
|
}
|
|
8093
|
-
const rawError = status
|
|
8094
|
-
|
|
9346
|
+
const rawError = isStatusObject(status) && typeof status.error === 'string'
|
|
9347
|
+
? status.error
|
|
9348
|
+
: 'TWAP cancellation failed';
|
|
8095
9349
|
return (0, hyperLiquidValidation_js_1.createErrorResult)(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_mapError).call(this, new Error(rawError)), {
|
|
8096
9350
|
success: false,
|
|
8097
9351
|
orderId: params.orderId,
|
|
@@ -8108,19 +9362,25 @@ async function _HyperLiquidProvider_cancelScaleOrder(params) {
|
|
|
8108
9362
|
if (!group) {
|
|
8109
9363
|
throw new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_HANDLE_UNKNOWN);
|
|
8110
9364
|
}
|
|
8111
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
|
|
8112
|
-
const
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
o: parseInt(orderId, 10),
|
|
8116
|
-
})),
|
|
9365
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
9366
|
+
const assetId = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getAssetIdWithRepair).call(this, {
|
|
9367
|
+
symbol: group.symbol,
|
|
9368
|
+
dexName: (0, hyperLiquidAdapter_js_1.parseAssetName)(group.symbol).dex,
|
|
8117
9369
|
});
|
|
8118
|
-
const
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
9370
|
+
const exchangeClient = __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").getExchangeClient();
|
|
9371
|
+
const cancelRequests = group.orderIds.map((orderId) => ({
|
|
9372
|
+
a: assetId,
|
|
9373
|
+
o: Number(orderId),
|
|
9374
|
+
}));
|
|
9375
|
+
const remaining = (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequests).call(this, exchangeClient, cancelRequests)).map(String);
|
|
9376
|
+
/*
|
|
9377
|
+
* A rung that filled or was cancelled individually comes back as a
|
|
9378
|
+
* rejection, but nothing of it is resting. The shared cancellation helper
|
|
9379
|
+
* distinguishes that result from a refusal while retaining every child
|
|
9380
|
+
* after a malformed or non-ok batch response.
|
|
9381
|
+
*/
|
|
8123
9382
|
if (remaining.length === 0) {
|
|
9383
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_cancelledScaleOrderGroups, "f").add(params.orderId);
|
|
8124
9384
|
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").delete(params.orderId);
|
|
8125
9385
|
return { success: true, orderId: params.orderId };
|
|
8126
9386
|
}
|
|
@@ -8128,7 +9388,7 @@ async function _HyperLiquidProvider_cancelScaleOrder(params) {
|
|
|
8128
9388
|
// handle registered against what is left means the caller can retry the
|
|
8129
9389
|
// same cancel rather than being told the ladder is gone when it is not.
|
|
8130
9390
|
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").set(params.orderId, {
|
|
8131
|
-
|
|
9391
|
+
symbol: group.symbol,
|
|
8132
9392
|
orderIds: remaining,
|
|
8133
9393
|
});
|
|
8134
9394
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Scale group cancel left children resting', {
|
|
@@ -8189,39 +9449,120 @@ async function _HyperLiquidProvider_performChaseTermination(params) {
|
|
|
8189
9449
|
// Nothing rests: the order filled, something else cancelled it, or a
|
|
8190
9450
|
// replacement failed to go up. Either way the session ends cleanly.
|
|
8191
9451
|
if (session.orderId === null) {
|
|
8192
|
-
|
|
9452
|
+
session.removeAfterRebalance = true;
|
|
9453
|
+
if (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session)) {
|
|
9454
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").delete(params.orderId);
|
|
9455
|
+
}
|
|
8193
9456
|
return { success: true, orderId: params.orderId };
|
|
8194
9457
|
}
|
|
8195
|
-
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this);
|
|
9458
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_ensureReadyForTrading).call(this, { requiresBuilderFee: false });
|
|
8196
9459
|
// Only a refusal leaves an order behind. A child that had already filled or
|
|
8197
9460
|
// been cancelled is reported as a rejection too, but nothing of it is
|
|
8198
9461
|
// resting — treating that as a failure would pin the handle open forever on
|
|
8199
9462
|
// a chase that is entirely finished.
|
|
8200
9463
|
const cancelOutcome = await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelChaseChild).call(this, session);
|
|
8201
|
-
if (cancelOutcome ===
|
|
9464
|
+
if (cancelOutcome === CancelChildOutcome.Refused) {
|
|
8202
9465
|
// The order is still resting. The session stays registered — stopped, but
|
|
8203
9466
|
// still cancellable — so the caller can retry with the same handle.
|
|
8204
9467
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Chase cancel left its order resting', {
|
|
8205
9468
|
sessionId: params.orderId,
|
|
8206
9469
|
orderId: session.orderId,
|
|
8207
9470
|
});
|
|
9471
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session);
|
|
8208
9472
|
return (0, hyperLiquidValidation_js_1.createErrorResult)(new Error(perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_STRATEGY_CANCEL_INCOMPLETE), { success: false, orderId: params.orderId });
|
|
8209
9473
|
}
|
|
8210
|
-
|
|
9474
|
+
session.orderId = null;
|
|
9475
|
+
session.status = perpsConfig_js_1.CHASE_ORDER_STATUS.Canceled;
|
|
9476
|
+
session.removeAfterRebalance = true;
|
|
9477
|
+
if (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session)) {
|
|
9478
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").delete(params.orderId);
|
|
9479
|
+
}
|
|
8211
9480
|
return { success: true, orderId: params.orderId };
|
|
8212
|
-
},
|
|
9481
|
+
}, _HyperLiquidProvider_cancelOrderRequests =
|
|
9482
|
+
/**
|
|
9483
|
+
* Cancel a batch and retain every order that may still be live.
|
|
9484
|
+
*
|
|
9485
|
+
* A malformed, truncated, or rejected response cannot prove which requests
|
|
9486
|
+
* reached the venue, so every requested ID remains recoverable for a retry.
|
|
9487
|
+
*
|
|
9488
|
+
* @param exchangeClient - Client that owns the orders.
|
|
9489
|
+
* @param requests - Venue cancel requests.
|
|
9490
|
+
* @returns Order IDs that may still be resting.
|
|
9491
|
+
*/
|
|
9492
|
+
async function _HyperLiquidProvider_cancelOrderRequests(exchangeClient, requests) {
|
|
9493
|
+
return (await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cancelOrderRequestBatch).call(this, exchangeClient, requests))
|
|
9494
|
+
.remainingOrderIds;
|
|
9495
|
+
}, _HyperLiquidProvider_cancelOrderRequestBatch =
|
|
9496
|
+
/**
|
|
9497
|
+
* Cancel a batch while distinguishing confirmed cancellations from orders
|
|
9498
|
+
* that were already gone. Replacement rollback may only restore the former.
|
|
9499
|
+
*
|
|
9500
|
+
* @param exchangeClient - Client that owns the orders.
|
|
9501
|
+
* @param requests - Venue cancel requests.
|
|
9502
|
+
* @returns IDs that may still rest and IDs this call confirmed it cancelled.
|
|
9503
|
+
*/
|
|
9504
|
+
async function _HyperLiquidProvider_cancelOrderRequestBatch(exchangeClient, requests) {
|
|
9505
|
+
if (requests.length === 0) {
|
|
9506
|
+
return {
|
|
9507
|
+
remainingOrderIds: [],
|
|
9508
|
+
cancelledOrderIds: [],
|
|
9509
|
+
responseComplete: true,
|
|
9510
|
+
};
|
|
9511
|
+
}
|
|
9512
|
+
try {
|
|
9513
|
+
const result = await exchangeClient.cancel({ cancels: requests });
|
|
9514
|
+
const statuses = result.response?.data?.statuses ?? [];
|
|
9515
|
+
if (result.status !== 'ok' || statuses.length !== requests.length) {
|
|
9516
|
+
return {
|
|
9517
|
+
remainingOrderIds: requests.map((request) => request.o),
|
|
9518
|
+
cancelledOrderIds: [],
|
|
9519
|
+
responseComplete: false,
|
|
9520
|
+
};
|
|
9521
|
+
}
|
|
9522
|
+
const remainingOrderIds = [];
|
|
9523
|
+
const cancelledOrderIds = [];
|
|
9524
|
+
requests.forEach((request, index) => {
|
|
9525
|
+
const outcome = classifyCancelStatus(statuses[index]);
|
|
9526
|
+
if (outcome === CancelChildOutcome.Refused) {
|
|
9527
|
+
remainingOrderIds.push(request.o);
|
|
9528
|
+
}
|
|
9529
|
+
else if (outcome === CancelChildOutcome.Cancelled) {
|
|
9530
|
+
cancelledOrderIds.push(request.o);
|
|
9531
|
+
}
|
|
9532
|
+
});
|
|
9533
|
+
return { remainingOrderIds, cancelledOrderIds, responseComplete: true };
|
|
9534
|
+
}
|
|
9535
|
+
catch (error) {
|
|
9536
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Order cancellation batch failed', {
|
|
9537
|
+
error: (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.cancelOrderRequests')
|
|
9538
|
+
.message,
|
|
9539
|
+
orderIds: requests.map((request) => request.o),
|
|
9540
|
+
});
|
|
9541
|
+
return {
|
|
9542
|
+
remainingOrderIds: requests.map((request) => request.o),
|
|
9543
|
+
cancelledOrderIds: [],
|
|
9544
|
+
responseComplete: false,
|
|
9545
|
+
};
|
|
9546
|
+
}
|
|
9547
|
+
}, _HyperLiquidProvider_readOrderPlacementOutcome = function _HyperLiquidProvider_readOrderPlacementOutcome(status) {
|
|
8213
9548
|
if (!isStatusObject(status)) {
|
|
8214
9549
|
return undefined;
|
|
8215
9550
|
}
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
9551
|
+
for (const state of ['resting', 'filled']) {
|
|
9552
|
+
if (!(0, utils_1.hasProperty)(status, state)) {
|
|
9553
|
+
continue;
|
|
9554
|
+
}
|
|
9555
|
+
const order = status[state];
|
|
9556
|
+
if (isStatusObject(order) &&
|
|
9557
|
+
typeof order.oid === 'number' &&
|
|
9558
|
+
Number.isSafeInteger(order.oid) &&
|
|
9559
|
+
order.oid >= 0) {
|
|
9560
|
+
return { orderId: order.oid.toString(), state };
|
|
9561
|
+
}
|
|
9562
|
+
}
|
|
9563
|
+
return undefined;
|
|
9564
|
+
}, _HyperLiquidProvider_readOrderIdFromStatus = function _HyperLiquidProvider_readOrderIdFromStatus(status) {
|
|
9565
|
+
return __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_readOrderPlacementOutcome).call(this, status)?.orderId;
|
|
8225
9566
|
}, _HyperLiquidProvider_getDiscountedBuilderFee = function _HyperLiquidProvider_getDiscountedBuilderFee() {
|
|
8226
9567
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_userFeeDiscountBips, "f") === undefined) {
|
|
8227
9568
|
return hyperLiquidConfig_js_1.BUILDER_FEE_CONFIG.MaxFeeTenthsBps;
|
|
@@ -8236,15 +9577,14 @@ async function _HyperLiquidProvider_performChaseTermination(params) {
|
|
|
8236
9577
|
* cached for this provider/account session. Until then, the ordinary builder
|
|
8237
9578
|
* and standard fee keep the trade attributable and non-blocking.
|
|
8238
9579
|
*
|
|
9580
|
+
* @param setupContext - Account, network, and builder approved for the order.
|
|
8239
9581
|
* @returns HyperLiquid builder address and fee payload.
|
|
8240
9582
|
*/
|
|
8241
|
-
async function _HyperLiquidProvider_getBuilderOrderContext() {
|
|
8242
|
-
const
|
|
8243
|
-
const
|
|
8244
|
-
const defaultBuilder = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getBuilderAddress).call(this, isTestnet);
|
|
9583
|
+
async function _HyperLiquidProvider_getBuilderOrderContext(setupContext) {
|
|
9584
|
+
const { network, userAddress, builderAddress: defaultBuilder, } = setupContext;
|
|
9585
|
+
const isTestnet = network === 'testnet';
|
|
8245
9586
|
if (__classPrivateFieldGet(this, _HyperLiquidProvider_userFeeResolution, "f")?.source === 'subscription') {
|
|
8246
9587
|
const subscriptionBuilder = __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getSubscriptionBuilderAddress).call(this, isTestnet);
|
|
8247
|
-
const userAddress = await __classPrivateFieldGet(this, _HyperLiquidProvider_walletService, "f").getUserAddressWithDefault();
|
|
8248
9588
|
if (subscriptionBuilder &&
|
|
8249
9589
|
__classPrivateFieldGet(this, _HyperLiquidProvider_approvedBuilderAddresses, "f").has(__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_getApprovedBuilderKey).call(this, network, userAddress, subscriptionBuilder))) {
|
|
8250
9590
|
return { b: subscriptionBuilder, f: 0 };
|
|
@@ -8394,6 +9734,41 @@ async function _HyperLiquidProvider_queryDexPositions(dexName) {
|
|
|
8394
9734
|
});
|
|
8395
9735
|
return { answered: false, positions: [] };
|
|
8396
9736
|
}
|
|
9737
|
+
}, _HyperLiquidProvider_restoreScaleOrderGroups = function _HyperLiquidProvider_restoreScaleOrderGroups(orders) {
|
|
9738
|
+
const recovered = new Map();
|
|
9739
|
+
for (const order of orders) {
|
|
9740
|
+
if (!order.strategyGroupId) {
|
|
9741
|
+
continue;
|
|
9742
|
+
}
|
|
9743
|
+
const group = recovered.get(order.strategyGroupId) ?? {
|
|
9744
|
+
symbol: order.symbol,
|
|
9745
|
+
orderIds: [],
|
|
9746
|
+
};
|
|
9747
|
+
group.orderIds.push(order.orderId);
|
|
9748
|
+
recovered.set(order.strategyGroupId, group);
|
|
9749
|
+
}
|
|
9750
|
+
for (const [groupId, group] of recovered) {
|
|
9751
|
+
if (__classPrivateFieldGet(this, _HyperLiquidProvider_cancelledScaleOrderGroups, "f").has(groupId)) {
|
|
9752
|
+
continue;
|
|
9753
|
+
}
|
|
9754
|
+
const existingGroup = __classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").get(groupId);
|
|
9755
|
+
if (!existingGroup) {
|
|
9756
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").set(groupId, group);
|
|
9757
|
+
continue;
|
|
9758
|
+
}
|
|
9759
|
+
if (existingGroup.symbol === group.symbol) {
|
|
9760
|
+
existingGroup.orderIds = [
|
|
9761
|
+
...new Set([...existingGroup.orderIds, ...group.orderIds]),
|
|
9762
|
+
];
|
|
9763
|
+
}
|
|
9764
|
+
else {
|
|
9765
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('Scale group symbol mismatch during recovery', {
|
|
9766
|
+
groupId,
|
|
9767
|
+
existingSymbol: existingGroup.symbol,
|
|
9768
|
+
recoveredSymbol: group.symbol,
|
|
9769
|
+
});
|
|
9770
|
+
}
|
|
9771
|
+
}
|
|
8397
9772
|
}, _HyperLiquidProvider_getAllMids =
|
|
8398
9773
|
/**
|
|
8399
9774
|
* Get allMids for a DEX — uses WS snapshot as primary source, REST as fallback.
|
|
@@ -8410,7 +9785,7 @@ async function _HyperLiquidProvider_getAllMids(infoClient, dexParam) {
|
|
|
8410
9785
|
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('[getMarketDataWithPrices] No WS allMids snapshot, falling back to REST', { dexParam: dexParam ?? 'main' });
|
|
8411
9786
|
const mids = await infoClient.allMids(dexParam ? { dex: dexParam } : undefined);
|
|
8412
9787
|
return mids ?? {};
|
|
8413
|
-
}, _HyperLiquidProvider_fetchSingleDexFresh = async function _HyperLiquidProvider_fetchSingleDexFresh(infoClient, dex) {
|
|
9788
|
+
}, _HyperLiquidProvider_fetchSingleDexFresh = async function _HyperLiquidProvider_fetchSingleDexFresh(infoClient, dex, lifecycleGeneration) {
|
|
8414
9789
|
const dexParam = dex ?? '';
|
|
8415
9790
|
let metaAndCtxs = null;
|
|
8416
9791
|
try {
|
|
@@ -8438,10 +9813,12 @@ async function _HyperLiquidProvider_getAllMids(infoClient, dexParam) {
|
|
|
8438
9813
|
allMidsErrorMessage = (0, errorUtils_js_1.ensureError)(error, 'HyperLiquidProvider.getMarketDataWithPrices.allMids').message;
|
|
8439
9814
|
}
|
|
8440
9815
|
if (meta?.universe) {
|
|
8441
|
-
__classPrivateFieldGet(this,
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
9816
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_cacheDexMetadataFromRead).call(this, {
|
|
9817
|
+
dex,
|
|
9818
|
+
meta,
|
|
9819
|
+
assetCtxs,
|
|
9820
|
+
lifecycleGeneration,
|
|
9821
|
+
});
|
|
8445
9822
|
}
|
|
8446
9823
|
return {
|
|
8447
9824
|
dex,
|
|
@@ -8544,6 +9921,128 @@ async function _HyperLiquidProvider_excludeNonUsdcCollateralResults(results) {
|
|
|
8544
9921
|
return false;
|
|
8545
9922
|
}
|
|
8546
9923
|
return Date.now() - cached.timestamp < cached.ttl;
|
|
9924
|
+
}, _HyperLiquidProvider_performDisconnect =
|
|
9925
|
+
/**
|
|
9926
|
+
* Perform one provider teardown shared by every concurrent caller.
|
|
9927
|
+
*
|
|
9928
|
+
* @returns A promise that resolves to the result.
|
|
9929
|
+
*/
|
|
9930
|
+
async function _HyperLiquidProvider_performDisconnect() {
|
|
9931
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementBlockers, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") + 1, "f");
|
|
9932
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_strategyGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_strategyGeneration, "f") + 1, "f");
|
|
9933
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_disconnectOperationsInFlight, __classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") + 1, "f");
|
|
9934
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_isDisconnected, true, "f");
|
|
9935
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_lifecycleGeneration, __classPrivateFieldGet(this, _HyperLiquidProvider_lifecycleGeneration, "f") + 1, "f");
|
|
9936
|
+
try {
|
|
9937
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Disconnecting provider', {
|
|
9938
|
+
isTestnet: __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").isTestnetMode(),
|
|
9939
|
+
timestamp: new Date().toISOString(),
|
|
9940
|
+
});
|
|
9941
|
+
// Clear subscriptions through subscription service
|
|
9942
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionService, "f").clearAll();
|
|
9943
|
+
// Stop every chase loop: each holds a pending timer, and re-pricing after
|
|
9944
|
+
// a disconnect would sign orders against a client that is being torn down.
|
|
9945
|
+
// Orders already resting are deliberately left alone — disconnecting is
|
|
9946
|
+
// not a request to cancel the user's positions or orders.
|
|
9947
|
+
// Invalidate placements first, then drain every mutation before clearing
|
|
9948
|
+
// the registry and tearing down the clients they use.
|
|
9949
|
+
for (const [sessionId, session] of __classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").entries()) {
|
|
9950
|
+
if (session.active) {
|
|
9951
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_stopChaseSession).call(this, sessionId);
|
|
9952
|
+
}
|
|
9953
|
+
}
|
|
9954
|
+
await Promise.all([...__classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementWaiters, "f")]);
|
|
9955
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_chaseTickQueue, "f");
|
|
9956
|
+
await Promise.allSettled([...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").values()]);
|
|
9957
|
+
await Promise.all([...__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").values()].map(async (session) => await __classPrivateFieldGet(this, _HyperLiquidProvider_instances, "m", _HyperLiquidProvider_rebalanceChaseSession).call(this, session)));
|
|
9958
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseSessions, "f").clear();
|
|
9959
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_chaseTerminations, "f").clear();
|
|
9960
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_terminatedChaseHandles, "f").clear();
|
|
9961
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_scaleOrderGroups, "f").clear();
|
|
9962
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_cancelledScaleOrderGroups, "f").clear();
|
|
9963
|
+
// Clear session caches. Capability and fee reads use the lifecycle
|
|
9964
|
+
// generation above to discard any old response that resolves later.
|
|
9965
|
+
this.clearFeeCache();
|
|
9966
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_referralCheckCache, "f").clear();
|
|
9967
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeCheckCache, "f").clear();
|
|
9968
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_subscriptionBuilderApprovalEpoch, __classPrivateFieldGet(this, _HyperLiquidProvider_subscriptionBuilderApprovalEpoch, "f") + 1, "f");
|
|
9969
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_approvedBuilderAddresses, "f").clear();
|
|
9970
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_userFeeResolution, undefined, "f");
|
|
9971
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_userFeeDiscountBips, undefined, "f");
|
|
9972
|
+
// UnifiedAccountCache stays global to avoid repeated signing requests.
|
|
9973
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_cachedMetaByDex, "f").clear();
|
|
9974
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_pendingValidatedDexsPromise, null, "f");
|
|
9975
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesMarketsByDex, "f").clear();
|
|
9976
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_orderCapabilitiesRefreshByDex, "f").clear();
|
|
9977
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_cachedSpotMeta, null, "f");
|
|
9978
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_dexDiscoveryCache, "f").reset();
|
|
9979
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_dexDiscoveryComplete, false, "f");
|
|
9980
|
+
// Await pending initialization before clearing to prevent the IIFE from
|
|
9981
|
+
// setting clientsInitialized = true after disconnect completes
|
|
9982
|
+
const pendingInit = __classPrivateFieldGet(this, _HyperLiquidProvider_initializationPromise, "f");
|
|
9983
|
+
const pendingReady = __classPrivateFieldGet(this, _HyperLiquidProvider_ensureReadyPromise, "f");
|
|
9984
|
+
const pendingTradingSetup = __classPrivateFieldGet(this, _HyperLiquidProvider_tradingSetupPromise, "f");
|
|
9985
|
+
const pendingBuilderFeeSetups = [
|
|
9986
|
+
...__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeSetupPromises, "f").values(),
|
|
9987
|
+
];
|
|
9988
|
+
// Clear references first to prevent new callers from reusing
|
|
9989
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_initializationPromise, null, "f");
|
|
9990
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_ensureReadyPromise, null, "f");
|
|
9991
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupPromise, null, "f");
|
|
9992
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_tradingSetupComplete, false, "f");
|
|
9993
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_builderFeeSetupPromises, "f").clear();
|
|
9994
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_pendingBuilderFeeApprovals, "f").clear();
|
|
9995
|
+
// Wait for pending operations to complete (ignore errors)
|
|
9996
|
+
// This prevents IIFEs from setting state after disconnect completes
|
|
9997
|
+
if (pendingInit) {
|
|
9998
|
+
try {
|
|
9999
|
+
await pendingInit;
|
|
10000
|
+
}
|
|
10001
|
+
catch {
|
|
10002
|
+
// Ignore - we're disconnecting anyway
|
|
10003
|
+
}
|
|
10004
|
+
}
|
|
10005
|
+
if (pendingReady) {
|
|
10006
|
+
try {
|
|
10007
|
+
await pendingReady;
|
|
10008
|
+
}
|
|
10009
|
+
catch {
|
|
10010
|
+
// Ignore - we're disconnecting anyway
|
|
10011
|
+
}
|
|
10012
|
+
}
|
|
10013
|
+
if (pendingTradingSetup) {
|
|
10014
|
+
try {
|
|
10015
|
+
await pendingTradingSetup;
|
|
10016
|
+
}
|
|
10017
|
+
catch {
|
|
10018
|
+
// Ignore - we're disconnecting anyway
|
|
10019
|
+
}
|
|
10020
|
+
}
|
|
10021
|
+
for (const pendingBuilderFeeSetup of pendingBuilderFeeSetups) {
|
|
10022
|
+
try {
|
|
10023
|
+
await pendingBuilderFeeSetup;
|
|
10024
|
+
}
|
|
10025
|
+
catch {
|
|
10026
|
+
// Ignore - we're disconnecting anyway
|
|
10027
|
+
}
|
|
10028
|
+
}
|
|
10029
|
+
// Reset client initialization flag so wallet adapter will be recreated with new account
|
|
10030
|
+
// This fixes account synchronization issue where old account's address persists in wallet adapter
|
|
10031
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_clientsInitialized, false, "f");
|
|
10032
|
+
// Disconnect client service
|
|
10033
|
+
await __classPrivateFieldGet(this, _HyperLiquidProvider_clientService, "f").disconnect();
|
|
10034
|
+
__classPrivateFieldGet(this, _HyperLiquidProvider_deps, "f").debugLogger.log('HyperLiquid: Provider fully disconnected', {
|
|
10035
|
+
timestamp: new Date().toISOString(),
|
|
10036
|
+
});
|
|
10037
|
+
return { success: true };
|
|
10038
|
+
}
|
|
10039
|
+
catch (error) {
|
|
10040
|
+
return (0, hyperLiquidValidation_js_1.createErrorResult)(error, { success: false });
|
|
10041
|
+
}
|
|
10042
|
+
finally {
|
|
10043
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_chasePlacementBlockers, __classPrivateFieldGet(this, _HyperLiquidProvider_chasePlacementBlockers, "f") - 1, "f");
|
|
10044
|
+
__classPrivateFieldSet(this, _HyperLiquidProvider_disconnectOperationsInFlight, __classPrivateFieldGet(this, _HyperLiquidProvider_disconnectOperationsInFlight, "f") - 1, "f");
|
|
10045
|
+
}
|
|
8547
10046
|
}, _HyperLiquidProvider_getBuilderAddress = function _HyperLiquidProvider_getBuilderAddress(isTestnet) {
|
|
8548
10047
|
// || intentional: env vars default to '' which must fall through to the hardcoded default
|
|
8549
10048
|
if (isTestnet) {
|
|
@@ -8797,4 +10296,9 @@ async function _HyperLiquidProvider_setReferralCode() {
|
|
|
8797
10296
|
throw error;
|
|
8798
10297
|
}
|
|
8799
10298
|
};
|
|
10299
|
+
// Native TWAP IDs and any manual HIP-3 collateral transfer must outlive one
|
|
10300
|
+
// provider instance: controller disconnect/reinitialization replaces the
|
|
10301
|
+
// provider while the venue schedule keeps running. Each controller messenger
|
|
10302
|
+
// owns one registry, so separate controller lifecycles never share handles.
|
|
10303
|
+
_HyperLiquidProvider_trackedTwapOrdersByMessenger = { value: new WeakMap() };
|
|
8800
10304
|
//# sourceMappingURL=HyperLiquidProvider.cjs.map
|