@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,55 +1,63 @@
1
- import { type DecimalString } from '@lifi/perps-types';
2
1
  /**
3
- * Off-grid resolution for {@link decimalToBaseUnits}:
4
- * - `truncate` — toward zero, for sizes and collateral amounts. The wire
5
- * value never exceeds the caller's intent.
6
- * - `round` — half away from zero, for prices, which snap to the nearest
7
- * tick.
2
+ * Off-grid resolution for {@link roundDecimalString}:
3
+ * - `truncate`: toward zero, for sizes and collateral amounts. The result
4
+ * never exceeds the caller's intent.
5
+ * - `round`: half away from zero, for prices, which snap to the nearest tick.
6
+ * - `up`: away from zero, for an amount that must cover a target.
8
7
  * @public
9
8
  */
10
- export type BaseUnitsRounding = 'truncate' | 'round';
9
+ export type DecimalRounding = 'truncate' | 'round' | 'up';
11
10
  /**
12
- * Scale a decimal string to a scaled integer in exact decimal arithmetic — an
13
- * on-grid input maps to its exact scaled integer with no binary float
14
- * artifacts (`'0.29'` at 2 decimals is 29, never 28). Off-grid input resolves
15
- * per `rounding`; there is no silent default.
11
+ * Round a decimal string to `decimals` places with exact decimal arithmetic.
12
+ * The result has no trailing zeros: `roundDecimalString('1.50', 1, 'round')`
13
+ * is `'1.5'`.
16
14
  *
17
- * @throws {PerpsError} `ValidationError` when `value` is not a
18
- * {@link DecimalString}, `decimals` is not a non-negative integer, or the scaled
19
- * result's magnitude exceeds `Number.MAX_SAFE_INTEGER`.
15
+ * @throws {PerpsError} `ValidationError` when `value` does not match the decimal pattern,
16
+ * or `decimals` is not a non-negative integer.
20
17
  * @public
21
18
  */
22
- export declare const decimalToBaseUnits: (value: DecimalString, decimals: number, rounding: BaseUnitsRounding) => number;
19
+ export declare function roundDecimalString(value: string, decimals: number, rounding: DecimalRounding): string;
23
20
  /**
24
- * Convert a base-unit amount (integer string) to a decimal string.
21
+ * {@link roundDecimalString}, or `undefined` with a warning when it throws.
22
+ *
23
+ * @public
24
+ */
25
+ export declare const safeRoundDecimalString: (value: string, decimals: number, rounding: DecimalRounding) => string | undefined;
26
+ /**
27
+ * Scale a decimal string to an integer at `decimals` places in exact decimal
28
+ * arithmetic: `'0.29'` at 2 decimals is 29, never 28. Off-grid input resolves
29
+ * per `rounding`. No `$`, `%` or `,` is removed first.
30
+ *
31
+ * @throws {PerpsError} `ValidationError` when `value` does not match the decimal pattern,
32
+ * `decimals` is not a non-negative integer, or the result's magnitude
33
+ * exceeds `Number.MAX_SAFE_INTEGER`.
34
+ * @public
35
+ */
36
+ export declare function decimalStringToScaledInteger(value: string, decimals: number, rounding: DecimalRounding): number;
37
+ /**
38
+ * {@link decimalStringToScaledInteger}, or `undefined` with a warning when it
39
+ * throws.
40
+ *
41
+ * @public
42
+ */
43
+ export declare const safeDecimalStringToScaledInteger: (value: string, decimals: number, rounding: DecimalRounding) => number | undefined;
44
+ export declare const BASE_UNITS_PATTERN: RegExp;
45
+ /**
46
+ * Convert a scaled integer string (a token amount in base units) to a decimal
47
+ * string: `scaledIntegerToDecimalString('1000000', 6)` is `'1'`.
25
48
  *
26
- * @param amount - Amount in base units (e.g. "1000000" for 1 USDC)
27
- * @param decimals - Token decimals (e.g. 6 for USDC)
28
49
  * @throws {PerpsError} `ValidationError` when `amount` is not an integer
29
50
  * string, or `decimals` is not a non-negative integer.
30
- * @example
31
- * ```ts
32
- * baseUnitsToDecimal('1000000', 6) // '1'
33
- * ```
34
51
  * @public
35
52
  */
36
- export declare function baseUnitsToDecimal(amount: DecimalString, decimals: number): DecimalString;
53
+ export declare function scaledIntegerToDecimalString(amount: string, decimals: number): string;
37
54
  /**
38
- * Round `value` down to `decimals` and pad the result to exactly that many
39
- * decimal places. The padding is the point: this seeds a fixed-decimal input,
40
- * where `'500.00'` and `'500'` are two renderings of one amount and the field
41
- * wants the first. For a canonical wire amount with no trailing zeros, read
42
- * the amount off `calculateOrderAmounts` or a provider snap instead.
43
- *
44
- * Exact decimal arithmetic throughout, so there is no 2^53 ceiling and no
45
- * float artifact: `'0.01'` at 18 decimals gives
46
- * `'0.010000000000000000'`, which `Number#toFixed` cannot.
55
+ * {@link scaledIntegerToDecimalString}, or `undefined` with a warning when it
56
+ * throws.
47
57
  *
48
- * @throws {PerpsError} `ValidationError` when `value` is not a
49
- * {@link DecimalString}, or `decimals` is not a non-negative integer.
50
58
  * @public
51
59
  */
52
- export declare function truncateDecimal(value: DecimalString, decimals: number): DecimalString;
60
+ export declare const safeScaledIntegerToDecimalString: (amount: string, decimals: number) => string | undefined;
53
61
  /**
54
62
  * Spell a `number` as a {@link DecimalString} in plain notation: `1e-7`
55
63
  * becomes `'0.0000001'`, never `'1e-7'`. The boundary helper for a venue or
@@ -60,5 +68,11 @@ export declare function truncateDecimal(value: DecimalString, decimals: number):
60
68
  * @throws {PerpsError} `ValidationError` when `value` is `NaN` or infinite.
61
69
  * @public
62
70
  */
63
- export declare function numberToDecimalString(value: number): DecimalString;
71
+ export declare function numberToDecimalString(value: number): string;
72
+ /**
73
+ * {@link numberToDecimalString}, or `undefined` with a warning when it throws.
74
+ *
75
+ * @public
76
+ */
77
+ export declare const safeNumberToDecimalString: (value: number) => string | undefined;
64
78
  //# sourceMappingURL=convert.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../../src/decimal/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,mBAAmB,CAAA;AAMtE;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAA;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,aAAa,EACpB,UAAU,MAAM,EAChB,UAAU,iBAAiB,KAC1B,MAiBF,CAAA;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,GACf,aAAa,CAcf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,GACf,aAAa,CAaf;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CASlE"}
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../../src/decimal/convert.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,IAAI,CAAA;AAQzD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,eAAe,GACxB,MAAM,CAUR;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,oFAGlC,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,eAAe,GACxB,MAAM,CAuBR;AAED;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,oFAG5C,CAAA;AAED,eAAO,MAAM,kBAAkB,QAAY,CAAA;AAE3C;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,MAAM,CAcR;AAED;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,0DAG5C,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS3D;AAED;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,uCAGrC,CAAA"}
@@ -2,76 +2,92 @@ import { PerpsErrorCode } from '@lifi/perps-types';
2
2
  import Big from 'big.js';
3
3
  import { formatUnits } from 'viem';
4
4
  import { PerpsError } from '../errors/PerpsError.js';
5
- import { requireDecimal } from './requireDecimal.js';
5
+ import { createSafeFunction } from '../utils/createSafeFunction.js';
6
+ import { bigToDecimalString, decimalStringToBig } from './decimalStringToBig.js';
7
+ import { isDecimalString } from './parse.js';
8
+ const BIG_ROUNDING = {
9
+ truncate: Big.roundDown,
10
+ round: Big.roundHalfUp,
11
+ up: Big.roundUp,
12
+ };
13
+ /**
14
+ * Round a decimal string to `decimals` places with exact decimal arithmetic.
15
+ * The result has no trailing zeros: `roundDecimalString('1.50', 1, 'round')`
16
+ * is `'1.5'`.
17
+ *
18
+ * @throws {PerpsError} `ValidationError` when `value` does not match the decimal pattern,
19
+ * or `decimals` is not a non-negative integer.
20
+ * @public
21
+ */
22
+ export function roundDecimalString(value, decimals, rounding) {
23
+ if (!Number.isInteger(decimals) || decimals < 0) {
24
+ throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid decimals for rounding: ${decimals}`);
25
+ }
26
+ return bigToDecimalString(decimalStringToBig(value).round(decimals, BIG_ROUNDING[rounding]));
27
+ }
6
28
  /**
7
- * Scale a decimal string to a scaled integer in exact decimal arithmetic — an
8
- * on-grid input maps to its exact scaled integer with no binary float
9
- * artifacts (`'0.29'` at 2 decimals is 29, never 28). Off-grid input resolves
10
- * per `rounding`; there is no silent default.
29
+ * {@link roundDecimalString}, or `undefined` with a warning when it throws.
11
30
  *
12
- * @throws {PerpsError} `ValidationError` when `value` is not a
13
- * {@link DecimalString}, `decimals` is not a non-negative integer, or the scaled
14
- * result's magnitude exceeds `Number.MAX_SAFE_INTEGER`.
15
31
  * @public
16
32
  */
17
- export const decimalToBaseUnits = (value, decimals, rounding) => {
33
+ export const safeRoundDecimalString = createSafeFunction('roundDecimalString', roundDecimalString);
34
+ /**
35
+ * Scale a decimal string to an integer at `decimals` places in exact decimal
36
+ * arithmetic: `'0.29'` at 2 decimals is 29, never 28. Off-grid input resolves
37
+ * per `rounding`. No `$`, `%` or `,` is removed first.
38
+ *
39
+ * @throws {PerpsError} `ValidationError` when `value` does not match the decimal pattern,
40
+ * `decimals` is not a non-negative integer, or the result's magnitude
41
+ * exceeds `Number.MAX_SAFE_INTEGER`.
42
+ * @public
43
+ */
44
+ export function decimalStringToScaledInteger(value, decimals, rounding) {
45
+ if (!isDecimalString(value)) {
46
+ throw new PerpsError(PerpsErrorCode.ValidationError, `'${value}' does not match the decimal pattern.`);
47
+ }
18
48
  if (!Number.isInteger(decimals) || decimals < 0) {
19
49
  throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid decimals for integer scaling: ${decimals}`);
20
50
  }
21
- const scaled = requireDecimal(value, 'decimalToBaseUnits(value)')
51
+ const scaled = new Big(value)
22
52
  .times(new Big(10).pow(decimals))
23
- .round(0, rounding === 'truncate' ? Big.roundDown : Big.roundHalfUp);
53
+ .round(0, BIG_ROUNDING[rounding]);
24
54
  if (scaled.abs().gt(Number.MAX_SAFE_INTEGER)) {
25
55
  throw new PerpsError(PerpsErrorCode.ValidationError, `Scaled value ${scaled.toFixed()} exceeds Number.MAX_SAFE_INTEGER and cannot be encoded exactly.`);
26
56
  }
27
57
  return scaled.toNumber();
28
- };
29
- const BASE_UNITS_PATTERN = /^-?\d+$/;
58
+ }
30
59
  /**
31
- * Convert a base-unit amount (integer string) to a decimal string.
60
+ * {@link decimalStringToScaledInteger}, or `undefined` with a warning when it
61
+ * throws.
62
+ *
63
+ * @public
64
+ */
65
+ export const safeDecimalStringToScaledInteger = createSafeFunction('decimalStringToScaledInteger', decimalStringToScaledInteger);
66
+ export const BASE_UNITS_PATTERN = /^-?\d+$/;
67
+ /**
68
+ * Convert a scaled integer string (a token amount in base units) to a decimal
69
+ * string: `scaledIntegerToDecimalString('1000000', 6)` is `'1'`.
32
70
  *
33
- * @param amount - Amount in base units (e.g. "1000000" for 1 USDC)
34
- * @param decimals - Token decimals (e.g. 6 for USDC)
35
71
  * @throws {PerpsError} `ValidationError` when `amount` is not an integer
36
72
  * string, or `decimals` is not a non-negative integer.
37
- * @example
38
- * ```ts
39
- * baseUnitsToDecimal('1000000', 6) // '1'
40
- * ```
41
73
  * @public
42
74
  */
43
- export function baseUnitsToDecimal(amount, decimals) {
75
+ export function scaledIntegerToDecimalString(amount, decimals) {
44
76
  if (!Number.isInteger(decimals) || decimals < 0) {
45
- throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid \`baseUnitsToDecimal(decimals)\`: ${decimals} is not a non-negative integer.`);
77
+ throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid \`scaledIntegerToDecimalString(decimals)\`: ${decimals} is not a non-negative integer.`);
46
78
  }
47
79
  if (!BASE_UNITS_PATTERN.test(amount)) {
48
- throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid \`baseUnitsToDecimal(amount)\`: '${amount}' is not an integer base-unit string.`);
80
+ throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid \`scaledIntegerToDecimalString(amount)\`: '${amount}' is not an integer base-unit string.`);
49
81
  }
50
82
  return formatUnits(BigInt(amount), decimals);
51
83
  }
52
84
  /**
53
- * Round `value` down to `decimals` and pad the result to exactly that many
54
- * decimal places. The padding is the point: this seeds a fixed-decimal input,
55
- * where `'500.00'` and `'500'` are two renderings of one amount and the field
56
- * wants the first. For a canonical wire amount with no trailing zeros, read
57
- * the amount off `calculateOrderAmounts` or a provider snap instead.
58
- *
59
- * Exact decimal arithmetic throughout, so there is no 2^53 ceiling and no
60
- * float artifact: `'0.01'` at 18 decimals gives
61
- * `'0.010000000000000000'`, which `Number#toFixed` cannot.
85
+ * {@link scaledIntegerToDecimalString}, or `undefined` with a warning when it
86
+ * throws.
62
87
  *
63
- * @throws {PerpsError} `ValidationError` when `value` is not a
64
- * {@link DecimalString}, or `decimals` is not a non-negative integer.
65
88
  * @public
66
89
  */
67
- export function truncateDecimal(value, decimals) {
68
- if (!Number.isInteger(decimals) || decimals < 0) {
69
- throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid decimals for truncation: ${decimals}`);
70
- }
71
- const truncated = requireDecimal(value, 'truncateDecimal(value)').round(decimals, Big.roundDown);
72
- // big.js carries the sign through a round to zero; '-0.00' is not a spelling.
73
- return (truncated.eq(0) ? new Big(0) : truncated).toFixed(decimals);
74
- }
90
+ export const safeScaledIntegerToDecimalString = createSafeFunction('scaledIntegerToDecimalString', scaledIntegerToDecimalString);
75
91
  /**
76
92
  * Spell a `number` as a {@link DecimalString} in plain notation: `1e-7`
77
93
  * becomes `'0.0000001'`, never `'1e-7'`. The boundary helper for a venue or
@@ -89,4 +105,10 @@ export function numberToDecimalString(value) {
89
105
  const parsed = new Big(value);
90
106
  return (parsed.eq(0) ? new Big(0) : parsed).toFixed();
91
107
  }
108
+ /**
109
+ * {@link numberToDecimalString}, or `undefined` with a warning when it throws.
110
+ *
111
+ * @public
112
+ */
113
+ export const safeNumberToDecimalString = createSafeFunction('numberToDecimalString', numberToDecimalString);
92
114
  //# sourceMappingURL=convert.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../../src/decimal/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,GAAG,MAAM,QAAQ,CAAA;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAA;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAYpD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAoB,EACpB,QAAgB,EAChB,QAA2B,EACnB,EAAE;IACV,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,yCAAyC,QAAQ,EAAE,CACpD,CAAA;IACH,CAAC;IACD,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,EAAE,2BAA2B,CAAC;SAC9D,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;SAChC,KAAK,CAAC,CAAC,EAAE,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACtE,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,gBAAgB,MAAM,CAAC,OAAO,EAAE,iEAAiE,CAClG,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAA;AAC1B,CAAC,CAAA;AAED,MAAM,kBAAkB,GAAG,SAAS,CAAA;AAEpC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAqB,EACrB,QAAgB;IAEhB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,6CAA6C,QAAQ,iCAAiC,CACvF,CAAA;IACH,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,4CAA4C,MAAM,uCAAuC,CAC1F,CAAA;IACH,CAAC;IACD,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAoB,EACpB,QAAgB;IAEhB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,oCAAoC,QAAQ,EAAE,CAC/C,CAAA;IACH,CAAC;IACD,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC,KAAK,CACrE,QAAQ,EACR,GAAG,CAAC,SAAS,CACd,CAAA;IACD,8EAA8E;IAC9E,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;AACrE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,0CAA0C,KAAK,EAAE,CAClD,CAAA;IACH,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAC7B,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAA;AACvD,CAAC"}
1
+ {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../../src/decimal/convert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import Big from 'big.js';
2
+ /**
3
+ * Read a decimal string as a `Big`. The string must match `DECIMAL_PATTERN`,
4
+ * so `'$1,234.5'`, `'0.05%'` and the exponent form `'1e5'` are rejected.
5
+ *
6
+ * @throws {PerpsError} `ValidationError` when `value` does not match the
7
+ * decimal pattern.
8
+ * @internal
9
+ */
10
+ export declare function decimalStringToBig(value: string): Big;
11
+ /**
12
+ * Spell a `Big` as a canonical decimal string, with no exponent and no `-0`.
13
+ *
14
+ * @internal
15
+ */
16
+ export declare function bigToDecimalString(value: Big): string;
17
+ /**
18
+ * {@link decimalStringToBig} as a `DivBig`, so a later `div` keeps 40 decimal
19
+ * places.
20
+ *
21
+ * @throws {PerpsError} `ValidationError` as {@link decimalStringToBig}.
22
+ * @internal
23
+ */
24
+ export declare function decimalStringToDivBig(value: string): Big;
25
+ //# sourceMappingURL=decimalStringToBig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decimalStringToBig.d.ts","sourceRoot":"","sources":["../../../src/decimal/decimalStringToBig.ts"],"names":[],"mappings":"AACA,OAAO,GAAG,MAAM,QAAQ,CAAA;AAIxB;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAQrD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAExD"}
@@ -0,0 +1,37 @@
1
+ import { DECIMAL_PATTERN, PerpsErrorCode } from '@lifi/perps-types';
2
+ import Big from 'big.js';
3
+ import { PerpsError } from '../errors/PerpsError.js';
4
+ import { DivBig } from './big.js';
5
+ /**
6
+ * Read a decimal string as a `Big`. The string must match `DECIMAL_PATTERN`,
7
+ * so `'$1,234.5'`, `'0.05%'` and the exponent form `'1e5'` are rejected.
8
+ *
9
+ * @throws {PerpsError} `ValidationError` when `value` does not match the
10
+ * decimal pattern.
11
+ * @internal
12
+ */
13
+ export function decimalStringToBig(value) {
14
+ if (typeof value !== 'string' || !DECIMAL_PATTERN.test(value)) {
15
+ throw new PerpsError(PerpsErrorCode.ValidationError, `'${String(value)}' does not match the decimal pattern.`);
16
+ }
17
+ return new Big(value);
18
+ }
19
+ /**
20
+ * Spell a `Big` as a canonical decimal string, with no exponent and no `-0`.
21
+ *
22
+ * @internal
23
+ */
24
+ export function bigToDecimalString(value) {
25
+ return value.eq(0) ? '0' : value.toFixed();
26
+ }
27
+ /**
28
+ * {@link decimalStringToBig} as a `DivBig`, so a later `div` keeps 40 decimal
29
+ * places.
30
+ *
31
+ * @throws {PerpsError} `ValidationError` as {@link decimalStringToBig}.
32
+ * @internal
33
+ */
34
+ export function decimalStringToDivBig(value) {
35
+ return new DivBig(decimalStringToBig(value));
36
+ }
37
+ //# sourceMappingURL=decimalStringToBig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decimalStringToBig.js","sourceRoot":"","sources":["../../../src/decimal/decimalStringToBig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,GAAG,MAAM,QAAQ,CAAA;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,IAAI,MAAM,CAAC,KAAK,CAAC,uCAAuC,CACzD,CAAA;IACH,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAU;IAC3C,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,IAAI,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAA;AAC9C,CAAC"}
@@ -7,7 +7,10 @@ import type { DecimalString } from '@lifi/perps-types';
7
7
  export interface FormatOptions {
8
8
  /** Fixed number of decimal places. Defaults are per-formatter. */
9
9
  decimals?: number;
10
- /** Rendered when the value is null/undefined/NaN/non-finite. Defaults to `'—'`. */
10
+ /**
11
+ * Rendered when the value is null, undefined, blank or a non-finite number.
12
+ * A string that is not a decimal is shown unchanged. Defaults to `'—'`.
13
+ */
11
14
  placeholder?: string;
12
15
  /** BCP 47 locale controlling digit grouping and separators (e.g. `'en-US'`). */
13
16
  locale?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/decimal/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEtD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAA;AAI7C,KAAK,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;AA6FrE;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAaR;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAaR;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAaR;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAaR;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAqBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAkBR"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/decimal/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAItD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAA;AAI7C,KAAK,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;AA+ErE;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAgBR;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAgBR;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAwBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAqBR"}
@@ -1,66 +1,49 @@
1
+ import Big from 'big.js';
2
+ import { decimalStringToBig } from './decimalStringToBig.js';
1
3
  const DEFAULT_PLACEHOLDER = '—';
2
4
  /**
3
- * Extra decimal places used to normalise IEEE-754 representation noise before
4
- * truncating. `toFixed` at this higher precision cleans values like
5
- * `0.28999999…` back to `0.29`; truncation then chops the guard digits.
5
+ * Read a display input as a `Big`. `null` means the formatter renders the
6
+ * placeholder; a string that does not match the decimal pattern is returned
7
+ * unchanged for display.
6
8
  */
7
- const FLOAT_GUARD_DIGITS = 9;
8
- /**
9
- * Tolerantly coerce a display input to a finite number.
10
- *
11
- * Strips `$`, `,`, and surrounding whitespace from strings. Returns `null`
12
- * when the value is null/undefined/blank or does not resolve to a finite
13
- * number, so callers can render a placeholder instead of `$0.00` or `$NaN`.
14
- */
15
- function toFiniteNumber(value) {
16
- let n;
17
- if (typeof value === 'string') {
18
- const cleaned = value.replace(/[$,\s]/g, '');
19
- if (!cleaned) {
20
- return null;
21
- }
22
- n = Number(cleaned);
23
- }
24
- else if (typeof value === 'number') {
25
- n = value;
26
- }
27
- else {
9
+ function toBig(value) {
10
+ if (typeof value === 'number') {
11
+ return Number.isFinite(value) ? new Big(value) : null;
12
+ }
13
+ if (typeof value !== 'string' || value.trim() === '') {
28
14
  return null;
29
15
  }
30
- return Number.isFinite(n) ? n : null;
16
+ try {
17
+ return decimalStringToBig(value);
18
+ }
19
+ catch {
20
+ return value;
21
+ }
31
22
  }
32
- /**
33
- * Truncate a non-negative value toward zero to `decimals` places using its
34
- * decimal string, never float scaling. Representation noise is first
35
- * normalised by `toFixed` at {@link FLOAT_GUARD_DIGITS} extra precision, then
36
- * the guard digits are chopped: `99.999` at 2dp → `99.99`, `0.29` → `0.29`.
37
- */
38
- function truncateAbs(abs, decimals) {
39
- // `toFixed` emits exponent notation at >= 1e21; every double that large is an integer.
40
- if (Number.isInteger(abs)) {
41
- return abs;
42
- }
43
- const s = abs.toFixed(Math.min(decimals + FLOAT_GUARD_DIGITS, 100));
44
- const dot = s.indexOf('.');
45
- const cut = decimals === 0 ? dot : dot + 1 + decimals;
46
- return Number(s.slice(0, cut));
23
+ function decimalSeparator(locale) {
24
+ return (new Intl.NumberFormat(locale)
25
+ .formatToParts(1.5)
26
+ .find((part) => part.type === 'decimal')?.value ?? '.');
47
27
  }
48
28
  /**
49
- * Reduce `n` to `decimals` places then split into a sign and the
29
+ * Reduce `value` to `decimals` places then split into a sign and the
50
30
  * locale-formatted absolute body. The sign is derived from the reduced value
51
31
  * so magnitudes that collapse to zero render without a spurious `-`/`+`.
52
32
  * `signed` emits `+` for positives; `rounding` selects half-up or truncation.
53
33
  */
54
- function signAndBody(n, decimals, locale, grouping, rounding, signed) {
55
- const reduced = rounding === 'floor'
56
- ? (n < 0 ? -1 : 1) * truncateAbs(Math.abs(n), decimals)
57
- : Number(n.toFixed(decimals));
58
- const sign = reduced < 0 ? '-' : signed && reduced > 0 ? '+' : '';
59
- const body = Math.abs(reduced).toLocaleString(locale, {
60
- minimumFractionDigits: decimals,
61
- maximumFractionDigits: decimals,
62
- useGrouping: grouping,
63
- });
34
+ function signAndBody(value, decimals, locale, grouping, rounding, signed) {
35
+ const reduced = value.round(decimals, rounding === 'floor' ? Big.roundDown : Big.roundHalfUp);
36
+ const sign = reduced.lt(0) ? '-' : signed && reduced.gt(0) ? '+' : '';
37
+ const [integerPart = '0', fractionPart] = reduced
38
+ .abs()
39
+ .toFixed(decimals)
40
+ .split('.');
41
+ const integerBody = grouping
42
+ ? BigInt(integerPart).toLocaleString(locale)
43
+ : integerPart;
44
+ const body = fractionPart === undefined
45
+ ? integerBody
46
+ : `${integerBody}${decimalSeparator(locale)}${fractionPart}`;
64
47
  return { sign, body };
65
48
  }
66
49
  /**
@@ -68,13 +51,13 @@ function signAndBody(n, decimals, locale, grouping, rounding, signed) {
68
51
  * `>=1` → 2, `>=0.1` → 4, `>=0.01` → 5, otherwise 6.
69
52
  */
70
53
  function autoDecimals(abs) {
71
- if (abs >= 1) {
54
+ if (abs.gte(1)) {
72
55
  return 2;
73
56
  }
74
- if (abs >= 0.1) {
57
+ if (abs.gte('0.1')) {
75
58
  return 4;
76
59
  }
77
- if (abs >= 0.01) {
60
+ if (abs.gte('0.01')) {
78
61
  return 5;
79
62
  }
80
63
  return 6;
@@ -93,10 +76,13 @@ function autoDecimals(abs) {
93
76
  */
94
77
  export function formatNumber(value, options = {}) {
95
78
  const { decimals = 2, placeholder = DEFAULT_PLACEHOLDER, locale, rounding = 'halfUp', } = options;
96
- const n = toFiniteNumber(value);
79
+ const n = toBig(value);
97
80
  if (n === null) {
98
81
  return placeholder;
99
82
  }
83
+ if (typeof n === 'string') {
84
+ return n;
85
+ }
100
86
  const { sign, body } = signAndBody(n, decimals, locale, true, rounding, false);
101
87
  return `${sign}${body}`;
102
88
  }
@@ -110,10 +96,13 @@ export function formatNumber(value, options = {}) {
110
96
  */
111
97
  export function formatUsd(value, options = {}) {
112
98
  const { decimals = 2, placeholder = DEFAULT_PLACEHOLDER, locale, rounding = 'halfUp', } = options;
113
- const n = toFiniteNumber(value);
99
+ const n = toBig(value);
114
100
  if (n === null) {
115
101
  return placeholder;
116
102
  }
103
+ if (typeof n === 'string') {
104
+ return n;
105
+ }
117
106
  const { sign, body } = signAndBody(n, decimals, locale, true, rounding, false);
118
107
  return `${sign}$${body}`;
119
108
  }
@@ -128,10 +117,13 @@ export function formatUsd(value, options = {}) {
128
117
  */
129
118
  export function formatSignedUsd(value, options = {}) {
130
119
  const { decimals = 2, placeholder = DEFAULT_PLACEHOLDER, locale, rounding = 'halfUp', } = options;
131
- const n = toFiniteNumber(value);
120
+ const n = toBig(value);
132
121
  if (n === null) {
133
122
  return placeholder;
134
123
  }
124
+ if (typeof n === 'string') {
125
+ return n;
126
+ }
135
127
  const { sign, body } = signAndBody(n, decimals, locale, true, rounding, true);
136
128
  return `${sign}$${body}`;
137
129
  }
@@ -146,10 +138,13 @@ export function formatSignedUsd(value, options = {}) {
146
138
  */
147
139
  export function formatSignedPercent(value, options = {}) {
148
140
  const { decimals = 2, placeholder = DEFAULT_PLACEHOLDER, locale, rounding = 'halfUp', } = options;
149
- const n = toFiniteNumber(value);
141
+ const n = toBig(value);
150
142
  if (n === null) {
151
143
  return placeholder;
152
144
  }
145
+ if (typeof n === 'string') {
146
+ return n;
147
+ }
153
148
  const { sign, body } = signAndBody(n, decimals, locale, false, rounding, true);
154
149
  return `${sign}${body}%`;
155
150
  }
@@ -165,13 +160,16 @@ export function formatSignedPercent(value, options = {}) {
165
160
  */
166
161
  export function formatPrice(value, options = {}) {
167
162
  const { placeholder = DEFAULT_PLACEHOLDER, locale, rounding = 'halfUp', } = options;
168
- const n = toFiniteNumber(value);
163
+ const n = toBig(value);
169
164
  if (n === null) {
170
165
  return placeholder;
171
166
  }
172
- const abs = Math.abs(n);
167
+ if (typeof n === 'string') {
168
+ return n;
169
+ }
170
+ const abs = n.abs();
173
171
  const decimals = options.decimals ?? autoDecimals(abs);
174
- const { sign, body } = signAndBody(n, decimals, locale, abs >= 1000, rounding, false);
172
+ const { sign, body } = signAndBody(n, decimals, locale, abs.gte(1000), rounding, false);
175
173
  return `${sign}$${body}`;
176
174
  }
177
175
  /**
@@ -185,20 +183,23 @@ export function formatPrice(value, options = {}) {
185
183
  */
186
184
  export function formatCompactUsd(value, options = {}) {
187
185
  const { decimals = 2, placeholder = DEFAULT_PLACEHOLDER } = options;
188
- const n = toFiniteNumber(value);
186
+ const n = toBig(value);
189
187
  if (n === null) {
190
188
  return placeholder;
191
189
  }
192
- const sign = n < 0 ? '-' : '';
193
- const abs = Math.abs(n);
194
- if (abs >= 1_000_000_000) {
195
- return `${sign}$${(abs / 1_000_000_000).toFixed(decimals)}B`;
190
+ if (typeof n === 'string') {
191
+ return n;
192
+ }
193
+ const sign = n.lt(0) ? '-' : '';
194
+ const abs = n.abs();
195
+ if (abs.gte(1_000_000_000)) {
196
+ return `${sign}$${abs.div(1_000_000_000).toFixed(decimals)}B`;
196
197
  }
197
- if (abs >= 1_000_000) {
198
- return `${sign}$${(abs / 1_000_000).toFixed(decimals)}M`;
198
+ if (abs.gte(1_000_000)) {
199
+ return `${sign}$${abs.div(1_000_000).toFixed(decimals)}M`;
199
200
  }
200
- if (abs >= 1_000) {
201
- return `${sign}$${(abs / 1_000).toFixed(decimals)}K`;
201
+ if (abs.gte(1_000)) {
202
+ return `${sign}$${abs.div(1_000).toFixed(decimals)}K`;
202
203
  }
203
204
  return `${sign}$${abs.toFixed(decimals)}`;
204
205
  }