@lifi/perps-sdk 23.1.0 → 25.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 (305) hide show
  1. package/README.md +102 -56
  2. package/dist/cjs/client/PerpsClient.d.ts +3 -2
  3. package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
  4. package/dist/cjs/client/PerpsClient.js +16 -9
  5. package/dist/cjs/client/PerpsClient.js.map +1 -1
  6. package/dist/cjs/decimal/arithmetic.d.ts +15 -0
  7. package/dist/cjs/decimal/arithmetic.d.ts.map +1 -0
  8. package/dist/cjs/decimal/arithmetic.js +53 -0
  9. package/dist/cjs/decimal/arithmetic.js.map +1 -0
  10. package/dist/cjs/decimal/big.d.ts +0 -1
  11. package/dist/cjs/decimal/big.d.ts.map +1 -1
  12. package/dist/cjs/decimal/big.js +0 -4
  13. package/dist/cjs/decimal/big.js.map +1 -1
  14. package/dist/cjs/decimal/compare.d.ts +6 -2
  15. package/dist/cjs/decimal/compare.d.ts.map +1 -1
  16. package/dist/cjs/decimal/compare.js +15 -2
  17. package/dist/cjs/decimal/compare.js.map +1 -1
  18. package/dist/cjs/decimal/convert.d.ts +10 -6
  19. package/dist/cjs/decimal/convert.d.ts.map +1 -1
  20. package/dist/cjs/decimal/convert.js +34 -21
  21. package/dist/cjs/decimal/convert.js.map +1 -1
  22. package/dist/cjs/decimal/decimalStringToBig.d.ts +5 -0
  23. package/dist/cjs/decimal/decimalStringToBig.d.ts.map +1 -0
  24. package/dist/cjs/decimal/decimalStringToBig.js +25 -0
  25. package/dist/cjs/decimal/decimalStringToBig.js.map +1 -0
  26. package/dist/cjs/decimal/format.d.ts.map +1 -1
  27. package/dist/cjs/decimal/format.js +70 -52
  28. package/dist/cjs/decimal/format.js.map +1 -1
  29. package/dist/cjs/decimal/parse.d.ts +5 -4
  30. package/dist/cjs/decimal/parse.d.ts.map +1 -1
  31. package/dist/cjs/decimal/parse.js +43 -25
  32. package/dist/cjs/decimal/parse.js.map +1 -1
  33. package/dist/cjs/errors/invalidInput.d.ts +3 -0
  34. package/dist/cjs/errors/invalidInput.d.ts.map +1 -0
  35. package/dist/cjs/errors/invalidInput.js +9 -0
  36. package/dist/cjs/errors/invalidInput.js.map +1 -0
  37. package/dist/cjs/index.d.ts +15 -12
  38. package/dist/cjs/index.d.ts.map +1 -1
  39. package/dist/cjs/index.js +69 -9
  40. package/dist/cjs/index.js.map +1 -1
  41. package/dist/cjs/math/fills.d.ts +1 -1
  42. package/dist/cjs/math/fills.d.ts.map +1 -1
  43. package/dist/cjs/math/fills.js +28 -13
  44. package/dist/cjs/math/fills.js.map +1 -1
  45. package/dist/cjs/math/order.d.ts +27 -16
  46. package/dist/cjs/math/order.d.ts.map +1 -1
  47. package/dist/cjs/math/order.js +131 -134
  48. package/dist/cjs/math/order.js.map +1 -1
  49. package/dist/cjs/math/position.d.ts +85 -35
  50. package/dist/cjs/math/position.d.ts.map +1 -1
  51. package/dist/cjs/math/position.js +93 -94
  52. package/dist/cjs/math/position.js.map +1 -1
  53. package/dist/cjs/services/getGasRecommendation.js +1 -1
  54. package/dist/cjs/services/getGasRecommendation.js.map +1 -1
  55. package/dist/cjs/services/getQuote.d.ts +1 -1
  56. package/dist/cjs/services/resolveSubscribeQuote.d.ts.map +1 -1
  57. package/dist/cjs/services/resolveSubscribeQuote.js +3 -2
  58. package/dist/cjs/services/resolveSubscribeQuote.js.map +1 -1
  59. package/dist/cjs/transport/request.d.ts +1 -0
  60. package/dist/cjs/transport/request.d.ts.map +1 -1
  61. package/dist/cjs/transport/request.js +2 -2
  62. package/dist/cjs/transport/request.js.map +1 -1
  63. package/dist/cjs/types/api.d.ts +4 -0
  64. package/dist/cjs/types/api.d.ts.map +1 -1
  65. package/dist/cjs/types/provider.d.ts +9 -5
  66. package/dist/cjs/types/provider.d.ts.map +1 -1
  67. package/dist/cjs/types/withdrawal.d.ts +12 -4
  68. package/dist/cjs/types/withdrawal.d.ts.map +1 -1
  69. package/dist/cjs/utils/createSafeFunction.d.ts +2 -0
  70. package/dist/cjs/utils/createSafeFunction.d.ts.map +1 -0
  71. package/dist/cjs/utils/createSafeFunction.js +15 -0
  72. package/dist/cjs/utils/createSafeFunction.js.map +1 -0
  73. package/dist/cjs/utils/timestampToIsoString.d.ts +3 -0
  74. package/dist/cjs/utils/timestampToIsoString.d.ts.map +1 -0
  75. package/dist/cjs/utils/timestampToIsoString.js +16 -0
  76. package/dist/cjs/utils/timestampToIsoString.js.map +1 -0
  77. package/dist/cjs/utils/warnOnce.d.ts +6 -0
  78. package/dist/cjs/utils/warnOnce.d.ts.map +1 -1
  79. package/dist/cjs/utils/warnOnce.js +19 -1
  80. package/dist/cjs/utils/warnOnce.js.map +1 -1
  81. package/dist/cjs/version.d.ts +1 -1
  82. package/dist/cjs/version.js +1 -1
  83. package/dist/cjs/websocket/PerpsWsClient.d.ts +2 -0
  84. package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
  85. package/dist/cjs/websocket/PerpsWsClient.js +14 -1
  86. package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
  87. package/dist/cjs/websocket/wsLog.d.ts +2 -0
  88. package/dist/cjs/websocket/wsLog.d.ts.map +1 -1
  89. package/dist/cjs/websocket/wsLog.js +9 -0
  90. package/dist/cjs/websocket/wsLog.js.map +1 -1
  91. package/dist/cjs/wire/orderAmounts.d.ts +3 -2
  92. package/dist/cjs/wire/orderAmounts.d.ts.map +1 -1
  93. package/dist/cjs/wire/orderAmounts.js +22 -21
  94. package/dist/cjs/wire/orderAmounts.js.map +1 -1
  95. package/dist/cjs/wire/refuel.d.ts +4 -1
  96. package/dist/cjs/wire/refuel.d.ts.map +1 -1
  97. package/dist/cjs/wire/refuel.js +23 -6
  98. package/dist/cjs/wire/refuel.js.map +1 -1
  99. package/dist/cjs/wire/transferable.js +3 -3
  100. package/dist/cjs/wire/transferable.js.map +1 -1
  101. package/dist/cjs/wire/withdraw.d.ts.map +1 -1
  102. package/dist/cjs/wire/withdraw.js +3 -3
  103. package/dist/cjs/wire/withdraw.js.map +1 -1
  104. package/dist/esm/client/PerpsClient.d.ts +17 -4
  105. package/dist/esm/client/PerpsClient.d.ts.map +1 -1
  106. package/dist/esm/client/PerpsClient.js +30 -8
  107. package/dist/esm/client/PerpsClient.js.map +1 -1
  108. package/dist/esm/decimal/arithmetic.d.ts +98 -0
  109. package/dist/esm/decimal/arithmetic.d.ts.map +1 -0
  110. package/dist/esm/decimal/arithmetic.js +126 -0
  111. package/dist/esm/decimal/arithmetic.js.map +1 -0
  112. package/dist/esm/decimal/big.d.ts +0 -2
  113. package/dist/esm/decimal/big.d.ts.map +1 -1
  114. package/dist/esm/decimal/big.js +0 -4
  115. package/dist/esm/decimal/big.js.map +1 -1
  116. package/dist/esm/decimal/compare.d.ts +40 -6
  117. package/dist/esm/decimal/compare.d.ts.map +1 -1
  118. package/dist/esm/decimal/compare.js +46 -6
  119. package/dist/esm/decimal/compare.js.map +1 -1
  120. package/dist/esm/decimal/convert.d.ts +50 -36
  121. package/dist/esm/decimal/convert.d.ts.map +1 -1
  122. package/dist/esm/decimal/convert.js +64 -42
  123. package/dist/esm/decimal/convert.js.map +1 -1
  124. package/dist/esm/decimal/decimalStringToBig.d.ts +25 -0
  125. package/dist/esm/decimal/decimalStringToBig.d.ts.map +1 -0
  126. package/dist/esm/decimal/decimalStringToBig.js +37 -0
  127. package/dist/esm/decimal/decimalStringToBig.js.map +1 -0
  128. package/dist/esm/decimal/format.d.ts +4 -1
  129. package/dist/esm/decimal/format.d.ts.map +1 -1
  130. package/dist/esm/decimal/format.js +71 -70
  131. package/dist/esm/decimal/format.js.map +1 -1
  132. package/dist/esm/decimal/parse.d.ts +29 -13
  133. package/dist/esm/decimal/parse.d.ts.map +1 -1
  134. package/dist/esm/decimal/parse.js +61 -44
  135. package/dist/esm/decimal/parse.js.map +1 -1
  136. package/dist/esm/errors/invalidInput.d.ts +4 -0
  137. package/dist/esm/errors/invalidInput.d.ts.map +1 -0
  138. package/dist/esm/errors/invalidInput.js +7 -0
  139. package/dist/esm/errors/invalidInput.js.map +1 -0
  140. package/dist/esm/index.d.ts +15 -12
  141. package/dist/esm/index.d.ts.map +1 -1
  142. package/dist/esm/index.js +11 -8
  143. package/dist/esm/index.js.map +1 -1
  144. package/dist/esm/math/fills.d.ts +6 -3
  145. package/dist/esm/math/fills.d.ts.map +1 -1
  146. package/dist/esm/math/fills.js +31 -16
  147. package/dist/esm/math/fills.js.map +1 -1
  148. package/dist/esm/math/order.d.ts +84 -66
  149. package/dist/esm/math/order.d.ts.map +1 -1
  150. package/dist/esm/math/order.js +178 -175
  151. package/dist/esm/math/order.js.map +1 -1
  152. package/dist/esm/math/position.d.ts +155 -98
  153. package/dist/esm/math/position.d.ts.map +1 -1
  154. package/dist/esm/math/position.js +160 -156
  155. package/dist/esm/math/position.js.map +1 -1
  156. package/dist/esm/services/getGasRecommendation.js +1 -1
  157. package/dist/esm/services/getGasRecommendation.js.map +1 -1
  158. package/dist/esm/services/getQuote.d.ts +2 -2
  159. package/dist/esm/services/getQuote.js +1 -1
  160. package/dist/esm/services/resolveSubscribeQuote.d.ts +1 -1
  161. package/dist/esm/services/resolveSubscribeQuote.d.ts.map +1 -1
  162. package/dist/esm/services/resolveSubscribeQuote.js +4 -3
  163. package/dist/esm/services/resolveSubscribeQuote.js.map +1 -1
  164. package/dist/esm/transport/request.d.ts +5 -0
  165. package/dist/esm/transport/request.d.ts.map +1 -1
  166. package/dist/esm/transport/request.js +2 -2
  167. package/dist/esm/transport/request.js.map +1 -1
  168. package/dist/esm/types/api.d.ts +9 -0
  169. package/dist/esm/types/api.d.ts.map +1 -1
  170. package/dist/esm/types/provider.d.ts +30 -16
  171. package/dist/esm/types/provider.d.ts.map +1 -1
  172. package/dist/esm/types/withdrawal.d.ts +32 -7
  173. package/dist/esm/types/withdrawal.d.ts.map +1 -1
  174. package/dist/esm/utils/createSafeFunction.d.ts +9 -0
  175. package/dist/esm/utils/createSafeFunction.d.ts.map +1 -0
  176. package/dist/esm/utils/createSafeFunction.js +19 -0
  177. package/dist/esm/utils/createSafeFunction.js.map +1 -0
  178. package/dist/esm/utils/timestampToIsoString.d.ts +15 -0
  179. package/dist/esm/utils/timestampToIsoString.d.ts.map +1 -0
  180. package/dist/esm/utils/timestampToIsoString.js +24 -0
  181. package/dist/esm/utils/timestampToIsoString.js.map +1 -0
  182. package/dist/esm/utils/warnOnce.d.ts +27 -0
  183. package/dist/esm/utils/warnOnce.d.ts.map +1 -1
  184. package/dist/esm/utils/warnOnce.js +36 -0
  185. package/dist/esm/utils/warnOnce.js.map +1 -1
  186. package/dist/esm/version.d.ts +1 -1
  187. package/dist/esm/version.js +1 -1
  188. package/dist/esm/websocket/PerpsWsClient.d.ts +7 -0
  189. package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
  190. package/dist/esm/websocket/PerpsWsClient.js +20 -2
  191. package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
  192. package/dist/esm/websocket/wsLog.d.ts +12 -0
  193. package/dist/esm/websocket/wsLog.d.ts.map +1 -1
  194. package/dist/esm/websocket/wsLog.js +19 -0
  195. package/dist/esm/websocket/wsLog.js.map +1 -1
  196. package/dist/esm/wire/orderAmounts.d.ts +9 -7
  197. package/dist/esm/wire/orderAmounts.d.ts.map +1 -1
  198. package/dist/esm/wire/orderAmounts.js +24 -20
  199. package/dist/esm/wire/orderAmounts.js.map +1 -1
  200. package/dist/esm/wire/refuel.d.ts +24 -14
  201. package/dist/esm/wire/refuel.d.ts.map +1 -1
  202. package/dist/esm/wire/refuel.js +38 -17
  203. package/dist/esm/wire/refuel.js.map +1 -1
  204. package/dist/esm/wire/transferable.d.ts +2 -2
  205. package/dist/esm/wire/transferable.js +5 -5
  206. package/dist/esm/wire/transferable.js.map +1 -1
  207. package/dist/esm/wire/withdraw.d.ts.map +1 -1
  208. package/dist/esm/wire/withdraw.js +3 -3
  209. package/dist/esm/wire/withdraw.js.map +1 -1
  210. package/dist/types/client/PerpsClient.d.ts +17 -4
  211. package/dist/types/client/PerpsClient.d.ts.map +1 -1
  212. package/dist/types/decimal/arithmetic.d.ts +98 -0
  213. package/dist/types/decimal/arithmetic.d.ts.map +1 -0
  214. package/dist/types/decimal/big.d.ts +0 -2
  215. package/dist/types/decimal/big.d.ts.map +1 -1
  216. package/dist/types/decimal/compare.d.ts +40 -6
  217. package/dist/types/decimal/compare.d.ts.map +1 -1
  218. package/dist/types/decimal/convert.d.ts +50 -36
  219. package/dist/types/decimal/convert.d.ts.map +1 -1
  220. package/dist/types/decimal/decimalStringToBig.d.ts +25 -0
  221. package/dist/types/decimal/decimalStringToBig.d.ts.map +1 -0
  222. package/dist/types/decimal/format.d.ts +4 -1
  223. package/dist/types/decimal/format.d.ts.map +1 -1
  224. package/dist/types/decimal/parse.d.ts +29 -13
  225. package/dist/types/decimal/parse.d.ts.map +1 -1
  226. package/dist/types/errors/invalidInput.d.ts +4 -0
  227. package/dist/types/errors/invalidInput.d.ts.map +1 -0
  228. package/dist/types/index.d.ts +15 -12
  229. package/dist/types/index.d.ts.map +1 -1
  230. package/dist/types/math/fills.d.ts +6 -3
  231. package/dist/types/math/fills.d.ts.map +1 -1
  232. package/dist/types/math/order.d.ts +84 -66
  233. package/dist/types/math/order.d.ts.map +1 -1
  234. package/dist/types/math/position.d.ts +155 -98
  235. package/dist/types/math/position.d.ts.map +1 -1
  236. package/dist/types/services/getQuote.d.ts +2 -2
  237. package/dist/types/services/resolveSubscribeQuote.d.ts +1 -1
  238. package/dist/types/services/resolveSubscribeQuote.d.ts.map +1 -1
  239. package/dist/types/transport/request.d.ts +5 -0
  240. package/dist/types/transport/request.d.ts.map +1 -1
  241. package/dist/types/types/api.d.ts +9 -0
  242. package/dist/types/types/api.d.ts.map +1 -1
  243. package/dist/types/types/provider.d.ts +30 -16
  244. package/dist/types/types/provider.d.ts.map +1 -1
  245. package/dist/types/types/withdrawal.d.ts +32 -7
  246. package/dist/types/types/withdrawal.d.ts.map +1 -1
  247. package/dist/types/utils/createSafeFunction.d.ts +9 -0
  248. package/dist/types/utils/createSafeFunction.d.ts.map +1 -0
  249. package/dist/types/utils/timestampToIsoString.d.ts +15 -0
  250. package/dist/types/utils/timestampToIsoString.d.ts.map +1 -0
  251. package/dist/types/utils/warnOnce.d.ts +27 -0
  252. package/dist/types/utils/warnOnce.d.ts.map +1 -1
  253. package/dist/types/version.d.ts +1 -1
  254. package/dist/types/websocket/PerpsWsClient.d.ts +7 -0
  255. package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
  256. package/dist/types/websocket/wsLog.d.ts +12 -0
  257. package/dist/types/websocket/wsLog.d.ts.map +1 -1
  258. package/dist/types/wire/orderAmounts.d.ts +9 -7
  259. package/dist/types/wire/orderAmounts.d.ts.map +1 -1
  260. package/dist/types/wire/refuel.d.ts +24 -14
  261. package/dist/types/wire/refuel.d.ts.map +1 -1
  262. package/dist/types/wire/transferable.d.ts +2 -2
  263. package/dist/types/wire/withdraw.d.ts.map +1 -1
  264. package/package.json +2 -2
  265. package/src/client/PerpsClient.ts +48 -10
  266. package/src/decimal/arithmetic.ts +170 -0
  267. package/src/decimal/big.ts +0 -5
  268. package/src/decimal/compare.ts +61 -11
  269. package/src/decimal/convert.ts +105 -63
  270. package/src/decimal/decimalStringToBig.ts +42 -0
  271. package/src/decimal/format.ts +81 -72
  272. package/src/decimal/parse.ts +78 -57
  273. package/src/errors/invalidInput.ts +10 -0
  274. package/src/index.ts +80 -12
  275. package/src/math/fills.ts +32 -17
  276. package/src/math/order.ts +279 -226
  277. package/src/math/position.ts +280 -196
  278. package/src/services/getGasRecommendation.ts +1 -1
  279. package/src/services/getQuote.ts +2 -2
  280. package/src/services/resolveSubscribeQuote.ts +4 -3
  281. package/src/transport/request.ts +7 -2
  282. package/src/types/api.ts +10 -0
  283. package/src/types/provider.ts +39 -16
  284. package/src/types/withdrawal.ts +35 -8
  285. package/src/utils/createSafeFunction.ts +20 -0
  286. package/src/utils/timestampToIsoString.ts +31 -0
  287. package/src/utils/warnOnce.ts +60 -0
  288. package/src/version.ts +1 -1
  289. package/src/websocket/PerpsWsClient.ts +25 -2
  290. package/src/websocket/wsLog.ts +44 -0
  291. package/src/wire/orderAmounts.ts +45 -26
  292. package/src/wire/refuel.ts +56 -20
  293. package/src/wire/transferable.ts +5 -5
  294. package/src/wire/withdraw.ts +3 -5
  295. package/dist/cjs/decimal/requireDecimal.d.ts +0 -4
  296. package/dist/cjs/decimal/requireDecimal.d.ts.map +0 -1
  297. package/dist/cjs/decimal/requireDecimal.js +0 -12
  298. package/dist/cjs/decimal/requireDecimal.js.map +0 -1
  299. package/dist/esm/decimal/requireDecimal.d.ts +0 -5
  300. package/dist/esm/decimal/requireDecimal.d.ts.map +0 -1
  301. package/dist/esm/decimal/requireDecimal.js +0 -7
  302. package/dist/esm/decimal/requireDecimal.js.map +0 -1
  303. package/dist/types/decimal/requireDecimal.d.ts +0 -5
  304. package/dist/types/decimal/requireDecimal.d.ts.map +0 -1
  305. package/src/decimal/requireDecimal.ts +0 -8
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Display-tier position formulas and margin-adjustment predicates. Every
3
- * formula takes and gives `number`; exact decimal arithmetic happens
4
- * internally with `DivBig`.
3
+ * formula takes and gives decimal strings; arithmetic is exact Big.js, with
4
+ * division to 40 decimal places. Each formula throws `ValidationError` on an
5
+ * input that does not match the decimal pattern and has a `safe*` pair that gives
6
+ * `undefined` in place of the throw.
5
7
  *
6
8
  * Sign convention: long = +1, short = -1. Sizes passed to the `estimate*`
7
9
  * helpers are always non-negative magnitudes; direction is carried by
@@ -10,318 +12,400 @@
10
12
 
11
13
  import {
12
14
  MarginMode,
15
+ type PerpsMarket,
13
16
  type Position,
14
17
  PositionMarginAdjustment,
15
18
  } from '@lifi/perps-types'
16
- import { areFinite, DivBig } from '../decimal/big.js'
19
+ import { DivBig } from '../decimal/big.js'
20
+ import {
21
+ bigToDecimalString,
22
+ decimalStringToBig,
23
+ decimalStringToDivBig,
24
+ } from '../decimal/decimalStringToBig.js'
25
+ import { invalidInput } from '../errors/invalidInput.js'
26
+ import type { LiquidationEstimateParams } from '../types/provider.js'
27
+ import { createSafeFunction } from '../utils/createSafeFunction.js'
17
28
 
18
29
  /**
19
- * Calculate notional value of a position.
30
+ * Notional value of a position: `|size| × price`.
20
31
  *
21
- * @param size - Position size in asset units
22
- * @param price - Current asset price
23
- * @returns Notional value in USD
32
+ * @throws {PerpsError} `ValidationError` when an input does not match the decimal pattern.
24
33
  * @public
25
34
  */
26
- export function calculateNotionalValue(size: number, price: number): number {
27
- if (!areFinite(size, price)) {
28
- return Number.NaN
29
- }
30
- return new DivBig(size).abs().times(price).toNumber()
35
+ export function calculateNotionalValue(size: string, price: string): string {
36
+ return bigToDecimalString(
37
+ decimalStringToBig(size).abs().times(decimalStringToBig(price))
38
+ )
31
39
  }
32
40
 
41
+ /** @public */
42
+ export const safeCalculateNotionalValue = createSafeFunction(
43
+ 'calculateNotionalValue',
44
+ calculateNotionalValue
45
+ )
46
+
33
47
  /**
34
- * Calculate unrealized PnL.
48
+ * Unrealized PnL: `(currentPrice - entryPrice) × size`, where `size` is
49
+ * positive for a long and negative for a short.
35
50
  *
36
- * @param entryPrice - Position entry price
37
- * @param currentPrice - Current market price
38
- * @param size - Position size (positive for long, negative for short)
39
- * @returns Unrealized PnL in USD
51
+ * @throws {PerpsError} `ValidationError` when an input does not match the decimal pattern.
40
52
  * @public
41
53
  */
42
54
  export function calculateUnrealizedPnl(
43
- entryPrice: number,
44
- currentPrice: number,
45
- size: number
46
- ): number {
47
- if (!areFinite(entryPrice, currentPrice, size)) {
48
- return Number.NaN
49
- }
50
- return new DivBig(currentPrice).minus(entryPrice).times(size).toNumber()
55
+ entryPrice: string,
56
+ currentPrice: string,
57
+ size: string
58
+ ): string {
59
+ return bigToDecimalString(
60
+ decimalStringToBig(currentPrice)
61
+ .minus(decimalStringToBig(entryPrice))
62
+ .times(decimalStringToBig(size))
63
+ )
51
64
  }
52
65
 
66
+ /** @public */
67
+ export const safeCalculateUnrealizedPnl = createSafeFunction(
68
+ 'calculateUnrealizedPnl',
69
+ calculateUnrealizedPnl
70
+ )
71
+
53
72
  /**
54
- * Calculate return on equity (ROE) percentage.
73
+ * Return on equity as a percentage (`'10'` for 10%): `pnl ÷ margin × 100`.
55
74
  *
56
- * @param pnl - Profit/loss in USD
57
- * @param margin - Initial margin in USD
58
- * @returns ROE as percentage (e.g., 10 for 10%)
75
+ * @throws {PerpsError} `ValidationError` when an input does not match the
76
+ * decimal pattern or `margin` is zero.
59
77
  * @public
60
78
  */
61
- export function calculateRoe(pnl: number, margin: number): number {
62
- if (margin === 0) {
63
- return 0
79
+ export function calculateRoe(pnl: string, margin: string): string {
80
+ const marginBig = decimalStringToBig(margin)
81
+ const pnlBig = decimalStringToDivBig(pnl)
82
+ if (marginBig.eq(0)) {
83
+ throw invalidInput('margin', 'must not be zero')
64
84
  }
65
- if (!areFinite(pnl, margin)) {
66
- return Number.NaN
67
- }
68
- return new DivBig(pnl).div(margin).times(100).toNumber()
85
+ return bigToDecimalString(pnlBig.div(marginBig).times(100))
69
86
  }
70
87
 
88
+ /** @public */
89
+ export const safeCalculateRoe = createSafeFunction('calculateRoe', calculateRoe)
90
+
71
91
  /**
72
- * Calculate required margin for a position.
92
+ * Required margin: `notionalValue ÷ leverage`.
73
93
  *
74
- * @param notionalValue - Position notional value in USD
75
- * @param leverage - Position leverage
76
- * @returns Required margin in USD
94
+ * @throws {PerpsError} `ValidationError` when an input does not match the decimal pattern
95
+ * or `leverage` is zero.
77
96
  * @public
78
97
  */
79
98
  export function calculateRequiredMargin(
80
- notionalValue: number,
81
- leverage: number
82
- ): number {
83
- if (leverage === 0) {
84
- return notionalValue / leverage
85
- }
86
- if (!areFinite(notionalValue, leverage)) {
87
- return Number.NaN
99
+ notionalValue: string,
100
+ leverage: string
101
+ ): string {
102
+ const notionalBig = decimalStringToDivBig(notionalValue)
103
+ const leverageBig = decimalStringToBig(leverage)
104
+ if (leverageBig.eq(0)) {
105
+ throw invalidInput('leverage', 'must not be zero')
88
106
  }
89
- return new DivBig(notionalValue).div(leverage).toNumber()
107
+ return bigToDecimalString(notionalBig.div(leverageBig))
90
108
  }
91
109
 
110
+ /** @public */
111
+ export const safeCalculateRequiredMargin = createSafeFunction(
112
+ 'calculateRequiredMargin',
113
+ calculateRequiredMargin
114
+ )
115
+
92
116
  /**
93
- * Distance from the current price to the liquidation price, as a percentage of
94
- * the current price.
117
+ * Distance from the current price to the liquidation price, as an absolute
118
+ * percentage of the current price.
95
119
  *
96
- * @param liquidationPrice - The position's liquidation price
97
- * @param currentPrice - Current market price
98
- * @returns Absolute distance as a percentage, or 0 when current price is zero
120
+ * @throws {PerpsError} `ValidationError` when an input does not match the
121
+ * decimal pattern or `currentPrice` is zero.
99
122
  * @public
100
123
  */
101
124
  export function calculateLiquidationDistance(params: {
102
- liquidationPrice: number
103
- currentPrice: number
104
- }): number {
105
- const { liquidationPrice, currentPrice } = params
106
- if (currentPrice === 0) {
107
- return 0
125
+ liquidationPrice: string
126
+ currentPrice: string
127
+ }): string {
128
+ const liquidationPrice = decimalStringToDivBig(params.liquidationPrice)
129
+ const currentPrice = decimalStringToBig(params.currentPrice)
130
+ if (currentPrice.eq(0)) {
131
+ throw invalidInput('currentPrice', 'must not be zero')
108
132
  }
109
- return Math.abs((liquidationPrice - currentPrice) / currentPrice) * 100
133
+ return bigToDecimalString(
134
+ liquidationPrice.minus(currentPrice).div(currentPrice).abs().times(100)
135
+ )
110
136
  }
111
137
 
138
+ /** @public */
139
+ export const safeCalculateLiquidationDistance = createSafeFunction(
140
+ 'calculateLiquidationDistance',
141
+ calculateLiquidationDistance
142
+ )
143
+
112
144
  /**
113
- * Effective leverage of an open position.
145
+ * Effective leverage of an open position: `positionValueUsd ÷ marginUsd`.
114
146
  *
115
- * leverage = positionValueUsd / marginUsd
116
- *
117
- * @param positionValueUsd - Position notional value in USD
118
- * @param marginUsd - Margin backing the position in USD
119
- * @returns Effective leverage, or 0 when margin is zero
147
+ * @throws {PerpsError} `ValidationError` when an input does not match the
148
+ * decimal pattern or `marginUsd` is zero.
120
149
  * @public
121
150
  */
122
151
  export function calculateEffectiveLeverage(params: {
123
- positionValueUsd: number
124
- marginUsd: number
125
- }): number {
126
- const { positionValueUsd, marginUsd } = params
127
- if (marginUsd === 0) {
128
- return 0
129
- }
130
- if (!areFinite(positionValueUsd, marginUsd)) {
131
- return Number.NaN
152
+ positionValueUsd: string
153
+ marginUsd: string
154
+ }): string {
155
+ const positionValue = decimalStringToDivBig(params.positionValueUsd)
156
+ const margin = decimalStringToBig(params.marginUsd)
157
+ if (margin.eq(0)) {
158
+ throw invalidInput('marginUsd', 'must not be zero')
132
159
  }
133
- return new DivBig(positionValueUsd).div(marginUsd).toNumber()
160
+ return bigToDecimalString(positionValue.div(margin))
134
161
  }
135
162
 
163
+ /** @public */
164
+ export const safeCalculateEffectiveLeverage = createSafeFunction(
165
+ 'calculateEffectiveLeverage',
166
+ calculateEffectiveLeverage
167
+ )
168
+
136
169
  /**
137
170
  * Estimated liquidation price for an isolated-margin position, parameterised
138
171
  * by the venue's maintenance margin rate.
139
172
  *
140
173
  * Standard isolated-margin model (new position, no existing exposure):
141
- * margin_per_unit = entryPrice / leverage
142
- * maintenance_per_unit = entryPrice * mmr
143
- * margin_available = margin_per_unit - maintenance_per_unit
144
- * liq_price = entryPrice - side * margin_available / (1 - mmr * side)
174
+ * margin_available = entryPrice × (1 / leverage - mmr)
175
+ * liq_price = entryPrice - side × margin_available / (1 - mmr × side)
145
176
  *
146
177
  * For existing positions, prefer `Position.liquidationPrice` from the venue.
147
178
  *
148
179
  * @param maintenanceMarginRate - Venue maintenance margin rate as a fraction
149
- * (e.g. 0.01 = 1%).
150
- * @returns Estimated liquidation price, or undefined if the inputs cannot
151
- * produce one (zero leverage, degenerate denominator).
180
+ * (`'0.01'` = 1%).
181
+ * @throws {PerpsError} `ValidationError` when an input does not match the
182
+ * decimal pattern, `leverage` is zero, or `maintenanceMarginRate` gives a
183
+ * zero denominator (`1` for a long, `-1` for a short).
152
184
  * @public
153
185
  */
154
186
  export function estimateLiquidationPrice(params: {
155
- entryPrice: number
156
- leverage: number
187
+ entryPrice: string
188
+ leverage: string
157
189
  isLong: boolean
158
- maintenanceMarginRate: number
159
- }): number | undefined {
160
- const { entryPrice, leverage, isLong, maintenanceMarginRate } = params
161
- if (leverage === 0) {
162
- return undefined
190
+ maintenanceMarginRate: string
191
+ }): string {
192
+ const entryPrice = decimalStringToBig(params.entryPrice)
193
+ const leverage = decimalStringToBig(params.leverage)
194
+ const mmr = decimalStringToBig(params.maintenanceMarginRate)
195
+ const side = params.isLong ? 1 : -1
196
+ const denominator = mmr.times(-side).plus(1)
197
+ if (leverage.eq(0)) {
198
+ throw invalidInput('leverage', 'must not be zero')
163
199
  }
164
- const side = isLong ? 1 : -1
165
- const denominator = 1 - maintenanceMarginRate * side
166
- if (denominator === 0) {
167
- return undefined
168
- }
169
- if (!areFinite(entryPrice, leverage, maintenanceMarginRate)) {
170
- return Number.NaN
200
+ if (denominator.eq(0)) {
201
+ throw invalidInput(
202
+ 'maintenanceMarginRate',
203
+ `must not be ${params.isLong ? '1' : '-1'} for this side`
204
+ )
171
205
  }
172
- const mmr = new DivBig(maintenanceMarginRate)
173
206
  const marginAvailable = new DivBig(1)
174
207
  .div(leverage)
175
208
  .minus(mmr)
176
209
  .times(entryPrice)
177
- return new DivBig(entryPrice)
178
- .minus(marginAvailable.times(side).div(mmr.times(-side).plus(1)))
179
- .toNumber()
210
+ return bigToDecimalString(
211
+ entryPrice.minus(marginAvailable.times(side).div(denominator))
212
+ )
213
+ }
214
+
215
+ /** @public */
216
+ export const safeEstimateLiquidationPrice = createSafeFunction(
217
+ 'estimateLiquidationPrice',
218
+ estimateLiquidationPrice
219
+ )
220
+
221
+ /**
222
+ * Estimate the liquidation price of a new isolated position from the flat
223
+ * `market.maintenanceMarginRate`.
224
+ *
225
+ * @returns The estimate, or `undefined` when the market carries no
226
+ * `maintenanceMarginRate`.
227
+ * @throws {PerpsError} `ValidationError` on an input that
228
+ * {@link estimateLiquidationPrice} rejects.
229
+ * @public
230
+ */
231
+ export function estimateLiquidationPriceAtMarketRate(
232
+ market: PerpsMarket,
233
+ params: LiquidationEstimateParams
234
+ ): string | undefined {
235
+ if (market.maintenanceMarginRate === undefined) {
236
+ return undefined
237
+ }
238
+ return estimateLiquidationPrice({
239
+ entryPrice: params.entryPrice,
240
+ leverage: params.leverage,
241
+ isLong: params.isLong,
242
+ maintenanceMarginRate: market.maintenanceMarginRate,
243
+ })
180
244
  }
181
245
 
246
+ /** @public */
247
+ export const safeEstimateLiquidationPriceAtMarketRate = createSafeFunction(
248
+ 'estimateLiquidationPriceAtMarketRate',
249
+ estimateLiquidationPriceAtMarketRate
250
+ )
251
+
182
252
  /**
183
253
  * Whether an isolated position with this liquidation price is already past
184
254
  * liquidation at `currentPrice`: a long liquidates when the price falls to its
185
255
  * liquidation level, a short when it rises to it. A non-positive price on
186
256
  * either side counts as unknown, so the result is `false`.
187
257
  *
258
+ * @throws {PerpsError} `ValidationError` when a price does not match the decimal pattern.
188
259
  * @public
189
260
  */
190
261
  export function wouldImmediatelyLiquidate(params: {
191
- liquidationPrice: number
192
- currentPrice: number
262
+ liquidationPrice: string
263
+ currentPrice: string
193
264
  isLong: boolean
194
265
  }): boolean {
195
- const { liquidationPrice, currentPrice, isLong } = params
196
- if (currentPrice <= 0 || liquidationPrice <= 0) {
266
+ const liquidationPrice = decimalStringToBig(params.liquidationPrice)
267
+ const currentPrice = decimalStringToBig(params.currentPrice)
268
+ if (currentPrice.lte(0) || liquidationPrice.lte(0)) {
197
269
  return false
198
270
  }
199
- return isLong
200
- ? liquidationPrice >= currentPrice
201
- : liquidationPrice <= currentPrice
271
+ return params.isLong
272
+ ? liquidationPrice.gte(currentPrice)
273
+ : liquidationPrice.lte(currentPrice)
202
274
  }
203
275
 
276
+ /** @public */
277
+ export const safeWouldImmediatelyLiquidate = createSafeFunction(
278
+ 'wouldImmediatelyLiquidate',
279
+ wouldImmediatelyLiquidate
280
+ )
281
+
204
282
  /**
205
- * Estimated average entry price after adding to an existing position.
206
- *
207
- * Weighted average of the current entry and the new fill price, weighted by
208
- * the size of each leg in coin units. Both legs assumed in the same direction
209
- * (this helper is for adding to, not flipping, a position).
283
+ * Estimated average entry price after adding to an existing position: the
284
+ * size-weighted average of the current entry and the fill price. Both legs
285
+ * are in the same direction (an add, not a flip).
210
286
  *
211
- * @param currentSize - Existing position size in coin units (>= 0).
212
- * @param currentEntry - Existing position's average entry price.
213
- * @param addSize - Size being added in coin units (>= 0).
214
- * @param fillPrice - Price the new size is expected to fill at (mid for
215
- * market, limitPrice for limit orders).
216
- * @returns The new weighted-average entry price, or undefined if the inputs
217
- * cannot produce a valid average (zero combined size, non-finite values).
287
+ * @param fillPrice - Expected fill price (mid for market, limit price for
288
+ * limit orders).
289
+ * @throws {PerpsError} `ValidationError` when an input does not match the
290
+ * decimal pattern or `currentSize + addSize` is not positive.
218
291
  * @public
219
292
  */
220
293
  export function estimateAverageEntryPrice(params: {
221
- currentSize: number
222
- currentEntry: number
223
- addSize: number
224
- fillPrice: number
225
- }): number | undefined {
226
- const { currentSize, currentEntry, addSize, fillPrice } = params
227
- const totalSize = currentSize + addSize
228
- if (totalSize <= 0) {
229
- return undefined
294
+ currentSize: string
295
+ currentEntry: string
296
+ addSize: string
297
+ fillPrice: string
298
+ }): string {
299
+ const currentSize = decimalStringToDivBig(params.currentSize)
300
+ const addSize = decimalStringToBig(params.addSize)
301
+ const currentEntry = decimalStringToBig(params.currentEntry)
302
+ const fillPrice = decimalStringToBig(params.fillPrice)
303
+ const totalSize = currentSize.plus(addSize)
304
+ if (totalSize.lte(0)) {
305
+ throw invalidInput('currentSize + addSize', 'must be positive')
230
306
  }
231
- if (!Number.isFinite(currentEntry) || !Number.isFinite(fillPrice)) {
232
- return undefined
233
- }
234
- if (!areFinite(currentSize, addSize)) {
235
- return Number.NaN
236
- }
237
- return new DivBig(currentSize)
238
- .times(currentEntry)
239
- .plus(new DivBig(addSize).times(fillPrice))
240
- .div(new DivBig(currentSize).plus(addSize))
241
- .toNumber()
307
+ return bigToDecimalString(
308
+ currentSize
309
+ .times(currentEntry)
310
+ .plus(addSize.times(fillPrice))
311
+ .div(totalSize)
312
+ )
242
313
  }
243
314
 
315
+ /** @public */
316
+ export const safeEstimateAverageEntryPrice = createSafeFunction(
317
+ 'estimateAverageEntryPrice',
318
+ estimateAverageEntryPrice
319
+ )
320
+
244
321
  /**
245
- * Estimated effective leverage after adding margin and notional.
246
- *
247
- * leverage = totalNotional / totalMargin. The caller computes notional from
248
- * size and price (`calculateNotionalValue`) and supplies the additional
249
- * margin the user is about to put up.
322
+ * Estimated effective leverage after adding margin and notional:
323
+ * `(currentNotional + addNotional) ÷ (currentMargin + addMargin)`.
250
324
  *
251
- * @returns The new effective leverage, or undefined if total margin is
252
- * non-positive.
325
+ * @throws {PerpsError} `ValidationError` when an input does not match the
326
+ * decimal pattern or `currentMargin + addMargin` is not positive.
253
327
  * @public
254
328
  */
255
329
  export function estimateNewLeverage(params: {
256
- currentNotional: number
257
- currentMargin: number
258
- addNotional: number
259
- addMargin: number
260
- }): number | undefined {
261
- const { currentNotional, currentMargin, addNotional, addMargin } = params
262
- const totalMargin = currentMargin + addMargin
263
- if (totalMargin <= 0) {
264
- return undefined
265
- }
266
- if (!areFinite(currentNotional, currentMargin, addNotional, addMargin)) {
267
- return Number.NaN
330
+ currentNotional: string
331
+ currentMargin: string
332
+ addNotional: string
333
+ addMargin: string
334
+ }): string {
335
+ const totalNotional = decimalStringToDivBig(params.currentNotional).plus(
336
+ decimalStringToBig(params.addNotional)
337
+ )
338
+ const totalMargin = decimalStringToBig(params.currentMargin).plus(
339
+ decimalStringToBig(params.addMargin)
340
+ )
341
+ if (totalMargin.lte(0)) {
342
+ throw invalidInput('currentMargin + addMargin', 'must be positive')
268
343
  }
269
- return new DivBig(currentNotional)
270
- .plus(addNotional)
271
- .div(new DivBig(currentMargin).plus(addMargin))
272
- .toNumber()
344
+ return bigToDecimalString(totalNotional.div(totalMargin))
273
345
  }
274
346
 
347
+ /** @public */
348
+ export const safeEstimateNewLeverage = createSafeFunction(
349
+ 'estimateNewLeverage',
350
+ estimateNewLeverage
351
+ )
352
+
275
353
  /**
276
- * Estimated unrealised PnL at the current mark price.
277
- *
278
- * `pnl = (markPrice - entryPrice) * size * (isLong ? 1 : -1)`
354
+ * Estimated unrealised PnL at the mark price:
355
+ * `(markPrice - entryPrice) × size × (isLong ? 1 : -1)`.
279
356
  *
280
357
  * @param size - Position size as a non-negative magnitude.
358
+ * @throws {PerpsError} `ValidationError` when an input does not match the decimal pattern.
281
359
  * @public
282
360
  */
283
361
  export function estimateUnrealizedPnl(params: {
284
- entryPrice: number
285
- markPrice: number
286
- size: number
362
+ entryPrice: string
363
+ markPrice: string
364
+ size: string
287
365
  isLong: boolean
288
- }): number {
289
- const { entryPrice, markPrice, size, isLong } = params
290
- if (!areFinite(entryPrice, markPrice, size)) {
291
- return Number.NaN
292
- }
293
- return new DivBig(markPrice)
294
- .minus(entryPrice)
295
- .times(size)
296
- .times(isLong ? 1 : -1)
297
- .toNumber()
366
+ }): string {
367
+ return bigToDecimalString(
368
+ decimalStringToBig(params.markPrice)
369
+ .minus(decimalStringToBig(params.entryPrice))
370
+ .times(decimalStringToBig(params.size))
371
+ .times(params.isLong ? 1 : -1)
372
+ )
298
373
  }
299
374
 
375
+ /** @public */
376
+ export const safeEstimateUnrealizedPnl = createSafeFunction(
377
+ 'estimateUnrealizedPnl',
378
+ estimateUnrealizedPnl
379
+ )
380
+
300
381
  /**
301
- * Realised PnL on the portion of a position being closed.
302
- *
303
- * `rPnl = (closePrice - entryPrice) * closeSize * (isLong ? 1 : -1)`
382
+ * Realised PnL on the portion of a position being closed:
383
+ * `(closePrice - entryPrice) × closeSize × (isLong ? 1 : -1)`.
304
384
  *
305
385
  * @param closeSize - Size being closed as a non-negative magnitude.
386
+ * @throws {PerpsError} `ValidationError` when an input does not match the decimal pattern.
306
387
  * @public
307
388
  */
308
389
  export function calculateRealizedPnl(params: {
309
- entryPrice: number
310
- closePrice: number
311
- closeSize: number
390
+ entryPrice: string
391
+ closePrice: string
392
+ closeSize: string
312
393
  isLong: boolean
313
- }): number {
314
- const { entryPrice, closePrice, closeSize, isLong } = params
315
- if (!areFinite(entryPrice, closePrice, closeSize)) {
316
- return Number.NaN
317
- }
318
- return new DivBig(closePrice)
319
- .minus(entryPrice)
320
- .times(closeSize)
321
- .times(isLong ? 1 : -1)
322
- .toNumber()
394
+ }): string {
395
+ return bigToDecimalString(
396
+ decimalStringToBig(params.closePrice)
397
+ .minus(decimalStringToBig(params.entryPrice))
398
+ .times(decimalStringToBig(params.closeSize))
399
+ .times(params.isLong ? 1 : -1)
400
+ )
323
401
  }
324
402
 
403
+ /** @public */
404
+ export const safeCalculateRealizedPnl = createSafeFunction(
405
+ 'calculateRealizedPnl',
406
+ calculateRealizedPnl
407
+ )
408
+
325
409
  /**
326
410
  * Whether this position can take a margin adjustment at all: it holds margin of
327
411
  * its own and its market exposes individual position margin.
@@ -39,7 +39,7 @@ export async function getGasRecommendation(
39
39
  return request<GasRecommendationResponse>(
40
40
  client.config,
41
41
  `${LIFI_API_URL}/gas/suggestion/${params.chainId}`,
42
- {},
42
+ { perpsSdkHeader: false },
43
43
  options
44
44
  )
45
45
  }
@@ -15,7 +15,7 @@ export interface GetQuoteParams {
15
15
  /** Buy consumes asks; sell consumes bids. */
16
16
  side: QuoteSide
17
17
  /** USD notional to fill. */
18
- size: number
18
+ size: string
19
19
  /** Product family used to distinguish spot and perpetual markets. */
20
20
  type: TradeType
21
21
  }
@@ -36,7 +36,7 @@ export interface GetQuoteParams {
36
36
  * provider: 'hyperliquid',
37
37
  * symbol: 'BTC',
38
38
  * side: 'buy',
39
- * size: 10_000,
39
+ * size: '10000',
40
40
  * type: 'perps',
41
41
  * })
42
42
  * console.log(quote.expectedFillPrice, quote.priceImpactBps)
@@ -4,6 +4,7 @@ import {
4
4
  type OrderbookResponse,
5
5
  PerpsErrorCode,
6
6
  } from '@lifi/perps-types'
7
+ import { isDecimalString } from '../decimal/parse.js'
7
8
  import { PerpsError } from '../errors/PerpsError.js'
8
9
  import { buildQuote } from '../math/order.js'
9
10
  import type {
@@ -44,7 +45,7 @@ export const QUOTE_THROTTLE_MS = 100
44
45
  * price, a throwing `onQuote`) is logged via `wsLog.listenerFailure` and the
45
46
  * emission is skipped, on both the immediate and the trailing-timer path.
46
47
  *
47
- * @throws {PerpsError} `ValidationError` when `params.size` is not finite.
48
+ * @throws {PerpsError} `ValidationError` when `params.size` does not match the decimal pattern.
48
49
  * @throws {PerpsError} `MarketNotFound` when no market matches symbol+type.
49
50
  * @internal
50
51
  */
@@ -56,10 +57,10 @@ export async function resolveSubscribeQuote(
56
57
  feeTier: FeeTier,
57
58
  onQuote: QuoteListener
58
59
  ): Promise<() => void> {
59
- if (!Number.isFinite(params.size)) {
60
+ if (!isDecimalString(params.size)) {
60
61
  throw new PerpsError(
61
62
  PerpsErrorCode.ValidationError,
62
- `Quote size must be a finite number, got ${params.size}`
63
+ `Quote size must be a decimal string, got '${params.size}'`
63
64
  )
64
65
  }
65
66
  const market = await resolveQuoteMarket(client, provider, params)