@lifi/perps-sdk 19.0.0 → 20.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 (146) hide show
  1. package/README.md +15 -5
  2. package/dist/cjs/client/PerpsClient.d.ts +1 -1
  3. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  4. package/dist/cjs/client/PerpsClient.js +4 -1
  5. package/dist/cjs/client/PerpsClient.js.map +1 -1
  6. package/dist/cjs/client/createPerpsClient.d.ts +1 -6
  7. package/dist/cjs/client/createPerpsClient.d.ts.map +1 -1
  8. package/dist/cjs/client/createPerpsClient.js +1 -14
  9. package/dist/cjs/client/createPerpsClient.js.map +1 -1
  10. package/dist/cjs/index.d.ts +5 -3
  11. package/dist/cjs/index.d.ts.map +1 -1
  12. package/dist/cjs/index.js +10 -3
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/services/getOhlcv.d.ts.map +1 -1
  15. package/dist/cjs/services/getOhlcv.js.map +1 -1
  16. package/dist/cjs/types/api.d.ts +3 -4
  17. package/dist/cjs/types/api.d.ts.map +1 -1
  18. package/dist/cjs/types/config.d.ts +0 -9
  19. package/dist/cjs/types/config.d.ts.map +1 -1
  20. package/dist/cjs/types/provider.d.ts +1 -1
  21. package/dist/cjs/types/provider.d.ts.map +1 -1
  22. package/dist/cjs/types/withdrawal.d.ts +4 -2
  23. package/dist/cjs/types/withdrawal.d.ts.map +1 -1
  24. package/dist/cjs/utils/calculations.d.ts.map +1 -1
  25. package/dist/cjs/utils/calculations.js +107 -38
  26. package/dist/cjs/utils/calculations.js.map +1 -1
  27. package/dist/cjs/utils/decimal.d.ts +4 -0
  28. package/dist/cjs/utils/decimal.d.ts.map +1 -0
  29. package/dist/cjs/utils/decimal.js +14 -0
  30. package/dist/cjs/utils/decimal.js.map +1 -0
  31. package/dist/cjs/utils/math.d.ts +4 -0
  32. package/dist/cjs/utils/math.d.ts.map +1 -0
  33. package/dist/cjs/utils/math.js +8 -0
  34. package/dist/cjs/utils/math.js.map +1 -0
  35. package/dist/cjs/utils/parse.d.ts +1 -0
  36. package/dist/cjs/utils/parse.d.ts.map +1 -1
  37. package/dist/cjs/utils/parse.js +15 -0
  38. package/dist/cjs/utils/parse.js.map +1 -1
  39. package/dist/cjs/utils/positionMath.d.ts +5 -0
  40. package/dist/cjs/utils/positionMath.d.ts.map +1 -1
  41. package/dist/cjs/utils/positionMath.js +53 -6
  42. package/dist/cjs/utils/positionMath.js.map +1 -1
  43. package/dist/cjs/version.d.ts +1 -1
  44. package/dist/cjs/version.js +1 -1
  45. package/dist/cjs/websocket/PerpsWsClient.d.ts +0 -1
  46. package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
  47. package/dist/cjs/websocket/PerpsWsClient.js +0 -7
  48. package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
  49. package/dist/esm/client/PerpsClient.d.ts +8 -7
  50. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  51. package/dist/esm/client/PerpsClient.js +11 -7
  52. package/dist/esm/client/PerpsClient.js.map +1 -1
  53. package/dist/esm/client/createPerpsClient.d.ts +1 -12
  54. package/dist/esm/client/createPerpsClient.d.ts.map +1 -1
  55. package/dist/esm/client/createPerpsClient.js +1 -19
  56. package/dist/esm/client/createPerpsClient.js.map +1 -1
  57. package/dist/esm/client/requireProvider.d.ts +1 -1
  58. package/dist/esm/client/requireProvider.js +1 -1
  59. package/dist/esm/index.d.ts +5 -3
  60. package/dist/esm/index.d.ts.map +1 -1
  61. package/dist/esm/index.js +4 -2
  62. package/dist/esm/index.js.map +1 -1
  63. package/dist/esm/services/getOhlcv.d.ts +1 -0
  64. package/dist/esm/services/getOhlcv.d.ts.map +1 -1
  65. package/dist/esm/services/getOhlcv.js.map +1 -1
  66. package/dist/esm/types/api.d.ts +8 -22
  67. package/dist/esm/types/api.d.ts.map +1 -1
  68. package/dist/esm/types/config.d.ts +0 -27
  69. package/dist/esm/types/config.d.ts.map +1 -1
  70. package/dist/esm/types/provider.d.ts +7 -6
  71. package/dist/esm/types/provider.d.ts.map +1 -1
  72. package/dist/esm/types/withdrawal.d.ts +24 -15
  73. package/dist/esm/types/withdrawal.d.ts.map +1 -1
  74. package/dist/esm/utils/calculations.d.ts +3 -2
  75. package/dist/esm/utils/calculations.d.ts.map +1 -1
  76. package/dist/esm/utils/calculations.js +109 -39
  77. package/dist/esm/utils/calculations.js.map +1 -1
  78. package/dist/esm/utils/decimal.d.ts +9 -0
  79. package/dist/esm/utils/decimal.d.ts.map +1 -0
  80. package/dist/esm/utils/decimal.js +12 -0
  81. package/dist/esm/utils/decimal.js.map +1 -0
  82. package/dist/esm/utils/math.d.ts +6 -0
  83. package/dist/esm/utils/math.d.ts.map +1 -0
  84. package/dist/esm/utils/math.js +5 -0
  85. package/dist/esm/utils/math.js.map +1 -0
  86. package/dist/esm/utils/parse.d.ts +7 -0
  87. package/dist/esm/utils/parse.d.ts.map +1 -1
  88. package/dist/esm/utils/parse.js +20 -0
  89. package/dist/esm/utils/parse.js.map +1 -1
  90. package/dist/esm/utils/positionMath.d.ts +13 -0
  91. package/dist/esm/utils/positionMath.d.ts.map +1 -1
  92. package/dist/esm/utils/positionMath.js +60 -6
  93. package/dist/esm/utils/positionMath.js.map +1 -1
  94. package/dist/esm/version.d.ts +1 -1
  95. package/dist/esm/version.js +1 -1
  96. package/dist/esm/websocket/PerpsWsClient.d.ts +0 -7
  97. package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
  98. package/dist/esm/websocket/PerpsWsClient.js +0 -7
  99. package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
  100. package/dist/types/client/PerpsClient.d.ts +8 -7
  101. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  102. package/dist/types/client/createPerpsClient.d.ts +1 -12
  103. package/dist/types/client/createPerpsClient.d.ts.map +1 -1
  104. package/dist/types/client/requireProvider.d.ts +1 -1
  105. package/dist/types/index.d.ts +5 -3
  106. package/dist/types/index.d.ts.map +1 -1
  107. package/dist/types/services/getOhlcv.d.ts +1 -0
  108. package/dist/types/services/getOhlcv.d.ts.map +1 -1
  109. package/dist/types/types/api.d.ts +8 -22
  110. package/dist/types/types/api.d.ts.map +1 -1
  111. package/dist/types/types/config.d.ts +0 -27
  112. package/dist/types/types/config.d.ts.map +1 -1
  113. package/dist/types/types/provider.d.ts +7 -6
  114. package/dist/types/types/provider.d.ts.map +1 -1
  115. package/dist/types/types/withdrawal.d.ts +24 -15
  116. package/dist/types/types/withdrawal.d.ts.map +1 -1
  117. package/dist/types/utils/calculations.d.ts +3 -2
  118. package/dist/types/utils/calculations.d.ts.map +1 -1
  119. package/dist/types/utils/decimal.d.ts +9 -0
  120. package/dist/types/utils/decimal.d.ts.map +1 -0
  121. package/dist/types/utils/math.d.ts +6 -0
  122. package/dist/types/utils/math.d.ts.map +1 -0
  123. package/dist/types/utils/parse.d.ts +7 -0
  124. package/dist/types/utils/parse.d.ts.map +1 -1
  125. package/dist/types/utils/positionMath.d.ts +13 -0
  126. package/dist/types/utils/positionMath.d.ts.map +1 -1
  127. package/dist/types/version.d.ts +1 -1
  128. package/dist/types/websocket/PerpsWsClient.d.ts +0 -7
  129. package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
  130. package/package.json +2 -2
  131. package/src/client/PerpsClient.ts +12 -8
  132. package/src/client/createPerpsClient.ts +4 -32
  133. package/src/client/requireProvider.ts +1 -1
  134. package/src/index.ts +4 -4
  135. package/src/services/getOhlcv.ts +1 -0
  136. package/src/types/api.ts +8 -26
  137. package/src/types/config.ts +0 -30
  138. package/src/types/provider.ts +8 -7
  139. package/src/types/withdrawal.ts +24 -15
  140. package/src/utils/calculations.ts +114 -43
  141. package/src/utils/decimal.ts +13 -0
  142. package/src/utils/math.ts +7 -0
  143. package/src/utils/parse.ts +25 -0
  144. package/src/utils/positionMath.ts +66 -6
  145. package/src/version.ts +1 -1
  146. package/src/websocket/PerpsWsClient.ts +0 -19
@@ -16,7 +16,9 @@ import {
16
16
  type QuoteSide,
17
17
  type TradeType,
18
18
  } from '@lifi/perps-types'
19
+ import type Big from 'big.js'
19
20
  import { PerpsError } from '../errors/PerpsError.js'
21
+ import { areFinite, DivBig } from './decimal.js'
20
22
 
21
23
  /**
22
24
  * Calculate position size in asset units from margin.
@@ -36,7 +38,13 @@ export function calculatePositionSize(
36
38
  leverage: number,
37
39
  price: number
38
40
  ): number {
39
- return (marginUsd * leverage) / price
41
+ if (price === 0) {
42
+ return (marginUsd * leverage) / price
43
+ }
44
+ if (!areFinite(marginUsd, leverage, price)) {
45
+ return Number.NaN
46
+ }
47
+ return new DivBig(marginUsd).times(leverage).div(price).toNumber()
40
48
  }
41
49
 
42
50
  /**
@@ -48,7 +56,10 @@ export function calculatePositionSize(
48
56
  * @public
49
57
  */
50
58
  export function calculateNotionalValue(size: number, price: number): number {
51
- return Math.abs(size) * price
59
+ if (!areFinite(size, price)) {
60
+ return Number.NaN
61
+ }
62
+ return new DivBig(size).abs().times(price).toNumber()
52
63
  }
53
64
 
54
65
  /**
@@ -65,7 +76,10 @@ export function calculateUnrealizedPnl(
65
76
  currentPrice: number,
66
77
  size: number
67
78
  ): number {
68
- return (currentPrice - entryPrice) * size
79
+ if (!areFinite(entryPrice, currentPrice, size)) {
80
+ return Number.NaN
81
+ }
82
+ return new DivBig(currentPrice).minus(entryPrice).times(size).toNumber()
69
83
  }
70
84
 
71
85
  /**
@@ -80,7 +94,10 @@ export function calculateRoe(pnl: number, margin: number): number {
80
94
  if (margin === 0) {
81
95
  return 0
82
96
  }
83
- return (pnl / margin) * 100
97
+ if (!areFinite(pnl, margin)) {
98
+ return Number.NaN
99
+ }
100
+ return new DivBig(pnl).div(margin).times(100).toNumber()
84
101
  }
85
102
 
86
103
  /**
@@ -95,7 +112,13 @@ export function calculateRequiredMargin(
95
112
  notionalValue: number,
96
113
  leverage: number
97
114
  ): number {
98
- return notionalValue / leverage
115
+ if (leverage === 0) {
116
+ return notionalValue / leverage
117
+ }
118
+ if (!areFinite(notionalValue, leverage)) {
119
+ return Number.NaN
120
+ }
121
+ return new DivBig(notionalValue).div(leverage).toNumber()
99
122
  }
100
123
 
101
124
  /**
@@ -107,7 +130,10 @@ export function calculateRequiredMargin(
107
130
  * @public
108
131
  */
109
132
  export function estimateFees(sizeUsd: number, feeRate: number): number {
110
- return sizeUsd * feeRate
133
+ if (!areFinite(sizeUsd, feeRate)) {
134
+ return Number.NaN
135
+ }
136
+ return new DivBig(sizeUsd).times(feeRate).toNumber()
111
137
  }
112
138
 
113
139
  /**
@@ -124,8 +150,17 @@ export function applySlippage(
124
150
  slippagePercent: number,
125
151
  isBuy: boolean
126
152
  ): number {
127
- const multiplier = 1 + slippagePercent / 100
128
- return isBuy ? price * multiplier : price / multiplier
153
+ if (!areFinite(price, slippagePercent)) {
154
+ return Number.NaN
155
+ }
156
+ const multiplier = new DivBig(slippagePercent).div(100).plus(1)
157
+ if (isBuy) {
158
+ return new DivBig(price).times(multiplier).toNumber()
159
+ }
160
+ if (multiplier.eq(0)) {
161
+ return price / multiplier.toNumber()
162
+ }
163
+ return new DivBig(price).div(multiplier).toNumber()
129
164
  }
130
165
 
131
166
  /**
@@ -166,7 +201,10 @@ export function effectiveLeverage(params: {
166
201
  if (marginUsd === 0) {
167
202
  return 0
168
203
  }
169
- return positionValueUsd / marginUsd
204
+ if (!areFinite(positionValueUsd, marginUsd)) {
205
+ return Number.NaN
206
+ }
207
+ return new DivBig(positionValueUsd).div(marginUsd).toNumber()
170
208
  }
171
209
 
172
210
  /**
@@ -202,12 +240,15 @@ export function calculateExpectedPnl(
202
240
  if (!triggerPrice || entryPrice === 0 || margin === 0) {
203
241
  return null
204
242
  }
243
+ if (!areFinite(triggerPrice, entryPrice, leverage, margin)) {
244
+ return { amount: Number.NaN, percent: Number.NaN }
245
+ }
205
246
  const priceDiff = isLong
206
- ? triggerPrice - entryPrice
207
- : entryPrice - triggerPrice
208
- const percent = (priceDiff / entryPrice) * leverage * 100
209
- const amount = margin * (percent / 100)
210
- return { amount, percent }
247
+ ? new DivBig(triggerPrice).minus(entryPrice)
248
+ : new DivBig(entryPrice).minus(triggerPrice)
249
+ const percent = priceDiff.div(entryPrice).times(leverage).times(100)
250
+ const amount = percent.times(margin).div(100)
251
+ return { amount: amount.toNumber(), percent: percent.toNumber() }
211
252
  }
212
253
 
213
254
  /**
@@ -228,8 +269,14 @@ export function priceFromPercent(
228
269
  if (entryPrice === 0 || leverage === 0) {
229
270
  return 0
230
271
  }
231
- const priceDelta = (percent / 100 / leverage) * entryPrice
232
- return isLong ? entryPrice + priceDelta : entryPrice - priceDelta
272
+ if (!areFinite(percent, entryPrice, leverage)) {
273
+ return Number.NaN
274
+ }
275
+ const priceDelta = new DivBig(percent)
276
+ .times(entryPrice)
277
+ .div(new DivBig(leverage).times(100))
278
+ const entry = new DivBig(entryPrice)
279
+ return (isLong ? entry.plus(priceDelta) : entry.minus(priceDelta)).toNumber()
233
280
  }
234
281
 
235
282
  /**
@@ -250,8 +297,13 @@ export function percentFromPrice(
250
297
  if (entryPrice === 0 || leverage === 0) {
251
298
  return 0
252
299
  }
253
- const priceDiff = isLong ? price - entryPrice : entryPrice - price
254
- return (priceDiff / entryPrice) * leverage * 100
300
+ if (!areFinite(price, entryPrice, leverage)) {
301
+ return Number.NaN
302
+ }
303
+ const priceDiff = isLong
304
+ ? new DivBig(price).minus(entryPrice)
305
+ : new DivBig(entryPrice).minus(price)
306
+ return priceDiff.div(entryPrice).times(leverage).times(100).toNumber()
255
307
  }
256
308
 
257
309
  /**
@@ -268,11 +320,14 @@ export function calculateRealizedPnlPercent(
268
320
  size: number,
269
321
  price: number
270
322
  ): number {
271
- const positionValue = Math.abs(size) * price
272
- if (positionValue === 0) {
323
+ if (!areFinite(realizedPnl, size, price)) {
324
+ return Number.NaN
325
+ }
326
+ const positionValue = new DivBig(size).abs().times(price)
327
+ if (positionValue.eq(0)) {
273
328
  return 0
274
329
  }
275
- return (realizedPnl / positionValue) * 100
330
+ return new DivBig(realizedPnl).div(positionValue).times(100).toNumber()
276
331
  }
277
332
 
278
333
  /** Result of {@link walkOrderbook} — the fill obtained for a USD-notional walk. */
@@ -283,7 +338,7 @@ interface BookWalk {
283
338
  filledNotional: number
284
339
  /** Volume-weighted average fill price, or 0 when the book is empty. */
285
340
  vwap: number
286
- /** True when the levels could not absorb the requested notional. */
341
+ /** True when the levels could not absorb the requested notional, and for a non-finite notional. */
287
342
  insufficientLiquidity: boolean
288
343
  }
289
344
 
@@ -293,7 +348,8 @@ interface BookWalk {
293
348
  * in array order — the caller passes asks for a buy and bids for a sell, each
294
349
  * already ordered best-price-first. When the book cannot absorb the full
295
350
  * notional, the walk stops at the last level and flags `insufficientLiquidity`,
296
- * returning the best obtainable fill.
351
+ * returning the best obtainable fill. A non-finite `sizeUsd` gives NaN fill
352
+ * fields with `insufficientLiquidity` set.
297
353
  *
298
354
  * @throws {PerpsError} `ValidationError` when a level's `price` or `size`
299
355
  * does not parse to a finite number.
@@ -303,32 +359,47 @@ export function walkOrderbook(
303
359
  levels: OrderbookLevel[],
304
360
  sizeUsd: number
305
361
  ): BookWalk {
306
- let remaining = sizeUsd
307
- let baseSize = 0
308
- let filledNotional = 0
362
+ if (!Number.isFinite(sizeUsd)) {
363
+ return {
364
+ baseSize: Number.NaN,
365
+ filledNotional: Number.NaN,
366
+ vwap: Number.NaN,
367
+ insufficientLiquidity: true,
368
+ }
369
+ }
370
+ let remaining = new DivBig(sizeUsd)
371
+ let baseSize = new DivBig(0)
372
+ let filledNotional = new DivBig(0)
309
373
  for (const level of levels) {
310
- if (remaining <= 0) {
374
+ if (remaining.lte(0)) {
311
375
  break
312
376
  }
313
- const price = Number.parseFloat(level.price)
314
- const size = Number.parseFloat(level.size)
315
- if (!Number.isFinite(price) || !Number.isFinite(size)) {
316
- throw new PerpsError(
317
- PerpsErrorCode.ValidationError,
318
- `Malformed orderbook level: price='${level.price}', size='${level.size}'`
319
- )
377
+ const { price, size } = parseLevel(level)
378
+ const levelNotional = size.times(price)
379
+ const take = remaining.lt(levelNotional) ? remaining : levelNotional
380
+ if (take.eq(0)) {
381
+ continue
320
382
  }
321
- const levelNotional = size * price
322
- const take = Math.min(remaining, levelNotional)
323
- filledNotional += take
324
- baseSize += take / price
325
- remaining -= take
383
+ filledNotional = filledNotional.plus(take)
384
+ baseSize = baseSize.plus(take.div(price))
385
+ remaining = remaining.minus(take)
326
386
  }
327
387
  return {
328
- baseSize,
329
- filledNotional,
330
- vwap: baseSize === 0 ? 0 : filledNotional / baseSize,
331
- insufficientLiquidity: remaining > 0,
388
+ baseSize: baseSize.toNumber(),
389
+ filledNotional: filledNotional.toNumber(),
390
+ vwap: baseSize.eq(0) ? 0 : filledNotional.div(baseSize).toNumber(),
391
+ insufficientLiquidity: remaining.gt(0),
392
+ }
393
+ }
394
+
395
+ function parseLevel(level: OrderbookLevel): { price: Big; size: Big } {
396
+ try {
397
+ return { price: new DivBig(level.price), size: new DivBig(level.size) }
398
+ } catch {
399
+ throw new PerpsError(
400
+ PerpsErrorCode.ValidationError,
401
+ `Malformed orderbook level: price='${level.price}', size='${level.size}'`
402
+ )
332
403
  }
333
404
  }
334
405
 
@@ -0,0 +1,13 @@
1
+ import Big from 'big.js'
2
+
3
+ /**
4
+ * Scoped big.js constructor with 40 decimal places for division, so the
5
+ * shared global `Big.DP` and `Big.RM` stay untouched.
6
+ */
7
+ export const DivBig = Big()
8
+ DivBig.DP = 40
9
+
10
+ /** True when every value is a finite number, so `new DivBig(value)` cannot throw. */
11
+ export function areFinite(...values: number[]): boolean {
12
+ return values.every(Number.isFinite)
13
+ }
@@ -0,0 +1,7 @@
1
+ import type Big from 'big.js'
2
+
3
+ /** The larger of two Big values, as `Math.max` for numbers. */
4
+ export const maxOf = (a: Big, b: Big): Big => (a.gt(b) ? a : b)
5
+
6
+ /** The smaller of two Big values, as `Math.min` for numbers. */
7
+ export const minOf = (a: Big, b: Big): Big => (a.lt(b) ? a : b)
@@ -27,3 +27,28 @@ export function stringToFloat(value: string): number {
27
27
  }
28
28
  return parseFloat(cleaned)
29
29
  }
30
+
31
+ const FORMATTED_NUMBER =
32
+ /^(?:[+-]\s*)?(?:\$\s*)?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?(?:\s*(?:%|USD))?$/i
33
+
34
+ /**
35
+ * Parse an optional decimal field, with the same formatting tolerance as {@link stringToFloat}.
36
+ * Gives back `undefined` for a missing, malformed or non-finite value, and `0` for an empty string.
37
+ *
38
+ * @public
39
+ */
40
+ export function parseDecimal(
41
+ value: string | null | undefined
42
+ ): number | undefined {
43
+ if (value == null) {
44
+ return undefined
45
+ }
46
+ if (value.trim() === '') {
47
+ return stringToFloat(value)
48
+ }
49
+ if (!FORMATTED_NUMBER.test(value.trim())) {
50
+ return undefined
51
+ }
52
+ const parsed = stringToFloat(value)
53
+ return Number.isFinite(parsed) ? parsed : undefined
54
+ }
@@ -6,6 +6,8 @@
6
6
  * always non-negative magnitudes; direction is carried by `isLong`.
7
7
  */
8
8
 
9
+ import { areFinite, DivBig } from './decimal.js'
10
+
9
11
  /**
10
12
  * Direction sign for a position.
11
13
  *
@@ -50,8 +52,39 @@ export function estimateIsolatedLiquidationPrice(params: {
50
52
  if (denominator === 0) {
51
53
  return undefined
52
54
  }
53
- const marginAvailable = entryPrice * (1 / leverage - maintenanceMarginRate)
54
- return entryPrice - (side * marginAvailable) / denominator
55
+ if (!areFinite(entryPrice, leverage, maintenanceMarginRate)) {
56
+ return Number.NaN
57
+ }
58
+ const mmr = new DivBig(maintenanceMarginRate)
59
+ const marginAvailable = new DivBig(1)
60
+ .div(leverage)
61
+ .minus(mmr)
62
+ .times(entryPrice)
63
+ return new DivBig(entryPrice)
64
+ .minus(marginAvailable.times(side).div(mmr.times(-side).plus(1)))
65
+ .toNumber()
66
+ }
67
+
68
+ /**
69
+ * Whether an isolated position with this liquidation price is already past
70
+ * liquidation at `currentPrice`: a long liquidates when the price falls to its
71
+ * liquidation level, a short when it rises to it. A non-positive price on
72
+ * either side counts as unknown, so the result is `false`.
73
+ *
74
+ * @public
75
+ */
76
+ export function wouldImmediatelyLiquidate(params: {
77
+ liquidationPrice: number
78
+ currentPrice: number
79
+ isLong: boolean
80
+ }): boolean {
81
+ const { liquidationPrice, currentPrice, isLong } = params
82
+ if (currentPrice <= 0 || liquidationPrice <= 0) {
83
+ return false
84
+ }
85
+ return isLong
86
+ ? liquidationPrice >= currentPrice
87
+ : liquidationPrice <= currentPrice
55
88
  }
56
89
 
57
90
  /**
@@ -84,7 +117,14 @@ export function predictAverageEntryPrice(params: {
84
117
  if (!Number.isFinite(currentEntry) || !Number.isFinite(fillPrice)) {
85
118
  return undefined
86
119
  }
87
- return (currentSize * currentEntry + addSize * fillPrice) / totalSize
120
+ if (!areFinite(currentSize, addSize)) {
121
+ return Number.NaN
122
+ }
123
+ return new DivBig(currentSize)
124
+ .times(currentEntry)
125
+ .plus(new DivBig(addSize).times(fillPrice))
126
+ .div(new DivBig(currentSize).plus(addSize))
127
+ .toNumber()
88
128
  }
89
129
 
90
130
  /**
@@ -109,7 +149,13 @@ export function predictNewLeverage(params: {
109
149
  if (totalMargin <= 0) {
110
150
  return undefined
111
151
  }
112
- return (currentNotional + addNotional) / totalMargin
152
+ if (!areFinite(currentNotional, currentMargin, addNotional, addMargin)) {
153
+ return Number.NaN
154
+ }
155
+ return new DivBig(currentNotional)
156
+ .plus(addNotional)
157
+ .div(new DivBig(currentMargin).plus(addMargin))
158
+ .toNumber()
113
159
  }
114
160
 
115
161
  /**
@@ -127,7 +173,14 @@ export function predictUnrealizedPnl(params: {
127
173
  isLong: boolean
128
174
  }): number {
129
175
  const { entryPrice, markPrice, size, isLong } = params
130
- return (markPrice - entryPrice) * size * directionSign(isLong)
176
+ if (!areFinite(entryPrice, markPrice, size)) {
177
+ return Number.NaN
178
+ }
179
+ return new DivBig(markPrice)
180
+ .minus(entryPrice)
181
+ .times(size)
182
+ .times(directionSign(isLong))
183
+ .toNumber()
131
184
  }
132
185
 
133
186
  /**
@@ -145,5 +198,12 @@ export function realizedPnlOnClose(params: {
145
198
  isLong: boolean
146
199
  }): number {
147
200
  const { entryPrice, closePrice, closeSize, isLong } = params
148
- return (closePrice - entryPrice) * closeSize * directionSign(isLong)
201
+ if (!areFinite(entryPrice, closePrice, closeSize)) {
202
+ return Number.NaN
203
+ }
204
+ return new DivBig(closePrice)
205
+ .minus(entryPrice)
206
+ .times(closeSize)
207
+ .times(directionSign(isLong))
208
+ .toNumber()
149
209
  }
package/src/version.ts CHANGED
@@ -10,4 +10,4 @@ export const name = '@lifi/perps-sdk'
10
10
  *
11
11
  * @public
12
12
  */
13
- export const version = '19.0.0'
13
+ export const version = '20.0.0'
@@ -20,13 +20,6 @@ export interface WsProviderFactoryParams {
20
20
  provider: string
21
21
  /** WS URL discovered from `/providers`. */
22
22
  wsUrl: string
23
- /**
24
- * Markets visible to this provider via `/providers`, optionally filtered
25
- * by the consumer's `createPerpsClient({ providers: { [key]: { markets } } })`
26
- * config. Each provider interprets these its own way — Hyperliquid uses
27
- * them to decide which sub-DEXes to subscribe to; Lighter ignores them.
28
- */
29
- markets: string[]
30
23
  /**
31
24
  * The SDK client. WS providers use it to call core services (e.g.
32
25
  * `getAssets` to source the wire-id ↔ display-symbol map) without
@@ -235,21 +228,9 @@ export class PerpsWsClient {
235
228
  throw new Error(`No WebSocket URL found for provider: ${provider}`)
236
229
  }
237
230
 
238
- const allMarkets = (providerInfo.categories ?? []) as Array<{
239
- id: string
240
- }>
241
- const providerConfig = this.client.config.providers?.[provider]
242
- const configuredMarkets = providerConfig?.markets
243
- const markets = (
244
- configuredMarkets
245
- ? allMarkets.filter((m) => configuredMarkets.includes(m.id))
246
- : allMarkets
247
- ).map((m) => m.id)
248
-
249
231
  const wsProvider = factory({
250
232
  provider,
251
233
  wsUrl: providerInfo.wsUrl,
252
- markets,
253
234
  client: this.client,
254
235
  })
255
236
  this.providers.set(provider, wsProvider)