@lifi/perps-sdk-provider-hyperliquid 13.0.1 → 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 +5 -2
- 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 +6 -3
- 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 +8 -4
- 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
package/src/utils/mapOrder.ts
CHANGED
|
@@ -1,31 +1,32 @@
|
|
|
1
|
+
import { PerpsError, triggerConditionFor } from '@lifi/perps-sdk'
|
|
1
2
|
import type {
|
|
2
3
|
MarketDisplay,
|
|
3
|
-
OpenOrder,
|
|
4
4
|
Order,
|
|
5
|
+
OrderBase,
|
|
5
6
|
TriggerOrder,
|
|
6
7
|
} from '@lifi/perps-types'
|
|
7
8
|
import {
|
|
8
9
|
OrderSide,
|
|
9
10
|
OrderStatus,
|
|
10
11
|
OrderType,
|
|
12
|
+
PerpsErrorCode,
|
|
11
13
|
TimeInForce,
|
|
12
14
|
} from '@lifi/perps-types'
|
|
13
|
-
import
|
|
15
|
+
import Big from 'big.js'
|
|
16
|
+
import { PROVIDER_KEY } from '../constants.js'
|
|
17
|
+
import type {
|
|
18
|
+
HlFrontendOpenOrder,
|
|
19
|
+
HlOrderDetail,
|
|
20
|
+
HlTwapHistoryEntry,
|
|
21
|
+
} from '../types/index.js'
|
|
14
22
|
|
|
15
|
-
/**
|
|
16
|
-
* An order as seen by the REST `frontendOpenOrders` payload, or the smaller
|
|
17
|
-
* shape nested in the `orderUpdates` WebSocket frame. `mapOpenOrder` and
|
|
18
|
-
* `mapTriggerOrder` accept either so both code paths share one mapper.
|
|
19
|
-
* @public
|
|
20
|
-
*/
|
|
23
|
+
/** Order payload shared by frontend, historical, and single-order reads. */
|
|
21
24
|
export type HlOrderLike = HlFrontendOpenOrder | HlOrderDetail['order']
|
|
22
25
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*/
|
|
28
|
-
export const mapOrderType = (orderType: string): OrderType => {
|
|
26
|
+
/** Translate documented venue execution types without reading trigger prose. */
|
|
27
|
+
export const mapOrderType = (
|
|
28
|
+
orderType: string
|
|
29
|
+
): Exclude<OrderType, OrderType.TWAP> => {
|
|
29
30
|
switch (orderType) {
|
|
30
31
|
case 'Take Profit Market':
|
|
31
32
|
return OrderType.TAKE_PROFIT_MARKET
|
|
@@ -37,243 +38,193 @@ export const mapOrderType = (orderType: string): OrderType => {
|
|
|
37
38
|
return OrderType.STOP_LIMIT
|
|
38
39
|
case 'Market':
|
|
39
40
|
return OrderType.MARKET
|
|
40
|
-
|
|
41
|
+
case 'Limit':
|
|
41
42
|
return OrderType.LIMIT
|
|
43
|
+
default:
|
|
44
|
+
throw venueError(`Unknown Hyperliquid order type: ${orderType}`)
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
/**
|
|
46
|
-
export const isTriggerType = (type: OrderType): boolean =>
|
|
47
|
-
type === OrderType.TAKE_PROFIT_MARKET ||
|
|
48
|
-
type === OrderType.TAKE_PROFIT_LIMIT ||
|
|
49
|
-
type === OrderType.STOP_MARKET ||
|
|
50
|
-
type === OrderType.STOP_LIMIT
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Decide whether a raw Hyperliquid order belongs in the cross-provider
|
|
54
|
-
* `triggerOrders` bucket. Single source of truth for both the REST
|
|
55
|
-
* `getOrders` path (`HlFrontendOpenOrder` payload) and the `orderUpdates`
|
|
56
|
-
* WS handler (`HlOrderDetail.order`, a strict subset).
|
|
57
|
-
*
|
|
58
|
-
* Authoritative signals, in order:
|
|
59
|
-
* 1. `isTrigger` — REST-only boolean Hyperliquid sets on
|
|
60
|
-
* `frontendOpenOrders`. Definitive when present.
|
|
61
|
-
* 2. `isPositionTpsl` — REST-only flag for TP/SL legs attached to a
|
|
62
|
-
* position.
|
|
63
|
-
* 3. `triggerCondition !== 'N/A'` — present on both REST and WS payloads.
|
|
64
|
-
* Non-trigger orders carry the literal `'N/A'`.
|
|
65
|
-
* 4. `triggerPx` non-null and non-zero — present on both. The reliable
|
|
66
|
-
* trigger signal on the WS wire when `orderType` lies (HL pushes
|
|
67
|
-
* `'Limit'` for a freshly-placed TP/SL until REST refetch lands the
|
|
68
|
-
* corrected type).
|
|
69
|
-
* 5. `orderType` — final fall-back via `isTriggerType`.
|
|
70
|
-
* @public
|
|
71
|
-
*/
|
|
72
|
-
export const isTriggerOrder = (o: HlOrderLike): boolean => {
|
|
73
|
-
if ('isTrigger' in o && o.isTrigger === true) {
|
|
74
|
-
return true
|
|
75
|
-
}
|
|
76
|
-
if ('isPositionTpsl' in o && o.isPositionTpsl === true) {
|
|
77
|
-
return true
|
|
78
|
-
}
|
|
79
|
-
if (o.triggerCondition && o.triggerCondition !== 'N/A') {
|
|
80
|
-
return true
|
|
81
|
-
}
|
|
82
|
-
if (
|
|
83
|
-
o.triggerPx != null &&
|
|
84
|
-
o.triggerPx !== '' &&
|
|
85
|
-
parseFloat(o.triggerPx) > 0
|
|
86
|
-
) {
|
|
87
|
-
return true
|
|
88
|
-
}
|
|
89
|
-
return isTriggerType(mapOrderType(o.orderType))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Map an open Hyperliquid order to the SDK's normalized open-order shape.
|
|
94
|
-
* Numeric IDs become strings and wire millisecond timestamps become ISO dates.
|
|
95
|
-
* @public
|
|
96
|
-
*/
|
|
97
|
-
export const mapOpenOrder = (
|
|
98
|
-
o: HlOrderLike,
|
|
99
|
-
market: MarketDisplay
|
|
100
|
-
): OpenOrder => ({
|
|
101
|
-
orderId: String(o.oid),
|
|
102
|
-
market,
|
|
103
|
-
side: o.side === 'B' ? OrderSide.BUY : OrderSide.SELL,
|
|
104
|
-
type: mapOrderType(o.orderType),
|
|
105
|
-
originalSize: o.origSz,
|
|
106
|
-
remainingSize: o.sz,
|
|
107
|
-
price: o.limitPx,
|
|
108
|
-
filledSize: o.origSz
|
|
109
|
-
? (parseFloat(o.origSz) - parseFloat(o.sz)).toString()
|
|
110
|
-
: '0',
|
|
111
|
-
reduceOnly: o.reduceOnly ?? false,
|
|
112
|
-
label: 'isTrigger' in o && o.isTrigger ? o.triggerCondition : undefined,
|
|
113
|
-
createdAt: new Date(o.timestamp).toISOString(),
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Map a Hyperliquid trigger/TP-SL order to the SDK's trigger-order shape.
|
|
118
|
-
* @public
|
|
119
|
-
*/
|
|
120
|
-
export const mapTriggerOrder = (
|
|
121
|
-
o: HlOrderLike,
|
|
122
|
-
market: MarketDisplay
|
|
123
|
-
): TriggerOrder => {
|
|
124
|
-
const type = mapOrderType(o.orderType)
|
|
125
|
-
const isLimit =
|
|
126
|
-
type === OrderType.TAKE_PROFIT_LIMIT || type === OrderType.STOP_LIMIT
|
|
127
|
-
return {
|
|
128
|
-
orderId: String(o.oid),
|
|
129
|
-
market,
|
|
130
|
-
type,
|
|
131
|
-
size: o.sz,
|
|
132
|
-
triggerPrice: o.triggerPx ?? '0',
|
|
133
|
-
...(isLimit ? { limitPrice: o.limitPx } : {}),
|
|
134
|
-
label: o.triggerCondition,
|
|
135
|
-
createdAt: new Date(o.timestamp).toISOString(),
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Map a raw Hyperliquid order status string to the SDK's OrderStatus enum.
|
|
141
|
-
*
|
|
142
|
-
* HL's terminal statuses are mostly compound strings ending in `Canceled`
|
|
143
|
-
* or `Rejected` (e.g. `siblingFilledCanceled`, `tickRejected`); classify
|
|
144
|
-
* those by suffix so a status HL adds later still lands in the correct
|
|
145
|
-
* terminal bucket instead of silently falling through to PENDING, which
|
|
146
|
-
* {@link isActiveOrderStatus} treats as active. `scheduledCancel` is the
|
|
147
|
-
* one documented cancel status without the `Canceled` suffix.
|
|
148
|
-
* @public
|
|
149
|
-
*/
|
|
48
|
+
/** Translate venue lifecycle statuses; unknown statuses are errors. */
|
|
150
49
|
export const mapOrderStatus = (status: string): OrderStatus => {
|
|
151
50
|
switch (status) {
|
|
152
51
|
case 'open':
|
|
153
|
-
case 'resting':
|
|
154
52
|
return OrderStatus.OPEN
|
|
155
53
|
case 'filled':
|
|
156
54
|
return OrderStatus.FILLED
|
|
157
55
|
case 'canceled':
|
|
158
|
-
case 'cancelled':
|
|
159
56
|
case 'scheduledCancel':
|
|
160
|
-
return OrderStatus.CANCELLED
|
|
161
|
-
case 'rejected':
|
|
162
|
-
return OrderStatus.REJECTED
|
|
163
|
-
case 'triggered':
|
|
164
|
-
return OrderStatus.TRIGGERED
|
|
165
|
-
default:
|
|
166
|
-
if (status.endsWith('Canceled') || status.endsWith('Cancelled')) {
|
|
167
|
-
return OrderStatus.CANCELLED
|
|
168
|
-
}
|
|
169
|
-
if (status.endsWith('Rejected')) {
|
|
170
|
-
return OrderStatus.REJECTED
|
|
171
|
-
}
|
|
172
|
-
return OrderStatus.PENDING
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Map a raw Hyperliquid order status to a short English sentence
|
|
178
|
-
* describing *why* the order ended in a terminal non-FILLED state. Bare
|
|
179
|
-
* `canceled`/`cancelled`/`rejected` carry no actionable detail and
|
|
180
|
-
* return `undefined`; so do non-terminal and unknown values.
|
|
181
|
-
* @public
|
|
182
|
-
*/
|
|
183
|
-
export const mapStatusReason = (status: string): string | undefined => {
|
|
184
|
-
switch (status) {
|
|
185
|
-
case 'iocCancelRejected':
|
|
186
|
-
return 'Order cancelled: not enough liquidity to fill immediately.'
|
|
187
|
-
case 'reduceOnlyCanceled':
|
|
188
|
-
return 'Order cancelled: would not reduce your position.'
|
|
189
57
|
case 'marginCanceled':
|
|
190
|
-
|
|
191
|
-
case '
|
|
192
|
-
return 'Order cancelled: account was liquidated.'
|
|
193
|
-
case 'siblingFilledCanceled':
|
|
194
|
-
return 'Order cancelled: sibling OCO order filled first.'
|
|
58
|
+
case 'vaultWithdrawalCanceled':
|
|
59
|
+
case 'openInterestCapCanceled':
|
|
195
60
|
case 'selfTradeCanceled':
|
|
196
|
-
|
|
197
|
-
case '
|
|
198
|
-
|
|
61
|
+
case 'reduceOnlyCanceled':
|
|
62
|
+
case 'siblingFilledCanceled':
|
|
63
|
+
case 'delistedCanceled':
|
|
64
|
+
case 'liquidatedCanceled':
|
|
65
|
+
return OrderStatus.CANCELLED
|
|
66
|
+
case 'rejected':
|
|
199
67
|
case 'tickRejected':
|
|
200
|
-
return 'Order rejected: price did not match the tick size.'
|
|
201
68
|
case 'minTradeNtlRejected':
|
|
202
|
-
return 'Order rejected: notional value below the minimum trade size.'
|
|
203
|
-
case 'delistedCanceled':
|
|
204
|
-
return 'Order cancelled: market has been delisted.'
|
|
205
69
|
case 'perpMarginRejected':
|
|
206
|
-
return 'Order rejected: insufficient margin.'
|
|
207
70
|
case 'reduceOnlyRejected':
|
|
208
|
-
return 'Order rejected: would not reduce your position.'
|
|
209
71
|
case 'badAloPxRejected':
|
|
210
|
-
|
|
72
|
+
case 'iocCancelRejected':
|
|
211
73
|
case 'badTriggerPxRejected':
|
|
212
|
-
return 'Order rejected: invalid take-profit/stop-loss trigger price.'
|
|
213
74
|
case 'marketOrderNoLiquidityRejected':
|
|
214
|
-
return 'Order rejected: not enough liquidity for the market order.'
|
|
215
|
-
case 'oracleRejected':
|
|
216
|
-
return 'Order rejected: price too far from the oracle price.'
|
|
217
|
-
case 'vaultWithdrawalCanceled':
|
|
218
|
-
return 'Order cancelled: a vault withdrawal occurred.'
|
|
219
|
-
case 'openInterestCapCanceled':
|
|
220
|
-
return 'Order cancelled: too aggressive while open interest was at its cap.'
|
|
221
75
|
case 'positionIncreaseAtOpenInterestCapRejected':
|
|
222
76
|
case 'positionFlipAtOpenInterestCapRejected':
|
|
223
|
-
case 'openInterestIncreaseRejected':
|
|
224
|
-
return 'Order rejected: open interest is at its cap.'
|
|
225
77
|
case 'tooAggressiveAtOpenInterestCapRejected':
|
|
226
|
-
|
|
78
|
+
case 'openInterestIncreaseRejected':
|
|
227
79
|
case 'insufficientSpotBalanceRejected':
|
|
228
|
-
|
|
80
|
+
case 'oracleRejected':
|
|
229
81
|
case 'perpMaxPositionRejected':
|
|
230
|
-
return
|
|
82
|
+
return OrderStatus.REJECTED
|
|
83
|
+
case 'triggered':
|
|
84
|
+
return OrderStatus.TRIGGERED
|
|
231
85
|
default:
|
|
232
|
-
|
|
86
|
+
throw venueError(`Unknown Hyperliquid order status: ${status}`)
|
|
233
87
|
}
|
|
234
88
|
}
|
|
235
89
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
case 'Ioc':
|
|
241
|
-
return TimeInForce.IOC
|
|
242
|
-
case 'Alo':
|
|
243
|
-
return TimeInForce.POST_ONLY
|
|
244
|
-
default:
|
|
245
|
-
return undefined
|
|
246
|
-
}
|
|
90
|
+
function venueError(message: string): PerpsError {
|
|
91
|
+
const error = new PerpsError(PerpsErrorCode.ThirdPartyError, message)
|
|
92
|
+
error.tool = PROVIDER_KEY
|
|
93
|
+
return error
|
|
247
94
|
}
|
|
248
95
|
|
|
249
|
-
/**
|
|
250
|
-
* Map an `orderStatus` detail to the SDK's normalized order shape, preserving
|
|
251
|
-
* decimal size/price strings and translating status, side, and time-in-force.
|
|
252
|
-
* @public
|
|
253
|
-
*/
|
|
96
|
+
/** Normalize regular, trigger, and TWAP rows through one lifecycle model. */
|
|
254
97
|
export const mapOrder = (
|
|
255
|
-
|
|
256
|
-
market: MarketDisplay
|
|
98
|
+
raw: HlOrderLike | HlOrderDetail | HlTwapHistoryEntry,
|
|
99
|
+
market: MarketDisplay,
|
|
100
|
+
parentOrderId?: string
|
|
257
101
|
): Order => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
102
|
+
if ('state' in raw) {
|
|
103
|
+
if (raw.twapId === undefined) {
|
|
104
|
+
throw venueError('Hyperliquid returned a TWAP without a twapId.')
|
|
105
|
+
}
|
|
106
|
+
const { state } = raw
|
|
107
|
+
const filled = new Big(state.executedSz)
|
|
108
|
+
let status: OrderStatus
|
|
109
|
+
switch (raw.status.status) {
|
|
110
|
+
case 'activated':
|
|
111
|
+
status = filled.gt(0) ? OrderStatus.PARTIALLY_FILLED : OrderStatus.OPEN
|
|
112
|
+
break
|
|
113
|
+
case 'waitingForTrigger':
|
|
114
|
+
status = OrderStatus.OPEN
|
|
115
|
+
break
|
|
116
|
+
case 'finished':
|
|
117
|
+
status = OrderStatus.FILLED
|
|
118
|
+
break
|
|
119
|
+
case 'terminated':
|
|
120
|
+
case 'stopped':
|
|
121
|
+
status = OrderStatus.CANCELLED
|
|
122
|
+
break
|
|
123
|
+
case 'error':
|
|
124
|
+
status = OrderStatus.REJECTED
|
|
125
|
+
break
|
|
126
|
+
default:
|
|
127
|
+
throw venueError(
|
|
128
|
+
`Unknown Hyperliquid TWAP status: ${raw.status.status}`
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
orderId: String(raw.twapId),
|
|
133
|
+
market,
|
|
134
|
+
type: OrderType.TWAP,
|
|
135
|
+
side: state.side === 'B' ? OrderSide.BUY : OrderSide.SELL,
|
|
136
|
+
originalSize: state.sz,
|
|
137
|
+
remainingSize: new Big(state.sz).minus(filled).toFixed(),
|
|
138
|
+
filledSize: state.executedSz,
|
|
139
|
+
...(filled.eq(0)
|
|
140
|
+
? {}
|
|
141
|
+
: { averagePrice: new Big(state.executedNtl).div(filled).toFixed() }),
|
|
142
|
+
reduceOnly: state.reduceOnly,
|
|
143
|
+
status,
|
|
144
|
+
...(status === OrderStatus.CANCELLED || status === OrderStatus.REJECTED
|
|
145
|
+
? { statusReason: raw.status.description ?? raw.status.status }
|
|
146
|
+
: {}),
|
|
147
|
+
createdAt: new Date(state.timestamp).toISOString(),
|
|
148
|
+
updatedAt: new Date(raw.time * 1000).toISOString(),
|
|
149
|
+
startedAt: new Date(state.timestamp).toISOString(),
|
|
150
|
+
durationSeconds: state.minutes * 60,
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const o = 'order' in raw ? raw.order : raw
|
|
154
|
+
const venueStatus = 'order' in raw ? raw.status : 'open'
|
|
155
|
+
const filled = new Big(o.origSz).minus(o.sz)
|
|
156
|
+
let status = mapOrderStatus(venueStatus)
|
|
157
|
+
if (parentOrderId !== undefined && !('order' in raw)) {
|
|
158
|
+
status = OrderStatus.PENDING
|
|
159
|
+
} else if (status === OrderStatus.OPEN && filled.gt(0)) {
|
|
160
|
+
status = OrderStatus.PARTIALLY_FILLED
|
|
161
|
+
}
|
|
162
|
+
const base: OrderBase = {
|
|
262
163
|
orderId: String(o.oid),
|
|
263
164
|
market,
|
|
165
|
+
...(typeof o.cloid === 'string' ? { clientOrderId: o.cloid } : {}),
|
|
264
166
|
side: o.side === 'B' ? OrderSide.BUY : OrderSide.SELL,
|
|
265
|
-
|
|
266
|
-
|
|
167
|
+
status,
|
|
168
|
+
...(status === OrderStatus.CANCELLED || status === OrderStatus.REJECTED
|
|
169
|
+
? { statusReason: venueStatus }
|
|
170
|
+
: {}),
|
|
267
171
|
originalSize: o.origSz,
|
|
268
172
|
remainingSize: o.sz,
|
|
269
|
-
filledSize: filled.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
isTrigger: o.triggerCondition !== undefined && o.triggerCondition !== 'N/A',
|
|
273
|
-
triggerPrice: o.triggerPx ?? undefined,
|
|
274
|
-
status: mapOrderStatus(detail.status),
|
|
275
|
-
statusReason: mapStatusReason(detail.status),
|
|
173
|
+
filledSize: filled.toFixed(),
|
|
174
|
+
reduceOnly: o.reduceOnly,
|
|
175
|
+
...(parentOrderId === undefined ? {} : { parentOrderId }),
|
|
276
176
|
createdAt: new Date(o.timestamp).toISOString(),
|
|
277
|
-
updatedAt: new Date(
|
|
177
|
+
updatedAt: new Date(
|
|
178
|
+
'order' in raw ? raw.statusTimestamp : o.timestamp
|
|
179
|
+
).toISOString(),
|
|
180
|
+
}
|
|
181
|
+
let type = mapOrderType(o.orderType)
|
|
182
|
+
if (o.isTrigger && (type === OrderType.MARKET || type === OrderType.LIMIT)) {
|
|
183
|
+
if (o.tpsl === undefined) {
|
|
184
|
+
throw venueError('Hyperliquid trigger order has no tpsl discriminator.')
|
|
185
|
+
}
|
|
186
|
+
type =
|
|
187
|
+
o.tpsl === 'tp'
|
|
188
|
+
? type === OrderType.MARKET
|
|
189
|
+
? OrderType.TAKE_PROFIT_MARKET
|
|
190
|
+
: OrderType.TAKE_PROFIT_LIMIT
|
|
191
|
+
: type === OrderType.MARKET
|
|
192
|
+
? OrderType.STOP_MARKET
|
|
193
|
+
: OrderType.STOP_LIMIT
|
|
194
|
+
}
|
|
195
|
+
if (type !== OrderType.MARKET && type !== OrderType.LIMIT) {
|
|
196
|
+
const triggerType: TriggerOrder['type'] = type
|
|
197
|
+
if (o.triggerPx === null) {
|
|
198
|
+
throw venueError('Hyperliquid trigger order has no trigger price.')
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
...base,
|
|
202
|
+
type: triggerType,
|
|
203
|
+
triggerPrice: o.triggerPx,
|
|
204
|
+
triggerCondition: triggerConditionFor(triggerType, base.side),
|
|
205
|
+
...(type === OrderType.STOP_LIMIT || type === OrderType.TAKE_PROFIT_LIMIT
|
|
206
|
+
? { limitPrice: o.limitPx }
|
|
207
|
+
: {}),
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
let timeInForce: TimeInForce
|
|
211
|
+
switch (o.tif) {
|
|
212
|
+
case 'Ioc':
|
|
213
|
+
case 'FrontendMarket':
|
|
214
|
+
case 'LiquidationMarket':
|
|
215
|
+
timeInForce = TimeInForce.IOC
|
|
216
|
+
break
|
|
217
|
+
case 'Alo':
|
|
218
|
+
timeInForce = TimeInForce.POST_ONLY
|
|
219
|
+
break
|
|
220
|
+
case 'Gtc':
|
|
221
|
+
case null:
|
|
222
|
+
case undefined:
|
|
223
|
+
timeInForce =
|
|
224
|
+
type === OrderType.MARKET ? TimeInForce.IOC : TimeInForce.GTC
|
|
225
|
+
break
|
|
226
|
+
default:
|
|
227
|
+
throw venueError(`Unknown Hyperliquid time in force: ${o.tif}`)
|
|
278
228
|
}
|
|
229
|
+
return { ...base, type, price: o.limitPx, timeInForce }
|
|
279
230
|
}
|
package/src/utils/spotBalance.ts
CHANGED
|
@@ -41,14 +41,19 @@ export const spotAssetFromToken = (b: HlSpotBalance): Asset => ({
|
|
|
41
41
|
logoURI: spotLogoURI(b.coin),
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
/** Assemble a typed spot {@link Balance}; `total` is native token units and its USD value
|
|
44
|
+
/** Assemble a typed spot {@link Balance}; `total` is native token units and its unit price and USD value use `priceById`. @public */
|
|
45
45
|
export const spotBalance = (
|
|
46
46
|
asset: Asset,
|
|
47
47
|
total: string,
|
|
48
48
|
priceById: Map<string, number>
|
|
49
|
-
): Balance =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
): Balance => {
|
|
50
|
+
const price = priceById.get(asset.id) ?? 0
|
|
51
|
+
return {
|
|
52
|
+
categoryId: SPOT_MARKET_ID,
|
|
53
|
+
asset,
|
|
54
|
+
units: total,
|
|
55
|
+
valueUsd: (stringToFloat(total) * price).toString(),
|
|
56
|
+
// A zero entry means the map holds no mark for the asset, not a free asset.
|
|
57
|
+
...(price > 0 ? { price: price.toString() } : {}),
|
|
58
|
+
}
|
|
59
|
+
}
|