@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,11 +1,17 @@
|
|
|
1
|
-
import { PerpsError, type SDKRequestOptions } from '@lifi/perps-sdk'
|
|
2
1
|
import {
|
|
2
|
+
PerpsError,
|
|
3
|
+
type SDKRequestOptions,
|
|
4
|
+
warnSkippedVenueRow,
|
|
5
|
+
} from '@lifi/perps-sdk'
|
|
6
|
+
import {
|
|
7
|
+
type DecimalString,
|
|
3
8
|
PerpsErrorCode,
|
|
4
9
|
type PortfolioHistoryPoint,
|
|
5
10
|
type PortfolioHistoryRange,
|
|
6
11
|
type PortfolioHistoryResponse,
|
|
7
12
|
} from '@lifi/perps-types'
|
|
8
13
|
import type { Address } from 'viem'
|
|
14
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
9
15
|
import type { HyperliquidContext } from '../context.js'
|
|
10
16
|
import type {
|
|
11
17
|
HlAbstractionMode,
|
|
@@ -40,19 +46,35 @@ const PERP_PERIOD_BY_RANGE: Record<PortfolioHistoryRange, HlPortfolioPeriod> = {
|
|
|
40
46
|
all: 'perpAllTime',
|
|
41
47
|
}
|
|
42
48
|
|
|
49
|
+
/** The samples with a finite timestamp; each other sample is skipped. */
|
|
50
|
+
const validSamples = (
|
|
51
|
+
samples: HlPortfolioWindow['pnlHistory'],
|
|
52
|
+
row: string
|
|
53
|
+
): [number, DecimalString][] =>
|
|
54
|
+
samples.flatMap(([timestamp, value]): [number, DecimalString][] => {
|
|
55
|
+
if (!Number.isFinite(timestamp)) {
|
|
56
|
+
warnSkippedVenueRow(PROVIDER_KEY, row, 'timestamp', timestamp, {
|
|
57
|
+
expected: 'timestamp',
|
|
58
|
+
})
|
|
59
|
+
return []
|
|
60
|
+
}
|
|
61
|
+
return [[timestamp, value]]
|
|
62
|
+
})
|
|
63
|
+
|
|
43
64
|
/**
|
|
44
65
|
* Join the window's two series on their timestamps. `pnlHistory` is cumulative
|
|
45
66
|
* from the window's start, so a point with no PnL sample carries the last
|
|
46
67
|
* sampled value — `'0'` before the first one.
|
|
47
68
|
*/
|
|
48
69
|
const joinWindow = (
|
|
49
|
-
|
|
70
|
+
accountValueHistory: [number, DecimalString][],
|
|
71
|
+
pnlHistory: [number, DecimalString][],
|
|
50
72
|
period: HlPortfolioPeriod
|
|
51
73
|
): PortfolioHistoryPoint[] => {
|
|
52
|
-
const pnlByTimestamp = new Map(
|
|
74
|
+
const pnlByTimestamp = new Map(pnlHistory)
|
|
53
75
|
let matched = 0
|
|
54
76
|
let cumulative = '0'
|
|
55
|
-
const points =
|
|
77
|
+
const points = accountValueHistory.map(([timestamp, accountValue]) => {
|
|
56
78
|
const sample = pnlByTimestamp.get(timestamp)
|
|
57
79
|
if (sample !== undefined) {
|
|
58
80
|
matched += 1
|
|
@@ -60,7 +82,7 @@ const joinWindow = (
|
|
|
60
82
|
}
|
|
61
83
|
return { timestamp, accountValue, pnl: cumulative }
|
|
62
84
|
})
|
|
63
|
-
if (points.length > 0 &&
|
|
85
|
+
if (points.length > 0 && pnlHistory.length > 0 && matched === 0) {
|
|
64
86
|
throw new PerpsError(
|
|
65
87
|
PerpsErrorCode.ThirdPartyError,
|
|
66
88
|
`Hyperliquid portfolio window '${period}' samples PnL on no ` +
|
|
@@ -111,10 +133,15 @@ export async function getPortfolioHistory(
|
|
|
111
133
|
)
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
const pnlHistory = validSamples(window.pnlHistory, 'portfolio PnL sample')
|
|
114
137
|
return {
|
|
115
138
|
range: params.range,
|
|
116
|
-
points: joinWindow(
|
|
139
|
+
points: joinWindow(
|
|
140
|
+
validSamples(window.accountValueHistory, 'portfolio value sample'),
|
|
141
|
+
pnlHistory,
|
|
142
|
+
period
|
|
143
|
+
),
|
|
117
144
|
volume: window.vlm,
|
|
118
|
-
totalPnl:
|
|
145
|
+
totalPnl: pnlHistory.at(-1)?.[1],
|
|
119
146
|
}
|
|
120
147
|
}
|
|
@@ -67,12 +67,13 @@ export const getPositions = async (
|
|
|
67
67
|
.filter(
|
|
68
68
|
(ap) => !assetIsOutcome(ap.position.coin) && isOpenAssetPosition(ap)
|
|
69
69
|
)
|
|
70
|
-
.
|
|
71
|
-
mapPosition(
|
|
70
|
+
.flatMap((ap) => {
|
|
71
|
+
const position = mapPosition(
|
|
72
72
|
ap,
|
|
73
73
|
toPerpsMarketDisplay(registry.require(ap.position.coin))
|
|
74
74
|
)
|
|
75
|
-
|
|
75
|
+
return position === undefined ? [] : [position]
|
|
76
|
+
})
|
|
76
77
|
)
|
|
77
78
|
|
|
78
79
|
if (params.marketId !== undefined) {
|
|
@@ -27,7 +27,7 @@ export type GetWithdrawableBalancesParams =
|
|
|
27
27
|
ProviderGetWithdrawableBalancesParams
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* The `(asset,
|
|
30
|
+
* The `(asset, category)` pairs `params.address` can withdraw from Hyperliquid,
|
|
31
31
|
* read from the venue's own `withdrawable` and spot `total`/`hold` figures.
|
|
32
32
|
* Hyperliquid charges its flat withdrawal fee in USDC, so the backend's
|
|
33
33
|
* `withdrawalFeeUsd` is the fee in quote-asset units on every USDC row.
|
package/src/types/ws.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Hyperliquid WebSocket incoming message types.
|
|
2
2
|
|
|
3
|
+
import type { DecimalString } from '@lifi/perps-types'
|
|
3
4
|
import type { HlClearinghouseState, HlSpotBalance } from './account.js'
|
|
4
5
|
import type { HlCandle, HlL2Book } from './asset.js'
|
|
5
6
|
import type { HlUserFill } from './fill.js'
|
|
@@ -77,8 +78,8 @@ export type HlWsMessage = {
|
|
|
77
78
|
* @public
|
|
78
79
|
*/
|
|
79
80
|
export type HlWsFastAssetCtx = {
|
|
80
|
-
markPx?:
|
|
81
|
-
midPx?:
|
|
81
|
+
markPx?: DecimalString
|
|
82
|
+
midPx?: DecimalString | null
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
/**
|
package/src/utils/index.ts
CHANGED
|
@@ -27,6 +27,8 @@ export { hlInfoOptions, infoRequest } from './infoClient.js'
|
|
|
27
27
|
export {
|
|
28
28
|
calculateLiquidationPrice,
|
|
29
29
|
calculateMaintenanceMarginRate,
|
|
30
|
+
safeCalculateLiquidationPrice,
|
|
31
|
+
safeCalculateMaintenanceMarginRate,
|
|
30
32
|
} from './liquidation.js'
|
|
31
33
|
export {
|
|
32
34
|
mapFundingActivity,
|
package/src/utils/liquidation.ts
CHANGED
|
@@ -12,63 +12,75 @@
|
|
|
12
12
|
* - margin_available = isolated_margin - maintenance_margin_required
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
createSafeFunction,
|
|
17
|
+
divideDecimalString,
|
|
18
|
+
estimateLiquidationPrice,
|
|
19
|
+
numberToDecimalString,
|
|
20
|
+
PerpsError,
|
|
21
|
+
} from '@lifi/perps-sdk'
|
|
22
|
+
import { type DecimalString, PerpsErrorCode } from '@lifi/perps-types'
|
|
16
23
|
|
|
17
24
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* Maintenance margin is half of the initial margin at max leverage.
|
|
25
|
+
* Maintenance margin fraction for a Hyperliquid asset: half of the initial
|
|
26
|
+
* margin at max leverage, `1 / (2 × maxLeverage)`.
|
|
21
27
|
*
|
|
22
28
|
* @param maxLeverage - Maximum leverage for the asset (e.g., 50 for BTC)
|
|
23
|
-
* @returns Maintenance margin fraction (
|
|
24
|
-
*
|
|
29
|
+
* @returns Maintenance margin fraction (`'0.01'` for 50x max leverage)
|
|
30
|
+
* @throws {PerpsError} `ValidationError` when `maxLeverage` is not a finite
|
|
31
|
+
* number above zero.
|
|
25
32
|
* @public
|
|
26
33
|
*/
|
|
27
34
|
export function calculateMaintenanceMarginRate(
|
|
28
35
|
maxLeverage: number
|
|
29
|
-
):
|
|
30
|
-
if (maxLeverage
|
|
31
|
-
|
|
36
|
+
): DecimalString {
|
|
37
|
+
if (!Number.isFinite(maxLeverage) || maxLeverage <= 0) {
|
|
38
|
+
throw new PerpsError(
|
|
39
|
+
PerpsErrorCode.ValidationError,
|
|
40
|
+
`\`maxLeverage\` must be a finite number above zero, got ${maxLeverage}.`
|
|
41
|
+
)
|
|
32
42
|
}
|
|
33
|
-
return 1
|
|
43
|
+
return divideDecimalString('1', numberToDecimalString(2 * maxLeverage))
|
|
34
44
|
}
|
|
35
45
|
|
|
46
|
+
/** @public */
|
|
47
|
+
export const safeCalculateMaintenanceMarginRate = createSafeFunction(
|
|
48
|
+
'calculateMaintenanceMarginRate',
|
|
49
|
+
calculateMaintenanceMarginRate
|
|
50
|
+
)
|
|
51
|
+
|
|
36
52
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* prefer Position.liquidationPrice from the API.
|
|
53
|
+
* Liquidation price of a new isolated position with the exact Hyperliquid
|
|
54
|
+
* formula. For an existing position, prefer `Position.liquidationPrice` from
|
|
55
|
+
* the API.
|
|
41
56
|
*
|
|
42
57
|
* Formula derivation (isolated margin, single position):
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* margin_available = margin_per_unit - maintenance_per_unit
|
|
46
|
-
* liq_price = entryPrice - side * margin_available / (1 - mmr * side)
|
|
58
|
+
* margin_available = entryPrice × (1 / leverage - mmr)
|
|
59
|
+
* liq_price = entryPrice - side × margin_available / (1 - mmr × side)
|
|
47
60
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @
|
|
52
|
-
*
|
|
53
|
-
* @param maxLeverage - Asset's maximum leverage (e.g., 50 for BTC). Determines
|
|
54
|
-
* the maintenance margin rate: mmr = 1 / (2 * maxLeverage)
|
|
55
|
-
* @returns Estimated liquidation price, or undefined if inputs are invalid
|
|
61
|
+
* @param leverage - User-selected leverage (e.g., `'10'`)
|
|
62
|
+
* @param maxLeverage - Asset's maximum leverage (e.g., 50 for BTC). Sets
|
|
63
|
+
* mmr = 1 / (2 × maxLeverage).
|
|
64
|
+
* @throws {PerpsError} `ValidationError` when `maxLeverage` is not a finite
|
|
65
|
+
* number above zero, or on an input that `estimateLiquidationPrice` rejects.
|
|
56
66
|
* @public
|
|
57
67
|
*/
|
|
58
68
|
export function calculateLiquidationPrice(
|
|
59
|
-
entryPrice:
|
|
60
|
-
leverage:
|
|
69
|
+
entryPrice: string,
|
|
70
|
+
leverage: string,
|
|
61
71
|
isLong: boolean,
|
|
62
72
|
maxLeverage: number
|
|
63
|
-
):
|
|
64
|
-
const mmr = calculateMaintenanceMarginRate(maxLeverage)
|
|
65
|
-
if (mmr === undefined) {
|
|
66
|
-
return undefined
|
|
67
|
-
}
|
|
73
|
+
): string {
|
|
68
74
|
return estimateLiquidationPrice({
|
|
69
75
|
entryPrice,
|
|
70
76
|
leverage,
|
|
71
77
|
isLong,
|
|
72
|
-
maintenanceMarginRate:
|
|
78
|
+
maintenanceMarginRate: calculateMaintenanceMarginRate(maxLeverage),
|
|
73
79
|
})
|
|
74
80
|
}
|
|
81
|
+
|
|
82
|
+
/** @public */
|
|
83
|
+
export const safeCalculateLiquidationPrice = createSafeFunction(
|
|
84
|
+
'calculateLiquidationPrice',
|
|
85
|
+
calculateLiquidationPrice
|
|
86
|
+
)
|
package/src/utils/mapActivity.ts
CHANGED
|
@@ -3,6 +3,10 @@ import {
|
|
|
3
3
|
ExplorerChainId,
|
|
4
4
|
explorerTxUrl,
|
|
5
5
|
PerpsError,
|
|
6
|
+
safeAddDecimalString,
|
|
7
|
+
safeMultiplyDecimalString,
|
|
8
|
+
safeSubtractDecimalString,
|
|
9
|
+
warnSkippedVenueRow,
|
|
6
10
|
} from '@lifi/perps-sdk'
|
|
7
11
|
import type {
|
|
8
12
|
ActivityItem,
|
|
@@ -16,7 +20,6 @@ import type {
|
|
|
16
20
|
WithdrawalActivity,
|
|
17
21
|
} from '@lifi/perps-types'
|
|
18
22
|
import { ActivityType, PerpsErrorCode } from '@lifi/perps-types'
|
|
19
|
-
import Big from 'big.js'
|
|
20
23
|
import { zeroHash } from 'viem'
|
|
21
24
|
import type {
|
|
22
25
|
HlBorrowLendOperation,
|
|
@@ -35,6 +38,7 @@ import {
|
|
|
35
38
|
isVaultTransferDelta,
|
|
36
39
|
isWithdrawDelta,
|
|
37
40
|
} from '../types/index.js'
|
|
41
|
+
import { rowTimestampToIsoStringOrUndefined } from './rowTimestamp.js'
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
44
|
* Hyperliquid settles every perp deposit and withdrawal in USDC, and charges
|
|
@@ -96,11 +100,14 @@ export const mapLedgerEntry = (
|
|
|
96
100
|
resolveMarket: (coin: string) => MarketDisplay | undefined
|
|
97
101
|
): ActivityItem | null => {
|
|
98
102
|
const { delta } = entry
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
const timestamp = rowTimestampToIsoStringOrUndefined(entry.time)
|
|
104
|
+
if (timestamp === undefined) {
|
|
105
|
+
warnSkippedVenueRow(providerKey, 'ledger', 'time', entry.time, {
|
|
106
|
+
expected: 'timestamp',
|
|
107
|
+
})
|
|
108
|
+
return null
|
|
103
109
|
}
|
|
110
|
+
const base = { id: entry.hash, provider: providerKey, timestamp }
|
|
104
111
|
|
|
105
112
|
if (
|
|
106
113
|
isSpotTransferDelta(delta) ||
|
|
@@ -315,7 +322,13 @@ export const mapFundingActivity = (
|
|
|
315
322
|
if (market === undefined) {
|
|
316
323
|
return null
|
|
317
324
|
}
|
|
318
|
-
const timestamp =
|
|
325
|
+
const timestamp = rowTimestampToIsoStringOrUndefined(entry.time)
|
|
326
|
+
if (timestamp === undefined) {
|
|
327
|
+
warnSkippedVenueRow(providerKey, 'funding', 'time', entry.time, {
|
|
328
|
+
expected: 'timestamp',
|
|
329
|
+
})
|
|
330
|
+
return null
|
|
331
|
+
}
|
|
319
332
|
return {
|
|
320
333
|
id: `funding:${entry.delta.coin}:${timestamp}`,
|
|
321
334
|
provider: providerKey,
|
|
@@ -334,7 +347,8 @@ export const mapFundingActivity = (
|
|
|
334
347
|
* parties, so only fills whose `liquidatedUser` is the queried address count.
|
|
335
348
|
* A fill whose hash a ledger liquidation row already carries is the same
|
|
336
349
|
* event and is skipped. The size sign follows the closed position: a sell
|
|
337
|
-
* fill closes a long. Groups whose market does not resolve are
|
|
350
|
+
* fill closes a long. Groups whose market or time does not resolve are
|
|
351
|
+
* dropped; an invalid fill size or price leaves the derived field absent.
|
|
338
352
|
* @public
|
|
339
353
|
*/
|
|
340
354
|
export const mapLiquidationFills = (
|
|
@@ -363,26 +377,40 @@ export const mapLiquidationFills = (
|
|
|
363
377
|
if (market === undefined) {
|
|
364
378
|
return []
|
|
365
379
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
380
|
+
const size = group.reduce<string | undefined>(
|
|
381
|
+
(sum, fill) =>
|
|
382
|
+
sum === undefined ? undefined : safeAddDecimalString(sum, fill.sz),
|
|
383
|
+
'0'
|
|
384
|
+
)
|
|
385
|
+
const notional = group.reduce<string | undefined>((sum, fill) => {
|
|
386
|
+
const fillNotional = safeMultiplyDecimalString(fill.px, fill.sz)
|
|
387
|
+
return sum === undefined || fillNotional === undefined
|
|
388
|
+
? undefined
|
|
389
|
+
: safeAddDecimalString(sum, fillNotional)
|
|
390
|
+
}, '0')
|
|
391
|
+
const time = Math.max(...group.map((fill) => fill.time))
|
|
392
|
+
const timestamp = rowTimestampToIsoStringOrUndefined(time)
|
|
393
|
+
if (timestamp === undefined) {
|
|
394
|
+
warnSkippedVenueRow(providerKey, 'liquidation', 'time', time, {
|
|
395
|
+
expected: 'timestamp',
|
|
396
|
+
})
|
|
397
|
+
return []
|
|
373
398
|
}
|
|
399
|
+
const closedSize =
|
|
400
|
+
size === undefined || first.side === 'A'
|
|
401
|
+
? size
|
|
402
|
+
: safeSubtractDecimalString('0', size)
|
|
374
403
|
return [
|
|
375
404
|
{
|
|
376
405
|
id: `liquidation:${oid}`,
|
|
377
406
|
provider: providerKey,
|
|
378
|
-
timestamp
|
|
407
|
+
timestamp,
|
|
379
408
|
type: ActivityType.LIQUIDATION,
|
|
380
|
-
|
|
409
|
+
...(notional === undefined
|
|
410
|
+
? {}
|
|
411
|
+
: { liquidatedNotionalPosition: notional }),
|
|
381
412
|
liquidatedPositions: [
|
|
382
|
-
{
|
|
383
|
-
market,
|
|
384
|
-
size: (first.side === 'A' ? size : size.neg()).toFixed(),
|
|
385
|
-
},
|
|
413
|
+
{ market, ...(closedSize === undefined ? {} : { size: closedSize }) },
|
|
386
414
|
],
|
|
387
415
|
} satisfies LiquidationActivity,
|
|
388
416
|
]
|
package/src/utils/mapFill.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
classifyFillFromPosition,
|
|
3
3
|
ExplorerChainId,
|
|
4
4
|
explorerTxUrl,
|
|
5
|
+
warnSkippedVenueRow,
|
|
5
6
|
} from '@lifi/perps-sdk'
|
|
6
7
|
import type { Fill, MarketDisplay } from '@lifi/perps-types'
|
|
7
8
|
import {
|
|
@@ -10,20 +11,35 @@ import {
|
|
|
10
11
|
OrderSide,
|
|
11
12
|
OrderType,
|
|
12
13
|
} from '@lifi/perps-types'
|
|
13
|
-
import { SPOT_MARKET_ID } from '../constants.js'
|
|
14
|
+
import { PROVIDER_KEY, SPOT_MARKET_ID } from '../constants.js'
|
|
14
15
|
import type { HlUserFill } from '../types/index.js'
|
|
16
|
+
import { rowTimestampToIsoStringOrUndefined } from './rowTimestamp.js'
|
|
15
17
|
|
|
16
18
|
/** Re-export the shared fill-position classifier used by Hyperliquid mappings. @public */
|
|
17
19
|
export { classifyFillFromPosition }
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* Spot-ness comes from the resolved market's category, not the coin string —
|
|
21
|
-
* HL's canonical spot pair 0 is addressed as `PURR/USDC`, not `@0`.
|
|
23
|
+
* HL's canonical spot pair 0 is addressed as `PURR/USDC`, not `@0`. A fill with
|
|
24
|
+
* an invalid time gives `undefined`.
|
|
22
25
|
* @public
|
|
23
26
|
*/
|
|
24
|
-
export const mapFill = (
|
|
27
|
+
export const mapFill = (
|
|
28
|
+
fill: HlUserFill,
|
|
29
|
+
market: MarketDisplay
|
|
30
|
+
): Fill | undefined => {
|
|
31
|
+
const size = fill.sz
|
|
32
|
+
const createdAt = rowTimestampToIsoStringOrUndefined(fill.time)
|
|
33
|
+
if (createdAt === undefined) {
|
|
34
|
+
warnSkippedVenueRow(PROVIDER_KEY, 'fill', 'time', fill.time, {
|
|
35
|
+
marketId: market.id,
|
|
36
|
+
expected: 'timestamp',
|
|
37
|
+
})
|
|
38
|
+
return undefined
|
|
39
|
+
}
|
|
25
40
|
// HL charges the builder portion in the same token as the total fee.
|
|
26
41
|
const feeAsset = fill.feeToken ?? market.quoteAsset.displaySymbol
|
|
42
|
+
const side = fill.side === 'B' ? OrderSide.BUY : OrderSide.SELL
|
|
27
43
|
|
|
28
44
|
return {
|
|
29
45
|
...(market.categoryId === SPOT_MARKET_ID
|
|
@@ -33,16 +49,16 @@ export const mapFill = (fill: HlUserFill, market: MarketDisplay): Fill => {
|
|
|
33
49
|
orderId: String(fill.oid),
|
|
34
50
|
clientOrderId: fill.cloid,
|
|
35
51
|
market,
|
|
36
|
-
side
|
|
52
|
+
side,
|
|
37
53
|
// HL fills don't carry the originating order type. A maker fill (crossed:
|
|
38
54
|
// false) can only come from a resting order, so it's necessarily a limit;
|
|
39
55
|
// a taker fill (crossed: true) may be a market OR an aggressive limit order,
|
|
40
56
|
// which the payload can't distinguish, so the type is left undefined.
|
|
41
57
|
type: fill.crossed ? undefined : OrderType.LIMIT,
|
|
42
|
-
size
|
|
58
|
+
size,
|
|
43
59
|
price: fill.px,
|
|
44
60
|
liquidity: fill.crossed ? LiquidityRole.TAKER : LiquidityRole.MAKER,
|
|
45
|
-
filledSize:
|
|
61
|
+
filledSize: size,
|
|
46
62
|
fee: {
|
|
47
63
|
amount: fill.fee,
|
|
48
64
|
asset: feeAsset,
|
|
@@ -55,10 +71,10 @@ export const mapFill = (fill: HlUserFill, market: MarketDisplay): Fill => {
|
|
|
55
71
|
explorerLink: explorerTxUrl(ExplorerChainId.HYPERLIQUID, fill.hash),
|
|
56
72
|
classification:
|
|
57
73
|
market.categoryId === SPOT_MARKET_ID
|
|
58
|
-
?
|
|
74
|
+
? side === OrderSide.BUY
|
|
59
75
|
? FillClassification.SPOT_BUY
|
|
60
76
|
: FillClassification.SPOT_SELL
|
|
61
|
-
: classifyFillFromPosition(fill.startPosition,
|
|
62
|
-
createdAt
|
|
77
|
+
: classifyFillFromPosition(fill.startPosition, side, size),
|
|
78
|
+
createdAt,
|
|
63
79
|
}
|
|
64
80
|
}
|
package/src/utils/mapMarket.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import { safeMultiplyDecimalString } from '@lifi/perps-sdk'
|
|
1
2
|
import type { PerpsMarket } from '@lifi/perps-types'
|
|
2
3
|
import { PositionMarginAdjustment } from '@lifi/perps-types'
|
|
3
|
-
import Big from 'big.js'
|
|
4
4
|
import { PROVIDER_KEY } from '../constants.js'
|
|
5
5
|
import type { HlMaxMarketOrderNtls, HlUniverseItem } from '../types/index.js'
|
|
6
|
-
import {
|
|
6
|
+
import { safeCalculateMaintenanceMarginRate } from './liquidation.js'
|
|
7
7
|
import { coinAsset } from './marketDisplay.js'
|
|
8
8
|
import { getMaxPriceDecimals } from './orderFormatting.js'
|
|
9
9
|
|
|
10
10
|
/** Hyperliquid quotes every perp market in USDC. */
|
|
11
11
|
const QUOTE_SYMBOL = 'USDC'
|
|
12
12
|
/** Hyperliquid documents the limit-order notional cap as 10x the market-order cap. */
|
|
13
|
-
const LIMIT_ORDER_VALUE_MULTIPLIER = 10
|
|
13
|
+
const LIMIT_ORDER_VALUE_MULTIPLIER = '10'
|
|
14
14
|
|
|
15
15
|
type MarketOrderLimits = Pick<
|
|
16
16
|
PerpsMarket,
|
|
@@ -28,19 +28,21 @@ const mapMarketOrderLimits = (
|
|
|
28
28
|
if (selected === undefined) {
|
|
29
29
|
return {}
|
|
30
30
|
}
|
|
31
|
-
const maxMarketOrderUsd =
|
|
32
|
-
|
|
33
|
-
maxMarketOrderUsd
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
const [, maxMarketOrderUsd] = selected
|
|
32
|
+
const maxLimitOrderUsd = safeMultiplyDecimalString(
|
|
33
|
+
maxMarketOrderUsd,
|
|
34
|
+
LIMIT_ORDER_VALUE_MULTIPLIER
|
|
35
|
+
)
|
|
36
|
+
if (maxLimitOrderUsd === undefined) {
|
|
37
|
+
return {}
|
|
37
38
|
}
|
|
39
|
+
return { maxMarketOrderUsd, maxLimitOrderUsd }
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* Map Hyperliquid universe metadata and optional `maxMarketOrderNtls` tiers to
|
|
42
|
-
* a {@link PerpsMarket}. Missing tiers leave both order caps
|
|
43
|
-
* stay on {@link MarketContext}; callers supply the provider category id
|
|
44
|
+
* a {@link PerpsMarket}. Missing tiers or an invalid cap leave both order caps
|
|
45
|
+
* unset. Live stats stay on {@link MarketContext}; callers supply the provider category id
|
|
44
46
|
* because the coin string does not contain it.
|
|
45
47
|
* @public
|
|
46
48
|
*/
|
|
@@ -70,5 +72,7 @@ export const mapMarket = (
|
|
|
70
72
|
(universe.marginMode === undefined && universe.onlyIsolated !== true)
|
|
71
73
|
? PositionMarginAdjustment.ADD_AND_REMOVE
|
|
72
74
|
: PositionMarginAdjustment.ADD_ONLY,
|
|
73
|
-
maintenanceMarginRate:
|
|
75
|
+
maintenanceMarginRate: safeCalculateMaintenanceMarginRate(
|
|
76
|
+
universe.maxLeverage
|
|
77
|
+
),
|
|
74
78
|
})
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
safeIsDecimalStringGreaterThan,
|
|
3
|
+
safeMultiplyDecimalString,
|
|
4
|
+
} from '@lifi/perps-sdk'
|
|
1
5
|
import type { MarketContext } from '@lifi/perps-types'
|
|
2
|
-
import Big from 'big.js'
|
|
3
6
|
import type { HlWsFastAssetCtx, HlWsPerpAssetCtx } from '../types/index.js'
|
|
4
7
|
|
|
5
8
|
const NEXT_FUNDING_INTERVAL_MS = 60 * 60 * 1000 // 1 hour
|
|
@@ -12,15 +15,10 @@ const toOpenInterestNotional = (
|
|
|
12
15
|
openInterest: string,
|
|
13
16
|
markPrice: string
|
|
14
17
|
): string | undefined => {
|
|
15
|
-
|
|
16
|
-
const mark = new Big(markPrice)
|
|
17
|
-
if (mark.lte(0)) {
|
|
18
|
-
return undefined
|
|
19
|
-
}
|
|
20
|
-
return new Big(openInterest).times(mark).toFixed()
|
|
21
|
-
} catch {
|
|
18
|
+
if (safeIsDecimalStringGreaterThan(markPrice, '0') !== true) {
|
|
22
19
|
return undefined
|
|
23
20
|
}
|
|
21
|
+
return safeMultiplyDecimalString(openInterest, markPrice)
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
/**
|