@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
@@ -1,5 +1,7 @@
1
+ import { type AssetRegistry, PerpsError } from '@lifi/perps-sdk'
1
2
  import type {
2
3
  ActivityItem,
4
+ Asset,
3
5
  DepositActivity,
4
6
  Fee,
5
7
  FundingActivity,
@@ -8,13 +10,20 @@ import type {
8
10
  TransferActivity,
9
11
  WithdrawalActivity,
10
12
  } from '@lifi/perps-types'
11
- import { ActivityType } from '@lifi/perps-types'
12
- import type { HlFundingUpdate, HlLedgerUpdate } from '../types/index.js'
13
+ import { ActivityType, PerpsErrorCode } from '@lifi/perps-types'
14
+ import Big from 'big.js'
15
+ import type {
16
+ HlFundingUpdate,
17
+ HlLedgerUpdate,
18
+ HlUserFill,
19
+ } from '../types/index.js'
13
20
  import {
21
+ isCollateralTransferDelta,
14
22
  isDepositDelta,
15
23
  isLiquidationDelta,
16
24
  isSendAssetDelta,
17
25
  isSpotTransferDelta,
26
+ isVaultTransferDelta,
18
27
  isWithdrawDelta,
19
28
  } from '../types/index.js'
20
29
 
@@ -30,34 +39,39 @@ const HL_COLLATERAL_SYMBOL = 'USDC'
30
39
  */
31
40
  const HL_NATIVE_TOKEN_SYMBOL = 'HYPE'
32
41
 
42
+ // Hyperliquid reserves spot token index 0 for USDC.
43
+ const HL_COLLATERAL_ASSET_ID = '0'
44
+
33
45
  /**
34
- * Display symbol for a ledger delta's wire token (`"USDC"`, `"PURR:0x..."`).
35
- * The colon separates the name from the token id, so the symbol is the part
36
- * BEFORE it the opposite half to a market coin's `dex:COIN`, which is why
37
- * `coinAsset` cannot be reused here.
46
+ * A ledger row moves a spot asset a perp contract cannot be sent, received
47
+ * or withdrawn so the delta's token symbol resolves inside the spot asset
48
+ * registry. The HIP-1 ticker auction keeps those symbols unique.
38
49
  */
39
- const ledgerTokenSymbol = (token: string): string => {
40
- const separator = token.indexOf(':')
41
- return separator === -1 ? token : token.slice(0, separator)
50
+ const resolveLedgerAsset = (symbol: string, registry: AssetRegistry): Asset => {
51
+ const asset = registry.assets.find(
52
+ (candidate) => candidate.displaySymbol === symbol
53
+ )
54
+ if (asset === undefined) {
55
+ const error = new PerpsError(
56
+ PerpsErrorCode.ValidationError,
57
+ `[hyperliquid] stale or mis-keyed asset registry: unknown spot symbol '${symbol}'`
58
+ )
59
+ error.tool = 'hyperliquid'
60
+ throw error
61
+ }
62
+ return asset
42
63
  }
43
64
 
44
65
  /**
45
- * Map a Hyperliquid non-funding ledger entry to an ActivityItem.
46
- *
47
- * Direction for `spotTransfer` and `sendAsset` is derived from
48
- * `queriedAddress` matching the delta's `user` (OUT) or `destination` (IN).
49
- * Returns null for unsupported delta types and for same-account moves, where
50
- * `user === destination === queriedAddress`.
51
- *
52
- * @param resolveMarket - Market identity for a venue coin, or `undefined` when
53
- * the backend market list does not hold it. A liquidated position the resolver
54
- * cannot identify is dropped.
66
+ * Map supported ledger entries; exclude same-account moves and unsupported types.
67
+ * Missing assets throw; unresolved liquidation markets omit only those positions.
55
68
  * @public
56
69
  */
57
70
  export const mapLedgerEntry = (
58
71
  entry: HlLedgerUpdate,
59
72
  providerKey: string,
60
73
  queriedAddress: string,
74
+ assetRegistry: AssetRegistry,
61
75
  resolveMarket: (coin: string) => MarketDisplay | undefined
62
76
  ): ActivityItem | null => {
63
77
  const { delta } = entry
@@ -67,48 +81,57 @@ export const mapLedgerEntry = (
67
81
  timestamp: new Date(entry.time).toISOString(),
68
82
  }
69
83
 
70
- // Handled before the switch: the catch-all arm of `HlLedgerDelta` is a
71
- // structural supertype of the concrete delta, so a `switch (delta.type)`
72
- // cannot narrow off the discriminant. The user-defined type guard does.
73
- if (isSpotTransferDelta(delta)) {
84
+ if (
85
+ isSpotTransferDelta(delta) ||
86
+ isSendAssetDelta(delta) ||
87
+ isCollateralTransferDelta(delta)
88
+ ) {
74
89
  const queried = queriedAddress.toLowerCase()
75
90
  const sender = delta.user.toLowerCase()
76
91
  const recipient = delta.destination.toLowerCase()
77
-
78
- // A transfer reports a movement between two accounts. A row whose sender
79
- // and recipient are the queried account moves nothing between accounts.
80
92
  if (sender === recipient && sender === queried) {
81
93
  return null
82
94
  }
83
-
84
95
  const direction: 'IN' | 'OUT' = queried === sender ? 'OUT' : 'IN'
85
- const counterpartyAddress = direction === 'OUT' ? recipient : sender
86
- const meta: Record<string, unknown> = {
87
- transferType: 'spotTransfer',
88
- }
89
- if (delta.usdcValue !== undefined) {
90
- meta.usdcValue = delta.usdcValue
91
- }
92
- if (delta.nonce !== undefined) {
93
- meta.nonce = delta.nonce
94
- }
95
96
  const fees: Fee[] = []
96
97
  if (delta.fee !== undefined) {
97
- fees.push({ amount: delta.fee, asset: HL_COLLATERAL_SYMBOL })
98
- }
99
- if (delta.nativeTokenFee !== undefined) {
100
98
  fees.push({
101
- amount: delta.nativeTokenFee,
102
- asset: HL_NATIVE_TOKEN_SYMBOL,
99
+ amount: delta.fee,
100
+ asset: isSendAssetDelta(delta)
101
+ ? delta.feeToken.split(':')[0]
102
+ : HL_COLLATERAL_SYMBOL,
103
103
  })
104
104
  }
105
+ if (
106
+ !isCollateralTransferDelta(delta) &&
107
+ delta.nativeTokenFee !== undefined
108
+ ) {
109
+ fees.push({ amount: delta.nativeTokenFee, asset: HL_NATIVE_TOKEN_SYMBOL })
110
+ }
111
+ const meta: Record<string, unknown> = {
112
+ transferType: isSendAssetDelta(delta) ? 'sendAsset' : delta.type,
113
+ }
114
+ if (!isCollateralTransferDelta(delta)) {
115
+ if (delta.usdcValue !== undefined) {
116
+ meta.usdcValue = delta.usdcValue
117
+ }
118
+ if (delta.nonce !== undefined) {
119
+ meta.nonce = delta.nonce
120
+ }
121
+ }
122
+ if (isSendAssetDelta(delta)) {
123
+ meta.sourceDex = delta.sourceDex
124
+ meta.destinationDex = delta.destinationDex
125
+ }
105
126
  return {
106
127
  ...base,
107
128
  type: ActivityType.TRANSFER,
108
129
  direction,
109
- counterpartyAddress,
110
- asset: ledgerTokenSymbol(delta.token),
111
- amount: delta.amount,
130
+ counterpartyAddress: direction === 'OUT' ? recipient : sender,
131
+ asset: isCollateralTransferDelta(delta)
132
+ ? assetRegistry.require(HL_COLLATERAL_ASSET_ID)
133
+ : resolveLedgerAsset(delta.token, assetRegistry),
134
+ amount: isCollateralTransferDelta(delta) ? delta.usdc : delta.amount,
112
135
  ...(fees.length === 0 ? {} : { fees }),
113
136
  meta,
114
137
  explorerLink: entry.hash
@@ -117,40 +140,44 @@ export const mapLedgerEntry = (
117
140
  } satisfies TransferActivity
118
141
  }
119
142
 
120
- // `sendAsset` (wire `type === 'send'`) covers cross-user transfers
121
- // (modelled as TRANSFER) and same-user dex moves (returned as null —
122
- // overloading TRANSFER for those would lie about direction). Pre-switch
123
- // narrowing for the same reason as spotTransfer.
124
- if (isSendAssetDelta(delta)) {
143
+ if (isVaultTransferDelta(delta)) {
125
144
  const queried = queriedAddress.toLowerCase()
126
- const sender = delta.user.toLowerCase()
127
- const recipient = delta.destination.toLowerCase()
128
-
129
- if (sender === recipient && sender === queried) {
130
- return null
145
+ const vault = delta.vault.toLowerCase()
146
+ if (delta.type === 'vaultDeposit' && queried === vault) {
147
+ throw new PerpsError(
148
+ PerpsErrorCode.ValidationError,
149
+ 'Hyperliquid vaultDeposit identifies no depositor for the vault account'
150
+ )
131
151
  }
132
-
133
- const direction: 'IN' | 'OUT' = queried === sender ? 'OUT' : 'IN'
134
- const counterpartyAddress = direction === 'OUT' ? recipient : sender
135
- const meta: Record<string, unknown> = {
136
- transferType: 'sendAsset',
137
- sourceDex: delta.sourceDex,
138
- destinationDex: delta.destinationDex,
139
- usdcValue: delta.usdcValue,
140
- nonce: delta.nonce,
152
+ if (
153
+ delta.type === 'vaultWithdraw' &&
154
+ delta.user.toLowerCase() === vault &&
155
+ queried === vault
156
+ ) {
157
+ return null
141
158
  }
142
159
  return {
143
160
  ...base,
144
161
  type: ActivityType.TRANSFER,
145
- direction,
146
- counterpartyAddress,
147
- asset: ledgerTokenSymbol(delta.token),
148
- amount: delta.amount,
149
- fees: [
150
- { amount: delta.fee, asset: ledgerTokenSymbol(delta.feeToken) },
151
- { amount: delta.nativeTokenFee, asset: HL_NATIVE_TOKEN_SYMBOL },
152
- ],
153
- meta,
162
+ direction:
163
+ delta.type === 'vaultDeposit' || queried === vault ? 'OUT' : 'IN',
164
+ counterpartyAddress:
165
+ delta.type === 'vaultWithdraw' && queried === vault
166
+ ? delta.user.toLowerCase()
167
+ : vault,
168
+ asset: assetRegistry.require(HL_COLLATERAL_ASSET_ID),
169
+ amount:
170
+ delta.type === 'vaultDeposit' ? delta.usdc : delta.netWithdrawnUsd,
171
+ meta:
172
+ delta.type === 'vaultDeposit'
173
+ ? { transferType: delta.type }
174
+ : {
175
+ transferType: delta.type,
176
+ requestedUsd: delta.requestedUsd,
177
+ commission: delta.commission,
178
+ closingCost: delta.closingCost,
179
+ basis: delta.basis,
180
+ },
154
181
  explorerLink: entry.hash
155
182
  ? `https://app.hyperliquid.xyz/explorer/tx/${entry.hash}`
156
183
  : undefined,
@@ -163,7 +190,7 @@ export const mapLedgerEntry = (
163
190
  return {
164
191
  ...base,
165
192
  type: ActivityType.DEPOSIT,
166
- asset: HL_COLLATERAL_SYMBOL,
193
+ asset: assetRegistry.require(HL_COLLATERAL_ASSET_ID),
167
194
  amount: delta.usdc,
168
195
  explorerLink: entry.hash
169
196
  ? `https://scan.li.fi/tx/${entry.hash}`
@@ -175,7 +202,7 @@ export const mapLedgerEntry = (
175
202
  return {
176
203
  ...base,
177
204
  type: ActivityType.WITHDRAWAL,
178
- asset: HL_COLLATERAL_SYMBOL,
205
+ asset: assetRegistry.require(HL_COLLATERAL_ASSET_ID),
179
206
  amount: delta.usdc,
180
207
  ...(delta.fee === undefined
181
208
  ? {}
@@ -247,3 +274,64 @@ export const mapFundingActivity = (
247
274
  fundingRate: entry.delta.fundingRate,
248
275
  }
249
276
  }
277
+
278
+ /**
279
+ * Build one liquidation activity per liquidation order from the fills of the
280
+ * liquidated account. Hyperliquid attaches `liquidation` to the fills of both
281
+ * parties, so only fills whose `liquidatedUser` is the queried address count.
282
+ * A fill whose hash a ledger liquidation row already carries is the same
283
+ * event and is skipped. The size sign follows the closed position: a sell
284
+ * fill closes a long. Groups whose market does not resolve are dropped.
285
+ * @public
286
+ */
287
+ export const mapLiquidationFills = (
288
+ fills: HlUserFill[],
289
+ providerKey: string,
290
+ queriedAddress: string,
291
+ resolveMarket: (coin: string) => MarketDisplay | undefined,
292
+ ledgerHashes: ReadonlySet<string>
293
+ ): LiquidationActivity[] => {
294
+ const queried = queriedAddress.toLowerCase()
295
+ const byOrder = new Map<number, HlUserFill[]>()
296
+ for (const fill of fills) {
297
+ if (
298
+ fill.liquidation?.liquidatedUser.toLowerCase() !== queried ||
299
+ (fill.hash !== undefined && ledgerHashes.has(fill.hash))
300
+ ) {
301
+ continue
302
+ }
303
+ const group = byOrder.get(fill.oid) ?? []
304
+ group.push(fill)
305
+ byOrder.set(fill.oid, group)
306
+ }
307
+ return [...byOrder.entries()].flatMap(([oid, group]) => {
308
+ const [first] = group
309
+ const market = resolveMarket(first.coin)
310
+ if (market === undefined) {
311
+ return []
312
+ }
313
+ let size = new Big(0)
314
+ let notional = new Big(0)
315
+ let time = first.time
316
+ for (const fill of group) {
317
+ size = size.plus(fill.sz)
318
+ notional = notional.plus(new Big(fill.px).times(fill.sz))
319
+ time = Math.max(time, fill.time)
320
+ }
321
+ return [
322
+ {
323
+ id: `liquidation:${oid}`,
324
+ provider: providerKey,
325
+ timestamp: new Date(time).toISOString(),
326
+ type: ActivityType.LIQUIDATION,
327
+ liquidatedNotionalPosition: notional.toFixed(),
328
+ liquidatedPositions: [
329
+ {
330
+ market,
331
+ size: (first.side === 'A' ? size : size.neg()).toFixed(),
332
+ },
333
+ ],
334
+ } satisfies LiquidationActivity,
335
+ ]
336
+ })
337
+ }
@@ -6,7 +6,6 @@ import {
6
6
  import type { Fill, MarketDisplay } from '@lifi/perps-types'
7
7
  import {
8
8
  FillClassification,
9
- FillStatus,
10
9
  LiquidityRole,
11
10
  OrderSide,
12
11
  OrderType,
@@ -42,7 +41,6 @@ export const mapFill = (fill: HlUserFill, market: MarketDisplay): Fill => {
42
41
  type: fill.crossed ? undefined : OrderType.LIMIT,
43
42
  size: fill.sz,
44
43
  price: fill.px,
45
- status: FillStatus.FILLED,
46
44
  liquidity: fill.crossed ? LiquidityRole.TAKER : LiquidityRole.MAKER,
47
45
  filledSize: fill.sz,
48
46
  fee: {