@lifi/perps-sdk-provider-hyperliquid 20.1.0 → 21.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 (76) hide show
  1. package/dist/cjs/HyperliquidProvider.d.ts.map +1 -1
  2. package/dist/cjs/HyperliquidProvider.js +2 -2
  3. package/dist/cjs/HyperliquidProvider.js.map +1 -1
  4. package/dist/cjs/services/getAccount.d.ts.map +1 -1
  5. package/dist/cjs/services/getAccount.js +5 -7
  6. package/dist/cjs/services/getAccount.js.map +1 -1
  7. package/dist/cjs/services/getWithdrawableBalances.js +1 -1
  8. package/dist/cjs/services/getWithdrawableBalances.js.map +1 -1
  9. package/dist/cjs/utils/index.d.ts +1 -1
  10. package/dist/cjs/utils/index.d.ts.map +1 -1
  11. package/dist/cjs/utils/index.js +3 -3
  12. package/dist/cjs/utils/index.js.map +1 -1
  13. package/dist/cjs/utils/liquidation.js +1 -1
  14. package/dist/cjs/utils/liquidation.js.map +1 -1
  15. package/dist/cjs/utils/orderFormatting.d.ts +3 -2
  16. package/dist/cjs/utils/orderFormatting.d.ts.map +1 -1
  17. package/dist/cjs/utils/orderFormatting.js +4 -4
  18. package/dist/cjs/utils/orderFormatting.js.map +1 -1
  19. package/dist/cjs/utils/spotBalance.d.ts.map +1 -1
  20. package/dist/cjs/utils/spotBalance.js +2 -2
  21. package/dist/cjs/utils/spotBalance.js.map +1 -1
  22. package/dist/cjs/utils/withdrawableBalances.d.ts +1 -1
  23. package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -1
  24. package/dist/cjs/utils/withdrawableBalances.js +7 -4
  25. package/dist/cjs/utils/withdrawableBalances.js.map +1 -1
  26. package/dist/cjs/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  27. package/dist/cjs/websocket/HyperliquidWsProvider.js +10 -4
  28. package/dist/cjs/websocket/HyperliquidWsProvider.js.map +1 -1
  29. package/dist/esm/HyperliquidProvider.d.ts.map +1 -1
  30. package/dist/esm/HyperliquidProvider.js +3 -3
  31. package/dist/esm/HyperliquidProvider.js.map +1 -1
  32. package/dist/esm/services/getAccount.d.ts.map +1 -1
  33. package/dist/esm/services/getAccount.js +6 -5
  34. package/dist/esm/services/getAccount.js.map +1 -1
  35. package/dist/esm/services/getWithdrawableBalances.js +1 -1
  36. package/dist/esm/services/getWithdrawableBalances.js.map +1 -1
  37. package/dist/esm/utils/index.d.ts +1 -1
  38. package/dist/esm/utils/index.d.ts.map +1 -1
  39. package/dist/esm/utils/index.js +1 -1
  40. package/dist/esm/utils/index.js.map +1 -1
  41. package/dist/esm/utils/liquidation.js +2 -2
  42. package/dist/esm/utils/liquidation.js.map +1 -1
  43. package/dist/esm/utils/orderFormatting.d.ts +14 -12
  44. package/dist/esm/utils/orderFormatting.d.ts.map +1 -1
  45. package/dist/esm/utils/orderFormatting.js +14 -14
  46. package/dist/esm/utils/orderFormatting.js.map +1 -1
  47. package/dist/esm/utils/spotBalance.d.ts.map +1 -1
  48. package/dist/esm/utils/spotBalance.js +3 -3
  49. package/dist/esm/utils/spotBalance.js.map +1 -1
  50. package/dist/esm/utils/withdrawableBalances.d.ts +1 -1
  51. package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -1
  52. package/dist/esm/utils/withdrawableBalances.js +7 -4
  53. package/dist/esm/utils/withdrawableBalances.js.map +1 -1
  54. package/dist/esm/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  55. package/dist/esm/websocket/HyperliquidWsProvider.js +11 -5
  56. package/dist/esm/websocket/HyperliquidWsProvider.js.map +1 -1
  57. package/dist/types/HyperliquidProvider.d.ts.map +1 -1
  58. package/dist/types/services/getAccount.d.ts.map +1 -1
  59. package/dist/types/utils/index.d.ts +1 -1
  60. package/dist/types/utils/index.d.ts.map +1 -1
  61. package/dist/types/utils/orderFormatting.d.ts +14 -12
  62. package/dist/types/utils/orderFormatting.d.ts.map +1 -1
  63. package/dist/types/utils/spotBalance.d.ts.map +1 -1
  64. package/dist/types/utils/withdrawableBalances.d.ts +1 -1
  65. package/dist/types/utils/withdrawableBalances.d.ts.map +1 -1
  66. package/dist/types/websocket/HyperliquidWsProvider.d.ts.map +1 -1
  67. package/package.json +3 -3
  68. package/src/HyperliquidProvider.ts +6 -5
  69. package/src/services/getAccount.ts +18 -18
  70. package/src/services/getWithdrawableBalances.ts +1 -1
  71. package/src/utils/index.ts +2 -2
  72. package/src/utils/liquidation.ts +2 -2
  73. package/src/utils/orderFormatting.ts +20 -16
  74. package/src/utils/spotBalance.ts +5 -3
  75. package/src/utils/withdrawableBalances.ts +12 -7
  76. package/src/websocket/HyperliquidWsProvider.ts +14 -4
@@ -1,11 +1,10 @@
1
1
  import {
2
+ calculateTransferable,
2
3
  getMarketRegistry,
3
4
  getMarketsContext,
4
- maxOf,
5
- minOf,
6
5
  type ProviderGetAccountParams,
6
+ parseDecimal,
7
7
  type SDKRequestOptions,
8
- stringToFloat,
9
8
  toPerpsMarketDisplay,
10
9
  } from '@lifi/perps-sdk'
11
10
  import type {
@@ -16,7 +15,7 @@ import type {
16
15
  HyperliquidDexAccountState,
17
16
  Position,
18
17
  } from '@lifi/perps-types'
19
- import Big from 'big.js'
18
+ import type Big from 'big.js'
20
19
  import { PROVIDER_KEY } from '../constants.js'
21
20
  import type { HyperliquidContext } from '../context.js'
22
21
  import type {
@@ -83,13 +82,12 @@ const buildBalances = (
83
82
  const total = toWireBig(b.total, 'spotClearinghouseState.total')
84
83
  return {
85
84
  ...spotBalance(spotAssetFromToken(b), b.total, priceById),
86
- transferable: minOf(
87
- maxOf(
88
- total.minus(toWireBig(b.hold, 'spotClearinghouseState.hold')),
89
- new Big(0)
90
- ),
85
+ transferable: calculateTransferable(
91
86
  total
92
- ).toFixed(),
87
+ .minus(toWireBig(b.hold, 'spotClearinghouseState.hold'))
88
+ .toFixed(),
89
+ total.toFixed()
90
+ ),
93
91
  }
94
92
  }),
95
93
  quoteAssetIds
@@ -114,13 +112,13 @@ const buildBalances = (
114
112
  units: value.toFixed(),
115
113
  valueUsd: value.toFixed(),
116
114
  price: '1',
117
- transferable: minOf(
118
- maxOf(
119
- toWireBig(state.withdrawable, 'clearinghouseState.withdrawable'),
120
- new Big(0)
121
- ),
122
- value
123
- ).toFixed(),
115
+ transferable: calculateTransferable(
116
+ toWireBig(
117
+ state.withdrawable,
118
+ 'clearinghouseState.withdrawable'
119
+ ).toFixed(),
120
+ value.toFixed()
121
+ ),
124
122
  })
125
123
  }
126
124
  }
@@ -209,7 +207,9 @@ export const getAccount = async (
209
207
 
210
208
  const priceById = spotPriceById(
211
209
  markets,
212
- new Map(prices.map((p) => [p.marketId, stringToFloat(p.markPrice)]))
210
+ new Map(
211
+ prices.map((p) => [p.marketId, parseDecimal(p.markPrice) ?? Number.NaN])
212
+ )
213
213
  )
214
214
 
215
215
  const positions: Position[] = stateResults.flatMap((state) =>
@@ -89,6 +89,6 @@ export const getWithdrawableBalances = async (
89
89
  state,
90
90
  spotState,
91
91
  quoteAsset.id,
92
- feeUsd === undefined ? undefined : String(feeUsd)
92
+ feeUsd
93
93
  )
94
94
  }
@@ -45,9 +45,9 @@ export {
45
45
  export { isOpenAssetPosition, mapPosition } from './mapPosition.js'
46
46
  export { coinAsset, perpsDexNames } from './marketDisplay.js'
47
47
  export {
48
- formatOrderPrice,
49
- formatOrderSize,
50
48
  getMaxPriceDecimals,
49
+ snapOrderPrice,
50
+ snapOrderSize,
51
51
  } from './orderFormatting.js'
52
52
  export { priceStepToAggregation } from './priceStepToAggregation.js'
53
53
  export {
@@ -12,7 +12,7 @@
12
12
  * - margin_available = isolated_margin - maintenance_margin_required
13
13
  */
14
14
 
15
- import { estimateIsolatedLiquidationPrice } from '@lifi/perps-sdk'
15
+ import { estimateLiquidationPrice } from '@lifi/perps-sdk'
16
16
 
17
17
  /**
18
18
  * Calculate the maintenance margin fraction for a Hyperliquid asset.
@@ -65,7 +65,7 @@ export function calculateLiquidationPrice(
65
65
  if (mmr === undefined) {
66
66
  return undefined
67
67
  }
68
- return estimateIsolatedLiquidationPrice({
68
+ return estimateLiquidationPrice({
69
69
  entryPrice,
70
70
  leverage,
71
71
  isLong,
@@ -1,12 +1,13 @@
1
1
  /**
2
- * Hyperliquid order size and price formatting for exchange submission.
2
+ * Hyperliquid order size and price snapping for exchange submission.
3
3
  *
4
- * These encode Hyperliquid-specific order submission rules. Getting size/price
5
- * formatting wrong causes rejected orders.
4
+ * These encode Hyperliquid-specific order submission rules. Snapping a size or
5
+ * a price onto the wrong grid causes rejected orders.
6
6
  *
7
7
  * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/tick-and-lot-size
8
8
  */
9
9
 
10
+ import type { DecimalString } from '@lifi/perps-types'
10
11
  import Big from 'big.js'
11
12
 
12
13
  /**
@@ -36,28 +37,30 @@ export function getMaxPriceDecimals(
36
37
  }
37
38
 
38
39
  /**
39
- * Format a size value for order submission.
40
+ * Snap a size onto the asset's lot grid for order submission.
40
41
  *
41
42
  * Per Hyperliquid docs (tick-and-lot-size):
42
43
  * - Size must be rounded to the asset's szDecimals
43
44
  * - Trailing zeroes must be removed for signing
44
45
  *
45
- * @param size - The size value to format
46
+ * @param size - The size to snap, as a decimal string
46
47
  * @param szDecimals - Number of decimal places allowed for this asset (from meta)
47
- * @returns Size as a string with correct precision, no trailing zeros
48
+ * @returns Size as a decimal string with correct precision, no trailing zeros
48
49
  * @public
49
50
  */
50
- export function formatOrderSize(size: number, szDecimals: number): string {
51
+ export function snapOrderSize(
52
+ size: DecimalString,
53
+ szDecimals: number
54
+ ): DecimalString {
51
55
  // Big.roundDown truncates toward zero — never round a size up, it could
52
- // exceed available balance. Exact decimal arithmetic: flooring the float
53
- // product dropped a lot step (0.29 * 100 === 28.999999999999996).
56
+ // exceed available balance.
54
57
  const truncated = new Big(size).round(szDecimals, Big.roundDown)
55
58
  // toFixed() with no dp always emits plain notation; eq(0) guards '-0'
56
59
  return truncated.eq(0) ? '0' : truncated.toFixed()
57
60
  }
58
61
 
59
62
  /**
60
- * Format a price value for order submission.
63
+ * Snap a price onto the asset's tick grid for order submission.
61
64
  *
62
65
  * Per Hyperliquid docs (tick-and-lot-size):
63
66
  * - Maximum 5 significant figures
@@ -66,19 +69,20 @@ export function formatOrderSize(size: number, szDecimals: number): string {
66
69
  * - Trailing zeroes must be removed for signing
67
70
  *
68
71
  * Rounding is half-up (away from zero at exact halfway) on the true decimal
69
- * value, not on the binary float — (1.005).toFixed(2) would give '1.00'.
72
+ * value, which is why the price arrives as a string: `(1.005).toFixed(2)`
73
+ * would give `'1.00'`.
70
74
  *
71
- * @param price - The price value to format
75
+ * @param price - The price to snap, as a decimal string
72
76
  * @param szDecimals - The asset's szDecimals (affects max price decimals)
73
77
  * @param market - Optional market type (e.g. 'spot'). Defaults to perps rules.
74
- * @returns Price as a string with correct precision, no trailing zeros
78
+ * @returns Price as a decimal string with correct precision, no trailing zeros
75
79
  * @public
76
80
  */
77
- export function formatOrderPrice(
78
- price: number,
81
+ export function snapOrderPrice(
82
+ price: DecimalString,
79
83
  szDecimals: number,
80
84
  market?: string
81
- ): string {
85
+ ): DecimalString {
82
86
  const maxPriceDecimals = getMaxPriceDecimals(szDecimals, market)
83
87
 
84
88
  let rounded = new Big(price).round(maxPriceDecimals, Big.roundHalfUp)
@@ -1,4 +1,4 @@
1
- import { stringToFloat } from '@lifi/perps-sdk'
1
+ import { numberToDecimalString, parseDecimal } from '@lifi/perps-sdk'
2
2
  import type { Asset, Balance, Market } from '@lifi/perps-types'
3
3
  import { SPOT_MARKET_ID } from '../constants.js'
4
4
  import type { HlSpotBalance } from '../types/index.js'
@@ -52,8 +52,10 @@ export const spotBalance = (
52
52
  categoryId: SPOT_MARKET_ID,
53
53
  asset,
54
54
  units: total,
55
- valueUsd: (stringToFloat(total) * price).toString(),
55
+ valueUsd: numberToDecimalString(
56
+ (parseDecimal(total) ?? Number.NaN) * price
57
+ ),
56
58
  // A zero entry means the map holds no mark for the asset, not a free asset.
57
- ...(price > 0 ? { price: price.toString() } : {}),
59
+ ...(price > 0 ? { price: numberToDecimalString(price) } : {}),
58
60
  }
59
61
  }
@@ -1,4 +1,7 @@
1
- import type { ProviderWithdrawableBalance } from '@lifi/perps-sdk'
1
+ import {
2
+ calculateWithdrawMax,
3
+ type ProviderWithdrawableBalance,
4
+ } from '@lifi/perps-sdk'
2
5
  import type {
3
6
  HlAbstractionMode,
4
7
  HlClearinghouseState,
@@ -50,24 +53,26 @@ export const hyperliquidWithdrawableBalances = (
50
53
  )
51
54
  if (spot.gt(0)) {
52
55
  const assetId = String(balance.token)
53
- rows.push({
56
+ const row = {
54
57
  assetId,
55
- route: 'spot',
58
+ route: 'spot' as const,
56
59
  available: spot.toFixed(),
57
60
  ...feeFor(assetId),
58
- })
61
+ }
62
+ rows.push({ ...row, max: calculateWithdrawMax(row) })
59
63
  }
60
64
  }
61
65
  }
62
66
 
63
67
  const perps = toWireBig(state.withdrawable, 'clearinghouseState.withdrawable')
64
68
  if (perps.gt(0)) {
65
- rows.push({
69
+ const row = {
66
70
  assetId: quoteAssetId,
67
- route: 'perps',
71
+ route: 'perps' as const,
68
72
  available: perps.toFixed(),
69
73
  ...feeFor(quoteAssetId),
70
- })
74
+ }
75
+ rows.push({ ...row, max: calculateWithdrawMax(row) })
71
76
  }
72
77
 
73
78
  return rows
@@ -1,4 +1,5 @@
1
1
  import {
2
+ calculateTransferable,
2
3
  DecodeChain,
3
4
  getMarketRegistry,
4
5
  isActiveMarket,
@@ -1507,10 +1508,19 @@ export class HyperliquidWsProvider extends WsProviderBase<object> {
1507
1508
  }
1508
1509
  return
1509
1510
  }
1510
- const rows = balances.map((balance) => ({
1511
- ...spotBalance(spotAssetFromToken(balance), balance.total, priceById),
1512
- locked: balance.hold,
1513
- }))
1511
+ const rows = balances.map((balance) => {
1512
+ const total = toWireBig(balance.total, 'spotState.balances.total')
1513
+ return {
1514
+ ...spotBalance(spotAssetFromToken(balance), balance.total, priceById),
1515
+ locked: balance.hold,
1516
+ transferable: calculateTransferable(
1517
+ total
1518
+ .minus(toWireBig(balance.hold, 'spotState.balances.hold'))
1519
+ .toFixed(),
1520
+ total.toFixed()
1521
+ ),
1522
+ }
1523
+ })
1514
1524
  this.emit(`spotState:${user}`, {
1515
1525
  channel: 'spotBalances',
1516
1526
  data: rows,