@lifi/perps-sdk-provider-hyperliquid 13.0.0 → 14.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/README.md +115 -0
- package/dist/cjs/HyperliquidProvider.d.ts.map +1 -1
- package/dist/cjs/HyperliquidProvider.js +1 -2
- package/dist/cjs/HyperliquidProvider.js.map +1 -1
- package/dist/cjs/constants.d.ts +1 -0
- package/dist/cjs/constants.d.ts.map +1 -1
- package/dist/cjs/constants.js +2 -1
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/services/getAccount.d.ts.map +1 -1
- package/dist/cjs/services/getAccount.js +16 -9
- package/dist/cjs/services/getAccount.js.map +1 -1
- package/dist/cjs/services/getActivity.d.ts.map +1 -1
- package/dist/cjs/services/getActivity.js +40 -7
- package/dist/cjs/services/getActivity.js.map +1 -1
- package/dist/cjs/services/getFills.d.ts.map +1 -1
- package/dist/cjs/services/getFills.js +3 -0
- package/dist/cjs/services/getFills.js.map +1 -1
- package/dist/cjs/services/getOrder.d.ts.map +1 -1
- package/dist/cjs/services/getOrder.js +14 -3
- package/dist/cjs/services/getOrder.js.map +1 -1
- package/dist/cjs/services/getOrders.d.ts +2 -7
- package/dist/cjs/services/getOrders.d.ts.map +1 -1
- package/dist/cjs/services/getOrders.js +94 -31
- package/dist/cjs/services/getOrders.js.map +1 -1
- package/dist/cjs/services/getPositions.d.ts.map +1 -1
- package/dist/cjs/services/getPositions.js +1 -1
- package/dist/cjs/services/getPositions.js.map +1 -1
- package/dist/cjs/types/explorer.d.ts +10 -0
- package/dist/cjs/types/explorer.d.ts.map +1 -0
- package/dist/cjs/types/explorer.js +17 -0
- package/dist/cjs/types/explorer.js.map +1 -0
- package/dist/cjs/types/fill.d.ts +6 -0
- package/dist/cjs/types/fill.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +1 -0
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/ledger.d.ts +24 -1
- package/dist/cjs/types/ledger.d.ts.map +1 -1
- package/dist/cjs/types/ledger.js +5 -1
- package/dist/cjs/types/ledger.js.map +1 -1
- package/dist/cjs/types/order.d.ts +24 -0
- package/dist/cjs/types/order.d.ts.map +1 -1
- package/dist/cjs/types/ws.d.ts +14 -0
- package/dist/cjs/types/ws.d.ts.map +1 -1
- package/dist/cjs/utils/assetId.d.ts +1 -0
- package/dist/cjs/utils/assetId.d.ts.map +1 -1
- package/dist/cjs/utils/assetId.js +6 -1
- package/dist/cjs/utils/assetId.js.map +1 -1
- package/dist/cjs/utils/explorer.d.ts +7 -0
- package/dist/cjs/utils/explorer.d.ts.map +1 -0
- package/dist/cjs/utils/explorer.js +49 -0
- package/dist/cjs/utils/explorer.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +4 -3
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +7 -6
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/infoClient.d.ts +1 -0
- package/dist/cjs/utils/infoClient.d.ts.map +1 -1
- package/dist/cjs/utils/infoClient.js +16 -10
- package/dist/cjs/utils/infoClient.js.map +1 -1
- package/dist/cjs/utils/mapActivity.d.ts +5 -3
- package/dist/cjs/utils/mapActivity.d.ts.map +1 -1
- package/dist/cjs/utils/mapActivity.js +116 -48
- package/dist/cjs/utils/mapActivity.js.map +1 -1
- package/dist/cjs/utils/mapFill.d.ts.map +1 -1
- package/dist/cjs/utils/mapFill.js +0 -1
- package/dist/cjs/utils/mapFill.js.map +1 -1
- package/dist/cjs/utils/mapOrder.d.ts +4 -9
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +149 -135
- package/dist/cjs/utils/mapOrder.js.map +1 -1
- package/dist/cjs/utils/spotBalance.d.ts.map +1 -1
- package/dist/cjs/utils/spotBalance.js +10 -6
- package/dist/cjs/utils/spotBalance.js.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +3 -0
- package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/HyperliquidWsProvider.js +100 -29
- package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
- package/dist/esm/HyperliquidProvider.js +1 -2
- package/dist/esm/HyperliquidProvider.js.map +1 -1
- package/dist/esm/constants.d.ts +8 -0
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +8 -0
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/index.d.ts +1 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/services/getAccount.d.ts.map +1 -1
- package/dist/esm/services/getAccount.js +14 -10
- package/dist/esm/services/getAccount.js.map +1 -1
- package/dist/esm/services/getActivity.d.ts +2 -2
- package/dist/esm/services/getActivity.d.ts.map +1 -1
- package/dist/esm/services/getActivity.js +44 -9
- package/dist/esm/services/getActivity.js.map +1 -1
- package/dist/esm/services/getFills.d.ts.map +1 -1
- package/dist/esm/services/getFills.js +4 -1
- package/dist/esm/services/getFills.js.map +1 -1
- package/dist/esm/services/getOrder.d.ts.map +1 -1
- package/dist/esm/services/getOrder.js +15 -4
- package/dist/esm/services/getOrder.js.map +1 -1
- package/dist/esm/services/getOrders.d.ts +4 -24
- package/dist/esm/services/getOrders.d.ts.map +1 -1
- package/dist/esm/services/getOrders.js +115 -42
- package/dist/esm/services/getOrders.js.map +1 -1
- package/dist/esm/services/getPositions.d.ts.map +1 -1
- package/dist/esm/services/getPositions.js +2 -2
- package/dist/esm/services/getPositions.js.map +1 -1
- package/dist/esm/types/explorer.d.ts +27 -0
- package/dist/esm/types/explorer.d.ts.map +1 -0
- package/dist/esm/types/explorer.js +20 -0
- package/dist/esm/types/explorer.js.map +1 -0
- package/dist/esm/types/fill.d.ts +11 -0
- package/dist/esm/types/fill.d.ts.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/ledger.d.ts +28 -1
- package/dist/esm/types/ledger.d.ts.map +1 -1
- package/dist/esm/types/ledger.js +4 -0
- package/dist/esm/types/ledger.js.map +1 -1
- package/dist/esm/types/order.d.ts +26 -0
- package/dist/esm/types/order.d.ts.map +1 -1
- package/dist/esm/types/ws.d.ts +15 -0
- package/dist/esm/types/ws.d.ts.map +1 -1
- package/dist/esm/utils/assetId.d.ts +9 -0
- package/dist/esm/utils/assetId.d.ts.map +1 -1
- package/dist/esm/utils/assetId.js +13 -0
- package/dist/esm/utils/assetId.js.map +1 -1
- package/dist/esm/utils/explorer.d.ts +31 -0
- package/dist/esm/utils/explorer.d.ts.map +1 -0
- package/dist/esm/utils/explorer.js +68 -0
- package/dist/esm/utils/explorer.js.map +1 -0
- package/dist/esm/utils/index.d.ts +4 -3
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +4 -3
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/infoClient.d.ts +14 -3
- package/dist/esm/utils/infoClient.d.ts.map +1 -1
- package/dist/esm/utils/infoClient.js +29 -14
- package/dist/esm/utils/infoClient.js.map +1 -1
- package/dist/esm/utils/mapActivity.d.ts +16 -13
- package/dist/esm/utils/mapActivity.d.ts.map +1 -1
- package/dist/esm/utils/mapActivity.js +128 -72
- package/dist/esm/utils/mapActivity.js.map +1 -1
- package/dist/esm/utils/mapFill.d.ts.map +1 -1
- package/dist/esm/utils/mapFill.js +1 -2
- package/dist/esm/utils/mapFill.js.map +1 -1
- package/dist/esm/utils/mapOrder.d.ts +8 -73
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +148 -187
- package/dist/esm/utils/mapOrder.js.map +1 -1
- package/dist/esm/utils/spotBalance.d.ts +1 -1
- package/dist/esm/utils/spotBalance.d.ts.map +1 -1
- package/dist/esm/utils/spotBalance.js +12 -7
- package/dist/esm/utils/spotBalance.js.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts +5 -1
- package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/HyperliquidWsProvider.js +105 -34
- package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
- package/dist/types/HyperliquidProvider.d.ts.map +1 -1
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/services/getAccount.d.ts.map +1 -1
- package/dist/types/services/getActivity.d.ts +2 -2
- package/dist/types/services/getActivity.d.ts.map +1 -1
- package/dist/types/services/getFills.d.ts.map +1 -1
- package/dist/types/services/getOrder.d.ts.map +1 -1
- package/dist/types/services/getOrders.d.ts +4 -24
- package/dist/types/services/getOrders.d.ts.map +1 -1
- package/dist/types/services/getPositions.d.ts.map +1 -1
- package/dist/types/types/explorer.d.ts +27 -0
- package/dist/types/types/explorer.d.ts.map +1 -0
- package/dist/types/types/fill.d.ts +11 -0
- package/dist/types/types/fill.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/types/ledger.d.ts +28 -1
- package/dist/types/types/ledger.d.ts.map +1 -1
- package/dist/types/types/order.d.ts +26 -0
- package/dist/types/types/order.d.ts.map +1 -1
- package/dist/types/types/ws.d.ts +15 -0
- package/dist/types/types/ws.d.ts.map +1 -1
- package/dist/types/utils/assetId.d.ts +9 -0
- package/dist/types/utils/assetId.d.ts.map +1 -1
- package/dist/types/utils/explorer.d.ts +31 -0
- package/dist/types/utils/explorer.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +4 -3
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/infoClient.d.ts +14 -3
- package/dist/types/utils/infoClient.d.ts.map +1 -1
- package/dist/types/utils/mapActivity.d.ts +16 -13
- package/dist/types/utils/mapActivity.d.ts.map +1 -1
- package/dist/types/utils/mapFill.d.ts.map +1 -1
- package/dist/types/utils/mapOrder.d.ts +8 -73
- package/dist/types/utils/mapOrder.d.ts.map +1 -1
- package/dist/types/utils/spotBalance.d.ts +1 -1
- package/dist/types/utils/spotBalance.d.ts.map +1 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts +5 -1
- package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/HyperliquidProvider.ts +1 -13
- package/src/constants.ts +10 -0
- package/src/index.ts +1 -2
- package/src/services/getAccount.ts +22 -14
- package/src/services/getActivity.ts +81 -6
- package/src/services/getFills.ts +4 -1
- package/src/services/getOrder.ts +29 -5
- package/src/services/getOrders.ts +185 -70
- package/src/services/getPositions.ts +4 -1
- package/src/types/explorer.ts +39 -0
- package/src/types/fill.ts +12 -0
- package/src/types/index.ts +1 -0
- package/src/types/ledger.ts +37 -0
- package/src/types/order.ts +25 -0
- package/src/types/ws.ts +16 -0
- package/src/utils/assetId.ts +16 -0
- package/src/utils/explorer.ts +93 -0
- package/src/utils/index.ts +16 -7
- package/src/utils/infoClient.ts +46 -24
- package/src/utils/mapActivity.ts +163 -75
- package/src/utils/mapFill.ts +0 -2
- package/src/utils/mapOrder.ts +163 -212
- package/src/utils/spotBalance.ts +12 -7
- package/src/websocket/HyperliquidWsProvider.ts +127 -40
- package/dist/cjs/services/getRunningTwaps.d.ts +0 -10
- package/dist/cjs/services/getRunningTwaps.d.ts.map +0 -1
- package/dist/cjs/services/getRunningTwaps.js +0 -46
- package/dist/cjs/services/getRunningTwaps.js.map +0 -1
- package/dist/esm/services/getRunningTwaps.d.ts +0 -12
- package/dist/esm/services/getRunningTwaps.d.ts.map +0 -1
- package/dist/esm/services/getRunningTwaps.js +0 -40
- package/dist/esm/services/getRunningTwaps.js.map +0 -1
- package/dist/types/services/getRunningTwaps.d.ts +0 -12
- package/dist/types/services/getRunningTwaps.d.ts.map +0 -1
- package/src/services/getRunningTwaps.ts +0 -90
|
@@ -1,102 +1,217 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
ACTIVE_ORDER_STATUSES,
|
|
3
|
+
createWarnOnce,
|
|
4
|
+
ExplorerChainId,
|
|
5
|
+
explorerTxUrl,
|
|
6
|
+
getMarketRegistry,
|
|
7
|
+
isActiveOrderStatus,
|
|
8
|
+
type MarketRegistry,
|
|
9
|
+
PerpsError,
|
|
10
|
+
type ProviderGetOrdersParams,
|
|
11
|
+
type SDKRequestOptions,
|
|
12
|
+
} from '@lifi/perps-sdk'
|
|
13
|
+
import type { MarketDisplay, Order, OrdersResponse } from '@lifi/perps-types'
|
|
4
14
|
import { PROVIDER_KEY } from '../constants.js'
|
|
5
15
|
import type { HyperliquidContext } from '../context.js'
|
|
6
16
|
import type {
|
|
7
|
-
|
|
17
|
+
HlExplorerTx,
|
|
8
18
|
HlFrontendOpenOrders,
|
|
19
|
+
HlHistoricalOrders,
|
|
20
|
+
HlTwapHistoryEntry,
|
|
9
21
|
} from '../types/index.js'
|
|
10
22
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
23
|
+
assetIsOutcome,
|
|
24
|
+
fetchUserTransactions,
|
|
25
|
+
mapOrder,
|
|
26
|
+
matchOrderActionHash,
|
|
14
27
|
perpsDexNames,
|
|
15
28
|
} from '../utils/index.js'
|
|
16
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
hlInfoOptions,
|
|
31
|
+
type InfoRequestOptions,
|
|
32
|
+
infoRequest,
|
|
33
|
+
} from '../utils/infoClient.js'
|
|
34
|
+
|
|
35
|
+
/** Parameters for a lifecycle-filtered Hyperliquid order read. */
|
|
36
|
+
export type GetOrdersParams = ProviderGetOrdersParams
|
|
37
|
+
|
|
38
|
+
const warn = createWarnOnce()
|
|
39
|
+
|
|
40
|
+
const warnOnce = (key: string, detail?: string): void => {
|
|
41
|
+
warn(
|
|
42
|
+
key,
|
|
43
|
+
`[${PROVIDER_KEY}] ${detail === undefined ? key : `${key}: ${detail}`}`
|
|
44
|
+
)
|
|
45
|
+
}
|
|
17
46
|
|
|
18
47
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
48
|
+
* Map one venue row, or drop it. An outcome market identity, a coin the backend
|
|
49
|
+
* market list does not hold, and a row the mapper rejects each drop only their
|
|
50
|
+
* own row instead of rejecting the whole page; each distinct mapper message
|
|
51
|
+
* warns once.
|
|
22
52
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
53
|
+
const mapRow = (
|
|
54
|
+
coin: string,
|
|
55
|
+
registry: MarketRegistry,
|
|
56
|
+
map: (market: MarketDisplay) => Order
|
|
57
|
+
): Order | undefined => {
|
|
58
|
+
if (assetIsOutcome(coin)) {
|
|
59
|
+
return undefined
|
|
60
|
+
}
|
|
61
|
+
const market = registry.get(coin)
|
|
62
|
+
if (market === undefined) {
|
|
63
|
+
return undefined
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return map(market)
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (!(error instanceof PerpsError)) {
|
|
69
|
+
throw error
|
|
70
|
+
}
|
|
71
|
+
warnOnce(`dropped order row: ${error.message}`)
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
29
74
|
}
|
|
30
75
|
|
|
31
76
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* `frontendOpenOrders` is read direct.
|
|
38
|
-
* @throws {PerpsError} On Hyperliquid REST error, network, or parsing failures.
|
|
39
|
-
* @public
|
|
77
|
+
* Set `explorerLink` on each row whose placement transaction the explorer
|
|
78
|
+
* window still holds. One explorer read serves the whole page, and it is
|
|
79
|
+
* skipped when no row carries a client order id to match on. The link is
|
|
80
|
+
* supplementary, so an explorer failure warns and leaves the rows unlinked
|
|
81
|
+
* instead of failing the order read.
|
|
40
82
|
*/
|
|
83
|
+
const withExplorerLinks = async (
|
|
84
|
+
orders: Order[],
|
|
85
|
+
address: string,
|
|
86
|
+
options: InfoRequestOptions
|
|
87
|
+
): Promise<Order[]> => {
|
|
88
|
+
if (!orders.some((order) => order.clientOrderId !== undefined)) {
|
|
89
|
+
return orders
|
|
90
|
+
}
|
|
91
|
+
let txs: HlExplorerTx[]
|
|
92
|
+
try {
|
|
93
|
+
txs = await fetchUserTransactions(address, options)
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (!(error instanceof PerpsError)) {
|
|
96
|
+
throw error
|
|
97
|
+
}
|
|
98
|
+
// The message stays out of the key: a transport failure names hosts and
|
|
99
|
+
// ports, so keying on it would let the dedupe set grow without bound.
|
|
100
|
+
warnOnce('explorer link lookup failed', error.message)
|
|
101
|
+
return orders
|
|
102
|
+
}
|
|
103
|
+
return orders.map((order) => {
|
|
104
|
+
const explorerLink = explorerTxUrl(
|
|
105
|
+
ExplorerChainId.HYPERLIQUID,
|
|
106
|
+
matchOrderActionHash(txs, order)
|
|
107
|
+
)
|
|
108
|
+
return explorerLink === undefined ? order : { ...order, explorerLink }
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Read regular, trigger, and TWAP orders from the requested lifecycle feeds. */
|
|
41
113
|
export const getOrders = async (
|
|
42
114
|
{ client, apiUrl }: HyperliquidContext,
|
|
43
115
|
params: GetOrdersParams,
|
|
44
116
|
options?: SDKRequestOptions
|
|
45
117
|
): Promise<OrdersResponse> => {
|
|
118
|
+
const statuses = params.statuses ?? [...ACTIVE_ORDER_STATUSES]
|
|
119
|
+
if (statuses.length === 0) {
|
|
120
|
+
return {
|
|
121
|
+
provider: PROVIDER_KEY,
|
|
122
|
+
orders: [],
|
|
123
|
+
pagination: { limit: params.limit ?? 0, hasMore: false },
|
|
124
|
+
}
|
|
125
|
+
}
|
|
46
126
|
const registry = getMarketRegistry(client, PROVIDER_KEY)
|
|
47
127
|
const markets = await registry.sync()
|
|
48
128
|
const infoOpts = hlInfoOptions(client, options)
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
129
|
+
const active = statuses.some(isActiveOrderStatus)
|
|
130
|
+
const terminal = statuses.some((status) => !isActiveOrderStatus(status))
|
|
131
|
+
const [open, historical, twaps] = await Promise.all([
|
|
132
|
+
active
|
|
133
|
+
? Promise.all(
|
|
134
|
+
perpsDexNames(markets).map((name) =>
|
|
135
|
+
infoRequest<HlFrontendOpenOrders>(
|
|
136
|
+
apiUrl,
|
|
137
|
+
{
|
|
138
|
+
type: 'frontendOpenOrders',
|
|
139
|
+
user: params.address,
|
|
140
|
+
...(name ? { dex: name } : {}),
|
|
141
|
+
},
|
|
142
|
+
infoOpts
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
: [],
|
|
147
|
+
terminal
|
|
148
|
+
? infoRequest<HlHistoricalOrders>(
|
|
149
|
+
apiUrl,
|
|
150
|
+
{ type: 'historicalOrders', user: params.address },
|
|
151
|
+
infoOpts
|
|
152
|
+
)
|
|
153
|
+
: [],
|
|
154
|
+
infoRequest<HlTwapHistoryEntry[]>(
|
|
155
|
+
apiUrl,
|
|
156
|
+
{ type: 'twapHistory', user: params.address },
|
|
157
|
+
infoOpts
|
|
158
|
+
),
|
|
159
|
+
])
|
|
160
|
+
const rows = new Map<string, Order>()
|
|
161
|
+
const keep = (key: string, order: Order | undefined): void => {
|
|
162
|
+
if (order !== undefined) {
|
|
163
|
+
rows.set(key, order)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const detail of historical) {
|
|
167
|
+
const key = String(detail.order.oid)
|
|
168
|
+
// The feed carries one row per lifecycle transition, newest first, and a
|
|
169
|
+
// terminal row shares its timestamp with the `open` row beneath it, so
|
|
170
|
+
// only the first row of an id states that order's current status.
|
|
171
|
+
if (rows.has(key)) {
|
|
172
|
+
continue
|
|
173
|
+
}
|
|
174
|
+
keep(
|
|
175
|
+
key,
|
|
176
|
+
mapRow(detail.order.coin, registry, (market) => mapOrder(detail, market))
|
|
61
177
|
)
|
|
178
|
+
}
|
|
179
|
+
const raw = open.flat()
|
|
180
|
+
const childIds = new Set(
|
|
181
|
+
raw.flatMap((order) => (order.children ?? []).map((child) => child.oid))
|
|
62
182
|
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
183
|
+
for (const order of raw) {
|
|
184
|
+
if (!childIds.has(order.oid)) {
|
|
185
|
+
keep(
|
|
186
|
+
String(order.oid),
|
|
187
|
+
mapRow(order.coin, registry, (market) => mapOrder(order, market))
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
for (const child of order.children ?? []) {
|
|
191
|
+
keep(
|
|
192
|
+
String(child.oid),
|
|
193
|
+
mapRow(child.coin, registry, (market) =>
|
|
194
|
+
mapOrder(child, market, String(order.oid))
|
|
195
|
+
)
|
|
196
|
+
)
|
|
70
197
|
}
|
|
71
198
|
}
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
let triggerOrders: TriggerOrder[] = [
|
|
80
|
-
...nonChild
|
|
81
|
-
.filter((o) => isTriggerOrder(o))
|
|
82
|
-
.map((o) => mapTriggerOrder(o, registry.require(o.coin))),
|
|
83
|
-
...raw
|
|
84
|
-
.filter((o) => childOids.has(o.oid))
|
|
85
|
-
.map((o) => mapTriggerOrder(o, registry.require(o.coin))),
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
if (params.marketId !== undefined) {
|
|
89
|
-
openOrders = openOrders.filter((o) => o.market.id === params.marketId)
|
|
90
|
-
triggerOrders = triggerOrders.filter((o) => o.market.id === params.marketId)
|
|
199
|
+
// TWAP ids and regular order ids occupy separate venue namespaces.
|
|
200
|
+
for (const twap of twaps) {
|
|
201
|
+
keep(
|
|
202
|
+
`twap:${twap.twapId}`,
|
|
203
|
+
mapRow(twap.state.coin, registry, (market) => mapOrder(twap, market))
|
|
204
|
+
)
|
|
91
205
|
}
|
|
92
|
-
|
|
206
|
+
const matching = [...rows.values()].filter(
|
|
207
|
+
(order) =>
|
|
208
|
+
statuses.includes(order.status) &&
|
|
209
|
+
(params.marketId === undefined || order.market.id === params.marketId)
|
|
210
|
+
)
|
|
211
|
+
const orders = await withExplorerLinks(matching, params.address, infoOpts)
|
|
93
212
|
return {
|
|
94
213
|
provider: PROVIDER_KEY,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
pagination: {
|
|
98
|
-
limit: params.limit ?? openOrders.length + triggerOrders.length,
|
|
99
|
-
hasMore: false,
|
|
100
|
-
},
|
|
214
|
+
orders,
|
|
215
|
+
pagination: { limit: params.limit ?? orders.length, hasMore: false },
|
|
101
216
|
}
|
|
102
217
|
}
|
|
@@ -9,6 +9,7 @@ import { PROVIDER_KEY } from '../constants.js'
|
|
|
9
9
|
import type { HyperliquidContext } from '../context.js'
|
|
10
10
|
import type { HlClearinghouseState } from '../types/index.js'
|
|
11
11
|
import {
|
|
12
|
+
assetIsOutcome,
|
|
12
13
|
isOpenAssetPosition,
|
|
13
14
|
mapPosition,
|
|
14
15
|
perpsDexNames,
|
|
@@ -61,7 +62,9 @@ export const getPositions = async (
|
|
|
61
62
|
|
|
62
63
|
let positions = stateResults.flatMap((state) =>
|
|
63
64
|
state.assetPositions
|
|
64
|
-
.filter(
|
|
65
|
+
.filter(
|
|
66
|
+
(ap) => !assetIsOutcome(ap.position.coin) && isOpenAssetPosition(ap)
|
|
67
|
+
)
|
|
65
68
|
.map((ap) =>
|
|
66
69
|
mapPosition(
|
|
67
70
|
ap,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One HyperCore transaction as the explorer `userDetails` RPC reports it.
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface HlExplorerTx {
|
|
7
|
+
time: number
|
|
8
|
+
user: string
|
|
9
|
+
/**
|
|
10
|
+
* The action body HyperCore received. Untyped because the shape varies by
|
|
11
|
+
* action type; read it through `getClientOrderIds`, not by field name.
|
|
12
|
+
*/
|
|
13
|
+
action: unknown
|
|
14
|
+
block: number
|
|
15
|
+
hash: string
|
|
16
|
+
/** `null` on a tx the engine applied, a message on one it landed but refused. */
|
|
17
|
+
error: string | null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether one `userDetails` entry carries every field this package reads. The
|
|
22
|
+
* explorer RPC is undocumented, so entries are checked one at a time and a
|
|
23
|
+
* drifted entry drops on its own instead of failing the whole window.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export const isHlExplorerTx = (value: unknown): value is HlExplorerTx =>
|
|
28
|
+
typeof value === 'object' &&
|
|
29
|
+
value !== null &&
|
|
30
|
+
'time' in value &&
|
|
31
|
+
typeof value.time === 'number' &&
|
|
32
|
+
'user' in value &&
|
|
33
|
+
typeof value.user === 'string' &&
|
|
34
|
+
'block' in value &&
|
|
35
|
+
typeof value.block === 'number' &&
|
|
36
|
+
'hash' in value &&
|
|
37
|
+
typeof value.hash === 'string' &&
|
|
38
|
+
'error' in value &&
|
|
39
|
+
(value.error === null || typeof value.error === 'string')
|
package/src/types/fill.ts
CHANGED
|
@@ -34,6 +34,18 @@ export type HlUserFill = {
|
|
|
34
34
|
crossed: boolean
|
|
35
35
|
time: number
|
|
36
36
|
startPosition: string
|
|
37
|
+
/**
|
|
38
|
+
* Present on both sides of a liquidation fill. `liquidatedUser` names the
|
|
39
|
+
* account that was liquidated; the other party is the liquidator.
|
|
40
|
+
*/
|
|
41
|
+
liquidation?: HlFillLiquidation
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Liquidation detail Hyperliquid attaches to a fill. @public */
|
|
45
|
+
export type HlFillLiquidation = {
|
|
46
|
+
liquidatedUser: string
|
|
47
|
+
markPx: string
|
|
48
|
+
method: string
|
|
37
49
|
}
|
|
38
50
|
|
|
39
51
|
/** All fills returned by the unbounded `userFills` query. @public */
|
package/src/types/index.ts
CHANGED
package/src/types/ledger.ts
CHANGED
|
@@ -50,6 +50,41 @@ export type HlSendAssetDelta = {
|
|
|
50
50
|
feeToken: string
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** USDC transfers between Hyperliquid accounts, including subaccounts. @public */
|
|
54
|
+
export type HlCollateralTransferDelta = {
|
|
55
|
+
type: 'internalTransfer' | 'subAccountTransfer'
|
|
56
|
+
usdc: string
|
|
57
|
+
user: Address
|
|
58
|
+
destination: Address
|
|
59
|
+
fee?: string
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Narrow the USDC account-transfer ledger variants. @public */
|
|
63
|
+
export const isCollateralTransferDelta = (
|
|
64
|
+
delta: HlLedgerDelta
|
|
65
|
+
): delta is HlCollateralTransferDelta =>
|
|
66
|
+
delta.type === 'internalTransfer' || delta.type === 'subAccountTransfer'
|
|
67
|
+
|
|
68
|
+
/** USDC movements into or out of a vault, including withdrawal accounting. @public */
|
|
69
|
+
export type HlVaultTransferDelta =
|
|
70
|
+
| { type: 'vaultDeposit'; vault: Address; usdc: string }
|
|
71
|
+
| {
|
|
72
|
+
type: 'vaultWithdraw'
|
|
73
|
+
vault: Address
|
|
74
|
+
user: Address
|
|
75
|
+
requestedUsd: string
|
|
76
|
+
commission: string
|
|
77
|
+
closingCost: string
|
|
78
|
+
basis: string
|
|
79
|
+
netWithdrawnUsd: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Narrow the vault fund-movement ledger variants. @public */
|
|
83
|
+
export const isVaultTransferDelta = (
|
|
84
|
+
delta: HlLedgerDelta
|
|
85
|
+
): delta is HlVaultTransferDelta =>
|
|
86
|
+
delta.type === 'vaultDeposit' || delta.type === 'vaultWithdraw'
|
|
87
|
+
|
|
53
88
|
/**
|
|
54
89
|
* Hyperliquid `deposit` ledger delta. Perp-collateral deposits are always
|
|
55
90
|
* USDC-denominated, which is why the amount arrives in a field named `usdc`.
|
|
@@ -103,6 +138,8 @@ export type HlLiquidationDelta = {
|
|
|
103
138
|
export type HlLedgerDelta =
|
|
104
139
|
| HlSpotTransferDelta
|
|
105
140
|
| HlSendAssetDelta
|
|
141
|
+
| HlCollateralTransferDelta
|
|
142
|
+
| HlVaultTransferDelta
|
|
106
143
|
| HlDepositDelta
|
|
107
144
|
| HlWithdrawDelta
|
|
108
145
|
| HlLiquidationDelta
|
package/src/types/order.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type HlFrontendOpenOrder = {
|
|
|
17
17
|
reduceOnly: boolean
|
|
18
18
|
timestamp: number
|
|
19
19
|
isTrigger: boolean
|
|
20
|
+
tpsl?: 'tp' | 'sl'
|
|
20
21
|
isPositionTpsl: boolean
|
|
21
22
|
triggerCondition: string
|
|
22
23
|
triggerPx: string
|
|
@@ -49,6 +50,10 @@ export type HlOrderDetail = {
|
|
|
49
50
|
cloid: string | null
|
|
50
51
|
triggerCondition: string
|
|
51
52
|
triggerPx: string | null
|
|
53
|
+
isTrigger?: boolean
|
|
54
|
+
tpsl?: 'tp' | 'sl'
|
|
55
|
+
children?: HlFrontendOpenOrder[]
|
|
56
|
+
isPositionTpsl?: boolean
|
|
52
57
|
}
|
|
53
58
|
status: string
|
|
54
59
|
statusTimestamp: number
|
|
@@ -68,3 +73,23 @@ export type HlOrderStatusFound = {
|
|
|
68
73
|
export type HlOrderStatusResponse =
|
|
69
74
|
| HlOrderStatusFound
|
|
70
75
|
| { status: 'unknownOid' }
|
|
76
|
+
|
|
77
|
+
/** Rows returned by the `historicalOrders` info query. */
|
|
78
|
+
export type HlHistoricalOrders = HlOrderDetail[]
|
|
79
|
+
|
|
80
|
+
/** TWAP execution state returned by `twapHistory`; time uses epoch seconds. */
|
|
81
|
+
export interface HlTwapHistoryEntry {
|
|
82
|
+
state: {
|
|
83
|
+
coin: string
|
|
84
|
+
executedNtl: string
|
|
85
|
+
executedSz: string
|
|
86
|
+
minutes: number
|
|
87
|
+
side: string
|
|
88
|
+
sz: string
|
|
89
|
+
timestamp: number
|
|
90
|
+
reduceOnly: boolean
|
|
91
|
+
}
|
|
92
|
+
status: { status: string; description?: string }
|
|
93
|
+
time: number
|
|
94
|
+
twapId?: number
|
|
95
|
+
}
|
package/src/types/ws.ts
CHANGED
|
@@ -6,6 +6,22 @@ import type { HlUserFill } from './fill.js'
|
|
|
6
6
|
|
|
7
7
|
type HlWsNumberString = string | number
|
|
8
8
|
|
|
9
|
+
/** Sparse order update returned by the `orderUpdates` WebSocket subscription. */
|
|
10
|
+
export interface HlWsOrder {
|
|
11
|
+
order: {
|
|
12
|
+
coin: string
|
|
13
|
+
side: string
|
|
14
|
+
limitPx: string
|
|
15
|
+
sz: string
|
|
16
|
+
oid: number
|
|
17
|
+
timestamp: number
|
|
18
|
+
origSz: string
|
|
19
|
+
cloid?: string
|
|
20
|
+
}
|
|
21
|
+
status: string
|
|
22
|
+
statusTimestamp: number
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
/**
|
|
10
26
|
* Perp asset context as carried on the `allDexsAssetCtxs` WS feed. Extends the
|
|
11
27
|
* REST `/info` `HlAssetCtx` shape with the wire-only `coin` tag, the order-book
|
package/src/utils/assetId.ts
CHANGED
|
@@ -5,6 +5,22 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export const assetIsSpot = (assetId: string): boolean => assetId.startsWith('@')
|
|
7
7
|
|
|
8
|
+
/** Lowest numeric asset ID Hyperliquid assigns to an outcome market. */
|
|
9
|
+
const OUTCOME_ASSET_ID_BASE = 100_000_000
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Return whether a Hyperliquid asset identity belongs to an HIP-4 outcome
|
|
13
|
+
* market: spot coin `#<encoding>`, token name `+<encoding>`, or numeric asset
|
|
14
|
+
* ID `100000000 + encoding`. LI.FI supports no outcome market, and the backend
|
|
15
|
+
* market list holds none, so the provider skips every such identity.
|
|
16
|
+
* @param assetId - Raw Hyperliquid coin, token name, or numeric asset ID.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export const assetIsOutcome = (assetId: string | number): boolean =>
|
|
20
|
+
typeof assetId === 'number'
|
|
21
|
+
? assetId >= OUTCOME_ASSET_ID_BASE
|
|
22
|
+
: assetId.startsWith('#') || assetId.startsWith('+')
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* Calculate Hyperliquid's numeric asset ID from a perp DEX index and the
|
|
10
26
|
* asset's zero-based index within that DEX. The main DEX uses the index
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { OrderBase } from '@lifi/perps-types'
|
|
2
|
+
import { isHex } from 'viem'
|
|
3
|
+
import { HYPERLIQUID_EXPLORER_RPC_URL } from '../constants.js'
|
|
4
|
+
import { type HlExplorerTx, isHlExplorerTx } from '../types/explorer.js'
|
|
5
|
+
import { hlPostJson, type InfoRequestOptions } from './infoClient.js'
|
|
6
|
+
|
|
7
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
8
|
+
typeof value === 'object' && value !== null
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Read the address's recent HyperCore transactions from the explorer RPC.
|
|
12
|
+
*
|
|
13
|
+
* The surface is undocumented, so it is read defensively: an address the
|
|
14
|
+
* explorer has never indexed answers `200` with no `txs` array, and each entry
|
|
15
|
+
* is checked on its own so one drifted entry cannot drop the rest.
|
|
16
|
+
*
|
|
17
|
+
* @throws {PerpsError} On a non-2xx status or a transport failure.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export const fetchUserTransactions = async (
|
|
21
|
+
address: string,
|
|
22
|
+
options?: InfoRequestOptions
|
|
23
|
+
): Promise<HlExplorerTx[]> => {
|
|
24
|
+
const body = await hlPostJson<{ txs?: unknown } | null>(
|
|
25
|
+
HYPERLIQUID_EXPLORER_RPC_URL,
|
|
26
|
+
'explorer userDetails',
|
|
27
|
+
{ type: 'userDetails', user: address },
|
|
28
|
+
options
|
|
29
|
+
)
|
|
30
|
+
const txs = body?.txs
|
|
31
|
+
return Array.isArray(txs) ? txs.filter(isHlExplorerTx) : []
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Every client order id an action names: `orders[].c` on a placement, `order.c`
|
|
36
|
+
* on a single modify, and `modifies[].order.c` on a batch modify. A batched
|
|
37
|
+
* placement names one id per leg, so every id is returned, not just the first.
|
|
38
|
+
*
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
export const getClientOrderIds = (
|
|
42
|
+
action: Record<string, unknown>
|
|
43
|
+
): string[] => {
|
|
44
|
+
const wires: unknown[] = [
|
|
45
|
+
...(Array.isArray(action.orders) ? action.orders : []),
|
|
46
|
+
...(Array.isArray(action.modifies)
|
|
47
|
+
? action.modifies.map((modify) =>
|
|
48
|
+
isRecord(modify) ? modify.order : undefined
|
|
49
|
+
)
|
|
50
|
+
: []),
|
|
51
|
+
action.order,
|
|
52
|
+
]
|
|
53
|
+
const ids: string[] = []
|
|
54
|
+
for (const wire of wires) {
|
|
55
|
+
if (!isRecord(wire)) {
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
const cloid = wire.c
|
|
59
|
+
if (
|
|
60
|
+
typeof cloid === 'string' &&
|
|
61
|
+
cloid !== '0x' &&
|
|
62
|
+
isHex(cloid, { strict: true })
|
|
63
|
+
) {
|
|
64
|
+
ids.push(cloid)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return ids
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The hash of the transaction whose action names the order's client order id.
|
|
72
|
+
*
|
|
73
|
+
* @returns The transaction hash, or `undefined` when the order carries no
|
|
74
|
+
* client order id or no transaction in the window names it.
|
|
75
|
+
* @public
|
|
76
|
+
*/
|
|
77
|
+
export const matchOrderActionHash = (
|
|
78
|
+
txs: HlExplorerTx[],
|
|
79
|
+
order: Pick<OrderBase, 'clientOrderId'>
|
|
80
|
+
): string | undefined => {
|
|
81
|
+
const { clientOrderId } = order
|
|
82
|
+
if (clientOrderId === undefined) {
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
// A client order id is hex, so the venue may echo a case the placer did not send.
|
|
86
|
+
const wanted = clientOrderId.toLowerCase()
|
|
87
|
+
const match = txs.find(
|
|
88
|
+
(tx) =>
|
|
89
|
+
isRecord(tx.action) &&
|
|
90
|
+
getClientOrderIds(tx.action).some((id) => id.toLowerCase() === wanted)
|
|
91
|
+
)
|
|
92
|
+
return match?.hash
|
|
93
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
// for the package's utility surface. Internal modules import per-file paths
|
|
3
3
|
// (e.g. `./assetId.js`, `./mapFill.js`) directly.
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export {
|
|
6
|
+
assetIsOutcome,
|
|
7
|
+
assetIsSpot,
|
|
8
|
+
calculateAssetId,
|
|
9
|
+
getProviderIndex,
|
|
10
|
+
} from './assetId.js'
|
|
6
11
|
export {
|
|
7
12
|
applyLogoOverride,
|
|
8
13
|
spotLogoURI,
|
|
@@ -12,26 +17,30 @@ export {
|
|
|
12
17
|
decodeCompressedJson,
|
|
13
18
|
decodeFastAssetCtxs,
|
|
14
19
|
} from './decodeFastAssetCtxs.js'
|
|
20
|
+
export {
|
|
21
|
+
fetchUserTransactions,
|
|
22
|
+
getClientOrderIds,
|
|
23
|
+
matchOrderActionHash,
|
|
24
|
+
} from './explorer.js'
|
|
15
25
|
export type { InfoRequestOptions } from './infoClient.js'
|
|
16
26
|
export { hlInfoOptions, infoRequest } from './infoClient.js'
|
|
17
27
|
export {
|
|
18
28
|
calculateLiquidationPrice,
|
|
19
29
|
calculateMaintenanceMarginRate,
|
|
20
30
|
} from './liquidation.js'
|
|
21
|
-
export {
|
|
31
|
+
export {
|
|
32
|
+
mapFundingActivity,
|
|
33
|
+
mapLedgerEntry,
|
|
34
|
+
mapLiquidationFills,
|
|
35
|
+
} from './mapActivity.js'
|
|
22
36
|
export { classifyFillFromPosition, mapFill } from './mapFill.js'
|
|
23
37
|
export { mapMarket } from './mapMarket.js'
|
|
24
38
|
export { mapMarketContext } from './mapMarketContext.js'
|
|
25
39
|
export {
|
|
26
40
|
type HlOrderLike,
|
|
27
|
-
isTriggerOrder,
|
|
28
|
-
isTriggerType,
|
|
29
|
-
mapOpenOrder,
|
|
30
41
|
mapOrder,
|
|
31
42
|
mapOrderStatus,
|
|
32
43
|
mapOrderType,
|
|
33
|
-
mapStatusReason,
|
|
34
|
-
mapTriggerOrder,
|
|
35
44
|
} from './mapOrder.js'
|
|
36
45
|
export { isOpenAssetPosition, mapPosition } from './mapPosition.js'
|
|
37
46
|
export { coinAsset, perpsDexNames } from './marketDisplay.js'
|