@lifi/perps-sdk-provider-hyperliquid 25.0.0 → 27.0.0
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/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +8 -14
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/services/getAccount.d.ts.map +1 -1
- package/dist/cjs/services/getAccount.js +18 -16
- package/dist/cjs/services/getAccount.js.map +1 -1
- package/dist/cjs/services/getFills.d.ts.map +1 -1
- package/dist/cjs/services/getFills.js +2 -1
- package/dist/cjs/services/getFills.js.map +1 -1
- package/dist/cjs/services/getMarketSettings.d.ts.map +1 -1
- package/dist/cjs/services/getMarketSettings.js +1 -1
- package/dist/cjs/services/getMarketSettings.js.map +1 -1
- package/dist/cjs/services/getOrder.d.ts.map +1 -1
- package/dist/cjs/services/getOrder.js +14 -4
- package/dist/cjs/services/getOrder.js.map +1 -1
- package/dist/cjs/services/getOrders.d.ts.map +1 -1
- package/dist/cjs/services/getOrders.js +8 -28
- package/dist/cjs/services/getOrders.js.map +1 -1
- package/dist/cjs/services/getPortfolioHistory.d.ts.map +1 -1
- package/dist/cjs/services/getPortfolioHistory.js +17 -6
- package/dist/cjs/services/getPortfolioHistory.js.map +1 -1
- package/dist/cjs/services/getPositions.d.ts.map +1 -1
- package/dist/cjs/services/getPositions.js +4 -1
- package/dist/cjs/services/getPositions.js.map +1 -1
- package/dist/cjs/types/ws.d.ts +3 -2
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +3 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/liquidation.d.ts +5 -2
- package/dist/cjs/utils/liquidation.d.ts.map +1 -1
- package/dist/cjs/utils/liquidation.js +8 -8
- package/dist/cjs/utils/liquidation.js.map +1 -1
- package/dist/cjs/utils/mapActivity.d.ts.map +1 -1
- package/dist/cjs/utils/mapActivity.js +38 -23
- package/dist/cjs/utils/mapActivity.js.map +1 -1
- package/dist/cjs/utils/mapFill.d.ts +1 -1
- package/dist/cjs/utils/mapFill.d.ts.map +1 -1
- package/dist/cjs/utils/mapFill.js +17 -6
- package/dist/cjs/utils/mapFill.js.map +1 -1
- package/dist/cjs/utils/mapMarket.d.ts.map +1 -1
- package/dist/cjs/utils/mapMarket.js +9 -13
- package/dist/cjs/utils/mapMarket.js.map +1 -1
- package/dist/cjs/utils/mapMarketContext.d.ts.map +1 -1
- package/dist/cjs/utils/mapMarketContext.js +3 -12
- package/dist/cjs/utils/mapMarketContext.js.map +1 -1
- package/dist/cjs/utils/mapOrder.d.ts +3 -1
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +73 -19
- package/dist/cjs/utils/mapOrder.js.map +1 -1
- package/dist/cjs/utils/mapPosition.d.ts +1 -1
- package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
- package/dist/cjs/utils/mapPosition.js +41 -15
- package/dist/cjs/utils/mapPosition.js.map +1 -1
- package/dist/cjs/utils/rowTimestamp.d.ts +2 -0
- package/dist/cjs/utils/rowTimestamp.d.ts.map +1 -0
- package/dist/cjs/utils/rowTimestamp.js +14 -0
- package/dist/cjs/utils/rowTimestamp.js.map +1 -0
- package/dist/cjs/utils/spotBalance.d.ts +3 -3
- package/dist/cjs/utils/spotBalance.d.ts.map +1 -1
- package/dist/cjs/utils/spotBalance.js +6 -5
- package/dist/cjs/utils/spotBalance.js.map +1 -1
- package/dist/cjs/utils/spotCollateral.d.ts.map +1 -1
- package/dist/cjs/utils/spotCollateral.js +3 -2
- package/dist/cjs/utils/spotCollateral.js.map +1 -1
- package/dist/cjs/utils/transferMargin.d.ts.map +1 -1
- package/dist/cjs/utils/transferMargin.js +16 -19
- package/dist/cjs/utils/transferMargin.js.map +1 -1
- package/dist/cjs/utils/venueTotals.d.ts +4 -5
- package/dist/cjs/utils/venueTotals.d.ts.map +1 -1
- package/dist/cjs/utils/venueTotals.js +18 -10
- package/dist/cjs/utils/venueTotals.js.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.js +10 -10
- package/dist/cjs/utils/withdrawableBalances.js.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +1 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +144 -115
- package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +2 -1
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +11 -13
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/services/getAccount.d.ts.map +1 -1
- package/dist/esm/services/getAccount.js +23 -21
- package/dist/esm/services/getAccount.js.map +1 -1
- package/dist/esm/services/getFills.d.ts.map +1 -1
- package/dist/esm/services/getFills.js +2 -1
- package/dist/esm/services/getFills.js.map +1 -1
- package/dist/esm/services/getMarketSettings.d.ts.map +1 -1
- package/dist/esm/services/getMarketSettings.js +2 -2
- package/dist/esm/services/getMarketSettings.js.map +1 -1
- package/dist/esm/services/getOrder.d.ts.map +1 -1
- package/dist/esm/services/getOrder.js +14 -4
- package/dist/esm/services/getOrder.js.map +1 -1
- package/dist/esm/services/getOrders.d.ts.map +1 -1
- package/dist/esm/services/getOrders.js +12 -37
- package/dist/esm/services/getOrders.js.map +1 -1
- package/dist/esm/services/getPortfolioHistory.d.ts.map +1 -1
- package/dist/esm/services/getPortfolioHistory.js +19 -7
- package/dist/esm/services/getPortfolioHistory.js.map +1 -1
- package/dist/esm/services/getPositions.d.ts.map +1 -1
- package/dist/esm/services/getPositions.js +4 -1
- package/dist/esm/services/getPositions.js.map +1 -1
- package/dist/esm/services/getWithdrawableBalances.d.ts +1 -1
- package/dist/esm/services/getWithdrawableBalances.js +1 -1
- package/dist/esm/types/ws.d.ts +3 -2
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/liquidation.d.ts +23 -24
- package/dist/esm/utils/liquidation.d.ts.map +1 -1
- package/dist/esm/utils/liquidation.js +26 -31
- package/dist/esm/utils/liquidation.js.map +1 -1
- package/dist/esm/utils/mapActivity.d.ts +2 -1
- package/dist/esm/utils/mapActivity.d.ts.map +1 -1
- package/dist/esm/utils/mapActivity.js +41 -22
- package/dist/esm/utils/mapActivity.js.map +1 -1
- package/dist/esm/utils/mapFill.d.ts +3 -2
- package/dist/esm/utils/mapFill.d.ts.map +1 -1
- package/dist/esm/utils/mapFill.js +21 -9
- package/dist/esm/utils/mapFill.js.map +1 -1
- package/dist/esm/utils/mapMarket.d.ts +2 -2
- package/dist/esm/utils/mapMarket.d.ts.map +1 -1
- package/dist/esm/utils/mapMarket.js +12 -13
- package/dist/esm/utils/mapMarket.js.map +1 -1
- package/dist/esm/utils/mapMarketContext.d.ts.map +1 -1
- package/dist/esm/utils/mapMarketContext.js +3 -9
- package/dist/esm/utils/mapMarketContext.js.map +1 -1
- package/dist/esm/utils/mapOrder.d.ts +12 -2
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +81 -17
- package/dist/esm/utils/mapOrder.js.map +1 -1
- package/dist/esm/utils/mapPosition.d.ts +4 -2
- package/dist/esm/utils/mapPosition.d.ts.map +1 -1
- package/dist/esm/utils/mapPosition.js +44 -13
- package/dist/esm/utils/mapPosition.js.map +1 -1
- package/dist/esm/utils/rowTimestamp.d.ts +6 -0
- package/dist/esm/utils/rowTimestamp.d.ts.map +1 -0
- package/dist/esm/utils/rowTimestamp.js +14 -0
- package/dist/esm/utils/rowTimestamp.js.map +1 -0
- package/dist/esm/utils/spotBalance.d.ts +5 -5
- package/dist/esm/utils/spotBalance.d.ts.map +1 -1
- package/dist/esm/utils/spotBalance.js +9 -8
- package/dist/esm/utils/spotBalance.js.map +1 -1
- package/dist/esm/utils/spotCollateral.d.ts.map +1 -1
- package/dist/esm/utils/spotCollateral.js +3 -2
- package/dist/esm/utils/spotCollateral.js.map +1 -1
- package/dist/esm/utils/transferMargin.d.ts +2 -1
- package/dist/esm/utils/transferMargin.d.ts.map +1 -1
- package/dist/esm/utils/transferMargin.js +19 -18
- package/dist/esm/utils/transferMargin.js.map +1 -1
- package/dist/esm/utils/venueTotals.d.ts +7 -6
- package/dist/esm/utils/venueTotals.d.ts.map +1 -1
- package/dist/esm/utils/venueTotals.js +21 -8
- package/dist/esm/utils/venueTotals.js.map +1 -1
- package/dist/esm/utils/withdrawableBalances.d.ts +6 -4
- package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/esm/utils/withdrawableBalances.js +17 -15
- package/dist/esm/utils/withdrawableBalances.js.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts +3 -0
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +155 -115
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/accountSummary.d.ts +2 -1
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/services/getFills.d.ts.map +1 -1
- package/dist/types/services/getMarketSettings.d.ts.map +1 -1
- package/dist/types/services/getOrder.d.ts.map +1 -1
- package/dist/types/services/getOrders.d.ts.map +1 -1
- package/dist/types/services/getPortfolioHistory.d.ts.map +1 -1
- package/dist/types/services/getPositions.d.ts.map +1 -1
- package/dist/types/services/getWithdrawableBalances.d.ts +1 -1
- package/dist/types/types/ws.d.ts +3 -2
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +1 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/liquidation.d.ts +23 -24
- package/dist/types/utils/liquidation.d.ts.map +1 -1
- package/dist/types/utils/mapActivity.d.ts +2 -1
- package/dist/types/utils/mapActivity.d.ts.map +1 -1
- package/dist/types/utils/mapFill.d.ts +3 -2
- package/dist/types/utils/mapFill.d.ts.map +1 -1
- package/dist/types/utils/mapMarket.d.ts +2 -2
- package/dist/types/utils/mapMarket.d.ts.map +1 -1
- package/dist/types/utils/mapMarketContext.d.ts.map +1 -1
- package/dist/types/utils/mapOrder.d.ts +12 -2
- package/dist/types/utils/mapOrder.d.ts.map +1 -1
- package/dist/types/utils/mapPosition.d.ts +4 -2
- package/dist/types/utils/mapPosition.d.ts.map +1 -1
- package/dist/types/utils/rowTimestamp.d.ts +6 -0
- package/dist/types/utils/rowTimestamp.d.ts.map +1 -0
- package/dist/types/utils/spotBalance.d.ts +5 -5
- package/dist/types/utils/spotBalance.d.ts.map +1 -1
- package/dist/types/utils/spotCollateral.d.ts.map +1 -1
- package/dist/types/utils/transferMargin.d.ts +2 -1
- package/dist/types/utils/transferMargin.d.ts.map +1 -1
- package/dist/types/utils/venueTotals.d.ts +7 -6
- package/dist/types/utils/venueTotals.d.ts.map +1 -1
- package/dist/types/utils/withdrawableBalances.d.ts +6 -4
- package/dist/types/utils/withdrawableBalances.d.ts.map +1 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts +3 -0
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/HyperliquidProvider.ts +1 -1
- package/src/accountSummary.ts +35 -23
- package/src/services/getAccount.ts +50 -33
- package/src/services/getFills.ts +2 -1
- package/src/services/getMarketSettings.ts +6 -2
- package/src/services/getOrder.ts +18 -7
- package/src/services/getOrders.ts +14 -46
- package/src/services/getPortfolioHistory.ts +34 -7
- package/src/services/getPositions.ts +4 -3
- package/src/services/getWithdrawableBalances.ts +1 -1
- package/src/types/ws.ts +3 -2
- package/src/utils/index.ts +2 -0
- package/src/utils/liquidation.ts +46 -34
- package/src/utils/mapActivity.ts +48 -20
- package/src/utils/mapFill.ts +25 -9
- package/src/utils/mapMarket.ts +16 -12
- package/src/utils/mapMarketContext.ts +6 -8
- package/src/utils/mapOrder.ts +107 -20
- package/src/utils/mapPosition.ts +72 -14
- package/src/utils/rowTimestamp.ts +15 -0
- package/src/utils/spotBalance.ts +19 -16
- package/src/utils/spotCollateral.ts +15 -2
- package/src/utils/transferMargin.ts +40 -18
- package/src/utils/venueTotals.ts +51 -17
- package/src/utils/withdrawableBalances.ts +33 -15
- package/src/websocket/HyperliquidWsProvider.ts +224 -133
- package/dist/cjs/utils/decimal.d.ts +0 -3
- package/dist/cjs/utils/decimal.d.ts.map +0 -1
- package/dist/cjs/utils/decimal.js +0 -19
- package/dist/cjs/utils/decimal.js.map +0 -1
- package/dist/esm/utils/decimal.d.ts +0 -10
- package/dist/esm/utils/decimal.d.ts.map +0 -1
- package/dist/esm/utils/decimal.js +0 -19
- package/dist/esm/utils/decimal.js.map +0 -1
- package/dist/types/utils/decimal.d.ts +0 -10
- package/dist/types/utils/decimal.d.ts.map +0 -1
- package/src/utils/decimal.ts +0 -21
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { calculateTransferable, DecodeChain, getMarketRegistry, isActiveMarket, isActiveOrderStatus,
|
|
1
|
+
import { addDecimalString, calculateTransferable, compareDecimalStrings, DecodeChain, getMarketRegistry, isActiveMarket, isActiveOrderStatus, isDecimalString, isDecimalStringZero, PerpsError, ReconnectingWebSocket, resolveSubscribeQuote, safeAddDecimalString, safeDecimalStringToNumber, safeDivideDecimalString, safeIsDecimalStringGreaterThan, safeIsDecimalStringZero, safeMultiplyDecimalString, safeNumberToDecimalString, safeSubtractDecimalString, subtractDecimalString, toAssetDisplay, toPerpsMarketDisplay, unknownToDecimalString, WsProviderBase, wsLog, } from '@lifi/perps-sdk';
|
|
2
2
|
import { PerpsErrorCode } from '@lifi/perps-types';
|
|
3
|
-
import Big from 'big.js';
|
|
4
3
|
import { isAddress } from 'viem';
|
|
5
|
-
import { DEFAULT_HYPERLIQUID_API_URL, HYPERLIQUID_FEE_TIER_FALLBACK, SPOT_MARKET_ID, } from '../constants.js';
|
|
4
|
+
import { DEFAULT_HYPERLIQUID_API_URL, HYPERLIQUID_FEE_TIER_FALLBACK, PROVIDER_KEY, SPOT_MARKET_ID, } from '../constants.js';
|
|
6
5
|
import { requireAccountExists } from '../services/getAccountExists.js';
|
|
7
6
|
import { HlAbstractionMode } from '../types/index.js';
|
|
8
|
-
import { toWireBig } from '../utils/decimal.js';
|
|
9
7
|
import { assetIsOutcome, decodeCompressedJson, decodeFastAssetCtxs, hlInfoOptions, infoRequest, isOpenAssetPosition, mapFill, mapMarketContext, mapOrder, mapPosition, partitionSpotBalances, perpsTotals, priceStepToAggregation, spotAssetFromToken, spotBalance, spotPriceById, sumUnrealizedPnl, } from '../utils/index.js';
|
|
8
|
+
import { mapOrderRow } from '../utils/mapOrder.js';
|
|
10
9
|
/** HL's compact `l2` snapshot carries 20 levels per side. */
|
|
11
10
|
const HL_L2_BOOK_MAX_LEVELS_PER_SIDE = 20;
|
|
12
11
|
const normalizeHlAddress = (address) => isAddress(address, { strict: false }) ? address.toLowerCase() : address;
|
|
@@ -390,7 +389,14 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
390
389
|
if (priceStep === undefined) {
|
|
391
390
|
return {};
|
|
392
391
|
}
|
|
393
|
-
|
|
392
|
+
const referencePrice = this.orderbookReferencePrice(marketId);
|
|
393
|
+
const referencePriceNumber = referencePrice === undefined
|
|
394
|
+
? undefined
|
|
395
|
+
: safeDecimalStringToNumber(referencePrice);
|
|
396
|
+
if (referencePriceNumber === undefined) {
|
|
397
|
+
return {};
|
|
398
|
+
}
|
|
399
|
+
return priceStepToAggregation(priceStep, referencePriceNumber);
|
|
394
400
|
}
|
|
395
401
|
orderbookAggregationKey(marketId, priceStep) {
|
|
396
402
|
const aggregation = this.orderbookAggregation(marketId, priceStep);
|
|
@@ -702,25 +708,26 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
702
708
|
});
|
|
703
709
|
}
|
|
704
710
|
/** Latest mid per `Market.id` across asset-context and fast feeds. */
|
|
711
|
+
/** Latest mid per `Market.id` across asset-context and fast feeds; a mid
|
|
712
|
+
* that does not match the decimal pattern is left out. */
|
|
705
713
|
mergedMids() {
|
|
706
714
|
const map = new Map();
|
|
715
|
+
const setMid = (id, mid) => {
|
|
716
|
+
const decimal = mid == null ? undefined : wsFigureToDecimalString(mid);
|
|
717
|
+
if (isDecimalString(decimal)) {
|
|
718
|
+
map.set(id, decimal);
|
|
719
|
+
}
|
|
720
|
+
};
|
|
707
721
|
for (const byMarketId of this.perpCtxBySubDex.values()) {
|
|
708
722
|
for (const [id, ctx] of Object.entries(byMarketId)) {
|
|
709
|
-
|
|
710
|
-
map.set(id, Number(mid));
|
|
723
|
+
setMid(id, ctx.midPx ?? ctx.markPx);
|
|
711
724
|
}
|
|
712
725
|
}
|
|
713
726
|
for (const [id, ctx] of Object.entries(this.spotCtxByMarketId)) {
|
|
714
|
-
|
|
715
|
-
if (mid != null) {
|
|
716
|
-
map.set(id, Number(mid));
|
|
717
|
-
}
|
|
727
|
+
setMid(id, ctx.midPx ?? ctx.markPx);
|
|
718
728
|
}
|
|
719
729
|
for (const [id, fast] of Object.entries(this.fastCtxByMarketId)) {
|
|
720
|
-
|
|
721
|
-
if (mid != null) {
|
|
722
|
-
map.set(id, Number(mid));
|
|
723
|
-
}
|
|
730
|
+
setMid(id, fast.midPx ?? fast.markPx);
|
|
724
731
|
}
|
|
725
732
|
return map;
|
|
726
733
|
}
|
|
@@ -732,21 +739,22 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
732
739
|
const book = this.latestOrderbookByMarketId.get(marketId);
|
|
733
740
|
const bid = book?.bids[0]?.price;
|
|
734
741
|
const ask = book?.asks[0]?.price;
|
|
735
|
-
if (bid
|
|
736
|
-
return
|
|
742
|
+
if (bid === undefined || ask === undefined) {
|
|
743
|
+
return undefined;
|
|
737
744
|
}
|
|
738
|
-
|
|
745
|
+
const sum = safeAddDecimalString(bid, ask);
|
|
746
|
+
return sum === undefined ? undefined : safeDivideDecimalString(sum, '2');
|
|
739
747
|
}
|
|
740
748
|
handleL2Book(data) {
|
|
741
749
|
const book = {
|
|
742
750
|
provider: this.providerKey,
|
|
743
751
|
marketId: data.coin,
|
|
744
752
|
bids: data.levels[0]
|
|
745
|
-
.
|
|
746
|
-
.
|
|
753
|
+
.flatMap((l) => toOrderbookLevel(data.coin, l.px, l.sz))
|
|
754
|
+
.slice(0, HL_L2_BOOK_MAX_LEVELS_PER_SIDE),
|
|
747
755
|
asks: data.levels[1]
|
|
748
|
-
.
|
|
749
|
-
.
|
|
756
|
+
.flatMap((l) => toOrderbookLevel(data.coin, l.px, l.sz))
|
|
757
|
+
.slice(0, HL_L2_BOOK_MAX_LEVELS_PER_SIDE),
|
|
750
758
|
timestamp: data.time,
|
|
751
759
|
};
|
|
752
760
|
this.latestOrderbookByMarketId.set(data.coin, book);
|
|
@@ -782,8 +790,8 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
782
790
|
const book = {
|
|
783
791
|
provider: this.providerKey,
|
|
784
792
|
marketId: delta.c,
|
|
785
|
-
bids: applyCompressedL2Side(previous.bids, delta.l[0], delta.r?.[0] ?? [], 'bid'),
|
|
786
|
-
asks: applyCompressedL2Side(previous.asks, delta.l[1], delta.r?.[1] ?? [], 'ask'),
|
|
793
|
+
bids: applyCompressedL2Side(delta.c, previous.bids, delta.l[0], delta.r?.[0] ?? [], 'bid'),
|
|
794
|
+
asks: applyCompressedL2Side(delta.c, previous.asks, delta.l[1], delta.r?.[1] ?? [], 'ask'),
|
|
787
795
|
timestamp: delta.t,
|
|
788
796
|
};
|
|
789
797
|
this.latestOrderbookByMarketId.set(delta.c, book);
|
|
@@ -846,40 +854,25 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
846
854
|
if (epoch !== this.orderUpdatesEpoch || key !== this.orderUpdatesKey) {
|
|
847
855
|
return;
|
|
848
856
|
}
|
|
857
|
+
const user = key.slice('orderUpdates:'.length);
|
|
849
858
|
const mapped = await Promise.all(data.map(async (update) => {
|
|
850
859
|
const basic = update.order;
|
|
851
|
-
if (assetIsOutcome(basic.coin)
|
|
860
|
+
if (assetIsOutcome(basic.coin) ||
|
|
861
|
+
this.registry?.get(basic.coin) === undefined) {
|
|
852
862
|
return undefined;
|
|
853
863
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
864
|
+
let detail;
|
|
865
|
+
try {
|
|
866
|
+
detail = await this.readOrderDetail(user, client, update);
|
|
857
867
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
throw new PerpsError(PerpsErrorCode.OrderNotFound, `Hyperliquid order metadata not found: ${basic.oid}`);
|
|
868
|
+
catch (error) {
|
|
869
|
+
if (!(error instanceof PerpsError)) {
|
|
870
|
+
throw error;
|
|
871
|
+
}
|
|
872
|
+
wsLog.droppedRow(this.providerKey, 'order', `${basic.oid}: ${error.message}`);
|
|
873
|
+
return undefined;
|
|
865
874
|
}
|
|
866
|
-
|
|
867
|
-
const detail = {
|
|
868
|
-
status: update.status,
|
|
869
|
-
statusTimestamp: update.statusTimestamp,
|
|
870
|
-
order: {
|
|
871
|
-
...response.order.order,
|
|
872
|
-
coin: basic.coin,
|
|
873
|
-
side: basic.side,
|
|
874
|
-
limitPx: basic.limitPx,
|
|
875
|
-
sz: basic.sz,
|
|
876
|
-
oid: basic.oid,
|
|
877
|
-
timestamp: basic.timestamp,
|
|
878
|
-
origSz: basic.origSz,
|
|
879
|
-
cloid: basic.cloid ?? response.order.order.cloid,
|
|
880
|
-
},
|
|
881
|
-
};
|
|
882
|
-
return mapOrder(detail, market);
|
|
875
|
+
return mapOrderRow(basic.coin, this.registry, (resolved) => mapOrder(detail, resolved));
|
|
883
876
|
}));
|
|
884
877
|
if (epoch !== this.orderUpdatesEpoch || key !== this.orderUpdatesKey) {
|
|
885
878
|
return;
|
|
@@ -898,6 +891,29 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
898
891
|
this.emit(key, { channel: 'orderUpdates', data: { orders, terminated } });
|
|
899
892
|
});
|
|
900
893
|
}
|
|
894
|
+
// REST supplies execution metadata; the stream owns this event's lifecycle and quantities.
|
|
895
|
+
async readOrderDetail(user, client, update) {
|
|
896
|
+
const basic = update.order;
|
|
897
|
+
const response = await infoRequest(this.orderApiUrl, { type: 'orderStatus', user, oid: basic.oid }, hlInfoOptions(client));
|
|
898
|
+
if (response.status !== 'order') {
|
|
899
|
+
throw new PerpsError(PerpsErrorCode.OrderNotFound, `Hyperliquid order metadata not found: ${basic.oid}`);
|
|
900
|
+
}
|
|
901
|
+
return {
|
|
902
|
+
status: update.status,
|
|
903
|
+
statusTimestamp: update.statusTimestamp,
|
|
904
|
+
order: {
|
|
905
|
+
...response.order.order,
|
|
906
|
+
coin: basic.coin,
|
|
907
|
+
side: basic.side,
|
|
908
|
+
limitPx: basic.limitPx,
|
|
909
|
+
sz: basic.sz,
|
|
910
|
+
oid: basic.oid,
|
|
911
|
+
timestamp: basic.timestamp,
|
|
912
|
+
origSz: basic.origSz,
|
|
913
|
+
cloid: basic.cloid ?? response.order.order.cloid,
|
|
914
|
+
},
|
|
915
|
+
};
|
|
916
|
+
}
|
|
901
917
|
handleUserFills(data) {
|
|
902
918
|
// The snapshot frame carries up to ~2000 historical fills and is replayed
|
|
903
919
|
// on every reconnect via `replaySubs`; emitting them would surface old
|
|
@@ -911,7 +927,8 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
911
927
|
return [];
|
|
912
928
|
}
|
|
913
929
|
const market = this.registry?.get(f.coin);
|
|
914
|
-
|
|
930
|
+
const mapped = market && mapFill(f, market);
|
|
931
|
+
return mapped ? [mapped] : [];
|
|
915
932
|
});
|
|
916
933
|
this.emit(`userFills:${data.user.toLowerCase()}`, {
|
|
917
934
|
channel: 'fills',
|
|
@@ -925,9 +942,10 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
925
942
|
return [];
|
|
926
943
|
}
|
|
927
944
|
const market = this.registry?.get(ap.position.coin);
|
|
928
|
-
|
|
929
|
-
?
|
|
930
|
-
:
|
|
945
|
+
const position = market === undefined
|
|
946
|
+
? undefined
|
|
947
|
+
: mapPosition(ap, toPerpsMarketDisplay(market));
|
|
948
|
+
return position === undefined ? [] : [position];
|
|
931
949
|
}));
|
|
932
950
|
this.emit(`positions:${data.user.toLowerCase()}`, {
|
|
933
951
|
channel: 'positions',
|
|
@@ -935,20 +953,17 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
935
953
|
});
|
|
936
954
|
const { accountValue, marginUsed } = perpsTotals(data.clearinghouseStates.map(([, state]) => state));
|
|
937
955
|
const key = data.user.toLowerCase();
|
|
938
|
-
this.latestPerpsByUser.set(key, {
|
|
939
|
-
positions,
|
|
940
|
-
marginUsed: marginUsed.toFixed(),
|
|
941
|
-
});
|
|
956
|
+
this.latestPerpsByUser.set(key, { positions, marginUsed });
|
|
942
957
|
this.emitUnifiedSummary(key);
|
|
943
958
|
// Equity semantics, matching the REST summary: `accountValue` already
|
|
944
959
|
// carries locked margin and unrealized PnL. Spot balances stream apart,
|
|
945
960
|
// so this portfolio value covers perps equity only — which is why the
|
|
946
961
|
// frame is gated on the abstraction mode below.
|
|
947
962
|
this.emitSummaryIfModeAllows(data.user, {
|
|
948
|
-
portfolioValue: accountValue
|
|
949
|
-
availableMargin: accountValue
|
|
950
|
-
marginUsed
|
|
951
|
-
unrealizedPnl: sumUnrealizedPnl(positions)
|
|
963
|
+
portfolioValue: accountValue,
|
|
964
|
+
availableMargin: subtractDecimalString(accountValue, marginUsed),
|
|
965
|
+
marginUsed,
|
|
966
|
+
unrealizedPnl: sumUnrealizedPnl(positions),
|
|
952
967
|
});
|
|
953
968
|
}
|
|
954
969
|
/** Whether the mode's collateral lives per-dex, making the perps-only
|
|
@@ -1039,14 +1054,14 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
1039
1054
|
const portfolioValue = [
|
|
1040
1055
|
...pipeline.spot.collateralBalances,
|
|
1041
1056
|
...pipeline.spot.balances,
|
|
1042
|
-
].reduce((sum, balance) => sum
|
|
1057
|
+
].reduce((sum, balance) => addDecimalString(sum, unknownToDecimalString(balance.valueUsd, 'spotBalance.valueUsd', this.providerKey)), '0');
|
|
1043
1058
|
this.emit(`accountSummary:${key}`, {
|
|
1044
1059
|
channel: 'accountSummary',
|
|
1045
1060
|
data: {
|
|
1046
|
-
portfolioValue
|
|
1061
|
+
portfolioValue,
|
|
1047
1062
|
availableMargin: pipeline.availableMargin,
|
|
1048
1063
|
marginUsed: perps.marginUsed,
|
|
1049
|
-
unrealizedPnl: sumUnrealizedPnl(perps.positions)
|
|
1064
|
+
unrealizedPnl: sumUnrealizedPnl(perps.positions),
|
|
1050
1065
|
},
|
|
1051
1066
|
});
|
|
1052
1067
|
}
|
|
@@ -1172,24 +1187,27 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
1172
1187
|
}
|
|
1173
1188
|
const markets = this.registry?.activeMarkets ?? [];
|
|
1174
1189
|
const priceById = spotPriceById(markets, this.mergedMids());
|
|
1175
|
-
const balances = data.spotState.balances
|
|
1176
|
-
|
|
1190
|
+
const balances = data.spotState.balances
|
|
1191
|
+
.filter((balance) => !assetIsOutcome(balance.coin))
|
|
1192
|
+
.filter((balance) => safeIsDecimalStringGreaterThan(balance.total, '0') === true)
|
|
1193
|
+
.map((balance) => ({ balance, total: balance.total }));
|
|
1177
1194
|
const pipeline = this.unifiedSummaryByUser.get(user);
|
|
1178
1195
|
// Known spot markets await a price; unlisted tokens keep their unpriced balance.
|
|
1179
|
-
if (balances.some((balance) =>
|
|
1196
|
+
if (balances.some(({ balance }) => {
|
|
1197
|
+
const price = priceById.get(String(balance.token));
|
|
1198
|
+
return price !== undefined && isDecimalStringZero(price);
|
|
1199
|
+
})) {
|
|
1180
1200
|
if (pipeline !== undefined) {
|
|
1181
1201
|
pipeline.spot = undefined;
|
|
1182
1202
|
}
|
|
1183
1203
|
return;
|
|
1184
1204
|
}
|
|
1185
|
-
const rows = balances.map((balance) => {
|
|
1186
|
-
const
|
|
1205
|
+
const rows = balances.map(({ balance, total }) => {
|
|
1206
|
+
const free = safeSubtractDecimalString(total, balance.hold);
|
|
1187
1207
|
return {
|
|
1188
|
-
...spotBalance(spotAssetFromToken(balance),
|
|
1208
|
+
...spotBalance(spotAssetFromToken(balance), total, priceById),
|
|
1189
1209
|
locked: balance.hold,
|
|
1190
|
-
transferable: calculateTransferable(total
|
|
1191
|
-
.minus(toWireBig(balance.hold, 'spotState.balances.hold'))
|
|
1192
|
-
.toFixed(), total.toFixed()),
|
|
1210
|
+
transferable: free === undefined ? '0' : calculateTransferable(free, total),
|
|
1193
1211
|
};
|
|
1194
1212
|
});
|
|
1195
1213
|
this.emit(`spotState:${user}`, {
|
|
@@ -1229,29 +1247,22 @@ export class HyperliquidWsProvider extends WsProviderBase {
|
|
|
1229
1247
|
}
|
|
1230
1248
|
}
|
|
1231
1249
|
const isObject = (v) => typeof v === 'object' && v !== null;
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1250
|
+
/** A WebSocket figure as a string; a venue number is spelled as a decimal
|
|
1251
|
+
* string, and a non-finite number gives `undefined`. */
|
|
1252
|
+
function wsFigureToDecimalString(value) {
|
|
1253
|
+
return typeof value === 'number' ? safeNumberToDecimalString(value) : value;
|
|
1254
|
+
}
|
|
1255
|
+
function optionalWsFigureToDecimalString(value) {
|
|
1256
|
+
return value == null ? undefined : wsFigureToDecimalString(value);
|
|
1257
|
+
}
|
|
1238
1258
|
const toMarketCapString = (price, circulatingSupply) => {
|
|
1239
|
-
const
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
}
|
|
1244
|
-
try {
|
|
1245
|
-
const parsedPrice = new Big(priceString);
|
|
1246
|
-
const parsedSupply = new Big(supplyString);
|
|
1247
|
-
if (parsedPrice.lte(0) || parsedSupply.lte(0)) {
|
|
1248
|
-
return undefined;
|
|
1249
|
-
}
|
|
1250
|
-
return parsedPrice.times(parsedSupply).toFixed();
|
|
1251
|
-
}
|
|
1252
|
-
catch {
|
|
1259
|
+
const supply = optionalWsFigureToDecimalString(circulatingSupply);
|
|
1260
|
+
if (supply === undefined ||
|
|
1261
|
+
safeIsDecimalStringGreaterThan(price, '0') !== true ||
|
|
1262
|
+
safeIsDecimalStringGreaterThan(supply, '0') !== true) {
|
|
1253
1263
|
return undefined;
|
|
1254
1264
|
}
|
|
1265
|
+
return safeMultiplyDecimalString(price, supply);
|
|
1255
1266
|
};
|
|
1256
1267
|
function mergePerpAssetCtx(previous, marketId, update) {
|
|
1257
1268
|
const funding = update.funding ?? previous?.funding;
|
|
@@ -1285,15 +1296,13 @@ function allDexsAssetCtxEntries(data) {
|
|
|
1285
1296
|
return data.assetCtxs ?? data.ctxs ?? [];
|
|
1286
1297
|
}
|
|
1287
1298
|
function activePerpAssetCtx(marketId, ctx) {
|
|
1288
|
-
const funding =
|
|
1289
|
-
const openInterest =
|
|
1290
|
-
const dayNtlVlm =
|
|
1291
|
-
const prevDayPx =
|
|
1292
|
-
const markPx =
|
|
1293
|
-
const midPx = ctx.midPx
|
|
1294
|
-
|
|
1295
|
-
: (toMarketContextString(ctx.midPx) ?? null);
|
|
1296
|
-
const oraclePx = toMarketContextString(ctx.oraclePx);
|
|
1299
|
+
const funding = optionalWsFigureToDecimalString(ctx.funding);
|
|
1300
|
+
const openInterest = optionalWsFigureToDecimalString(ctx.openInterest);
|
|
1301
|
+
const dayNtlVlm = optionalWsFigureToDecimalString(ctx.dayNtlVlm);
|
|
1302
|
+
const prevDayPx = optionalWsFigureToDecimalString(ctx.prevDayPx);
|
|
1303
|
+
const markPx = optionalWsFigureToDecimalString(ctx.markPx);
|
|
1304
|
+
const midPx = optionalWsFigureToDecimalString(ctx.midPx) ?? null;
|
|
1305
|
+
const oraclePx = optionalWsFigureToDecimalString(ctx.oraclePx);
|
|
1297
1306
|
if (funding === undefined ||
|
|
1298
1307
|
openInterest === undefined ||
|
|
1299
1308
|
dayNtlVlm === undefined ||
|
|
@@ -1314,8 +1323,8 @@ function activePerpAssetCtx(marketId, ctx) {
|
|
|
1314
1323
|
};
|
|
1315
1324
|
}
|
|
1316
1325
|
function mapSpotMarketContext(marketId, ctx, fast) {
|
|
1317
|
-
const midPrice =
|
|
1318
|
-
const markPrice =
|
|
1326
|
+
const midPrice = optionalWsFigureToDecimalString(ctx.midPx ?? ctx.markPx);
|
|
1327
|
+
const markPrice = optionalWsFigureToDecimalString(ctx.markPx);
|
|
1319
1328
|
if (midPrice === undefined || markPrice === undefined) {
|
|
1320
1329
|
return undefined;
|
|
1321
1330
|
}
|
|
@@ -1324,18 +1333,43 @@ function mapSpotMarketContext(marketId, ctx, fast) {
|
|
|
1324
1333
|
marketId,
|
|
1325
1334
|
midPrice: fast?.midPx != null ? fast.midPx : midPrice,
|
|
1326
1335
|
markPrice: emittedMarkPrice,
|
|
1327
|
-
prevDayPrice:
|
|
1328
|
-
volume24h:
|
|
1336
|
+
prevDayPrice: optionalWsFigureToDecimalString(ctx.prevDayPx),
|
|
1337
|
+
volume24h: optionalWsFigureToDecimalString(ctx.dayNtlVlm),
|
|
1329
1338
|
marketCap: toMarketCapString(emittedMarkPrice, ctx.circulatingSupply),
|
|
1330
1339
|
};
|
|
1331
1340
|
}
|
|
1341
|
+
const BOOK_LEVEL_ROW = 'order book level';
|
|
1342
|
+
/** The venue price when it is a decimal string, or `undefined` after a logged skip. */
|
|
1343
|
+
function bookLevelPrice(marketId, price) {
|
|
1344
|
+
if (!isDecimalString(price)) {
|
|
1345
|
+
wsLog.skippedRow(PROVIDER_KEY, BOOK_LEVEL_ROW, 'price', price, marketId);
|
|
1346
|
+
return undefined;
|
|
1347
|
+
}
|
|
1348
|
+
return price;
|
|
1349
|
+
}
|
|
1350
|
+
/** The venue size when it is a decimal string, or `undefined` after a logged skip. */
|
|
1351
|
+
function bookLevelSize(marketId, size) {
|
|
1352
|
+
if (!isDecimalString(size)) {
|
|
1353
|
+
wsLog.skippedRow(PROVIDER_KEY, BOOK_LEVEL_ROW, 'size', size, marketId);
|
|
1354
|
+
return undefined;
|
|
1355
|
+
}
|
|
1356
|
+
return size;
|
|
1357
|
+
}
|
|
1358
|
+
/** One order-book level, or none when the venue price or size is invalid. */
|
|
1359
|
+
function toOrderbookLevel(marketId, price, size) {
|
|
1360
|
+
const levelPrice = bookLevelPrice(marketId, price);
|
|
1361
|
+
const levelSize = levelPrice === undefined ? undefined : bookLevelSize(marketId, size);
|
|
1362
|
+
return levelPrice === undefined || levelSize === undefined
|
|
1363
|
+
? []
|
|
1364
|
+
: [{ price: levelPrice, size: levelSize }];
|
|
1365
|
+
}
|
|
1332
1366
|
function compactRemovalPrice(levels, value) {
|
|
1333
1367
|
if (typeof value === 'number') {
|
|
1334
1368
|
return levels[value]?.price;
|
|
1335
1369
|
}
|
|
1336
1370
|
return typeof value === 'string' ? value : value.p;
|
|
1337
1371
|
}
|
|
1338
|
-
function applyCompressedL2Side(previous, updates, removals, side) {
|
|
1372
|
+
function applyCompressedL2Side(marketId, previous, updates, removals, side) {
|
|
1339
1373
|
const byPrice = new Map(previous.map((level) => [level.price, level.size]));
|
|
1340
1374
|
for (const removal of removals) {
|
|
1341
1375
|
const price = compactRemovalPrice(previous, removal);
|
|
@@ -1344,18 +1378,24 @@ function applyCompressedL2Side(previous, updates, removals, side) {
|
|
|
1344
1378
|
}
|
|
1345
1379
|
}
|
|
1346
1380
|
for (const update of updates) {
|
|
1347
|
-
|
|
1348
|
-
|
|
1381
|
+
const price = bookLevelPrice(marketId, update.p);
|
|
1382
|
+
if (price === undefined) {
|
|
1383
|
+
continue;
|
|
1384
|
+
}
|
|
1385
|
+
const size = bookLevelSize(marketId, update.s);
|
|
1386
|
+
// A level whose new size is unknown must not keep its old size.
|
|
1387
|
+
if (size === undefined || safeIsDecimalStringZero(size) !== false) {
|
|
1388
|
+
byPrice.delete(price);
|
|
1349
1389
|
}
|
|
1350
1390
|
else {
|
|
1351
|
-
byPrice.set(
|
|
1391
|
+
byPrice.set(price, size);
|
|
1352
1392
|
}
|
|
1353
1393
|
}
|
|
1354
1394
|
return [...byPrice.entries()]
|
|
1355
1395
|
.map(([price, size]) => ({ price, size }))
|
|
1356
1396
|
.sort((a, b) => side === 'bid'
|
|
1357
|
-
?
|
|
1358
|
-
:
|
|
1397
|
+
? compareDecimalStrings(b.price, a.price)
|
|
1398
|
+
: compareDecimalStrings(a.price, b.price))
|
|
1359
1399
|
.slice(0, HL_L2_BOOK_MAX_LEVELS_PER_SIDE);
|
|
1360
1400
|
}
|
|
1361
1401
|
/**
|