@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.
Files changed (245) hide show
  1. package/README.md +115 -0
  2. package/dist/cjs/HyperliquidProvider.d.ts.map +1 -1
  3. package/dist/cjs/HyperliquidProvider.js +1 -2
  4. package/dist/cjs/HyperliquidProvider.js.map +1 -1
  5. package/dist/cjs/constants.d.ts +1 -0
  6. package/dist/cjs/constants.d.ts.map +1 -1
  7. package/dist/cjs/constants.js +2 -1
  8. package/dist/cjs/constants.js.map +1 -1
  9. package/dist/cjs/index.d.ts +1 -3
  10. package/dist/cjs/index.d.ts.map +1 -1
  11. package/dist/cjs/index.js +2 -3
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/services/getAccount.d.ts.map +1 -1
  14. package/dist/cjs/services/getAccount.js +5 -2
  15. package/dist/cjs/services/getAccount.js.map +1 -1
  16. package/dist/cjs/services/getActivity.d.ts.map +1 -1
  17. package/dist/cjs/services/getActivity.js +40 -7
  18. package/dist/cjs/services/getActivity.js.map +1 -1
  19. package/dist/cjs/services/getFills.d.ts.map +1 -1
  20. package/dist/cjs/services/getFills.js +3 -0
  21. package/dist/cjs/services/getFills.js.map +1 -1
  22. package/dist/cjs/services/getOrder.d.ts.map +1 -1
  23. package/dist/cjs/services/getOrder.js +14 -3
  24. package/dist/cjs/services/getOrder.js.map +1 -1
  25. package/dist/cjs/services/getOrders.d.ts +2 -7
  26. package/dist/cjs/services/getOrders.d.ts.map +1 -1
  27. package/dist/cjs/services/getOrders.js +94 -31
  28. package/dist/cjs/services/getOrders.js.map +1 -1
  29. package/dist/cjs/services/getPositions.d.ts.map +1 -1
  30. package/dist/cjs/services/getPositions.js +1 -1
  31. package/dist/cjs/services/getPositions.js.map +1 -1
  32. package/dist/cjs/types/explorer.d.ts +10 -0
  33. package/dist/cjs/types/explorer.d.ts.map +1 -0
  34. package/dist/cjs/types/explorer.js +17 -0
  35. package/dist/cjs/types/explorer.js.map +1 -0
  36. package/dist/cjs/types/fill.d.ts +6 -0
  37. package/dist/cjs/types/fill.d.ts.map +1 -1
  38. package/dist/cjs/types/index.d.ts +1 -0
  39. package/dist/cjs/types/index.d.ts.map +1 -1
  40. package/dist/cjs/types/index.js +1 -0
  41. package/dist/cjs/types/index.js.map +1 -1
  42. package/dist/cjs/types/ledger.d.ts +24 -1
  43. package/dist/cjs/types/ledger.d.ts.map +1 -1
  44. package/dist/cjs/types/ledger.js +5 -1
  45. package/dist/cjs/types/ledger.js.map +1 -1
  46. package/dist/cjs/types/order.d.ts +24 -0
  47. package/dist/cjs/types/order.d.ts.map +1 -1
  48. package/dist/cjs/types/ws.d.ts +14 -0
  49. package/dist/cjs/types/ws.d.ts.map +1 -1
  50. package/dist/cjs/utils/assetId.d.ts +1 -0
  51. package/dist/cjs/utils/assetId.d.ts.map +1 -1
  52. package/dist/cjs/utils/assetId.js +6 -1
  53. package/dist/cjs/utils/assetId.js.map +1 -1
  54. package/dist/cjs/utils/explorer.d.ts +7 -0
  55. package/dist/cjs/utils/explorer.d.ts.map +1 -0
  56. package/dist/cjs/utils/explorer.js +49 -0
  57. package/dist/cjs/utils/explorer.js.map +1 -0
  58. package/dist/cjs/utils/index.d.ts +4 -3
  59. package/dist/cjs/utils/index.d.ts.map +1 -1
  60. package/dist/cjs/utils/index.js +7 -6
  61. package/dist/cjs/utils/index.js.map +1 -1
  62. package/dist/cjs/utils/infoClient.d.ts +1 -0
  63. package/dist/cjs/utils/infoClient.d.ts.map +1 -1
  64. package/dist/cjs/utils/infoClient.js +16 -10
  65. package/dist/cjs/utils/infoClient.js.map +1 -1
  66. package/dist/cjs/utils/mapActivity.d.ts +5 -3
  67. package/dist/cjs/utils/mapActivity.d.ts.map +1 -1
  68. package/dist/cjs/utils/mapActivity.js +116 -48
  69. package/dist/cjs/utils/mapActivity.js.map +1 -1
  70. package/dist/cjs/utils/mapFill.d.ts.map +1 -1
  71. package/dist/cjs/utils/mapFill.js +0 -1
  72. package/dist/cjs/utils/mapFill.js.map +1 -1
  73. package/dist/cjs/utils/mapOrder.d.ts +4 -9
  74. package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
  75. package/dist/cjs/utils/mapOrder.js +149 -135
  76. package/dist/cjs/utils/mapOrder.js.map +1 -1
  77. package/dist/cjs/utils/spotBalance.d.ts.map +1 -1
  78. package/dist/cjs/utils/spotBalance.js +10 -6
  79. package/dist/cjs/utils/spotBalance.js.map +1 -1
  80. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +3 -0
  81. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  82. package/dist/cjs/websocket/HyperliquidWsProvider.js +100 -29
  83. package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
  84. package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
  85. package/dist/esm/HyperliquidProvider.js +1 -2
  86. package/dist/esm/HyperliquidProvider.js.map +1 -1
  87. package/dist/esm/constants.d.ts +8 -0
  88. package/dist/esm/constants.d.ts.map +1 -1
  89. package/dist/esm/constants.js +8 -0
  90. package/dist/esm/constants.js.map +1 -1
  91. package/dist/esm/index.d.ts +1 -3
  92. package/dist/esm/index.d.ts.map +1 -1
  93. package/dist/esm/index.js +1 -2
  94. package/dist/esm/index.js.map +1 -1
  95. package/dist/esm/services/getAccount.d.ts.map +1 -1
  96. package/dist/esm/services/getAccount.js +6 -3
  97. package/dist/esm/services/getAccount.js.map +1 -1
  98. package/dist/esm/services/getActivity.d.ts +2 -2
  99. package/dist/esm/services/getActivity.d.ts.map +1 -1
  100. package/dist/esm/services/getActivity.js +44 -9
  101. package/dist/esm/services/getActivity.js.map +1 -1
  102. package/dist/esm/services/getFills.d.ts.map +1 -1
  103. package/dist/esm/services/getFills.js +4 -1
  104. package/dist/esm/services/getFills.js.map +1 -1
  105. package/dist/esm/services/getOrder.d.ts.map +1 -1
  106. package/dist/esm/services/getOrder.js +15 -4
  107. package/dist/esm/services/getOrder.js.map +1 -1
  108. package/dist/esm/services/getOrders.d.ts +4 -24
  109. package/dist/esm/services/getOrders.d.ts.map +1 -1
  110. package/dist/esm/services/getOrders.js +115 -42
  111. package/dist/esm/services/getOrders.js.map +1 -1
  112. package/dist/esm/services/getPositions.d.ts.map +1 -1
  113. package/dist/esm/services/getPositions.js +2 -2
  114. package/dist/esm/services/getPositions.js.map +1 -1
  115. package/dist/esm/types/explorer.d.ts +27 -0
  116. package/dist/esm/types/explorer.d.ts.map +1 -0
  117. package/dist/esm/types/explorer.js +20 -0
  118. package/dist/esm/types/explorer.js.map +1 -0
  119. package/dist/esm/types/fill.d.ts +11 -0
  120. package/dist/esm/types/fill.d.ts.map +1 -1
  121. package/dist/esm/types/index.d.ts +1 -0
  122. package/dist/esm/types/index.d.ts.map +1 -1
  123. package/dist/esm/types/index.js +1 -0
  124. package/dist/esm/types/index.js.map +1 -1
  125. package/dist/esm/types/ledger.d.ts +28 -1
  126. package/dist/esm/types/ledger.d.ts.map +1 -1
  127. package/dist/esm/types/ledger.js +4 -0
  128. package/dist/esm/types/ledger.js.map +1 -1
  129. package/dist/esm/types/order.d.ts +26 -0
  130. package/dist/esm/types/order.d.ts.map +1 -1
  131. package/dist/esm/types/ws.d.ts +15 -0
  132. package/dist/esm/types/ws.d.ts.map +1 -1
  133. package/dist/esm/utils/assetId.d.ts +9 -0
  134. package/dist/esm/utils/assetId.d.ts.map +1 -1
  135. package/dist/esm/utils/assetId.js +13 -0
  136. package/dist/esm/utils/assetId.js.map +1 -1
  137. package/dist/esm/utils/explorer.d.ts +31 -0
  138. package/dist/esm/utils/explorer.d.ts.map +1 -0
  139. package/dist/esm/utils/explorer.js +68 -0
  140. package/dist/esm/utils/explorer.js.map +1 -0
  141. package/dist/esm/utils/index.d.ts +4 -3
  142. package/dist/esm/utils/index.d.ts.map +1 -1
  143. package/dist/esm/utils/index.js +4 -3
  144. package/dist/esm/utils/index.js.map +1 -1
  145. package/dist/esm/utils/infoClient.d.ts +14 -3
  146. package/dist/esm/utils/infoClient.d.ts.map +1 -1
  147. package/dist/esm/utils/infoClient.js +29 -14
  148. package/dist/esm/utils/infoClient.js.map +1 -1
  149. package/dist/esm/utils/mapActivity.d.ts +16 -13
  150. package/dist/esm/utils/mapActivity.d.ts.map +1 -1
  151. package/dist/esm/utils/mapActivity.js +128 -72
  152. package/dist/esm/utils/mapActivity.js.map +1 -1
  153. package/dist/esm/utils/mapFill.d.ts.map +1 -1
  154. package/dist/esm/utils/mapFill.js +1 -2
  155. package/dist/esm/utils/mapFill.js.map +1 -1
  156. package/dist/esm/utils/mapOrder.d.ts +8 -73
  157. package/dist/esm/utils/mapOrder.d.ts.map +1 -1
  158. package/dist/esm/utils/mapOrder.js +148 -187
  159. package/dist/esm/utils/mapOrder.js.map +1 -1
  160. package/dist/esm/utils/spotBalance.d.ts +1 -1
  161. package/dist/esm/utils/spotBalance.d.ts.map +1 -1
  162. package/dist/esm/utils/spotBalance.js +12 -7
  163. package/dist/esm/utils/spotBalance.js.map +1 -1
  164. package/dist/esm/websocket/HyperliquidWsProvider.d.ts +5 -1
  165. package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  166. package/dist/esm/websocket/HyperliquidWsProvider.js +105 -34
  167. package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
  168. package/dist/types/HyperliquidProvider.d.ts.map +1 -1
  169. package/dist/types/constants.d.ts +8 -0
  170. package/dist/types/constants.d.ts.map +1 -1
  171. package/dist/types/index.d.ts +1 -3
  172. package/dist/types/index.d.ts.map +1 -1
  173. package/dist/types/services/getAccount.d.ts.map +1 -1
  174. package/dist/types/services/getActivity.d.ts +2 -2
  175. package/dist/types/services/getActivity.d.ts.map +1 -1
  176. package/dist/types/services/getFills.d.ts.map +1 -1
  177. package/dist/types/services/getOrder.d.ts.map +1 -1
  178. package/dist/types/services/getOrders.d.ts +4 -24
  179. package/dist/types/services/getOrders.d.ts.map +1 -1
  180. package/dist/types/services/getPositions.d.ts.map +1 -1
  181. package/dist/types/types/explorer.d.ts +27 -0
  182. package/dist/types/types/explorer.d.ts.map +1 -0
  183. package/dist/types/types/fill.d.ts +11 -0
  184. package/dist/types/types/fill.d.ts.map +1 -1
  185. package/dist/types/types/index.d.ts +1 -0
  186. package/dist/types/types/index.d.ts.map +1 -1
  187. package/dist/types/types/ledger.d.ts +28 -1
  188. package/dist/types/types/ledger.d.ts.map +1 -1
  189. package/dist/types/types/order.d.ts +26 -0
  190. package/dist/types/types/order.d.ts.map +1 -1
  191. package/dist/types/types/ws.d.ts +15 -0
  192. package/dist/types/types/ws.d.ts.map +1 -1
  193. package/dist/types/utils/assetId.d.ts +9 -0
  194. package/dist/types/utils/assetId.d.ts.map +1 -1
  195. package/dist/types/utils/explorer.d.ts +31 -0
  196. package/dist/types/utils/explorer.d.ts.map +1 -0
  197. package/dist/types/utils/index.d.ts +4 -3
  198. package/dist/types/utils/index.d.ts.map +1 -1
  199. package/dist/types/utils/infoClient.d.ts +14 -3
  200. package/dist/types/utils/infoClient.d.ts.map +1 -1
  201. package/dist/types/utils/mapActivity.d.ts +16 -13
  202. package/dist/types/utils/mapActivity.d.ts.map +1 -1
  203. package/dist/types/utils/mapFill.d.ts.map +1 -1
  204. package/dist/types/utils/mapOrder.d.ts +8 -73
  205. package/dist/types/utils/mapOrder.d.ts.map +1 -1
  206. package/dist/types/utils/spotBalance.d.ts +1 -1
  207. package/dist/types/utils/spotBalance.d.ts.map +1 -1
  208. package/dist/types/websocket/HyperliquidWsProvider.d.ts +5 -1
  209. package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  210. package/package.json +3 -3
  211. package/src/HyperliquidProvider.ts +1 -13
  212. package/src/constants.ts +10 -0
  213. package/src/index.ts +1 -2
  214. package/src/services/getAccount.ts +8 -4
  215. package/src/services/getActivity.ts +81 -6
  216. package/src/services/getFills.ts +4 -1
  217. package/src/services/getOrder.ts +29 -5
  218. package/src/services/getOrders.ts +185 -70
  219. package/src/services/getPositions.ts +4 -1
  220. package/src/types/explorer.ts +39 -0
  221. package/src/types/fill.ts +12 -0
  222. package/src/types/index.ts +1 -0
  223. package/src/types/ledger.ts +37 -0
  224. package/src/types/order.ts +25 -0
  225. package/src/types/ws.ts +16 -0
  226. package/src/utils/assetId.ts +16 -0
  227. package/src/utils/explorer.ts +93 -0
  228. package/src/utils/index.ts +16 -7
  229. package/src/utils/infoClient.ts +46 -24
  230. package/src/utils/mapActivity.ts +163 -75
  231. package/src/utils/mapFill.ts +0 -2
  232. package/src/utils/mapOrder.ts +163 -212
  233. package/src/utils/spotBalance.ts +12 -7
  234. package/src/websocket/HyperliquidWsProvider.ts +127 -40
  235. package/dist/cjs/services/getRunningTwaps.d.ts +0 -10
  236. package/dist/cjs/services/getRunningTwaps.d.ts.map +0 -1
  237. package/dist/cjs/services/getRunningTwaps.js +0 -46
  238. package/dist/cjs/services/getRunningTwaps.js.map +0 -1
  239. package/dist/esm/services/getRunningTwaps.d.ts +0 -12
  240. package/dist/esm/services/getRunningTwaps.d.ts.map +0 -1
  241. package/dist/esm/services/getRunningTwaps.js +0 -40
  242. package/dist/esm/services/getRunningTwaps.js.map +0 -1
  243. package/dist/types/services/getRunningTwaps.d.ts +0 -12
  244. package/dist/types/services/getRunningTwaps.d.ts.map +0 -1
  245. package/src/services/getRunningTwaps.ts +0 -90
@@ -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 */
@@ -5,6 +5,7 @@
5
5
  export * from './account.js'
6
6
  export * from './action.js'
7
7
  export * from './asset.js'
8
+ export * from './explorer.js'
8
9
  export * from './fill.js'
9
10
  export * from './ledger.js'
10
11
  export * from './order.js'
@@ -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
@@ -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
@@ -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
+ }
@@ -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 { assetIsSpot, calculateAssetId, getProviderIndex } from './assetId.js'
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 { mapFundingActivity, mapLedgerEntry } from './mapActivity.js'
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'
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  errorCodeFromStatus,
3
3
  fetchWithRetry,
4
+ isAbortError,
4
5
  PerpsError,
5
6
  type PerpsSDKClient,
6
7
  type ResolvedRetryPolicy,
@@ -57,7 +58,7 @@ export const HYPERLIQUID_RETRY_DEFAULTS: ResolvedRetryPolicy = {
57
58
  }
58
59
 
59
60
  /**
60
- * Transport options for a direct Hyperliquid `/info` request. `policy`
61
+ * Transport options for a direct Hyperliquid REST request. `policy`
61
62
  * controls retries, `signal` cancels the request, and `fetchImpl` overrides
62
63
  * the runtime's global `fetch` implementation.
63
64
  * @public
@@ -87,7 +88,7 @@ export const hlInfoOptions = (
87
88
  })
88
89
 
89
90
  /**
90
- * POST to the Hyperliquid `/info` endpoint and return the parsed JSON body.
91
+ * POST a JSON body to a Hyperliquid REST surface and return the parsed body.
91
92
  *
92
93
  * Direct-to-venue: no proxy, no AJV validation, no cache. The caller's type
93
94
  * parameter is trusted; consumers should treat the response shape as
@@ -97,20 +98,24 @@ export const hlInfoOptions = (
97
98
  * Non-2xx responses raise a {@link PerpsError} tagged with the Hyperliquid
98
99
  * provider key, carrying the code the status resolves to: `RateLimitExceeded`
99
100
  * for a 429, `Unauthorized` for a 401, `AgentUnauthorized` for a 403, and
100
- * `ThirdPartyError` for every other status.
101
- * @public
101
+ * `ThirdPartyError` for every other status. A transport failure and a 2xx body
102
+ * that is not JSON both raise `ServerError`, so every failure but a caller
103
+ * abort reaches the caller as a `PerpsError`. An abort rejects untouched.
104
+ *
105
+ * @param label - Names the surface in the error message, e.g. `info request`.
106
+ * @internal
102
107
  */
103
- export async function infoRequest<T>(
104
- apiUrl: string,
108
+ export async function hlPostJson<T>(
109
+ url: string,
110
+ label: string,
105
111
  body: Record<string, unknown>,
106
112
  options?: InfoRequestOptions
107
113
  ): Promise<T> {
108
114
  const policy = options?.policy ?? HYPERLIQUID_RETRY_DEFAULTS
109
115
 
110
- let response: Response
111
116
  try {
112
- response = await fetchWithRetry(
113
- `${apiUrl}/info`,
117
+ const response = await fetchWithRetry(
118
+ url,
114
119
  {
115
120
  method: 'POST',
116
121
  headers: { 'Content-Type': 'application/json' },
@@ -122,27 +127,44 @@ export async function infoRequest<T>(
122
127
  signal: options?.signal,
123
128
  }
124
129
  )
130
+
131
+ if (!response.ok) {
132
+ const err = new PerpsError(
133
+ errorCodeFromStatus(
134
+ response.status,
135
+ PerpsErrorCode.ThirdPartyError,
136
+ HYPERLIQUID_STATUS_ERROR_CODES
137
+ ),
138
+ `Hyperliquid ${label} failed: ${response.status}`
139
+ )
140
+ err.tool = PROVIDER_KEY
141
+ throw err
142
+ }
143
+
144
+ return (await response.json()) as T
125
145
  } catch (error) {
146
+ if (error instanceof PerpsError || isAbortError(error)) {
147
+ throw error
148
+ }
126
149
  const err = new PerpsError(
127
150
  PerpsErrorCode.ServerError,
128
- error instanceof Error ? error.message : 'Hyperliquid info request failed'
129
- )
130
- err.tool = PROVIDER_KEY
131
- throw err
132
- }
133
-
134
- if (!response.ok) {
135
- const err = new PerpsError(
136
- errorCodeFromStatus(
137
- response.status,
138
- PerpsErrorCode.ThirdPartyError,
139
- HYPERLIQUID_STATUS_ERROR_CODES
140
- ),
141
- `Hyperliquid info request failed: ${response.status}`
151
+ error instanceof Error ? error.message : `Hyperliquid ${label} failed`
142
152
  )
143
153
  err.tool = PROVIDER_KEY
144
154
  throw err
145
155
  }
156
+ }
146
157
 
147
- return (await response.json()) as T
158
+ /**
159
+ * POST to the Hyperliquid `/info` endpoint and return the parsed JSON body.
160
+ * See {@link hlPostJson} for the transport and error contract.
161
+ *
162
+ * @public
163
+ */
164
+ export function infoRequest<T>(
165
+ apiUrl: string,
166
+ body: Record<string, unknown>,
167
+ options?: InfoRequestOptions
168
+ ): Promise<T> {
169
+ return hlPostJson<T>(`${apiUrl}/info`, 'info request', body, options)
148
170
  }