@lifi/perps-sdk-provider-hyperliquid 15.0.0 → 16.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/HyperliquidProvider.d.ts.map +1 -1
- package/dist/cjs/HyperliquidProvider.js +4 -0
- package/dist/cjs/HyperliquidProvider.js.map +1 -1
- package/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +34 -7
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/services/activeAssetData.d.ts +6 -0
- package/dist/cjs/services/activeAssetData.d.ts.map +1 -0
- package/dist/cjs/services/activeAssetData.js +7 -0
- package/dist/cjs/services/activeAssetData.js.map +1 -0
- package/dist/cjs/services/getAccount.d.ts.map +1 -1
- package/dist/cjs/services/getAccount.js +23 -35
- package/dist/cjs/services/getAccount.js.map +1 -1
- package/dist/cjs/services/getAvailableToTrade.d.ts +10 -0
- package/dist/cjs/services/getAvailableToTrade.d.ts.map +1 -0
- package/dist/cjs/services/getAvailableToTrade.js +32 -0
- package/dist/cjs/services/getAvailableToTrade.js.map +1 -0
- package/dist/cjs/services/getMarketSettings.d.ts +1 -1
- package/dist/cjs/services/getMarketSettings.d.ts.map +1 -1
- package/dist/cjs/services/getMarketSettings.js +3 -7
- package/dist/cjs/services/getMarketSettings.js.map +1 -1
- package/dist/cjs/services/getWithdrawableBalances.d.ts +5 -0
- package/dist/cjs/services/getWithdrawableBalances.d.ts.map +1 -0
- package/dist/cjs/services/getWithdrawableBalances.js +27 -0
- package/dist/cjs/services/getWithdrawableBalances.js.map +1 -0
- package/dist/cjs/types/account.d.ts +11 -8
- package/dist/cjs/types/account.d.ts.map +1 -1
- package/dist/cjs/types/account.js.map +1 -1
- package/dist/cjs/types/ws.d.ts +3 -4
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/abstractionMode.d.ts +1 -1
- package/dist/cjs/utils/abstractionMode.d.ts.map +1 -1
- package/dist/cjs/utils/abstractionMode.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +2 -0
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +6 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/mapPosition.d.ts.map +1 -1
- package/dist/cjs/utils/mapPosition.js +1 -4
- package/dist/cjs/utils/mapPosition.js.map +1 -1
- package/dist/cjs/utils/spotCollateral.d.ts +1 -1
- package/dist/cjs/utils/spotCollateral.d.ts.map +1 -1
- package/dist/cjs/utils/spotCollateral.js +1 -12
- package/dist/cjs/utils/spotCollateral.js.map +1 -1
- package/dist/cjs/utils/venueTotals.d.ts +11 -0
- package/dist/cjs/utils/venueTotals.d.ts.map +1 -0
- package/dist/cjs/utils/venueTotals.js +24 -0
- package/dist/cjs/utils/venueTotals.js.map +1 -0
- package/dist/cjs/utils/withdrawableBalances.d.ts +4 -0
- package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/cjs/utils/withdrawableBalances.js +35 -0
- package/dist/cjs/utils/withdrawableBalances.js.map +1 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +3 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +102 -36
- package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
- package/dist/esm/HyperliquidProvider.js +4 -0
- package/dist/esm/HyperliquidProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +4 -3
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +36 -18
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/services/activeAssetData.d.ts +13 -0
- package/dist/esm/services/activeAssetData.d.ts.map +1 -0
- package/dist/esm/services/activeAssetData.js +10 -0
- package/dist/esm/services/activeAssetData.js.map +1 -0
- package/dist/esm/services/getAccount.d.ts.map +1 -1
- package/dist/esm/services/getAccount.js +19 -29
- package/dist/esm/services/getAccount.js.map +1 -1
- package/dist/esm/services/getAvailableToTrade.d.ts +26 -0
- package/dist/esm/services/getAvailableToTrade.d.ts.map +1 -0
- package/dist/esm/services/getAvailableToTrade.js +42 -0
- package/dist/esm/services/getAvailableToTrade.js.map +1 -0
- package/dist/esm/services/getMarketSettings.d.ts +1 -1
- package/dist/esm/services/getMarketSettings.d.ts.map +1 -1
- package/dist/esm/services/getMarketSettings.js +3 -7
- package/dist/esm/services/getMarketSettings.js.map +1 -1
- package/dist/esm/services/getWithdrawableBalances.d.ts +22 -0
- package/dist/esm/services/getWithdrawableBalances.d.ts.map +1 -0
- package/dist/esm/services/getWithdrawableBalances.js +35 -0
- package/dist/esm/services/getWithdrawableBalances.js.map +1 -0
- package/dist/esm/types/account.d.ts +21 -8
- package/dist/esm/types/account.d.ts.map +1 -1
- package/dist/esm/types/account.js.map +1 -1
- package/dist/esm/types/ws.d.ts +10 -4
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/utils/abstractionMode.d.ts +1 -1
- package/dist/esm/utils/abstractionMode.d.ts.map +1 -1
- package/dist/esm/utils/abstractionMode.js.map +1 -1
- package/dist/esm/utils/index.d.ts +2 -0
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapPosition.d.ts.map +1 -1
- package/dist/esm/utils/mapPosition.js +1 -4
- package/dist/esm/utils/mapPosition.js.map +1 -1
- package/dist/esm/utils/spotCollateral.d.ts +4 -4
- package/dist/esm/utils/spotCollateral.d.ts.map +1 -1
- package/dist/esm/utils/spotCollateral.js +4 -23
- package/dist/esm/utils/spotCollateral.js.map +1 -1
- package/dist/esm/utils/venueTotals.d.ts +26 -0
- package/dist/esm/utils/venueTotals.d.ts.map +1 -0
- package/dist/esm/utils/venueTotals.js +26 -0
- package/dist/esm/utils/venueTotals.js.map +1 -0
- package/dist/esm/utils/withdrawableBalances.d.ts +14 -0
- package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/esm/utils/withdrawableBalances.js +41 -0
- package/dist/esm/utils/withdrawableBalances.js.map +1 -0
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts +4 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +101 -35
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/HyperliquidProvider.d.ts.map +1 -1
- package/dist/types/accountSummary.d.ts +4 -3
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/services/activeAssetData.d.ts +13 -0
- package/dist/types/services/activeAssetData.d.ts.map +1 -0
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/services/getAvailableToTrade.d.ts +26 -0
- package/dist/types/services/getAvailableToTrade.d.ts.map +1 -0
- package/dist/types/services/getMarketSettings.d.ts +1 -1
- package/dist/types/services/getMarketSettings.d.ts.map +1 -1
- package/dist/types/services/getWithdrawableBalances.d.ts +22 -0
- package/dist/types/services/getWithdrawableBalances.d.ts.map +1 -0
- package/dist/types/types/account.d.ts +21 -8
- package/dist/types/types/account.d.ts.map +1 -1
- package/dist/types/types/ws.d.ts +10 -4
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/abstractionMode.d.ts +1 -1
- package/dist/types/utils/abstractionMode.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/mapPosition.d.ts.map +1 -1
- package/dist/types/utils/spotCollateral.d.ts +4 -4
- package/dist/types/utils/spotCollateral.d.ts.map +1 -1
- package/dist/types/utils/venueTotals.d.ts +26 -0
- package/dist/types/utils/venueTotals.d.ts.map +1 -0
- package/dist/types/utils/withdrawableBalances.d.ts +14 -0
- package/dist/types/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/types/websocket/HyperliquidWsProvider.d.ts +4 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/HyperliquidProvider.ts +26 -0
- package/src/accountSummary.ts +64 -19
- package/src/index.ts +2 -0
- package/src/services/activeAssetData.ts +24 -0
- package/src/services/getAccount.ts +37 -52
- package/src/services/getAvailableToTrade.ts +72 -0
- package/src/services/getMarketSettings.ts +7 -11
- package/src/services/getWithdrawableBalances.ts +84 -0
- package/src/types/account.ts +22 -8
- package/src/types/ws.ts +18 -5
- package/src/utils/abstractionMode.ts +1 -1
- package/src/utils/index.ts +6 -0
- package/src/utils/mapPosition.ts +1 -5
- package/src/utils/spotCollateral.ts +4 -25
- package/src/utils/venueTotals.ts +48 -0
- package/src/utils/withdrawableBalances.ts +57 -0
- package/src/websocket/HyperliquidWsProvider.ts +149 -42
- package/dist/cjs/websocket/decodeChain.d.ts +0 -11
- package/dist/cjs/websocket/decodeChain.d.ts.map +0 -1
- package/dist/cjs/websocket/decodeChain.js +0 -37
- package/dist/cjs/websocket/decodeChain.js.map +0 -1
- package/dist/esm/websocket/decodeChain.d.ts +0 -30
- package/dist/esm/websocket/decodeChain.d.ts.map +0 -1
- package/dist/esm/websocket/decodeChain.js +0 -44
- package/dist/esm/websocket/decodeChain.js.map +0 -1
- package/dist/types/websocket/decodeChain.d.ts +0 -30
- package/dist/types/websocket/decodeChain.d.ts.map +0 -1
- package/src/websocket/decodeChain.ts +0 -54
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMarketRegistry,
|
|
3
|
+
PerpsError,
|
|
4
|
+
type SDKRequestOptions,
|
|
5
|
+
toAssetDisplay,
|
|
6
|
+
} from '@lifi/perps-sdk'
|
|
7
|
+
import type { AvailableToTrade } from '@lifi/perps-types'
|
|
8
|
+
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
9
|
+
import type { Address } from 'viem'
|
|
10
|
+
import { PROVIDER_KEY, SPOT_MARKET_ID } from '../constants.js'
|
|
11
|
+
import type { HyperliquidContext } from '../context.js'
|
|
12
|
+
import { fetchActiveAssetData } from './activeAssetData.js'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parameters for {@link getAvailableToTrade}.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export interface GetAvailableToTradeParams {
|
|
20
|
+
address: Address
|
|
21
|
+
marketId: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The amounts the account can still buy and sell on one perps market, read
|
|
26
|
+
* from `activeAssetData`. The amounts are denominated in the market's margin
|
|
27
|
+
* asset: USDC on the main dex, and the dex margin asset on a builder-deployed
|
|
28
|
+
* dex. Resolves `undefined` for a spot market, which carries no such state.
|
|
29
|
+
*
|
|
30
|
+
* @throws {PerpsError} On an unknown market, an `availableToTrade` payload
|
|
31
|
+
* that is not a buy/sell pair, Hyperliquid REST error, network, or parsing
|
|
32
|
+
* failures.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export const getAvailableToTrade = async (
|
|
36
|
+
context: HyperliquidContext,
|
|
37
|
+
params: GetAvailableToTradeParams,
|
|
38
|
+
options?: SDKRequestOptions
|
|
39
|
+
): Promise<AvailableToTrade | undefined> => {
|
|
40
|
+
const registry = getMarketRegistry(context.client, PROVIDER_KEY)
|
|
41
|
+
await registry.sync()
|
|
42
|
+
const market = registry.require(params.marketId)
|
|
43
|
+
if (market.categoryId === SPOT_MARKET_ID) {
|
|
44
|
+
return undefined
|
|
45
|
+
}
|
|
46
|
+
const data = await fetchActiveAssetData(
|
|
47
|
+
context,
|
|
48
|
+
params.address,
|
|
49
|
+
params.marketId,
|
|
50
|
+
options
|
|
51
|
+
)
|
|
52
|
+
// The wire type states the pair; nothing verifies the response, so read it
|
|
53
|
+
// as a plain list to keep the length check in reach of the type checker.
|
|
54
|
+
const amounts: readonly string[] = data.availableToTrade
|
|
55
|
+
if (amounts.length !== 2) {
|
|
56
|
+
const err = new PerpsError(
|
|
57
|
+
PerpsErrorCode.ValidationError,
|
|
58
|
+
`Hyperliquid returned ${amounts.length} availableToTrade amounts for market '${params.marketId}'. Expected a buy amount and a sell amount.`
|
|
59
|
+
)
|
|
60
|
+
err.tool = PROVIDER_KEY
|
|
61
|
+
throw err
|
|
62
|
+
}
|
|
63
|
+
// Hyperliquid orders the pair buy-side first, sell-side second.
|
|
64
|
+
const [buy, sell] = amounts
|
|
65
|
+
return {
|
|
66
|
+
providerId: market.providerId,
|
|
67
|
+
marketId: market.id,
|
|
68
|
+
asset: toAssetDisplay(market.quoteAsset),
|
|
69
|
+
buy,
|
|
70
|
+
sell,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -7,8 +7,7 @@ import {
|
|
|
7
7
|
import type { Address } from 'viem'
|
|
8
8
|
import { SPOT_MARKET_ID } from '../constants.js'
|
|
9
9
|
import type { HyperliquidContext } from '../context.js'
|
|
10
|
-
import
|
|
11
|
-
import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
|
|
10
|
+
import { fetchActiveAssetData } from './activeAssetData.js'
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Parameters for {@link getMarketSettings}.
|
|
@@ -27,7 +26,7 @@ export interface GetMarketSettingsParams {
|
|
|
27
26
|
* @public
|
|
28
27
|
*/
|
|
29
28
|
export const getMarketSettings = async (
|
|
30
|
-
|
|
29
|
+
context: HyperliquidContext,
|
|
31
30
|
params: GetMarketSettingsParams,
|
|
32
31
|
options?: SDKRequestOptions
|
|
33
32
|
): Promise<MarketSettings | undefined> => {
|
|
@@ -35,14 +34,11 @@ export const getMarketSettings = async (
|
|
|
35
34
|
if (params.market.categoryId === SPOT_MARKET_ID) {
|
|
36
35
|
return undefined
|
|
37
36
|
}
|
|
38
|
-
const data = await
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
coin: params.market.marketId,
|
|
44
|
-
},
|
|
45
|
-
hlInfoOptions(client, options)
|
|
37
|
+
const data = await fetchActiveAssetData(
|
|
38
|
+
context,
|
|
39
|
+
params.address,
|
|
40
|
+
params.market.marketId,
|
|
41
|
+
options
|
|
46
42
|
)
|
|
47
43
|
const leverage = data.leverage
|
|
48
44
|
if (!leverage) {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMarketRegistry,
|
|
3
|
+
PerpsError,
|
|
4
|
+
type ProviderGetWithdrawableBalancesParams,
|
|
5
|
+
type ProviderWithdrawableBalance,
|
|
6
|
+
type SDKRequestOptions,
|
|
7
|
+
} from '@lifi/perps-sdk'
|
|
8
|
+
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
9
|
+
import { MAIN_MARKET_ID, PROVIDER_KEY } from '../constants.js'
|
|
10
|
+
import type { HyperliquidContext } from '../context.js'
|
|
11
|
+
import type {
|
|
12
|
+
HlAbstractionMode,
|
|
13
|
+
HlClearinghouseState,
|
|
14
|
+
HlSpotClearinghouseState,
|
|
15
|
+
} from '../types/index.js'
|
|
16
|
+
import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
|
|
17
|
+
import { hyperliquidWithdrawableBalances } from '../utils/withdrawableBalances.js'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Parameters for {@link getWithdrawableBalances}.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export type GetWithdrawableBalancesParams =
|
|
25
|
+
ProviderGetWithdrawableBalancesParams
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The `(asset, route)` pairs `params.address` can withdraw from Hyperliquid,
|
|
29
|
+
* read from the venue's own `withdrawable` and spot `total`/`hold` figures.
|
|
30
|
+
*
|
|
31
|
+
* Only the main perps dex is read: a withdrawal to L1 draws on that account,
|
|
32
|
+
* and a sub-dex balance reaches it through a transfer first.
|
|
33
|
+
*
|
|
34
|
+
* @throws {PerpsError} On Hyperliquid REST error, network, or parsing
|
|
35
|
+
* failures, and `SDKError` when the market registry carries no main perps
|
|
36
|
+
* market to name the quote asset.
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
export const getWithdrawableBalances = async (
|
|
40
|
+
{ client, apiUrl }: HyperliquidContext,
|
|
41
|
+
params: GetWithdrawableBalancesParams,
|
|
42
|
+
options?: SDKRequestOptions
|
|
43
|
+
): Promise<ProviderWithdrawableBalance[]> => {
|
|
44
|
+
const registry = getMarketRegistry(client, PROVIDER_KEY)
|
|
45
|
+
const infoOpts = hlInfoOptions(client, options)
|
|
46
|
+
|
|
47
|
+
const [markets, abstraction, state, spotState] = await Promise.all([
|
|
48
|
+
registry.sync(),
|
|
49
|
+
infoRequest<HlAbstractionMode | null>(
|
|
50
|
+
apiUrl,
|
|
51
|
+
{ type: 'userAbstraction', user: params.address },
|
|
52
|
+
infoOpts
|
|
53
|
+
),
|
|
54
|
+
infoRequest<HlClearinghouseState>(
|
|
55
|
+
apiUrl,
|
|
56
|
+
{ type: 'clearinghouseState', user: params.address },
|
|
57
|
+
infoOpts
|
|
58
|
+
),
|
|
59
|
+
infoRequest<HlSpotClearinghouseState>(
|
|
60
|
+
apiUrl,
|
|
61
|
+
{ type: 'spotClearinghouseState', user: params.address },
|
|
62
|
+
infoOpts
|
|
63
|
+
),
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
const quoteAsset = markets.find(
|
|
67
|
+
(market) => market.categoryId === MAIN_MARKET_ID
|
|
68
|
+
)?.quoteAsset
|
|
69
|
+
if (quoteAsset === undefined) {
|
|
70
|
+
const error = new PerpsError(
|
|
71
|
+
PerpsErrorCode.SDKError,
|
|
72
|
+
`Hyperliquid market registry carries no '${MAIN_MARKET_ID}' market to name the withdrawal quote asset`
|
|
73
|
+
)
|
|
74
|
+
error.tool = PROVIDER_KEY
|
|
75
|
+
throw error
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return hyperliquidWithdrawableBalances(
|
|
79
|
+
abstraction,
|
|
80
|
+
state,
|
|
81
|
+
spotState,
|
|
82
|
+
quoteAsset.id
|
|
83
|
+
)
|
|
84
|
+
}
|
package/src/types/account.ts
CHANGED
|
@@ -51,6 +51,19 @@ export type HlAssetPosition = {
|
|
|
51
51
|
position: HlPosition
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Margin totals block of a Hyperliquid clearinghouse state. Monetary fields
|
|
56
|
+
* are decimal strings in the account's quote asset.
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export type HlMarginSummary = {
|
|
60
|
+
/** Total equity: locked margin and unrealized PnL included. */
|
|
61
|
+
accountValue: string
|
|
62
|
+
totalNtlPos: string
|
|
63
|
+
totalRawUsd: string
|
|
64
|
+
totalMarginUsed: string
|
|
65
|
+
}
|
|
66
|
+
|
|
54
67
|
/**
|
|
55
68
|
* Perpetual clearinghouse account state returned by Hyperliquid `/info`.
|
|
56
69
|
* `assetPositions` includes zero-size rows that callers may discard. Monetary
|
|
@@ -60,14 +73,10 @@ export type HlAssetPosition = {
|
|
|
60
73
|
*/
|
|
61
74
|
export type HlClearinghouseState = {
|
|
62
75
|
assetPositions: HlAssetPosition[]
|
|
63
|
-
marginSummary:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
crossMarginSummary: {
|
|
68
|
-
accountValue: string
|
|
69
|
-
totalMarginUsed: string
|
|
70
|
-
}
|
|
76
|
+
marginSummary: HlMarginSummary
|
|
77
|
+
crossMarginSummary: HlMarginSummary
|
|
78
|
+
crossMaintenanceMarginUsed: string
|
|
79
|
+
withdrawable: string
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
/**
|
|
@@ -90,6 +99,11 @@ export type HlSpotBalance = {
|
|
|
90
99
|
*/
|
|
91
100
|
export type HlSpotClearinghouseState = {
|
|
92
101
|
balances: HlSpotBalance[]
|
|
102
|
+
/**
|
|
103
|
+
* Venue buying power per spot token, as `[token index, amount]` pairs.
|
|
104
|
+
* The venue reports the amount after maintenance margin.
|
|
105
|
+
*/
|
|
106
|
+
tokenToAvailableAfterMaintenance: [number, string][]
|
|
93
107
|
}
|
|
94
108
|
|
|
95
109
|
/**
|
package/src/types/ws.ts
CHANGED
|
@@ -184,6 +184,18 @@ export type HlWsUserFillsData = {
|
|
|
184
184
|
fills: HlUserFill[]
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* One sub-dex slice of an `allDexsClearinghouseState` frame. `marginSummary`
|
|
189
|
+
* is absent on a frame that reports positions only, so a reader must treat it
|
|
190
|
+
* as optional.
|
|
191
|
+
* @public
|
|
192
|
+
*/
|
|
193
|
+
export type HlWsDexClearinghouseState = Pick<
|
|
194
|
+
HlClearinghouseState,
|
|
195
|
+
'assetPositions'
|
|
196
|
+
> &
|
|
197
|
+
Partial<Pick<HlClearinghouseState, 'marginSummary'>>
|
|
198
|
+
|
|
187
199
|
/**
|
|
188
200
|
* Per-dex clearinghouse event for one user. Each tuple contains a wire DEX name
|
|
189
201
|
* and the perp positions/equity fields supplied by that DEX.
|
|
@@ -191,14 +203,15 @@ export type HlWsUserFillsData = {
|
|
|
191
203
|
*/
|
|
192
204
|
export type HlWsAllDexsClearinghouseStateData = {
|
|
193
205
|
user: string
|
|
194
|
-
clearinghouseStates: [
|
|
195
|
-
string,
|
|
196
|
-
Pick<HlClearinghouseState, 'assetPositions' | 'marginSummary'>,
|
|
197
|
-
][]
|
|
206
|
+
clearinghouseStates: [string, HlWsDexClearinghouseState][]
|
|
198
207
|
}
|
|
199
208
|
|
|
200
209
|
/** User spot clearinghouse event containing the current spot balances. @public */
|
|
201
210
|
export type HlWsSpotStateData = {
|
|
202
211
|
user: string
|
|
203
|
-
spotState: {
|
|
212
|
+
spotState: {
|
|
213
|
+
balances: HlSpotBalance[]
|
|
214
|
+
/** Absent on some frames; the REST `spotClearinghouseState` read covers it. */
|
|
215
|
+
tokenToAvailableAfterMaintenance?: [number, string][]
|
|
216
|
+
}
|
|
204
217
|
}
|
|
@@ -6,7 +6,7 @@ import { HlAbstractionMode } from '../types/account.js'
|
|
|
6
6
|
* per-dex, apart from the spot balances.
|
|
7
7
|
*/
|
|
8
8
|
export const isUnifiedAbstraction = (
|
|
9
|
-
abstraction: HlAbstractionMode | null
|
|
9
|
+
abstraction: HlAbstractionMode | string | null
|
|
10
10
|
): boolean =>
|
|
11
11
|
abstraction === HlAbstractionMode.UNIFIED_ACCOUNT ||
|
|
12
12
|
abstraction === HlAbstractionMode.PORTFOLIO_MARGIN
|
package/src/utils/index.ts
CHANGED
|
@@ -57,3 +57,9 @@ export {
|
|
|
57
57
|
} from './spotBalance.js'
|
|
58
58
|
export { partitionSpotBalances, type SpotPartition } from './spotCollateral.js'
|
|
59
59
|
export { positionMarginConstraints } from './transferMargin.js'
|
|
60
|
+
export {
|
|
61
|
+
type DexMarginSummary,
|
|
62
|
+
perpsTotals,
|
|
63
|
+
sumUnrealizedPnl,
|
|
64
|
+
} from './venueTotals.js'
|
|
65
|
+
export { hyperliquidWithdrawableBalances } from './withdrawableBalances.js'
|
package/src/utils/mapPosition.ts
CHANGED
|
@@ -30,10 +30,6 @@ export const mapPosition = (
|
|
|
30
30
|
const leverage = new Big(pos.leverage.value)
|
|
31
31
|
const marginMode =
|
|
32
32
|
pos.leverage.type === 'cross' ? MarginMode.CROSS : MarginMode.ISOLATED
|
|
33
|
-
const marginUsed =
|
|
34
|
-
marginMode === MarginMode.ISOLATED
|
|
35
|
-
? new Big(pos.marginUsed).minus(pos.unrealizedPnl).toFixed()
|
|
36
|
-
: pos.marginUsed
|
|
37
33
|
|
|
38
34
|
return {
|
|
39
35
|
market,
|
|
@@ -45,7 +41,7 @@ export const mapPosition = (
|
|
|
45
41
|
unrealizedPnl: pos.unrealizedPnl,
|
|
46
42
|
accruedFunding: new Big(pos.cumFunding.sinceOpen).neg().toFixed(),
|
|
47
43
|
leverage: ap.position.leverage.value,
|
|
48
|
-
marginUsed,
|
|
44
|
+
marginUsed: pos.marginUsed,
|
|
49
45
|
initialMarginRequirement: positionValue.div(leverage).toFixed(),
|
|
50
46
|
marginMode,
|
|
51
47
|
}
|
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
import type { Balance } from '@lifi/perps-types'
|
|
2
2
|
import { toWireBig } from './decimal.js'
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Portfolio-margin collateral beyond the category quote assets, keyed by spot
|
|
6
|
-
* display symbol with its loan-to-value weight. Hyperliquid credits these
|
|
7
|
-
* toward buying power at the given fraction (0.5 for both today). Quote assets
|
|
8
|
-
* (USDC/USDT) are already full-value collateral via the category model, so
|
|
9
|
-
* they are not listed here.
|
|
10
|
-
* https://hyperliquid.gitbook.io/hyperliquid-docs/trading/portfolio-margin
|
|
11
|
-
*/
|
|
12
|
-
const PORTFOLIO_MARGIN_LTV: Readonly<Record<string, number>> = {
|
|
13
|
-
HYPE: 0.5,
|
|
14
|
-
UBTC: 0.5,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
4
|
/**
|
|
18
5
|
* Result of {@link partitionSpotBalances}: balances that count toward
|
|
19
6
|
* collateral and balances treated as ordinary holdings.
|
|
@@ -25,15 +12,14 @@ export interface SpotPartition {
|
|
|
25
12
|
}
|
|
26
13
|
|
|
27
14
|
/**
|
|
28
|
-
* Partition spot balances into collateral and ordinary holdings.
|
|
29
|
-
* are
|
|
30
|
-
*
|
|
15
|
+
* Partition spot balances into collateral and ordinary holdings. Category
|
|
16
|
+
* quote assets are collateral; every other token is an ordinary holding.
|
|
17
|
+
* Zero-unit rows are dropped from both lists.
|
|
31
18
|
* @public
|
|
32
19
|
*/
|
|
33
20
|
export const partitionSpotBalances = (
|
|
34
21
|
spotBalances: readonly Balance[],
|
|
35
|
-
quoteAssetIds: ReadonlySet<string
|
|
36
|
-
portfolioMargin: boolean
|
|
22
|
+
quoteAssetIds: ReadonlySet<string>
|
|
37
23
|
): SpotPartition => {
|
|
38
24
|
const collateralBalances: Balance[] = []
|
|
39
25
|
const balances: Balance[] = []
|
|
@@ -43,13 +29,6 @@ export const partitionSpotBalances = (
|
|
|
43
29
|
}
|
|
44
30
|
if (quoteAssetIds.has(balance.asset.id)) {
|
|
45
31
|
collateralBalances.push(balance)
|
|
46
|
-
continue
|
|
47
|
-
}
|
|
48
|
-
const ltv = portfolioMargin
|
|
49
|
-
? PORTFOLIO_MARGIN_LTV[balance.asset.displaySymbol]
|
|
50
|
-
: undefined
|
|
51
|
-
if (ltv !== undefined) {
|
|
52
|
-
collateralBalances.push({ ...balance, collateralWeight: ltv })
|
|
53
32
|
} else {
|
|
54
33
|
balances.push(balance)
|
|
55
34
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { HyperliquidMarginSummary, Position } from '@lifi/perps-types'
|
|
2
|
+
import Big from 'big.js'
|
|
3
|
+
import { toWireBig } from './decimal.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One perps sub-dex entry {@link perpsTotals} reads. The REST response always
|
|
7
|
+
* carries `marginSummary`; a WebSocket frame may omit it.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export interface DexMarginSummary {
|
|
11
|
+
marginSummary?: HyperliquidMarginSummary
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sum the venue `marginSummary` totals over every perps sub-dex of an
|
|
16
|
+
* account. `accountValue` is total equity, so it already carries locked
|
|
17
|
+
* margin and unrealized PnL. An entry without a `marginSummary` adds nothing.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export const perpsTotals = (
|
|
21
|
+
dexStates: readonly DexMarginSummary[]
|
|
22
|
+
): { accountValue: Big; marginUsed: Big } => {
|
|
23
|
+
let accountValue = new Big(0)
|
|
24
|
+
let marginUsed = new Big(0)
|
|
25
|
+
for (const { marginSummary } of dexStates) {
|
|
26
|
+
if (marginSummary === undefined) {
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
accountValue = accountValue.plus(
|
|
30
|
+
toWireBig(marginSummary.accountValue, 'marginSummary.accountValue')
|
|
31
|
+
)
|
|
32
|
+
marginUsed = marginUsed.plus(
|
|
33
|
+
toWireBig(marginSummary.totalMarginUsed, 'marginSummary.totalMarginUsed')
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
return { accountValue, marginUsed }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Sum the unrealized PnL of every position, in quote-asset units.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export const sumUnrealizedPnl = (positions: readonly Position[]): Big =>
|
|
44
|
+
positions.reduce(
|
|
45
|
+
(sum, position) =>
|
|
46
|
+
sum.plus(toWireBig(position.unrealizedPnl, 'position.unrealizedPnl')),
|
|
47
|
+
new Big(0)
|
|
48
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ProviderWithdrawableBalance } from '@lifi/perps-sdk'
|
|
2
|
+
import type {
|
|
3
|
+
HlAbstractionMode,
|
|
4
|
+
HlClearinghouseState,
|
|
5
|
+
HlSpotClearinghouseState,
|
|
6
|
+
} from '../types/index.js'
|
|
7
|
+
import { isUnifiedAbstraction } from './abstractionMode.js'
|
|
8
|
+
import { assetIsOutcome } from './assetId.js'
|
|
9
|
+
import { toWireBig } from './decimal.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Split a Hyperliquid account's venue figures into the routes a withdrawal
|
|
13
|
+
* draws on. A unified or portfolio-margin account holds its collateral in spot,
|
|
14
|
+
* so each spot token adds the part of `total` that no order or margin holds. A
|
|
15
|
+
* route with nothing left to draw carries no row, and the caller applies the
|
|
16
|
+
* per-asset venue minimum.
|
|
17
|
+
*
|
|
18
|
+
* @param quoteAssetId - `Asset.id` the perps-route row is keyed by.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export const hyperliquidWithdrawableBalances = (
|
|
22
|
+
abstraction: HlAbstractionMode | null,
|
|
23
|
+
state: HlClearinghouseState,
|
|
24
|
+
spotState: HlSpotClearinghouseState,
|
|
25
|
+
quoteAssetId: string
|
|
26
|
+
): ProviderWithdrawableBalance[] => {
|
|
27
|
+
const rows: ProviderWithdrawableBalance[] = []
|
|
28
|
+
|
|
29
|
+
if (isUnifiedAbstraction(abstraction)) {
|
|
30
|
+
for (const balance of spotState.balances) {
|
|
31
|
+
if (assetIsOutcome(balance.coin)) {
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
const spot = toWireBig(balance.total, 'spotBalance.total').minus(
|
|
35
|
+
toWireBig(balance.hold, 'spotBalance.hold')
|
|
36
|
+
)
|
|
37
|
+
if (spot.gt(0)) {
|
|
38
|
+
rows.push({
|
|
39
|
+
assetId: String(balance.token),
|
|
40
|
+
route: 'spot',
|
|
41
|
+
available: spot.toFixed(),
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const perps = toWireBig(state.withdrawable, 'clearinghouseState.withdrawable')
|
|
48
|
+
if (perps.gt(0)) {
|
|
49
|
+
rows.push({
|
|
50
|
+
assetId: quoteAssetId,
|
|
51
|
+
route: 'perps',
|
|
52
|
+
available: perps.toFixed(),
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return rows
|
|
57
|
+
}
|