@lifi/perps-sdk-provider-hyperliquid 25.0.0 → 26.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 +19 -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 +3 -1
- 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 +15 -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/liquidation.d.ts +1 -1
- package/dist/cjs/utils/liquidation.d.ts.map +1 -1
- package/dist/cjs/utils/liquidation.js +3 -4
- 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 +32 -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 +14 -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 +8 -12
- 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 +1 -1
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +60 -18
- 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 +40 -14
- 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 +5 -5
- package/dist/cjs/utils/venueTotals.d.ts.map +1 -1
- package/dist/cjs/utils/venueTotals.js +10 -11
- 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.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +109 -89
- 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 +24 -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 +5 -2
- 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 +17 -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/liquidation.d.ts +1 -1
- package/dist/esm/utils/liquidation.d.ts.map +1 -1
- package/dist/esm/utils/liquidation.js +4 -5
- 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 +35 -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 +18 -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 +10 -11
- 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 +5 -2
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +65 -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 +43 -12
- 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 +10 -5
- package/dist/esm/utils/venueTotals.d.ts.map +1 -1
- package/dist/esm/utils/venueTotals.js +13 -7
- 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 +2 -0
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +119 -88
- 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/liquidation.d.ts +1 -1
- 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 +5 -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 +10 -5
- 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 +2 -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 +6 -3
- package/src/services/getPortfolioHistory.ts +38 -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/liquidation.ts +14 -8
- package/src/utils/mapActivity.ts +42 -20
- package/src/utils/mapFill.ts +22 -9
- package/src/utils/mapMarket.ts +12 -10
- package/src/utils/mapMarketContext.ts +6 -8
- package/src/utils/mapOrder.ts +81 -20
- package/src/utils/mapPosition.ts +67 -13
- 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 +54 -13
- package/src/utils/withdrawableBalances.ts +33 -15
- package/src/websocket/HyperliquidWsProvider.ts +169 -102
- 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
package/src/utils/mapMarket.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
6
|
import { calculateMaintenanceMarginRate } from './liquidation.js'
|
|
@@ -10,7 +10,7 @@ import { getMaxPriceDecimals } from './orderFormatting.js'
|
|
|
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
|
*/
|
|
@@ -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
|
/**
|
package/src/utils/mapOrder.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
isDecimalStringGreaterThan,
|
|
3
|
+
PerpsError,
|
|
4
|
+
safeDivideDecimalString,
|
|
5
|
+
safeIsDecimalStringGreaterThan,
|
|
6
|
+
safeIsDecimalStringZero,
|
|
7
|
+
safeSubtractDecimalString,
|
|
8
|
+
subtractDecimalString,
|
|
9
|
+
triggerConditionFor,
|
|
10
|
+
unknownToDecimalString,
|
|
11
|
+
warnSkippedVenueRow,
|
|
12
|
+
} from '@lifi/perps-sdk'
|
|
2
13
|
import type {
|
|
3
14
|
MarketDisplay,
|
|
4
15
|
Order,
|
|
@@ -12,13 +23,13 @@ import {
|
|
|
12
23
|
PerpsErrorCode,
|
|
13
24
|
TimeInForce,
|
|
14
25
|
} from '@lifi/perps-types'
|
|
15
|
-
import Big from 'big.js'
|
|
16
26
|
import { PROVIDER_KEY } from '../constants.js'
|
|
17
27
|
import type {
|
|
18
28
|
HlFrontendOpenOrder,
|
|
19
29
|
HlOrderDetail,
|
|
20
30
|
HlTwapHistoryEntry,
|
|
21
31
|
} from '../types/index.js'
|
|
32
|
+
import { rowTimestampToIsoStringOrUndefined } from './rowTimestamp.js'
|
|
22
33
|
|
|
23
34
|
/** Order payload shared by frontend, historical, and single-order reads. */
|
|
24
35
|
export type HlOrderLike = HlFrontendOpenOrder | HlOrderDetail['order']
|
|
@@ -87,28 +98,58 @@ export const mapOrderStatus = (status: string): OrderStatus => {
|
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
100
|
|
|
101
|
+
const skipOrder = (field: string, value: unknown): undefined => {
|
|
102
|
+
warnSkippedVenueRow(PROVIDER_KEY, 'order', field, value)
|
|
103
|
+
return undefined
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const venueDecimal = (value: unknown, field: string): string | undefined => {
|
|
107
|
+
try {
|
|
108
|
+
return unknownToDecimalString(value, field, PROVIDER_KEY)
|
|
109
|
+
} catch {
|
|
110
|
+
return undefined
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
90
114
|
function venueError(message: string): PerpsError {
|
|
91
115
|
const error = new PerpsError(PerpsErrorCode.ThirdPartyError, message)
|
|
92
116
|
error.tool = PROVIDER_KEY
|
|
93
117
|
return error
|
|
94
118
|
}
|
|
95
119
|
|
|
96
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Normalize regular, trigger, and TWAP rows through one lifecycle model. A row
|
|
122
|
+
* whose filled or remaining size or timestamp cannot be derived gives `undefined`.
|
|
123
|
+
*/
|
|
97
124
|
export const mapOrder = (
|
|
98
125
|
raw: HlOrderLike | HlOrderDetail | HlTwapHistoryEntry,
|
|
99
126
|
market: MarketDisplay,
|
|
100
127
|
parentOrderId?: string
|
|
101
|
-
): Order => {
|
|
128
|
+
): Order | undefined => {
|
|
102
129
|
if ('state' in raw) {
|
|
103
130
|
if (raw.twapId === undefined) {
|
|
104
131
|
throw venueError('Hyperliquid returned a TWAP without a twapId.')
|
|
105
132
|
}
|
|
106
133
|
const { state } = raw
|
|
107
|
-
const
|
|
134
|
+
const remainingSize = safeSubtractDecimalString(state.sz, state.executedSz)
|
|
135
|
+
if (remainingSize === undefined) {
|
|
136
|
+
return skipOrder('executedSz', state.executedSz)
|
|
137
|
+
}
|
|
138
|
+
const createdAt = rowTimestampToIsoStringOrUndefined(state.timestamp)
|
|
139
|
+
if (createdAt === undefined) {
|
|
140
|
+
return skipOrder('timestamp', state.timestamp)
|
|
141
|
+
}
|
|
142
|
+
const updatedAt = rowTimestampToIsoStringOrUndefined(raw.time * 1000)
|
|
143
|
+
if (updatedAt === undefined) {
|
|
144
|
+
return skipOrder('time', raw.time)
|
|
145
|
+
}
|
|
108
146
|
let status: OrderStatus
|
|
109
147
|
switch (raw.status.status) {
|
|
110
148
|
case 'activated':
|
|
111
|
-
status =
|
|
149
|
+
status =
|
|
150
|
+
safeIsDecimalStringGreaterThan(state.executedSz, '0') === true
|
|
151
|
+
? OrderStatus.PARTIALLY_FILLED
|
|
152
|
+
: OrderStatus.OPEN
|
|
112
153
|
break
|
|
113
154
|
case 'waitingForTrigger':
|
|
114
155
|
status = OrderStatus.OPEN
|
|
@@ -128,35 +169,57 @@ export const mapOrder = (
|
|
|
128
169
|
`Unknown Hyperliquid TWAP status: ${raw.status.status}`
|
|
129
170
|
)
|
|
130
171
|
}
|
|
172
|
+
const averagePrice =
|
|
173
|
+
safeIsDecimalStringZero(state.executedSz) === false
|
|
174
|
+
? safeDivideDecimalString(state.executedNtl, state.executedSz)
|
|
175
|
+
: undefined
|
|
131
176
|
return {
|
|
132
177
|
orderId: String(raw.twapId),
|
|
133
178
|
market,
|
|
134
179
|
type: OrderType.TWAP,
|
|
135
180
|
side: state.side === 'B' ? OrderSide.BUY : OrderSide.SELL,
|
|
136
181
|
originalSize: state.sz,
|
|
137
|
-
remainingSize
|
|
182
|
+
remainingSize,
|
|
138
183
|
filledSize: state.executedSz,
|
|
139
|
-
...(
|
|
140
|
-
? {}
|
|
141
|
-
: { averagePrice: new Big(state.executedNtl).div(filled).toFixed() }),
|
|
184
|
+
...(averagePrice === undefined ? {} : { averagePrice }),
|
|
142
185
|
reduceOnly: state.reduceOnly,
|
|
143
186
|
status,
|
|
144
187
|
...(status === OrderStatus.CANCELLED || status === OrderStatus.REJECTED
|
|
145
188
|
? { statusReason: raw.status.description ?? raw.status.status }
|
|
146
189
|
: {}),
|
|
147
|
-
createdAt
|
|
148
|
-
updatedAt
|
|
149
|
-
startedAt:
|
|
190
|
+
createdAt,
|
|
191
|
+
updatedAt,
|
|
192
|
+
startedAt: createdAt,
|
|
150
193
|
durationSeconds: state.minutes * 60,
|
|
151
194
|
}
|
|
152
195
|
}
|
|
153
196
|
const o = 'order' in raw ? raw.order : raw
|
|
154
197
|
const venueStatus = 'order' in raw ? raw.status : 'open'
|
|
155
|
-
const
|
|
198
|
+
const originalSize = venueDecimal(o.origSz, 'origSz')
|
|
199
|
+
if (originalSize === undefined) {
|
|
200
|
+
return skipOrder('origSz', o.origSz)
|
|
201
|
+
}
|
|
202
|
+
const remainingSize = venueDecimal(o.sz, 'sz')
|
|
203
|
+
if (remainingSize === undefined) {
|
|
204
|
+
return skipOrder('sz', o.sz)
|
|
205
|
+
}
|
|
206
|
+
const filledSize = subtractDecimalString(originalSize, remainingSize)
|
|
207
|
+
const createdAt = rowTimestampToIsoStringOrUndefined(o.timestamp)
|
|
208
|
+
if (createdAt === undefined) {
|
|
209
|
+
return skipOrder('timestamp', o.timestamp)
|
|
210
|
+
}
|
|
211
|
+
const statusTimestamp = 'order' in raw ? raw.statusTimestamp : o.timestamp
|
|
212
|
+
const updatedAt = rowTimestampToIsoStringOrUndefined(statusTimestamp)
|
|
213
|
+
if (updatedAt === undefined) {
|
|
214
|
+
return skipOrder('statusTimestamp', statusTimestamp)
|
|
215
|
+
}
|
|
156
216
|
let status = mapOrderStatus(venueStatus)
|
|
157
217
|
if (parentOrderId !== undefined && !('order' in raw)) {
|
|
158
218
|
status = OrderStatus.PENDING
|
|
159
|
-
} else if (
|
|
219
|
+
} else if (
|
|
220
|
+
status === OrderStatus.OPEN &&
|
|
221
|
+
isDecimalStringGreaterThan(filledSize, '0')
|
|
222
|
+
) {
|
|
160
223
|
status = OrderStatus.PARTIALLY_FILLED
|
|
161
224
|
}
|
|
162
225
|
const base: OrderBase = {
|
|
@@ -170,13 +233,11 @@ export const mapOrder = (
|
|
|
170
233
|
: {}),
|
|
171
234
|
originalSize: o.origSz,
|
|
172
235
|
remainingSize: o.sz,
|
|
173
|
-
filledSize
|
|
236
|
+
filledSize,
|
|
174
237
|
reduceOnly: o.reduceOnly,
|
|
175
238
|
...(parentOrderId === undefined ? {} : { parentOrderId }),
|
|
176
|
-
createdAt
|
|
177
|
-
updatedAt
|
|
178
|
-
'order' in raw ? raw.statusTimestamp : o.timestamp
|
|
179
|
-
).toISOString(),
|
|
239
|
+
createdAt,
|
|
240
|
+
updatedAt,
|
|
180
241
|
}
|
|
181
242
|
let type = mapOrderType(o.orderType)
|
|
182
243
|
if (o.isTrigger && (type === OrderType.MARKET || type === OrderType.LIMIT)) {
|
package/src/utils/mapPosition.ts
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
absDecimalString,
|
|
3
|
+
createWarnOnce,
|
|
4
|
+
isDecimalString,
|
|
5
|
+
isDecimalStringGreaterThan,
|
|
6
|
+
isDecimalStringZero,
|
|
7
|
+
safeAbsDecimalString,
|
|
8
|
+
safeDivideDecimalString,
|
|
9
|
+
safeIsDecimalStringZero,
|
|
10
|
+
safeNumberToDecimalString,
|
|
11
|
+
safeSubtractDecimalString,
|
|
12
|
+
warnSkippedVenueRow,
|
|
13
|
+
} from '@lifi/perps-sdk'
|
|
1
14
|
import type { PerpsMarketDisplay, Position } from '@lifi/perps-types'
|
|
2
15
|
import { MarginMode, PositionSide } from '@lifi/perps-types'
|
|
3
|
-
import
|
|
16
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
4
17
|
import type { HlAssetPosition } from '../types/index.js'
|
|
5
18
|
|
|
19
|
+
const warnNonPositiveLeverageOnce = createWarnOnce()
|
|
20
|
+
|
|
21
|
+
const skipPosition = (field: string, value: unknown): undefined => {
|
|
22
|
+
warnSkippedVenueRow(PROVIDER_KEY, 'position', field, value)
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
6
26
|
/**
|
|
7
27
|
* True when the assetPosition has non-zero size. Hyperliquid keeps zero-size
|
|
8
28
|
* rows in clearinghouse states after a close; both the REST and WS positions
|
|
@@ -10,39 +30,73 @@ import type { HlAssetPosition } from '../types/index.js'
|
|
|
10
30
|
* @public
|
|
11
31
|
*/
|
|
12
32
|
export const isOpenAssetPosition = (ap: HlAssetPosition): boolean =>
|
|
13
|
-
|
|
33
|
+
safeIsDecimalStringZero(ap.position.szi) !== true
|
|
14
34
|
|
|
15
35
|
/**
|
|
16
36
|
* Map a non-zero Hyperliquid position payload to the SDK's normalized
|
|
17
37
|
* position. Signed wire size determines side; decimal strings remain strings
|
|
18
38
|
* in the normalized response. `cumFunding.sinceOpen` is negated because
|
|
19
39
|
* Hyperliquid signs funding paid as positive and `accruedFunding` signs it as
|
|
20
|
-
* negative.
|
|
40
|
+
* negative. A row with an invalid size gives `undefined`; an invalid position
|
|
41
|
+
* value, a non-positive leverage or an invalid funding leaves the derived field
|
|
42
|
+
* absent.
|
|
21
43
|
* @public
|
|
22
44
|
*/
|
|
23
45
|
export const mapPosition = (
|
|
24
46
|
ap: HlAssetPosition,
|
|
25
47
|
market: PerpsMarketDisplay
|
|
26
|
-
): Position => {
|
|
48
|
+
): Position | undefined => {
|
|
27
49
|
const pos = ap.position
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
50
|
+
if (!isDecimalString(pos.szi)) {
|
|
51
|
+
return skipPosition('szi', pos.szi)
|
|
52
|
+
}
|
|
53
|
+
const size = absDecimalString(pos.szi)
|
|
54
|
+
const positionValue = safeAbsDecimalString(pos.positionValue)
|
|
55
|
+
const markPrice =
|
|
56
|
+
positionValue === undefined
|
|
57
|
+
? undefined
|
|
58
|
+
: isDecimalStringZero(size)
|
|
59
|
+
? '0'
|
|
60
|
+
: safeDivideDecimalString(positionValue, size)
|
|
61
|
+
const accruedFunding = safeSubtractDecimalString(
|
|
62
|
+
'0',
|
|
63
|
+
pos.cumFunding.sinceOpen
|
|
64
|
+
)
|
|
65
|
+
const venueLeverage = safeNumberToDecimalString(pos.leverage.value)
|
|
66
|
+
const leverage =
|
|
67
|
+
venueLeverage !== undefined &&
|
|
68
|
+
isDecimalStringGreaterThan(venueLeverage, '0')
|
|
69
|
+
? venueLeverage
|
|
70
|
+
: undefined
|
|
71
|
+
if (venueLeverage !== undefined && leverage === undefined) {
|
|
72
|
+
warnNonPositiveLeverageOnce(
|
|
73
|
+
venueLeverage,
|
|
74
|
+
`[${PROVIDER_KEY}] position \`leverage.value\` is not positive: '${venueLeverage}'`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
const initialMarginRequirement =
|
|
78
|
+
positionValue === undefined || leverage === undefined
|
|
79
|
+
? undefined
|
|
80
|
+
: safeDivideDecimalString(positionValue, leverage)
|
|
31
81
|
const marginMode =
|
|
32
82
|
pos.leverage.type === 'cross' ? MarginMode.CROSS : MarginMode.ISOLATED
|
|
33
83
|
|
|
34
84
|
return {
|
|
35
85
|
market,
|
|
36
|
-
side:
|
|
37
|
-
|
|
86
|
+
side: isDecimalStringGreaterThan('0', pos.szi)
|
|
87
|
+
? PositionSide.SHORT
|
|
88
|
+
: PositionSide.LONG,
|
|
89
|
+
size,
|
|
38
90
|
entryPrice: pos.entryPx ?? '0',
|
|
39
|
-
markPrice
|
|
91
|
+
...(markPrice === undefined ? {} : { markPrice }),
|
|
40
92
|
liquidationPrice: pos.liquidationPx ?? '0',
|
|
41
93
|
unrealizedPnl: pos.unrealizedPnl,
|
|
42
|
-
accruedFunding:
|
|
43
|
-
leverage:
|
|
94
|
+
...(accruedFunding === undefined ? {} : { accruedFunding }),
|
|
95
|
+
...(leverage === undefined ? {} : { leverage }),
|
|
44
96
|
marginUsed: pos.marginUsed,
|
|
45
|
-
initialMarginRequirement
|
|
97
|
+
...(initialMarginRequirement === undefined
|
|
98
|
+
? {}
|
|
99
|
+
: { initialMarginRequirement }),
|
|
46
100
|
marginMode,
|
|
47
101
|
}
|
|
48
102
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { timestampToIsoString } from '@lifi/perps-sdk'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read a venue row time as an ISO-8601 string, or `undefined` when the time is
|
|
5
|
+
* not valid. The caller logs the row skip, so this logs nothing.
|
|
6
|
+
*/
|
|
7
|
+
export const rowTimestampToIsoStringOrUndefined = (
|
|
8
|
+
value: string | number
|
|
9
|
+
): string | undefined => {
|
|
10
|
+
try {
|
|
11
|
+
return timestampToIsoString(value)
|
|
12
|
+
} catch {
|
|
13
|
+
return undefined
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/utils/spotBalance.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
isDecimalString,
|
|
3
|
+
isDecimalStringGreaterThan,
|
|
4
|
+
multiplyDecimalString,
|
|
5
|
+
} from '@lifi/perps-sdk'
|
|
6
|
+
import type { Asset, Balance, DecimalString, Market } from '@lifi/perps-types'
|
|
3
7
|
import { SPOT_MARKET_ID } from '../constants.js'
|
|
4
8
|
import type { HlSpotBalance } from '../types/index.js'
|
|
5
9
|
import { spotLogoURI } from './assetLogo.js'
|
|
@@ -7,23 +11,24 @@ import { coinAsset } from './marketDisplay.js'
|
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Build USD prices keyed by spot token asset ID. Base tokens use the supplied
|
|
10
|
-
* market mark price; quote tokens default to exactly `$1`; missing
|
|
11
|
-
* default to `0`.
|
|
14
|
+
* market mark price; quote tokens default to exactly `$1`; missing or invalid
|
|
15
|
+
* base prices default to `0`.
|
|
12
16
|
* @public
|
|
13
17
|
*/
|
|
14
18
|
export const spotPriceById = (
|
|
15
19
|
markets: readonly Market[],
|
|
16
|
-
priceByMarketId: ReadonlyMap<string,
|
|
17
|
-
): Map<string,
|
|
18
|
-
const map = new Map<string,
|
|
20
|
+
priceByMarketId: ReadonlyMap<string, DecimalString>
|
|
21
|
+
): Map<string, DecimalString> => {
|
|
22
|
+
const map = new Map<string, DecimalString>()
|
|
19
23
|
for (const m of markets) {
|
|
20
24
|
if (m.categoryId === SPOT_MARKET_ID) {
|
|
21
|
-
|
|
25
|
+
const price = priceByMarketId.get(m.id)
|
|
26
|
+
map.set(m.baseAsset.id, isDecimalString(price) ? price : '0')
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
for (const m of markets) {
|
|
25
30
|
if (!map.has(m.quoteAsset.id)) {
|
|
26
|
-
map.set(m.quoteAsset.id, 1)
|
|
31
|
+
map.set(m.quoteAsset.id, '1')
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
return map
|
|
@@ -44,18 +49,16 @@ export const spotAssetFromToken = (b: HlSpotBalance): Asset => ({
|
|
|
44
49
|
/** Assemble a typed spot {@link Balance}; `total` is native token units and its unit price and USD value use `priceById`. @public */
|
|
45
50
|
export const spotBalance = (
|
|
46
51
|
asset: Asset,
|
|
47
|
-
total:
|
|
48
|
-
priceById:
|
|
52
|
+
total: DecimalString,
|
|
53
|
+
priceById: ReadonlyMap<string, DecimalString>
|
|
49
54
|
): Balance => {
|
|
50
|
-
const price = priceById.get(asset.id) ?? 0
|
|
55
|
+
const price = priceById.get(asset.id) ?? '0'
|
|
51
56
|
return {
|
|
52
57
|
categoryId: SPOT_MARKET_ID,
|
|
53
58
|
asset,
|
|
54
59
|
units: total,
|
|
55
|
-
valueUsd:
|
|
56
|
-
(parseDecimal(total) ?? Number.NaN) * price
|
|
57
|
-
),
|
|
60
|
+
valueUsd: multiplyDecimalString(total, price),
|
|
58
61
|
// A zero entry means the map holds no mark for the asset, not a free asset.
|
|
59
|
-
...(price
|
|
62
|
+
...(isDecimalStringGreaterThan(price, '0') ? { price } : {}),
|
|
60
63
|
}
|
|
61
64
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isDecimalStringGreaterThan,
|
|
3
|
+
unknownToDecimalString,
|
|
4
|
+
} from '@lifi/perps-sdk'
|
|
1
5
|
import type { Balance } from '@lifi/perps-types'
|
|
2
|
-
import {
|
|
6
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* Result of {@link partitionSpotBalances}: balances that count toward
|
|
@@ -24,7 +28,16 @@ export const partitionSpotBalances = (
|
|
|
24
28
|
const collateralBalances: Balance[] = []
|
|
25
29
|
const balances: Balance[] = []
|
|
26
30
|
for (const balance of spotBalances) {
|
|
27
|
-
if (
|
|
31
|
+
if (
|
|
32
|
+
!isDecimalStringGreaterThan(
|
|
33
|
+
unknownToDecimalString(
|
|
34
|
+
balance.units,
|
|
35
|
+
'spotBalance.units',
|
|
36
|
+
PROVIDER_KEY
|
|
37
|
+
),
|
|
38
|
+
'0'
|
|
39
|
+
)
|
|
40
|
+
) {
|
|
28
41
|
continue
|
|
29
42
|
}
|
|
30
43
|
if (quoteAssetIds.has(balance.asset.id)) {
|
|
@@ -1,32 +1,49 @@
|
|
|
1
1
|
import {
|
|
2
|
+
isDecimalString,
|
|
3
|
+
isDecimalStringGreaterThan,
|
|
4
|
+
multiplyDecimalString,
|
|
2
5
|
PerpsError,
|
|
3
6
|
positionSupportsMarginAdjustment,
|
|
4
7
|
positionSupportsMarginRemoval,
|
|
5
|
-
|
|
8
|
+
roundDecimalString,
|
|
9
|
+
subtractDecimalString,
|
|
6
10
|
} from '@lifi/perps-sdk'
|
|
7
11
|
import {
|
|
8
12
|
type DecimalString,
|
|
9
13
|
PerpsErrorCode,
|
|
10
14
|
type Position,
|
|
11
15
|
} from '@lifi/perps-types'
|
|
12
|
-
import Big from 'big.js'
|
|
13
16
|
|
|
14
17
|
const NOTIONAL_FLOOR_RATIO = '0.1'
|
|
15
18
|
const AMOUNT_DECIMALS = 6
|
|
16
19
|
|
|
17
|
-
function
|
|
18
|
-
|
|
20
|
+
function requirePositionAmount(
|
|
21
|
+
value: DecimalString,
|
|
22
|
+
field: string
|
|
23
|
+
): DecimalString {
|
|
24
|
+
if (!isDecimalString(value)) {
|
|
25
|
+
throw new PerpsError(
|
|
26
|
+
PerpsErrorCode.ValidationError,
|
|
27
|
+
`Invalid \`Position.${field}\`: '${value}' is not a decimal string.`
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
return value
|
|
19
31
|
}
|
|
20
32
|
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
function requirePositivePositionAmount(
|
|
34
|
+
value: DecimalString | undefined,
|
|
35
|
+
field: string
|
|
36
|
+
): DecimalString {
|
|
37
|
+
if (
|
|
38
|
+
value === undefined ||
|
|
39
|
+
!isDecimalStringGreaterThan(requirePositionAmount(value, field), '0')
|
|
40
|
+
) {
|
|
24
41
|
throw new PerpsError(
|
|
25
42
|
PerpsErrorCode.ValidationError,
|
|
26
43
|
`Position.${field} must be greater than zero.`
|
|
27
44
|
)
|
|
28
45
|
}
|
|
29
|
-
return
|
|
46
|
+
return value
|
|
30
47
|
}
|
|
31
48
|
|
|
32
49
|
/**
|
|
@@ -40,7 +57,8 @@ function positivePositionAmount(value: DecimalString, field: string): Big {
|
|
|
40
57
|
* margin adjustment; `'0'` for add-only strict-isolated markets and when
|
|
41
58
|
* nothing is removable.
|
|
42
59
|
* @throws {PerpsError} `ValidationError` when a required `Position` decimal
|
|
43
|
-
* is malformed, or when a size, price or requirement is not
|
|
60
|
+
* is absent or malformed, or when a size, price or requirement is not
|
|
61
|
+
* positive.
|
|
44
62
|
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/trading/margining
|
|
45
63
|
* @public
|
|
46
64
|
*/
|
|
@@ -53,21 +71,25 @@ export function positionRemovableMargin(
|
|
|
53
71
|
if (!positionSupportsMarginRemoval(position)) {
|
|
54
72
|
return '0'
|
|
55
73
|
}
|
|
56
|
-
const marginUsed =
|
|
57
|
-
const initialMargin =
|
|
74
|
+
const marginUsed = requirePositionAmount(position.marginUsed, 'marginUsed')
|
|
75
|
+
const initialMargin = requirePositivePositionAmount(
|
|
58
76
|
position.initialMarginRequirement,
|
|
59
77
|
'initialMarginRequirement'
|
|
60
78
|
)
|
|
61
|
-
const notionalFloor =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
const notionalFloor = multiplyDecimalString(
|
|
80
|
+
multiplyDecimalString(
|
|
81
|
+
requirePositivePositionAmount(position.size, 'size'),
|
|
82
|
+
requirePositivePositionAmount(position.markPrice, 'markPrice')
|
|
83
|
+
),
|
|
84
|
+
NOTIONAL_FLOOR_RATIO
|
|
85
|
+
)
|
|
86
|
+
const minimumMargin = isDecimalStringGreaterThan(initialMargin, notionalFloor)
|
|
65
87
|
? initialMargin
|
|
66
88
|
: notionalFloor
|
|
67
89
|
|
|
68
|
-
const removable = marginUsed
|
|
69
|
-
if (removable
|
|
90
|
+
const removable = subtractDecimalString(marginUsed, minimumMargin)
|
|
91
|
+
if (!isDecimalStringGreaterThan(removable, '0')) {
|
|
70
92
|
return '0'
|
|
71
93
|
}
|
|
72
|
-
return removable
|
|
94
|
+
return roundDecimalString(removable, AMOUNT_DECIMALS, 'truncate')
|
|
73
95
|
}
|
package/src/utils/venueTotals.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
addDecimalString,
|
|
3
|
+
safeAddDecimalString,
|
|
4
|
+
unknownToDecimalString,
|
|
5
|
+
} from '@lifi/perps-sdk'
|
|
6
|
+
import type {
|
|
7
|
+
DecimalString,
|
|
8
|
+
HyperliquidMarginSummary,
|
|
9
|
+
Position,
|
|
10
|
+
} from '@lifi/perps-types'
|
|
11
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
4
12
|
|
|
5
13
|
/**
|
|
6
14
|
* One perps sub-dex entry {@link perpsTotals} reads. The REST response always
|
|
@@ -15,22 +23,33 @@ export interface DexMarginSummary {
|
|
|
15
23
|
* Sum the venue `marginSummary` totals over every perps sub-dex of an
|
|
16
24
|
* account. `accountValue` is total equity, so it already carries locked
|
|
17
25
|
* margin and unrealized PnL. An entry without a `marginSummary` adds nothing.
|
|
26
|
+
* @throws {PerpsError} `SDKError` when a venue figure is not a decimal.
|
|
18
27
|
* @public
|
|
19
28
|
*/
|
|
20
29
|
export const perpsTotals = (
|
|
21
30
|
dexStates: readonly DexMarginSummary[]
|
|
22
|
-
): { accountValue:
|
|
23
|
-
let accountValue =
|
|
24
|
-
let marginUsed =
|
|
31
|
+
): { accountValue: DecimalString; marginUsed: DecimalString } => {
|
|
32
|
+
let accountValue = '0'
|
|
33
|
+
let marginUsed = '0'
|
|
25
34
|
for (const { marginSummary } of dexStates) {
|
|
26
35
|
if (marginSummary === undefined) {
|
|
27
36
|
continue
|
|
28
37
|
}
|
|
29
|
-
accountValue =
|
|
30
|
-
|
|
38
|
+
accountValue = addDecimalString(
|
|
39
|
+
accountValue,
|
|
40
|
+
unknownToDecimalString(
|
|
41
|
+
marginSummary.accountValue,
|
|
42
|
+
'marginSummary.accountValue',
|
|
43
|
+
PROVIDER_KEY
|
|
44
|
+
)
|
|
31
45
|
)
|
|
32
|
-
marginUsed =
|
|
33
|
-
|
|
46
|
+
marginUsed = addDecimalString(
|
|
47
|
+
marginUsed,
|
|
48
|
+
unknownToDecimalString(
|
|
49
|
+
marginSummary.totalMarginUsed,
|
|
50
|
+
'marginSummary.totalMarginUsed',
|
|
51
|
+
PROVIDER_KEY
|
|
52
|
+
)
|
|
34
53
|
)
|
|
35
54
|
}
|
|
36
55
|
return { accountValue, marginUsed }
|
|
@@ -40,9 +59,31 @@ export const perpsTotals = (
|
|
|
40
59
|
* Sum the unrealized PnL of every position, in quote-asset units.
|
|
41
60
|
* @public
|
|
42
61
|
*/
|
|
43
|
-
export const sumUnrealizedPnl = (
|
|
62
|
+
export const sumUnrealizedPnl = (
|
|
63
|
+
positions: readonly Position[]
|
|
64
|
+
): DecimalString =>
|
|
44
65
|
positions.reduce(
|
|
45
66
|
(sum, position) =>
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
addDecimalString(
|
|
68
|
+
sum,
|
|
69
|
+
unknownToDecimalString(
|
|
70
|
+
position.unrealizedPnl,
|
|
71
|
+
'position.unrealizedPnl',
|
|
72
|
+
PROVIDER_KEY
|
|
73
|
+
)
|
|
74
|
+
),
|
|
75
|
+
'0'
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Sum every term, or `undefined` with a warning when any term is not a
|
|
80
|
+
* decimal string. A bad term never gives a partial sum.
|
|
81
|
+
*/
|
|
82
|
+
export const safeSumDecimalStrings = (
|
|
83
|
+
terms: readonly string[]
|
|
84
|
+
): DecimalString | undefined =>
|
|
85
|
+
terms.reduce<DecimalString | undefined>(
|
|
86
|
+
(sum, term) =>
|
|
87
|
+
sum === undefined ? undefined : safeAddDecimalString(sum, term),
|
|
88
|
+
'0'
|
|
48
89
|
)
|