@swapkit/helpers 4.5.7 → 4.5.9
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.
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +3 -3
- package/dist/index.js.map +4 -4
- package/dist/types/modules/bigIntArithmetics.d.ts +2 -1
- package/dist/types/modules/bigIntArithmetics.d.ts.map +1 -1
- package/dist/types/utils/wallets.d.ts +1 -1
- package/dist/types/utils/wallets.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/modules/__tests__/assetValue.test.ts +816 -16
- package/src/modules/__tests__/bigIntArithmetics.test.ts +49 -22
- package/src/modules/__tests__/feeMultiplier.test.ts +125 -0
- package/src/modules/__tests__/swapKitNumber.test.ts +0 -100
- package/src/modules/bigIntArithmetics.ts +20 -21
- package/src/utils/__tests__/derivationPath.test.ts +133 -7
- package/src/utils/__tests__/liquidity.test.ts +302 -0
- package/src/utils/__tests__/memo.test.ts +6 -6
- package/src/utils/__tests__/others.test.ts +104 -22
- package/src/utils/__tests__/validators.test.ts +80 -20
- package/src/utils/__tests__/wallets.test.ts +621 -0
- package/src/utils/wallets.ts +1 -1
|
@@ -75,7 +75,7 @@ describe("BigIntArithmetics", () => {
|
|
|
75
75
|
expect(num.toFixed(6)).toBe("0.000001");
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
test("handles negative numbers", () => {
|
|
78
|
+
test("handles negative numbers with toFixed", () => {
|
|
79
79
|
const num = new BigIntArithmetics(-123.456);
|
|
80
80
|
expect(num.toFixed(2)).toBe("-123.46");
|
|
81
81
|
expect(num.toFixed(4)).toBe("-123.4560");
|
|
@@ -230,7 +230,7 @@ describe("BigIntArithmetics", () => {
|
|
|
230
230
|
});
|
|
231
231
|
|
|
232
232
|
describe("toAbbreviation edge cases", () => {
|
|
233
|
-
test("handles negative numbers", () => {
|
|
233
|
+
test("handles negative numbers with abbreviation", () => {
|
|
234
234
|
const num = new BigIntArithmetics(-1234567);
|
|
235
235
|
expect(num.toAbbreviation()).toBe("-1.23M");
|
|
236
236
|
});
|
|
@@ -260,37 +260,64 @@ describe("BigIntArithmetics", () => {
|
|
|
260
260
|
});
|
|
261
261
|
|
|
262
262
|
describe("toCurrency edge cases", () => {
|
|
263
|
-
test("
|
|
263
|
+
test("currency symbols €, £, ¥", () => {
|
|
264
264
|
const num = new BigIntArithmetics(1234.56);
|
|
265
|
-
expect(num.toCurrency("€")).
|
|
266
|
-
expect(num.toCurrency("£")).
|
|
267
|
-
expect(num.toCurrency("¥")).
|
|
265
|
+
expect(num.toCurrency("€")).toBe("€1,234.56");
|
|
266
|
+
expect(num.toCurrency("£")).toBe("£1,234.56");
|
|
267
|
+
expect(num.toCurrency("¥")).toBe("¥1,234.56");
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
-
test("
|
|
270
|
+
test("currency position start and end", () => {
|
|
271
271
|
const num = new BigIntArithmetics(1234.56);
|
|
272
|
-
expect(num.toCurrency("€", { currencyPosition: "start" })).
|
|
273
|
-
expect(num.toCurrency("€", { currencyPosition: "end" })).
|
|
272
|
+
expect(num.toCurrency("€", { currencyPosition: "start" })).toBe("€1,234.56");
|
|
273
|
+
expect(num.toCurrency("€", { currencyPosition: "end" })).toBe("1,234.56€");
|
|
274
274
|
});
|
|
275
275
|
|
|
276
|
-
test("
|
|
276
|
+
test("european format with custom separators", () => {
|
|
277
277
|
const num = new BigIntArithmetics(1234567.89);
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
expect(num.toCurrency("€", { currencyPosition: "end", decimalSeparator: ",", thousandSeparator: "." })).toBe(
|
|
279
|
+
"1.234.567,89€",
|
|
280
|
+
);
|
|
281
281
|
});
|
|
282
282
|
|
|
283
|
-
test("
|
|
284
|
-
|
|
285
|
-
expect(
|
|
286
|
-
expect(
|
|
283
|
+
test("small values < 1 rounds to decimal with trailing zeros removed without floating-point artifacts", () => {
|
|
284
|
+
expect(new BigIntArithmetics(0.015072).toCurrency("")).toBe("0.02");
|
|
285
|
+
expect(new BigIntArithmetics(0.333145).toCurrency("")).toBe("0.33");
|
|
286
|
+
expect(new BigIntArithmetics(0.000005).toCurrency("")).toBe("0");
|
|
287
|
+
expect(new BigIntArithmetics(0.00000548).toCurrency("", { decimal: 6 })).toBe("0.000005");
|
|
288
|
+
expect(new BigIntArithmetics(0.00003801).toCurrency("", { decimal: 6 })).toBe("0.000038");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("small values strip trailing zeros", () => {
|
|
292
|
+
expect(new BigIntArithmetics(0.12).toCurrency("")).toBe("0.12");
|
|
293
|
+
expect(new BigIntArithmetics(0.1).toCurrency("")).toBe("0.1");
|
|
294
|
+
expect(new BigIntArithmetics(0.10000001).toCurrency("")).toBe("0.1");
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("negative small values", () => {
|
|
298
|
+
expect(new BigIntArithmetics(-0.015072).toCurrency("")).toBe("-0.02");
|
|
299
|
+
expect(new BigIntArithmetics(-0.00000001).toCurrency("", { decimal: 8 })).toBe("-0.00000001");
|
|
300
|
+
expect(new BigIntArithmetics(-0.00003801).toCurrency("", { decimal: 6 })).toBe("-0.000038");
|
|
301
|
+
expect(new BigIntArithmetics(-0.00000548).toCurrency("")).toBe("0");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("values >= 1 round to decimal param", () => {
|
|
305
|
+
expect(new BigIntArithmetics(5.12).toCurrency("", { decimal: 2 })).toBe("5.12");
|
|
306
|
+
expect(new BigIntArithmetics(80.865327).toCurrency("", { decimal: 2 })).toBe("80.87");
|
|
307
|
+
expect(new BigIntArithmetics(33.432207).toCurrency("", { decimal: 2 })).toBe("33.43");
|
|
308
|
+
expect(new BigIntArithmetics(999.999).toCurrency("$")).toBe("$1,000");
|
|
309
|
+
expect(new BigIntArithmetics(0.0000000000000000000000000000001).toCurrency("", { decimal: 8 })).toBe("0");
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test("zero value", () => {
|
|
313
|
+
expect(new BigIntArithmetics(0).toCurrency("$")).toBe("$0");
|
|
314
|
+
expect(new BigIntArithmetics(0).toCurrency("")).toBe("0");
|
|
287
315
|
});
|
|
288
316
|
|
|
289
|
-
test("
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
expect(result).toContain("1");
|
|
317
|
+
test("custom decimal separator for small values", () => {
|
|
318
|
+
expect(
|
|
319
|
+
new BigIntArithmetics(0.015072).toCurrency("€", { currencyPosition: "end", decimal: 6, decimalSeparator: "," }),
|
|
320
|
+
).toBe("0,015072€");
|
|
294
321
|
});
|
|
295
322
|
});
|
|
296
323
|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { FeeOption } from "../../types";
|
|
4
|
+
import {
|
|
5
|
+
applyFeeMultiplier,
|
|
6
|
+
applyFeeMultiplierToBigInt,
|
|
7
|
+
DEFAULT_FEE_MULTIPLIERS,
|
|
8
|
+
getFeeMultiplier,
|
|
9
|
+
getFeeMultiplierAsBigInt,
|
|
10
|
+
} from "../feeMultiplier";
|
|
11
|
+
import { SKConfig } from "../swapKitConfig";
|
|
12
|
+
|
|
13
|
+
describe("feeMultiplier", () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
SKConfig.reinitialize();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
SKConfig.reinitialize();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("getFeeMultiplier", () => {
|
|
23
|
+
test("returns 1.0 for Average, 1.5 for Fast, 2.0 for Fastest", () => {
|
|
24
|
+
expect(getFeeMultiplier(FeeOption.Average)).toBe(1.0);
|
|
25
|
+
expect(getFeeMultiplier(FeeOption.Fast)).toBe(1.5);
|
|
26
|
+
expect(getFeeMultiplier(FeeOption.Fastest)).toBe(2.0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("defaults to Average when no option provided", () => {
|
|
30
|
+
expect(getFeeMultiplier()).toBe(1.0);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("uses custom multipliers from SKConfig when set", () => {
|
|
34
|
+
SKConfig.set({ feeMultipliers: { [FeeOption.Average]: 1.2, [FeeOption.Fast]: 1.8, [FeeOption.Fastest]: 2.5 } });
|
|
35
|
+
|
|
36
|
+
expect(getFeeMultiplier(FeeOption.Average)).toBe(1.2);
|
|
37
|
+
expect(getFeeMultiplier(FeeOption.Fast)).toBe(1.8);
|
|
38
|
+
expect(getFeeMultiplier(FeeOption.Fastest)).toBe(2.5);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("getFeeMultiplierAsBigInt", () => {
|
|
43
|
+
test("converts multipliers to numerator/denominator for precise bigint math", () => {
|
|
44
|
+
expect(getFeeMultiplierAsBigInt(FeeOption.Average)).toEqual({ denominator: 10n, numerator: 10n });
|
|
45
|
+
expect(getFeeMultiplierAsBigInt(FeeOption.Fast)).toEqual({ denominator: 10n, numerator: 15n });
|
|
46
|
+
expect(getFeeMultiplierAsBigInt(FeeOption.Fastest)).toEqual({ denominator: 10n, numerator: 20n });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("defaults to Average for bigint multiplier", () => {
|
|
50
|
+
expect(getFeeMultiplierAsBigInt()).toEqual({ denominator: 10n, numerator: 10n });
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("applyFeeMultiplierToBigInt", () => {
|
|
55
|
+
test("applies multiplier to bigint values", () => {
|
|
56
|
+
expect(applyFeeMultiplierToBigInt(100n, FeeOption.Average)).toBe(100n);
|
|
57
|
+
expect(applyFeeMultiplierToBigInt(100n, FeeOption.Fast)).toBe(150n);
|
|
58
|
+
expect(applyFeeMultiplierToBigInt(100n, FeeOption.Fastest)).toBe(200n);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("handles large values without overflow", () => {
|
|
62
|
+
expect(applyFeeMultiplierToBigInt(1000000000000000000n, FeeOption.Fastest)).toBe(2000000000000000000n);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("defaults to Average for applyFeeMultiplierToBigInt", () => {
|
|
66
|
+
expect(applyFeeMultiplierToBigInt(100n)).toBe(100n);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("applyFeeMultiplier", () => {
|
|
71
|
+
test("applies multiplier to number values", () => {
|
|
72
|
+
expect(applyFeeMultiplier(100, FeeOption.Average)).toBe(100);
|
|
73
|
+
expect(applyFeeMultiplier(100, FeeOption.Fast)).toBe(150);
|
|
74
|
+
expect(applyFeeMultiplier(100, FeeOption.Fastest)).toBe(200);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("floors result when floor=true", () => {
|
|
78
|
+
expect(applyFeeMultiplier(33, FeeOption.Fast, true)).toBe(49);
|
|
79
|
+
expect(applyFeeMultiplier(10.5, FeeOption.Fastest, true)).toBe(21);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("preserves decimals when floor=false", () => {
|
|
83
|
+
expect(applyFeeMultiplier(33, FeeOption.Fast, false)).toBe(49.5);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("defaults to Average for applyFeeMultiplier", () => {
|
|
87
|
+
expect(applyFeeMultiplier(100)).toBe(100);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("DEFAULT_FEE_MULTIPLIERS", () => {
|
|
92
|
+
test("exports correct default values", () => {
|
|
93
|
+
expect(DEFAULT_FEE_MULTIPLIERS[FeeOption.Average]).toBe(1.0);
|
|
94
|
+
expect(DEFAULT_FEE_MULTIPLIERS[FeeOption.Fast]).toBe(1.5);
|
|
95
|
+
expect(DEFAULT_FEE_MULTIPLIERS[FeeOption.Fastest]).toBe(2.0);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe("edge cases", () => {
|
|
100
|
+
test("applies multiplier to zero value", () => {
|
|
101
|
+
expect(applyFeeMultiplierToBigInt(0n, FeeOption.Fastest)).toBe(0n);
|
|
102
|
+
expect(applyFeeMultiplier(0, FeeOption.Fastest)).toBe(0);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("handles negative numbers", () => {
|
|
106
|
+
expect(applyFeeMultiplier(-100, FeeOption.Fast)).toBe(-150);
|
|
107
|
+
expect(applyFeeMultiplier(-100, FeeOption.Fastest)).toBe(-200);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("handles negative bigint values", () => {
|
|
111
|
+
expect(applyFeeMultiplierToBigInt(-100n, FeeOption.Fast)).toBe(-150n);
|
|
112
|
+
expect(applyFeeMultiplierToBigInt(-100n, FeeOption.Fastest)).toBe(-200n);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("handles decimal values with multiplier", () => {
|
|
116
|
+
expect(applyFeeMultiplier(0.5, FeeOption.Fastest)).toBe(1);
|
|
117
|
+
expect(applyFeeMultiplier(0.333, FeeOption.Fast)).toBeCloseTo(0.4995, 4);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("handles very small bigint values", () => {
|
|
121
|
+
expect(applyFeeMultiplierToBigInt(1n, FeeOption.Fast)).toBe(1n); // 1 * 15 / 10 = 1 (integer division)
|
|
122
|
+
expect(applyFeeMultiplierToBigInt(5n, FeeOption.Fast)).toBe(7n); // 5 * 15 / 10 = 7
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -139,106 +139,6 @@ describe("SwapKitNumber", () => {
|
|
|
139
139
|
});
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
-
describe("toSignificant", () => {
|
|
143
|
-
describe("normal cases", () => {
|
|
144
|
-
test("returns first significant number of digits", () => {
|
|
145
|
-
const usdLikeNumber = new SwapKitNumber(1234.5678);
|
|
146
|
-
expect(usdLikeNumber.toSignificant(2)).toBe("1200");
|
|
147
|
-
expect(usdLikeNumber.toSignificant(3)).toBe("1230");
|
|
148
|
-
expect(usdLikeNumber.toSignificant(4)).toBe("1234");
|
|
149
|
-
expect(usdLikeNumber.toSignificant(5)).toBe("1234.5");
|
|
150
|
-
expect(usdLikeNumber.toSignificant(6)).toBe("1234.56");
|
|
151
|
-
expect(usdLikeNumber.toSignificant(7)).toBe("1234.567");
|
|
152
|
-
expect(usdLikeNumber.toSignificant(8)).toBe("1234.5678");
|
|
153
|
-
|
|
154
|
-
const btcLikeNumber = new SwapKitNumber(0.00005678);
|
|
155
|
-
expect(btcLikeNumber.toSignificant(2)).toBe("0.000056");
|
|
156
|
-
expect(btcLikeNumber.toSignificant(3)).toBe("0.0000567");
|
|
157
|
-
expect(btcLikeNumber.toSignificant(4)).toBe("0.00005678");
|
|
158
|
-
expect(btcLikeNumber.toSignificant(5)).toBe("0.00005678");
|
|
159
|
-
expect(btcLikeNumber.toSignificant(8)).toBe("0.00005678");
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe("custom decimals", () => {
|
|
164
|
-
test("returns first significant number of digits", () => {
|
|
165
|
-
const usdLikeNumber = new SwapKitNumber({ decimal: 2, value: 1234.5678 });
|
|
166
|
-
expect(usdLikeNumber.toSignificant(2)).toBe("1200");
|
|
167
|
-
expect(usdLikeNumber.toSignificant(3)).toBe("1230");
|
|
168
|
-
expect(usdLikeNumber.toSignificant(4)).toBe("1234");
|
|
169
|
-
expect(usdLikeNumber.toSignificant(5)).toBe("1234.5");
|
|
170
|
-
expect(usdLikeNumber.toSignificant(6)).toBe("1234.57");
|
|
171
|
-
expect(usdLikeNumber.toSignificant(7)).toBe("1234.57");
|
|
172
|
-
expect(usdLikeNumber.toSignificant(8)).toBe("1234.57");
|
|
173
|
-
|
|
174
|
-
const ethLikeNumber = new SwapKitNumber({ decimal: 18, value: 0.00005678 });
|
|
175
|
-
expect(ethLikeNumber.toSignificant(2)).toBe("0.000056");
|
|
176
|
-
expect(ethLikeNumber.toSignificant(3)).toBe("0.0000567");
|
|
177
|
-
expect(ethLikeNumber.toSignificant(4)).toBe("0.00005678");
|
|
178
|
-
expect(ethLikeNumber.toSignificant(5)).toBe("0.00005678");
|
|
179
|
-
expect(ethLikeNumber.toSignificant(8)).toBe("0.00005678");
|
|
180
|
-
expect(ethLikeNumber.toSignificant(18)).toBe("0.00005678");
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
describe("toAbbreviation", () => {
|
|
186
|
-
test("returns abbreviation with up to 3 integer digits", () => {
|
|
187
|
-
const skNumber = new SwapKitNumber(1234.5678);
|
|
188
|
-
expect(skNumber.toAbbreviation()).toBe("1.23K");
|
|
189
|
-
|
|
190
|
-
const skNumber2 = new SwapKitNumber(1234567.5678);
|
|
191
|
-
expect(skNumber2.toAbbreviation()).toBe("1.23M");
|
|
192
|
-
|
|
193
|
-
const skNumber3 = new SwapKitNumber(1234567890.5678);
|
|
194
|
-
expect(skNumber3.toAbbreviation()).toBe("1.23B");
|
|
195
|
-
|
|
196
|
-
const skNumber4 = new SwapKitNumber("1234567890123.5678");
|
|
197
|
-
expect(skNumber4.toAbbreviation()).toBe("1.23T");
|
|
198
|
-
|
|
199
|
-
const skNumber5 = new SwapKitNumber("1234567890123456.5678");
|
|
200
|
-
expect(skNumber5.toAbbreviation()).toBe("1.23Q");
|
|
201
|
-
|
|
202
|
-
const skNumber6 = new SwapKitNumber("1234567890123456789.5678");
|
|
203
|
-
expect(skNumber6.toAbbreviation()).toBe("1.23Qi");
|
|
204
|
-
|
|
205
|
-
const skNumber7 = new SwapKitNumber("1234567890123456789012.5678");
|
|
206
|
-
expect(skNumber7.toAbbreviation()).toBe("1.23S");
|
|
207
|
-
|
|
208
|
-
const skNumber8 = new SwapKitNumber(1234.5678);
|
|
209
|
-
expect(skNumber8.toAbbreviation(0)).toBe("1K");
|
|
210
|
-
|
|
211
|
-
const skNumber9 = new SwapKitNumber(1234.5678);
|
|
212
|
-
expect(skNumber9.toAbbreviation(1)).toBe("1.2K");
|
|
213
|
-
|
|
214
|
-
const skNumber10 = new SwapKitNumber(123456.78);
|
|
215
|
-
expect(skNumber10.toAbbreviation()).toBe("123.46K");
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe("toCurrency", () => {
|
|
220
|
-
test("returns abbreviation with up to 3 integer digits", () => {
|
|
221
|
-
const skNumber = new SwapKitNumber(1234.5678);
|
|
222
|
-
expect(skNumber.toCurrency()).toBe("$1,234.57");
|
|
223
|
-
expect(skNumber.toCurrency("€", { currencyPosition: "end", decimalSeparator: ",", thousandSeparator: " " })).toBe(
|
|
224
|
-
"1 234,57€",
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
const skNumber2 = new SwapKitNumber(0.5678);
|
|
228
|
-
expect(skNumber2.toCurrency()).toBe("$0.5678");
|
|
229
|
-
expect(skNumber2.toCurrency("€", { currencyPosition: "end", decimalSeparator: "," })).toBe("0,5678€");
|
|
230
|
-
|
|
231
|
-
const skNumber3 = new SwapKitNumber(0.00005678);
|
|
232
|
-
expect(skNumber3.toCurrency()).toBe("$0.00005678");
|
|
233
|
-
expect(
|
|
234
|
-
skNumber3.toCurrency("€", { currencyPosition: "end", decimalSeparator: ",", thousandSeparator: " " }),
|
|
235
|
-
).toBe("0,00005678€");
|
|
236
|
-
|
|
237
|
-
const skNumber4 = new SwapKitNumber(12345);
|
|
238
|
-
expect(skNumber4.toCurrency()).toBe("$12,345");
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
142
|
describe("add", () => {
|
|
243
143
|
test("adds same type numbers correctly", () => {
|
|
244
144
|
const skNumber1 = new SwapKitNumber(10);
|
|
@@ -183,7 +183,8 @@ export class BigIntArithmetics {
|
|
|
183
183
|
const valueStr = this.getValue("string");
|
|
184
184
|
const isNegative = valueStr.startsWith("-");
|
|
185
185
|
const [int = "0", dec = ""] = (isNegative ? valueStr.slice(1) : valueStr).split(".");
|
|
186
|
-
const
|
|
186
|
+
const valueRoundsToZero = int === "0" && Number.parseInt(dec.slice(0, fixedDigits), 10) === 0;
|
|
187
|
+
const sign = isNegative && !valueRoundsToZero ? "-" : "";
|
|
187
188
|
|
|
188
189
|
if (fixedDigits === 0) {
|
|
189
190
|
if (int === "0" && !dec) return "0";
|
|
@@ -219,29 +220,27 @@ export class BigIntArithmetics {
|
|
|
219
220
|
|
|
220
221
|
toCurrency(
|
|
221
222
|
currency = "$",
|
|
222
|
-
{
|
|
223
|
+
{
|
|
224
|
+
currencyPosition = "start",
|
|
225
|
+
decimal = 2,
|
|
226
|
+
decimalSeparator = ".",
|
|
227
|
+
thousandSeparator = ",",
|
|
228
|
+
trimTrailingZeros = true,
|
|
229
|
+
} = {},
|
|
223
230
|
) {
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
.with("end", () => `${formatted}${currency}`)
|
|
232
|
-
.otherwise(() => `${currency}${formatted}`);
|
|
233
|
-
}
|
|
231
|
+
const fixedValue = this.toFixed(decimal);
|
|
232
|
+
const isCurrencyAtEnd = currencyPosition === "end";
|
|
233
|
+
const [int = "0", dec = ""] = fixedValue.split(".");
|
|
234
|
+
|
|
235
|
+
const formattedInt = int.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
|
|
236
|
+
const hasDecimals = dec && Number.parseInt(dec, 10) > 0;
|
|
237
|
+
const formattedValue = hasDecimals ? `${formattedInt}${decimalSeparator}${dec}` : formattedInt;
|
|
234
238
|
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
const hasDecimals = roundedDec && Number.parseInt(roundedDec, 10) > 0;
|
|
239
|
-
const value = hasDecimals ? `${formattedInt}${decimalSeparator}${roundedDec}` : formattedInt;
|
|
239
|
+
// Prevent regex from taking too long for large values
|
|
240
|
+
const canTrimTrailingZeros = formattedValue.length < 100 && trimTrailingZeros && hasDecimals;
|
|
241
|
+
const value = canTrimTrailingZeros ? formattedValue.replace(/\.?0*$/, "") : formattedValue;
|
|
240
242
|
|
|
241
|
-
return
|
|
242
|
-
.with("start", () => `${currency}${value}`)
|
|
243
|
-
.with("end", () => `${value}${currency}`)
|
|
244
|
-
.otherwise(() => `${currency}${value}`);
|
|
243
|
+
return isCurrencyAtEnd ? `${value}${currency}` : `${currency}${value}`;
|
|
245
244
|
}
|
|
246
245
|
|
|
247
246
|
formatBigIntToSafeValue(value: bigint, decimal?: number) {
|
|
@@ -1,16 +1,142 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { Chain } from "@swapkit/types";
|
|
2
3
|
|
|
3
4
|
import type { DerivationPathArray } from "../../types";
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
DerivationPath,
|
|
7
|
+
derivationPathToString,
|
|
8
|
+
getDerivationPathFor,
|
|
9
|
+
getWalletFormatFor,
|
|
10
|
+
updateDerivationPath,
|
|
11
|
+
} from "../derivationPath";
|
|
5
12
|
|
|
6
13
|
describe("derivationPathToString", () => {
|
|
7
|
-
test("
|
|
8
|
-
|
|
9
|
-
expect(derivationPathToString(
|
|
14
|
+
test("full 5-element path", () => {
|
|
15
|
+
expect(derivationPathToString([44, 60, 0, 0, 0] as DerivationPathArray)).toBe("m/44'/60'/0'/0/0");
|
|
16
|
+
expect(derivationPathToString([84, 0, 0, 0, 5] as DerivationPathArray)).toBe("m/84'/0'/0'/0/5");
|
|
10
17
|
});
|
|
11
18
|
|
|
12
|
-
test("
|
|
13
|
-
|
|
14
|
-
expect(derivationPathToString(
|
|
19
|
+
test("4-element path without index", () => {
|
|
20
|
+
expect(derivationPathToString([44, 60, 0, 0] as DerivationPathArray)).toBe("m/44'/60'/0'/0");
|
|
21
|
+
expect(derivationPathToString([49, 2, 0, 1] as DerivationPathArray)).toBe("m/49'/2'/0'/1");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("3-element account path", () => {
|
|
25
|
+
expect(derivationPathToString([44, 60, 0] as unknown as DerivationPathArray)).toBe("m/44'/60'/0'");
|
|
26
|
+
expect(derivationPathToString([44, 501, 5] as unknown as DerivationPathArray)).toBe("m/44'/501'/5'");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("updateDerivationPath", () => {
|
|
31
|
+
const basePath: DerivationPathArray = [44, 60, 0, 0, 0];
|
|
32
|
+
|
|
33
|
+
test("updates index (last element)", () => {
|
|
34
|
+
expect(updateDerivationPath(basePath, { index: 5 })).toEqual([44, 60, 0, 0, 5]);
|
|
35
|
+
expect(updateDerivationPath(basePath, { index: 100 })).toEqual([44, 60, 0, 0, 100]);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("updates change (4th element)", () => {
|
|
39
|
+
expect(updateDerivationPath(basePath, { change: 1 })).toEqual([44, 60, 0, 1, 0]);
|
|
40
|
+
expect(updateDerivationPath([84, 0, 2, 0, 3], { change: 1 })).toEqual([84, 0, 2, 1, 3]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("updates account (3rd element)", () => {
|
|
44
|
+
expect(updateDerivationPath(basePath, { account: 5 })).toEqual([44, 60, 5, 0, 0]);
|
|
45
|
+
expect(updateDerivationPath([84, 0, 0, 1, 10], { account: 3 })).toEqual([84, 0, 3, 1, 10]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("returns unchanged path for empty params", () => {
|
|
49
|
+
expect(updateDerivationPath(basePath, {} as any)).toEqual(basePath);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("getDerivationPathFor", () => {
|
|
54
|
+
describe("EVM chains", () => {
|
|
55
|
+
test("Ethereum default path", () => {
|
|
56
|
+
expect(getDerivationPathFor({ chain: Chain.Ethereum, index: 0 })).toEqual([44, 60, 0, 0, 0]);
|
|
57
|
+
expect(getDerivationPathFor({ chain: Chain.Ethereum, index: 5 })).toEqual([44, 60, 0, 0, 5]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("Ethereum legacy type", () => {
|
|
61
|
+
expect(getDerivationPathFor({ chain: Chain.Ethereum, index: 3, type: "legacy" })).toEqual([44, 60, 0, 3]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("Ethereum account type", () => {
|
|
65
|
+
expect(getDerivationPathFor({ chain: Chain.Ethereum, index: 2, type: "account" })).toEqual([44, 60, 0, 2]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("Ethereum ledgerLive type", () => {
|
|
69
|
+
expect(getDerivationPathFor({ chain: Chain.Ethereum, index: 0, type: "ledgerLive" })).toEqual([44, 60, 0, 0, 0]);
|
|
70
|
+
expect(getDerivationPathFor({ addressIndex: 1, chain: Chain.Ethereum, index: 2, type: "ledgerLive" })).toEqual([
|
|
71
|
+
44, 60, 2, 0, 1,
|
|
72
|
+
]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("other EVM chains use same derivation", () => {
|
|
76
|
+
expect(getDerivationPathFor({ chain: Chain.BinanceSmartChain, index: 0 })).toEqual([44, 60, 0, 0, 0]);
|
|
77
|
+
expect(getDerivationPathFor({ chain: Chain.Avalanche, index: 0 })).toEqual([44, 60, 0, 0, 0]);
|
|
78
|
+
expect(getDerivationPathFor({ chain: Chain.Arbitrum, index: 0 })).toEqual([44, 60, 0, 0, 0]);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("Solana", () => {
|
|
83
|
+
test("default path", () => {
|
|
84
|
+
const result = getDerivationPathFor({ chain: Chain.Solana, index: 0 });
|
|
85
|
+
expect(result[1]).toBe(501);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("account type", () => {
|
|
89
|
+
expect(getDerivationPathFor({ chain: Chain.Solana, index: 3, type: "account" })).toEqual([44, 501, 0, 3]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("UTXO chains", () => {
|
|
94
|
+
test("Bitcoin nativeSegwitMiddleAccount", () => {
|
|
95
|
+
expect(getDerivationPathFor({ chain: Chain.Bitcoin, index: 0, type: "nativeSegwitMiddleAccount" })).toEqual([
|
|
96
|
+
84, 0, 0, 0, 0,
|
|
97
|
+
]);
|
|
98
|
+
expect(
|
|
99
|
+
getDerivationPathFor({ addressIndex: 5, chain: Chain.Bitcoin, index: 2, type: "nativeSegwitMiddleAccount" }),
|
|
100
|
+
).toEqual([84, 0, 2, 0, 5]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("Bitcoin segwit", () => {
|
|
104
|
+
expect(getDerivationPathFor({ chain: Chain.Bitcoin, index: 3, type: "segwit" })).toEqual([49, 0, 0, 0, 3]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("Bitcoin legacy", () => {
|
|
108
|
+
expect(getDerivationPathFor({ chain: Chain.Bitcoin, index: 0, type: "legacy" })).toEqual([44, 0, 0, 0, 0]);
|
|
109
|
+
expect(getDerivationPathFor({ chain: Chain.Bitcoin, index: 5, type: "legacy" })).toEqual([44, 0, 0, 0, 5]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("Litecoin uses chainId 2", () => {
|
|
113
|
+
expect(getDerivationPathFor({ chain: Chain.Litecoin, index: 0, type: "legacy" })).toEqual([44, 2, 0, 0, 0]);
|
|
114
|
+
expect(getDerivationPathFor({ chain: Chain.Litecoin, index: 0, type: "segwit" })).toEqual([49, 2, 0, 0, 0]);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("getWalletFormatFor", () => {
|
|
120
|
+
test("returns legacy for purpose 44", () => {
|
|
121
|
+
expect(getWalletFormatFor("m/44'/0'/0'/0/0")).toBe("legacy");
|
|
122
|
+
expect(getWalletFormatFor("m/44'/60'/0'/0/0")).toBe("legacy");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("returns p2sh for purpose 49", () => {
|
|
126
|
+
expect(getWalletFormatFor("m/49'/0'/0'/0/0")).toBe("p2sh");
|
|
127
|
+
expect(getWalletFormatFor("m/49'/2'/0'/0/0")).toBe("p2sh");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("returns bech32 for purpose 84 and others", () => {
|
|
131
|
+
expect(getWalletFormatFor("m/84'/0'/0'/0/0")).toBe("bech32");
|
|
132
|
+
expect(getWalletFormatFor("m/86'/0'/0'/0/0")).toBe("bech32");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("DerivationPath export", () => {
|
|
137
|
+
test("exports string paths for common chains", () => {
|
|
138
|
+
expect(typeof DerivationPath[Chain.Ethereum]).toBe("string");
|
|
139
|
+
expect(typeof DerivationPath[Chain.Bitcoin]).toBe("string");
|
|
140
|
+
expect(DerivationPath[Chain.Ethereum]).toMatch(/^m\/\d+'\/\d+'\/\d+'/);
|
|
15
141
|
});
|
|
16
142
|
});
|