@lifi/perps-sdk-provider-hyperliquid 21.0.0 → 23.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 (115) hide show
  1. package/README.md +15 -0
  2. package/dist/cjs/services/getAccount.d.ts.map +1 -1
  3. package/dist/cjs/services/getAccount.js +3 -1
  4. package/dist/cjs/services/getAccount.js.map +1 -1
  5. package/dist/cjs/services/getAccountExists.d.ts +3 -1
  6. package/dist/cjs/services/getAccountExists.d.ts.map +1 -1
  7. package/dist/cjs/services/getAccountExists.js +27 -6
  8. package/dist/cjs/services/getAccountExists.js.map +1 -1
  9. package/dist/cjs/services/getActivity.d.ts.map +1 -1
  10. package/dist/cjs/services/getActivity.js +3 -1
  11. package/dist/cjs/services/getActivity.js.map +1 -1
  12. package/dist/cjs/services/getAvailableToTrade.d.ts.map +1 -1
  13. package/dist/cjs/services/getAvailableToTrade.js +3 -0
  14. package/dist/cjs/services/getAvailableToTrade.js.map +1 -1
  15. package/dist/cjs/services/getFills.d.ts.map +1 -1
  16. package/dist/cjs/services/getFills.js +3 -1
  17. package/dist/cjs/services/getFills.js.map +1 -1
  18. package/dist/cjs/services/getMarketSettings.d.ts.map +1 -1
  19. package/dist/cjs/services/getMarketSettings.js +3 -0
  20. package/dist/cjs/services/getMarketSettings.js.map +1 -1
  21. package/dist/cjs/services/getOrder.d.ts.map +1 -1
  22. package/dist/cjs/services/getOrder.js +2 -0
  23. package/dist/cjs/services/getOrder.js.map +1 -1
  24. package/dist/cjs/services/getOrders.d.ts.map +1 -1
  25. package/dist/cjs/services/getOrders.js +3 -1
  26. package/dist/cjs/services/getOrders.js.map +1 -1
  27. package/dist/cjs/services/getPortfolioHistory.d.ts.map +1 -1
  28. package/dist/cjs/services/getPortfolioHistory.js +2 -0
  29. package/dist/cjs/services/getPortfolioHistory.js.map +1 -1
  30. package/dist/cjs/services/getPositions.d.ts.map +1 -1
  31. package/dist/cjs/services/getPositions.js +3 -1
  32. package/dist/cjs/services/getPositions.js.map +1 -1
  33. package/dist/cjs/services/getWithdrawableBalances.d.ts.map +1 -1
  34. package/dist/cjs/services/getWithdrawableBalances.js +2 -0
  35. package/dist/cjs/services/getWithdrawableBalances.js.map +1 -1
  36. package/dist/cjs/utils/transferMargin.d.ts +2 -2
  37. package/dist/cjs/utils/transferMargin.d.ts.map +1 -1
  38. package/dist/cjs/utils/transferMargin.js +2 -2
  39. package/dist/cjs/utils/transferMargin.js.map +1 -1
  40. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts +2 -0
  41. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  42. package/dist/cjs/websocket/HyperliquidWsProvider.js +38 -9
  43. package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
  44. package/dist/esm/services/getAccount.d.ts.map +1 -1
  45. package/dist/esm/services/getAccount.js +3 -1
  46. package/dist/esm/services/getAccount.js.map +1 -1
  47. package/dist/esm/services/getAccountExists.d.ts +3 -1
  48. package/dist/esm/services/getAccountExists.d.ts.map +1 -1
  49. package/dist/esm/services/getAccountExists.js +29 -9
  50. package/dist/esm/services/getAccountExists.js.map +1 -1
  51. package/dist/esm/services/getActivity.d.ts.map +1 -1
  52. package/dist/esm/services/getActivity.js +3 -1
  53. package/dist/esm/services/getActivity.js.map +1 -1
  54. package/dist/esm/services/getAvailableToTrade.d.ts.map +1 -1
  55. package/dist/esm/services/getAvailableToTrade.js +3 -0
  56. package/dist/esm/services/getAvailableToTrade.js.map +1 -1
  57. package/dist/esm/services/getFills.d.ts.map +1 -1
  58. package/dist/esm/services/getFills.js +3 -1
  59. package/dist/esm/services/getFills.js.map +1 -1
  60. package/dist/esm/services/getMarketSettings.d.ts.map +1 -1
  61. package/dist/esm/services/getMarketSettings.js +3 -0
  62. package/dist/esm/services/getMarketSettings.js.map +1 -1
  63. package/dist/esm/services/getOrder.d.ts.map +1 -1
  64. package/dist/esm/services/getOrder.js +2 -0
  65. package/dist/esm/services/getOrder.js.map +1 -1
  66. package/dist/esm/services/getOrders.d.ts.map +1 -1
  67. package/dist/esm/services/getOrders.js +3 -1
  68. package/dist/esm/services/getOrders.js.map +1 -1
  69. package/dist/esm/services/getPortfolioHistory.d.ts.map +1 -1
  70. package/dist/esm/services/getPortfolioHistory.js +2 -0
  71. package/dist/esm/services/getPortfolioHistory.js.map +1 -1
  72. package/dist/esm/services/getPositions.d.ts.map +1 -1
  73. package/dist/esm/services/getPositions.js +3 -1
  74. package/dist/esm/services/getPositions.js.map +1 -1
  75. package/dist/esm/services/getWithdrawableBalances.d.ts.map +1 -1
  76. package/dist/esm/services/getWithdrawableBalances.js +2 -0
  77. package/dist/esm/services/getWithdrawableBalances.js.map +1 -1
  78. package/dist/esm/utils/transferMargin.d.ts +2 -2
  79. package/dist/esm/utils/transferMargin.d.ts.map +1 -1
  80. package/dist/esm/utils/transferMargin.js +2 -2
  81. package/dist/esm/utils/transferMargin.js.map +1 -1
  82. package/dist/esm/websocket/HyperliquidWsProvider.d.ts +2 -0
  83. package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  84. package/dist/esm/websocket/HyperliquidWsProvider.js +39 -12
  85. package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
  86. package/dist/types/services/getAccount.d.ts.map +1 -1
  87. package/dist/types/services/getAccountExists.d.ts +3 -1
  88. package/dist/types/services/getAccountExists.d.ts.map +1 -1
  89. package/dist/types/services/getActivity.d.ts.map +1 -1
  90. package/dist/types/services/getAvailableToTrade.d.ts.map +1 -1
  91. package/dist/types/services/getFills.d.ts.map +1 -1
  92. package/dist/types/services/getMarketSettings.d.ts.map +1 -1
  93. package/dist/types/services/getOrder.d.ts.map +1 -1
  94. package/dist/types/services/getOrders.d.ts.map +1 -1
  95. package/dist/types/services/getPortfolioHistory.d.ts.map +1 -1
  96. package/dist/types/services/getPositions.d.ts.map +1 -1
  97. package/dist/types/services/getWithdrawableBalances.d.ts.map +1 -1
  98. package/dist/types/utils/transferMargin.d.ts +2 -2
  99. package/dist/types/utils/transferMargin.d.ts.map +1 -1
  100. package/dist/types/websocket/HyperliquidWsProvider.d.ts +2 -0
  101. package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  102. package/package.json +3 -3
  103. package/src/services/getAccount.ts +3 -1
  104. package/src/services/getAccountExists.ts +55 -14
  105. package/src/services/getActivity.ts +3 -1
  106. package/src/services/getAvailableToTrade.ts +7 -0
  107. package/src/services/getFills.ts +3 -1
  108. package/src/services/getMarketSettings.ts +7 -0
  109. package/src/services/getOrder.ts +2 -0
  110. package/src/services/getOrders.ts +3 -1
  111. package/src/services/getPortfolioHistory.ts +2 -0
  112. package/src/services/getPositions.ts +3 -1
  113. package/src/services/getWithdrawableBalances.ts +2 -0
  114. package/src/utils/transferMargin.ts +7 -4
  115. package/src/websocket/HyperliquidWsProvider.ts +48 -15
@@ -19,6 +19,7 @@ import type {
19
19
  import { withExplorerLinks } from '../utils/explorer.js'
20
20
  import { assetIsOutcome, mapOrder, perpsDexNames } from '../utils/index.js'
21
21
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
22
+ import { requireAccountExists } from './getAccountExists.js'
22
23
 
23
24
  /** Parameters for a lifecycle-filtered Hyperliquid order read. */
24
25
  export type GetOrdersParams = ProviderGetOrdersParams
@@ -65,6 +66,8 @@ export const getOrders = async (
65
66
  options?: SDKRequestOptions
66
67
  ): Promise<OrdersResponse> => {
67
68
  const statuses = params.statuses ?? [...ACTIVE_ORDER_STATUSES]
69
+ const infoOpts = hlInfoOptions(client, options)
70
+ await requireAccountExists(apiUrl, params.address, infoOpts)
68
71
  if (statuses.length === 0) {
69
72
  return {
70
73
  provider: PROVIDER_KEY,
@@ -74,7 +77,6 @@ export const getOrders = async (
74
77
  }
75
78
  const registry = getMarketRegistry(client, PROVIDER_KEY)
76
79
  const markets = await registry.sync()
77
- const infoOpts = hlInfoOptions(client, options)
78
80
  const active = statuses.some(isActiveOrderStatus)
79
81
  const terminal = statuses.some((status) => !isActiveOrderStatus(status))
80
82
  const [open, historical, twaps] = await Promise.all([
@@ -15,6 +15,7 @@ import type {
15
15
  } from '../types/index.js'
16
16
  import { isUnifiedAbstraction } from '../utils/abstractionMode.js'
17
17
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
18
+ import { requireAccountExists } from './getAccountExists.js'
18
19
 
19
20
  /** Parameters for {@link getPortfolioHistory}. @public */
20
21
  export interface GetPortfolioHistoryParams {
@@ -83,6 +84,7 @@ export async function getPortfolioHistory(
83
84
  ): Promise<PortfolioHistoryResponse> {
84
85
  const { client, apiUrl } = ctx
85
86
  const infoOpts = hlInfoOptions(client, options)
87
+ await requireAccountExists(apiUrl, params.address, infoOpts)
86
88
  const [portfolio, abstraction] = await Promise.all([
87
89
  infoRequest<HlPortfolio>(
88
90
  apiUrl,
@@ -15,6 +15,7 @@ import {
15
15
  perpsDexNames,
16
16
  } from '../utils/index.js'
17
17
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
18
+ import { requireAccountExists } from './getAccountExists.js'
18
19
 
19
20
  /**
20
21
  * Parameters for {@link getPositions}.
@@ -42,9 +43,10 @@ export const getPositions = async (
42
43
  params: GetPositionsParams,
43
44
  options?: SDKRequestOptions
44
45
  ): Promise<PositionsResponse> => {
46
+ const infoOpts = hlInfoOptions(client, options)
47
+ await requireAccountExists(apiUrl, params.address, infoOpts)
45
48
  const registry = getMarketRegistry(client, PROVIDER_KEY)
46
49
  const markets = await registry.sync()
47
- const infoOpts = hlInfoOptions(client, options)
48
50
 
49
51
  const stateResults = await Promise.all(
50
52
  perpsDexNames(markets).map((name) =>
@@ -16,6 +16,7 @@ import type {
16
16
  } from '../types/index.js'
17
17
  import { hlInfoOptions, infoRequest } from '../utils/infoClient.js'
18
18
  import { hyperliquidWithdrawableBalances } from '../utils/withdrawableBalances.js'
19
+ import { requireAccountExists } from './getAccountExists.js'
19
20
 
20
21
  /**
21
22
  * Parameters for {@link getWithdrawableBalances}.
@@ -46,6 +47,7 @@ export const getWithdrawableBalances = async (
46
47
  ): Promise<ProviderWithdrawableBalance[]> => {
47
48
  const registry = getMarketRegistry(client, PROVIDER_KEY)
48
49
  const infoOpts = hlInfoOptions(client, options)
50
+ await requireAccountExists(apiUrl, params.address, infoOpts)
49
51
 
50
52
  const [{ providers }, markets, abstraction, state, spotState] =
51
53
  await Promise.all([
@@ -1,9 +1,12 @@
1
- import { PerpsError } from '@lifi/perps-sdk'
2
1
  import {
3
- PerpsErrorCode,
4
- type Position,
2
+ PerpsError,
5
3
  positionSupportsMarginAdjustment,
6
4
  positionSupportsMarginRemoval,
5
+ } from '@lifi/perps-sdk'
6
+ import {
7
+ type DecimalString,
8
+ PerpsErrorCode,
9
+ type Position,
7
10
  } from '@lifi/perps-types'
8
11
  import Big from 'big.js'
9
12
 
@@ -49,7 +52,7 @@ function positivePositionAmount(value: string, field: string): Big {
49
52
  */
50
53
  export function positionRemovableMargin(
51
54
  position: Position
52
- ): string | undefined {
55
+ ): DecimalString | undefined {
53
56
  if (!positionSupportsMarginAdjustment(position)) {
54
57
  return undefined
55
58
  }
@@ -5,6 +5,7 @@ import {
5
5
  isActiveMarket,
6
6
  isActiveOrderStatus,
7
7
  type MarketRegistry,
8
+ numberToDecimalString,
8
9
  PerpsError,
9
10
  type PerpsSDKClient,
10
11
  type ProviderGetQuoteParams,
@@ -31,12 +32,13 @@ import type {
31
32
  } from '@lifi/perps-types'
32
33
  import { PerpsErrorCode } from '@lifi/perps-types'
33
34
  import Big from 'big.js'
34
- import { isAddress } from 'viem'
35
+ import { type Address, isAddress } from 'viem'
35
36
  import {
36
37
  DEFAULT_HYPERLIQUID_API_URL,
37
38
  HYPERLIQUID_FEE_TIER_FALLBACK,
38
39
  SPOT_MARKET_ID,
39
40
  } from '../constants.js'
41
+ import { requireAccountExists } from '../services/getAccountExists.js'
40
42
  import type {
41
43
  HlActiveAssetData,
42
44
  HlAssetPosition,
@@ -138,6 +140,7 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
138
140
  private readonly clearinghouseRefs = new Map<string, number>()
139
141
  private readonly client: PerpsSDKClient | undefined
140
142
  private readonly registry: MarketRegistry | undefined
143
+ private readonly accountChecksByUser = new Map<string, Promise<void>>()
141
144
  // Spot-funded modes need both spot valuation and clearinghouse margin state.
142
145
  private readonly abstractionByUser = new Map<
143
146
  string,
@@ -230,6 +233,26 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
230
233
  this.orderApiUrl = orderApiUrl.origin
231
234
  }
232
235
 
236
+ private ensureAccountExists(address: Address): Promise<void> {
237
+ const user = normalizeHlAddress(address)
238
+ const existing = this.accountChecksByUser.get(user)
239
+ if (existing !== undefined) {
240
+ return existing
241
+ }
242
+ const check = requireAccountExists(
243
+ this.orderApiUrl,
244
+ address,
245
+ this.client === undefined ? undefined : hlInfoOptions(this.client)
246
+ )
247
+ this.accountChecksByUser.set(user, check)
248
+ void check.catch(() => {
249
+ if (this.accountChecksByUser.get(user) === check) {
250
+ this.accountChecksByUser.delete(user)
251
+ }
252
+ })
253
+ return check
254
+ }
255
+
233
256
  override async subscribe(
234
257
  sub: Subscription,
235
258
  listener: SubscriptionListener,
@@ -279,23 +302,19 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
279
302
  }
280
303
 
281
304
  protected async openChannel(sub: Subscription): Promise<() => void> {
282
- // Must run synchronously, before any await, so two concurrent opens
283
- // cannot both pass the exclusivity check.
284
- if (sub.channel === 'orderUpdates') {
285
- this.claimOrderUpdatesKey(this.toKey(sub))
286
- }
287
-
288
- await this.registry?.sync()
289
-
305
+ const registry = this.registry
306
+ let marketValidated = false
290
307
  if (
291
- this.registry !== undefined &&
308
+ registry !== undefined &&
292
309
  (sub.channel === 'marketContext' ||
293
310
  sub.channel === 'orderbook' ||
294
311
  sub.channel === 'candle' ||
295
312
  sub.channel === 'trades' ||
296
313
  sub.channel === 'availableToTrade')
297
314
  ) {
298
- const market = this.registry.requireActive(sub.marketId)
315
+ await registry.sync()
316
+ marketValidated = true
317
+ const market = registry.requireActive(sub.marketId)
299
318
  if (
300
319
  sub.channel === 'availableToTrade' &&
301
320
  market.categoryId === SPOT_MARKET_ID
@@ -309,6 +328,18 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
309
328
  }
310
329
  }
311
330
 
331
+ if ('address' in sub) {
332
+ await this.ensureAccountExists(sub.address)
333
+ }
334
+
335
+ if (sub.channel === 'orderUpdates') {
336
+ this.claimOrderUpdatesKey(this.toKey(sub))
337
+ }
338
+
339
+ if (registry !== undefined && !marketValidated) {
340
+ await registry.sync()
341
+ }
342
+
312
343
  // Markets context aggregates slower asset-context feeds with fast mid/mark
313
344
  // ticks from `fastAssetCtxs`.
314
345
  if (sub.channel === 'marketsContext') {
@@ -1578,10 +1609,12 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
1578
1609
  const isObject = (v: unknown): v is Record<string, unknown> =>
1579
1610
  typeof v === 'object' && v !== null
1580
1611
 
1581
- const toMarketContextString = (value: unknown): string | undefined =>
1582
- typeof value === 'string' || typeof value === 'number'
1583
- ? String(value)
1584
- : undefined
1612
+ const toMarketContextString = (value: unknown): string | undefined => {
1613
+ if (typeof value === 'number') {
1614
+ return numberToDecimalString(value)
1615
+ }
1616
+ return typeof value === 'string' ? value : undefined
1617
+ }
1585
1618
 
1586
1619
  const toMarketCapString = (
1587
1620
  price: unknown,