@swapkit/helpers 4.5.7 → 4.5.8
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.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 +256 -16
- package/src/modules/__tests__/bigIntArithmetics.test.ts +47 -22
- package/src/modules/__tests__/feeMultiplier.test.ts +125 -0
- package/src/modules/__tests__/swapKitNumber.test.ts +0 -100
- package/src/modules/bigIntArithmetics.ts +7 -2
- 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
|
@@ -5,7 +5,7 @@ import { AssetValue, getMinAmountByChain } from "../assetValue";
|
|
|
5
5
|
|
|
6
6
|
describe("AssetValue", () => {
|
|
7
7
|
describe("creation", () => {
|
|
8
|
-
test("
|
|
8
|
+
test("regression cases", () => {
|
|
9
9
|
const arbWeth = AssetValue.from({ asset: "ARB.WETH-0x82aF49447D8a07e3bd95BD0d56f35241523fBab1" });
|
|
10
10
|
expect(arbWeth.toString()).toBe("ARB.WETH-0x82aF49447D8a07e3bd95BD0d56f35241523fBab1");
|
|
11
11
|
|
|
@@ -90,7 +90,7 @@ describe("AssetValue", () => {
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
describe("NEAR", () => {
|
|
93
|
-
test("assets creation", () => {
|
|
93
|
+
test("NEAR token assets creation", () => {
|
|
94
94
|
// Standard NEAR token formats
|
|
95
95
|
const wNear = AssetValue.from({ asset: "NEAR.wNEAR-wrap.near" });
|
|
96
96
|
expect(wNear.toString()).toBe("NEAR.wNEAR-wrap.near");
|
|
@@ -339,7 +339,7 @@ describe("AssetValue", () => {
|
|
|
339
339
|
});
|
|
340
340
|
|
|
341
341
|
describe("SUI", () => {
|
|
342
|
-
test("
|
|
342
|
+
test("SUI native asset creation", () => {
|
|
343
343
|
const sui = AssetValue.from({ asset: "SUI.SUI" });
|
|
344
344
|
expect(sui.toString()).toBe("SUI.SUI");
|
|
345
345
|
expect(sui).toMatchObject({ address: undefined, chain: Chain.Sui, symbol: "SUI", ticker: "SUI" });
|
|
@@ -534,7 +534,7 @@ describe("toString", () => {
|
|
|
534
534
|
});
|
|
535
535
|
|
|
536
536
|
describe("fromIdentifier", () => {
|
|
537
|
-
test("creates AssetValue from
|
|
537
|
+
test("creates AssetValue from known token identifier", async () => {
|
|
538
538
|
const avaxUSDCAsset = await AssetValue.from({
|
|
539
539
|
asset: "AVAX.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e",
|
|
540
540
|
asyncTokenLookup: true,
|
|
@@ -553,7 +553,7 @@ describe("fromIdentifier", () => {
|
|
|
553
553
|
);
|
|
554
554
|
});
|
|
555
555
|
|
|
556
|
-
test("creates AssetValue from
|
|
556
|
+
test("creates AssetValue from identifier with multiple dashes", async () => {
|
|
557
557
|
const ethPendleLptAsset = await AssetValue.from({ asset: "ETH.PENDLE-LPT-0x1234", asyncTokenLookup: true });
|
|
558
558
|
|
|
559
559
|
expect(ethPendleLptAsset).toEqual(
|
|
@@ -571,7 +571,7 @@ describe("fromIdentifier", () => {
|
|
|
571
571
|
});
|
|
572
572
|
|
|
573
573
|
describe("fromString", () => {
|
|
574
|
-
test("creates AssetValue from string", async () => {
|
|
574
|
+
test("creates AssetValue from unknown token string", async () => {
|
|
575
575
|
const fakeAvaxAssetString = "AVAX.ASDF-1234";
|
|
576
576
|
const fakeAvaxAsset = await AssetValue.from({ asset: fakeAvaxAssetString, asyncTokenLookup: true });
|
|
577
577
|
|
|
@@ -588,7 +588,7 @@ describe("fromString", () => {
|
|
|
588
588
|
);
|
|
589
589
|
});
|
|
590
590
|
|
|
591
|
-
test("creates AssetValue from string with multiple dashes", async () => {
|
|
591
|
+
test("creates AssetValue from unknown token string with multiple dashes", async () => {
|
|
592
592
|
const fakeAvaxAssetString = "AVAX.ASDF-LP-1234";
|
|
593
593
|
const fakeAvaxAsset = await AssetValue.from({ asset: fakeAvaxAssetString, asyncTokenLookup: true });
|
|
594
594
|
|
|
@@ -605,7 +605,7 @@ describe("fromString", () => {
|
|
|
605
605
|
);
|
|
606
606
|
});
|
|
607
607
|
|
|
608
|
-
test
|
|
608
|
+
test("creates AssetValue with _ symbol", async () => {
|
|
609
609
|
const radixXWBTC = await AssetValue.from({
|
|
610
610
|
asset: "XRD.XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75",
|
|
611
611
|
asyncTokenLookup: true,
|
|
@@ -615,11 +615,12 @@ describe("fromString", () => {
|
|
|
615
615
|
expect.objectContaining({
|
|
616
616
|
address: "resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75",
|
|
617
617
|
chain: Chain.Radix,
|
|
618
|
-
|
|
618
|
+
// TODO: Failed to fetch Radix asset decimals for resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75: helpers_invalid_response: {"status":404,"statusText":"Not Found"}
|
|
619
|
+
// decimal: 8,
|
|
619
620
|
isGasAsset: false,
|
|
620
621
|
isSynthetic: false,
|
|
621
|
-
symbol: "
|
|
622
|
-
ticker: "
|
|
622
|
+
symbol: "xwBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75",
|
|
623
|
+
ticker: "xwBTC",
|
|
623
624
|
}),
|
|
624
625
|
);
|
|
625
626
|
});
|
|
@@ -877,6 +878,11 @@ describe("fromUrl", () => {
|
|
|
877
878
|
expect(fromUrlTron.ticker).toBe("TRX");
|
|
878
879
|
expect(fromUrlTron.isGasAsset).toBe(true);
|
|
879
880
|
});
|
|
881
|
+
|
|
882
|
+
test("throws error for invalid URL without dot separator", () => {
|
|
883
|
+
expect(() => AssetValue.fromUrl("INVALIDURL")).toThrow("helpers_invalid_asset_url");
|
|
884
|
+
expect(() => AssetValue.fromUrl("")).toThrow("helpers_invalid_asset_url");
|
|
885
|
+
});
|
|
880
886
|
});
|
|
881
887
|
|
|
882
888
|
describe("fromIdentifierSync", () => {
|
|
@@ -932,7 +938,7 @@ describe("fromStringSync", () => {
|
|
|
932
938
|
);
|
|
933
939
|
});
|
|
934
940
|
|
|
935
|
-
test("returns safe decimals
|
|
941
|
+
test("returns safe decimals for unknown token sync", async () => {
|
|
936
942
|
await AssetValue.loadStaticAssets();
|
|
937
943
|
const fakeAvaxUSDCAssetString = "AVAX.USDC-1234";
|
|
938
944
|
const fakeAvaxUSDCAsset = AssetValue.from({ asset: fakeAvaxUSDCAssetString });
|
|
@@ -951,7 +957,7 @@ describe("fromStringSync", () => {
|
|
|
951
957
|
);
|
|
952
958
|
});
|
|
953
959
|
|
|
954
|
-
test("returns safe decimals
|
|
960
|
+
test("returns safe decimals for unknown token sync with multiple dashes", async () => {
|
|
955
961
|
await AssetValue.loadStaticAssets();
|
|
956
962
|
const fakeAvaxUSDCAssetString = "AVAX.USDC-LPT-1234";
|
|
957
963
|
const fakeAvaxUSDCAsset2 = AssetValue.from({ asset: fakeAvaxUSDCAssetString });
|
|
@@ -970,7 +976,7 @@ describe("fromStringSync", () => {
|
|
|
970
976
|
);
|
|
971
977
|
});
|
|
972
978
|
|
|
973
|
-
test("returns proper
|
|
979
|
+
test("returns proper BTC.b token with address from static lists", async () => {
|
|
974
980
|
await AssetValue.loadStaticAssets();
|
|
975
981
|
const avaxBTCb = "AVAX.BTC.b-0x152b9d0fdc40c096757f570a51e494bd4b943e50";
|
|
976
982
|
const AvaxBTCb = AssetValue.from({ asset: avaxBTCb });
|
|
@@ -1011,7 +1017,7 @@ describe("fromStringWithBaseSync", () => {
|
|
|
1011
1017
|
expect(btc.getBaseValue("string")).toBe("5200000000000");
|
|
1012
1018
|
});
|
|
1013
1019
|
|
|
1014
|
-
test("returns safe decimals
|
|
1020
|
+
test("returns safe decimals for unknown token with base decimal conversion", async () => {
|
|
1015
1021
|
await AssetValue.loadStaticAssets();
|
|
1016
1022
|
const fakeAvaxUSDCAssetString = "AVAX.USDC-1234";
|
|
1017
1023
|
const fakeAvaxUSDCAsset = AssetValue.from({ asset: fakeAvaxUSDCAssetString, fromBaseDecimal: 8, value: 1 });
|
|
@@ -1033,7 +1039,7 @@ describe("fromStringWithBaseSync", () => {
|
|
|
1033
1039
|
expect(fakeAvaxUSDCAsset.getBaseValue("string")).toBe("10000000000");
|
|
1034
1040
|
});
|
|
1035
1041
|
|
|
1036
|
-
test("returns proper
|
|
1042
|
+
test("returns proper USDC token with base decimal conversion from static lists", async () => {
|
|
1037
1043
|
await AssetValue.loadStaticAssets();
|
|
1038
1044
|
const avaxUSDC = "AVAX.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e";
|
|
1039
1045
|
const AvaxUSDC = AssetValue.from({ asset: avaxUSDC, fromBaseDecimal: 8, value: 100000000 });
|
|
@@ -1650,3 +1656,237 @@ describe("asyncTokenLookup", () => {
|
|
|
1650
1656
|
});
|
|
1651
1657
|
});
|
|
1652
1658
|
});
|
|
1659
|
+
|
|
1660
|
+
describe("arithmetic", () => {
|
|
1661
|
+
test("add with number, string, AssetValue, and chained calls", () => {
|
|
1662
|
+
const base = AssetValue.from({ asset: "BTC.BTC", value: 10 });
|
|
1663
|
+
const other = AssetValue.from({ asset: "ETH.ETH", value: 5 });
|
|
1664
|
+
|
|
1665
|
+
expect(base.add(5).getValue("string")).toBe("15");
|
|
1666
|
+
expect(base.add("2.5").getValue("string")).toBe("12.5");
|
|
1667
|
+
expect(base.add(other).getValue("string")).toBe("15");
|
|
1668
|
+
expect(base.add(1, 2, 3).getValue("string")).toBe("16");
|
|
1669
|
+
expect(base.add(0.00000001).getValue("string")).toBe("10.00000001");
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1672
|
+
test("sub with negative result and precision edge", () => {
|
|
1673
|
+
const base = AssetValue.from({ asset: "MAYA.CACAO", value: 100 });
|
|
1674
|
+
|
|
1675
|
+
expect(base.sub(30).getValue("string")).toBe("70");
|
|
1676
|
+
expect(base.sub(100).getValue("string")).toBe("0");
|
|
1677
|
+
expect(base.sub(150).getValue("string")).toBe("-50");
|
|
1678
|
+
expect(base.sub(0.00000001).getValue("string")).toBe("99.99999999");
|
|
1679
|
+
});
|
|
1680
|
+
|
|
1681
|
+
test("mul with decimals, zero, and large numbers", () => {
|
|
1682
|
+
const base = AssetValue.from({ asset: "SOL.SOL", value: "0.00001" });
|
|
1683
|
+
|
|
1684
|
+
expect(base.mul(1000000).getValue("string")).toBe("10");
|
|
1685
|
+
expect(base.mul(0).getValue("string")).toBe("0");
|
|
1686
|
+
expect(base.mul(0.5).getValue("string")).toBe("0.000005");
|
|
1687
|
+
|
|
1688
|
+
const large = AssetValue.from({ asset: "ETH.ETH", value: "999999999" });
|
|
1689
|
+
expect(large.mul(2).getValue("string")).toBe("1999999998");
|
|
1690
|
+
});
|
|
1691
|
+
|
|
1692
|
+
test("div with precision loss prevention and small divisors", () => {
|
|
1693
|
+
const base = AssetValue.from({ asset: "GAIA.ATOM", value: 1 });
|
|
1694
|
+
|
|
1695
|
+
expect(base.div(3).getValue("string")).toMatch(/^0\.333333/);
|
|
1696
|
+
expect(base.div(1000000).getValue("string")).toBe("0.000001");
|
|
1697
|
+
expect(base.div(100000000).getValue("string")).toBe("0.00000001");
|
|
1698
|
+
|
|
1699
|
+
expect(() => base.div(0)).toThrow();
|
|
1700
|
+
});
|
|
1701
|
+
|
|
1702
|
+
test("chained operations preserve synth/trade identity", () => {
|
|
1703
|
+
const synth = AssetValue.from({ asset: "THOR.BTC/BTC", value: 1 });
|
|
1704
|
+
const trade = AssetValue.from({ asset: "THOR.ETH~ETH", value: 1 });
|
|
1705
|
+
|
|
1706
|
+
const synthResult = synth.add(1).mul(2).div(4);
|
|
1707
|
+
expect(synthResult.isSynthetic).toBe(true);
|
|
1708
|
+
expect(synthResult.symbol).toBe("BTC/BTC");
|
|
1709
|
+
|
|
1710
|
+
const tradeResult = trade.sub(0.5).mul(3);
|
|
1711
|
+
expect(tradeResult.isTradeAsset).toBe(true);
|
|
1712
|
+
expect(tradeResult.symbol).toBe("ETH~ETH");
|
|
1713
|
+
});
|
|
1714
|
+
});
|
|
1715
|
+
|
|
1716
|
+
describe("comparison", () => {
|
|
1717
|
+
test("gt/gte/lt/lte with various value types", () => {
|
|
1718
|
+
const value = AssetValue.from({ asset: "BTC.BTC", value: "0.00000100" });
|
|
1719
|
+
|
|
1720
|
+
expect(value.gt(0.00000099)).toBe(true);
|
|
1721
|
+
expect(value.gt(0.000001)).toBe(false);
|
|
1722
|
+
expect(value.gt("0.00000101")).toBe(false);
|
|
1723
|
+
|
|
1724
|
+
expect(value.gte(0.000001)).toBe(true);
|
|
1725
|
+
expect(value.gte("0.00000101")).toBe(false);
|
|
1726
|
+
|
|
1727
|
+
expect(value.lt(0.00000101)).toBe(true);
|
|
1728
|
+
expect(value.lt(0.000001)).toBe(false);
|
|
1729
|
+
|
|
1730
|
+
expect(value.lte(0.000001)).toBe(true);
|
|
1731
|
+
expect(value.lte(0.00000099)).toBe(false);
|
|
1732
|
+
});
|
|
1733
|
+
|
|
1734
|
+
test("eqValue across different decimals", () => {
|
|
1735
|
+
const btc = AssetValue.from({ asset: "BTC.BTC", value: 1 });
|
|
1736
|
+
const eth = AssetValue.from({ asset: "ETH.ETH", value: 1 });
|
|
1737
|
+
const usdc = AssetValue.from({ asset: "ETH.USDC-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", value: 1 });
|
|
1738
|
+
|
|
1739
|
+
expect(btc.eqValue(eth)).toBe(true);
|
|
1740
|
+
expect(btc.eqValue(usdc)).toBe(true);
|
|
1741
|
+
expect(btc.eqValue(1)).toBe(true);
|
|
1742
|
+
expect(btc.eqValue("1")).toBe(true);
|
|
1743
|
+
expect(btc.eqValue(1.00000001)).toBe(false);
|
|
1744
|
+
});
|
|
1745
|
+
|
|
1746
|
+
test("comparison with zero and negative", () => {
|
|
1747
|
+
const zero = AssetValue.from({ asset: "BTC.BTC", value: 0 });
|
|
1748
|
+
const neg = AssetValue.from({ asset: "BTC.BTC", value: 10 }).sub(15);
|
|
1749
|
+
|
|
1750
|
+
expect(zero.eqValue(0)).toBe(true);
|
|
1751
|
+
expect(zero.gt(0)).toBe(false);
|
|
1752
|
+
expect(zero.lt(0)).toBe(false);
|
|
1753
|
+
|
|
1754
|
+
expect(neg.lt(0)).toBe(true);
|
|
1755
|
+
expect(neg.lte(-5)).toBe(true);
|
|
1756
|
+
expect(neg.gt(-6)).toBe(true);
|
|
1757
|
+
});
|
|
1758
|
+
});
|
|
1759
|
+
|
|
1760
|
+
describe("getValue and getBaseValue", () => {
|
|
1761
|
+
test("getBaseValue respects asset decimal", async () => {
|
|
1762
|
+
await AssetValue.loadStaticAssets();
|
|
1763
|
+
|
|
1764
|
+
const btc = AssetValue.from({ asset: "BTC.BTC", value: 1.5 });
|
|
1765
|
+
expect(btc.getBaseValue("bigint")).toBe(150000000n);
|
|
1766
|
+
expect(btc.getBaseValue("string")).toBe("150000000");
|
|
1767
|
+
|
|
1768
|
+
const usdc = AssetValue.from({ asset: "AVAX.USDC-0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", value: 100 });
|
|
1769
|
+
expect(usdc.getBaseValue("bigint", 6)).toBe(100000000n);
|
|
1770
|
+
|
|
1771
|
+
const cacao = AssetValue.from({ asset: "MAYA.CACAO", value: 1 });
|
|
1772
|
+
expect(cacao.getBaseValue("bigint")).toBe(10000000000n);
|
|
1773
|
+
});
|
|
1774
|
+
|
|
1775
|
+
test("getValue truncates to requested decimal", () => {
|
|
1776
|
+
const eth = AssetValue.from({ asset: "ETH.ETH", value: "1.123456789012345678" });
|
|
1777
|
+
|
|
1778
|
+
expect(eth.getValue("string", 18)).toBe("1.123456789012345678");
|
|
1779
|
+
expect(eth.getValue("string", 8)).toBe("1.12345679");
|
|
1780
|
+
expect(eth.getValue("string", 2)).toBe("1.12");
|
|
1781
|
+
expect(eth.getValue("number", 4)).toBe(1.1235);
|
|
1782
|
+
});
|
|
1783
|
+
|
|
1784
|
+
test("getValue bigint scaling", () => {
|
|
1785
|
+
const value = AssetValue.from({ asset: "BTC.BTC", value: 2.5 });
|
|
1786
|
+
expect(value.getValue("bigint")).toBe(250000000n);
|
|
1787
|
+
});
|
|
1788
|
+
});
|
|
1789
|
+
|
|
1790
|
+
describe("formatting", () => {
|
|
1791
|
+
test("toSignificant with integers, decimals, and edge cases", () => {
|
|
1792
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 123456 }).toSignificant(3)).toBe("123000");
|
|
1793
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0.00012345 }).toSignificant(3)).toBe("0.000123");
|
|
1794
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0 }).toSignificant(6)).toBe("0");
|
|
1795
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 9.99999 }).toSignificant(2)).toBe("9.9");
|
|
1796
|
+
});
|
|
1797
|
+
|
|
1798
|
+
test("toFixed rounding and padding", () => {
|
|
1799
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: 1.005 }).toFixed(2)).toBe("1.01");
|
|
1800
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: 1.004 }).toFixed(2)).toBe("1.00");
|
|
1801
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: 100 }).toFixed(4)).toBe("100.0000");
|
|
1802
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: -1.999 }).toFixed(2)).toBe("-2.00");
|
|
1803
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: 0 }).toFixed(0)).toBe("0");
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
test("toAbbreviation across magnitudes", () => {
|
|
1807
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 500 }).toAbbreviation()).toBe("500");
|
|
1808
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 1500 }).toAbbreviation()).toBe("1.50K");
|
|
1809
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 1500000 }).toAbbreviation()).toBe("1.50M");
|
|
1810
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 1500000000 }).toAbbreviation()).toBe("1.50B");
|
|
1811
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: "1500000000000" }).toAbbreviation()).toBe("1.50T");
|
|
1812
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 1234 }).toAbbreviation(0)).toBe("1K");
|
|
1813
|
+
});
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
describe("toCurrency", () => {
|
|
1817
|
+
test("small values preserve precision without floating-point artifacts", () => {
|
|
1818
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0.015072 }).toCurrency("")).toBe("0.015072");
|
|
1819
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0.333145 }).toCurrency("")).toBe("0.333145");
|
|
1820
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0.00000548 }).toCurrency("")).toBe("0.00000548");
|
|
1821
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0.1 }).toCurrency("")).toBe("0.1");
|
|
1822
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 0.10000001 }).toCurrency("")).toBe("0.10000001");
|
|
1823
|
+
});
|
|
1824
|
+
|
|
1825
|
+
test("negative small values handled correctly", () => {
|
|
1826
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: -0.015072 }).toCurrency("")).toBe("-0.015072");
|
|
1827
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: -0.00000001 }).toCurrency("")).toBe("-0.00000001");
|
|
1828
|
+
});
|
|
1829
|
+
|
|
1830
|
+
test("large values with thousand separators and rounding", () => {
|
|
1831
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 1234567.891 }).toCurrency("$")).toBe("$1,234,567.89");
|
|
1832
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 1000000 }).toCurrency("$")).toBe("$1,000,000");
|
|
1833
|
+
expect(AssetValue.from({ asset: "ETH.ETH", value: 999.999 }).toCurrency("$")).toBe("$1,000");
|
|
1834
|
+
});
|
|
1835
|
+
|
|
1836
|
+
test("custom currency symbol and position", () => {
|
|
1837
|
+
const v = AssetValue.from({ asset: "ETH.ETH", value: 1234.56 });
|
|
1838
|
+
expect(v.toCurrency("€", { currencyPosition: "end" })).toBe("1,234.56€");
|
|
1839
|
+
expect(v.toCurrency("¥", { currencyPosition: "start" })).toBe("¥1,234.56");
|
|
1840
|
+
expect(v.toCurrency("", { decimal: 4 })).toBe("1,234.5600");
|
|
1841
|
+
});
|
|
1842
|
+
|
|
1843
|
+
test("custom separators for european format", () => {
|
|
1844
|
+
const v = AssetValue.from({ asset: "ETH.ETH", value: 1234567.89 });
|
|
1845
|
+
expect(v.toCurrency("€", { currencyPosition: "end", decimalSeparator: ",", thousandSeparator: "." })).toBe(
|
|
1846
|
+
"1.234.567,89€",
|
|
1847
|
+
);
|
|
1848
|
+
});
|
|
1849
|
+
|
|
1850
|
+
test("zero value", () => {
|
|
1851
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: 0 }).toCurrency("$")).toBe("$0");
|
|
1852
|
+
expect(AssetValue.from({ asset: "BTC.BTC", value: 0 }).toCurrency("")).toBe("0");
|
|
1853
|
+
});
|
|
1854
|
+
});
|
|
1855
|
+
|
|
1856
|
+
describe("edge cases", () => {
|
|
1857
|
+
test("set creates immutable copy", () => {
|
|
1858
|
+
const a = AssetValue.from({ asset: "THOR.ETH/ETH", value: 10 });
|
|
1859
|
+
const b = a.set(20);
|
|
1860
|
+
|
|
1861
|
+
expect(a.getValue("string")).toBe("10");
|
|
1862
|
+
expect(b.getValue("string")).toBe("20");
|
|
1863
|
+
expect(b.isSynthetic).toBe(true);
|
|
1864
|
+
expect(b.toString({ includeSynthProtocol: true })).toBe("THOR.ETH/ETH");
|
|
1865
|
+
});
|
|
1866
|
+
|
|
1867
|
+
test("minimum precision values", () => {
|
|
1868
|
+
const btcMin = AssetValue.from({ asset: "BTC.BTC", value: 0.00000001 });
|
|
1869
|
+
expect(btcMin.getBaseValue("bigint")).toBe(1n);
|
|
1870
|
+
expect(btcMin.mul(2).getBaseValue("bigint")).toBe(2n);
|
|
1871
|
+
expect(btcMin.div(2).getBaseValue("bigint")).toBe(1n);
|
|
1872
|
+
|
|
1873
|
+
const ethMin = AssetValue.from({ asset: "ETH.ETH", value: "0.000000000000000001" });
|
|
1874
|
+
expect(ethMin.getValue("string")).toBe("0.000000000000000001");
|
|
1875
|
+
});
|
|
1876
|
+
|
|
1877
|
+
test("large value arithmetic precision", () => {
|
|
1878
|
+
const large1 = AssetValue.from({ asset: "ETH.ETH", value: "999999999999999" });
|
|
1879
|
+
const large2 = AssetValue.from({ asset: "ETH.ETH", value: "1" });
|
|
1880
|
+
|
|
1881
|
+
expect(large1.add(large2).getValue("string")).toBe("1000000000000000");
|
|
1882
|
+
expect(large1.mul(2).getValue("string")).toBe("1999999999999998");
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
test("fromBaseDecimal conversion", () => {
|
|
1886
|
+
const fromBase8 = AssetValue.from({ asset: "BTC.BTC", fromBaseDecimal: 8, value: 100000000 });
|
|
1887
|
+
expect(fromBase8.getValue("string")).toBe("1");
|
|
1888
|
+
|
|
1889
|
+
const fromBase18 = AssetValue.from({ asset: "ETH.ETH", fromBaseDecimal: 18, value: "1000000000000000000" });
|
|
1890
|
+
expect(fromBase18.getValue("string")).toBe("1");
|
|
1891
|
+
});
|
|
1892
|
+
});
|
|
@@ -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,62 @@ 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 preserve precision without floating-point artifacts", () => {
|
|
284
|
+
expect(new BigIntArithmetics(0.015072).toCurrency("")).toBe("0.015072");
|
|
285
|
+
expect(new BigIntArithmetics(0.333145).toCurrency("")).toBe("0.333145");
|
|
286
|
+
expect(new BigIntArithmetics(0.000005).toCurrency("")).toBe("0.000005");
|
|
287
|
+
expect(new BigIntArithmetics(0.00000548).toCurrency("")).toBe("0.00000548");
|
|
288
|
+
expect(new BigIntArithmetics(0.00003801).toCurrency("")).toBe("0.00003801");
|
|
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.10000001");
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test("negative small values", () => {
|
|
298
|
+
expect(new BigIntArithmetics(-0.015072).toCurrency("")).toBe("-0.015072");
|
|
299
|
+
expect(new BigIntArithmetics(-0.00000001).toCurrency("")).toBe("-0.00000001");
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test("values >= 1 round to decimal param", () => {
|
|
303
|
+
expect(new BigIntArithmetics(5.12).toCurrency("", { decimal: 2 })).toBe("5.12");
|
|
304
|
+
expect(new BigIntArithmetics(80.865327).toCurrency("", { decimal: 2 })).toBe("80.87");
|
|
305
|
+
expect(new BigIntArithmetics(33.432207).toCurrency("", { decimal: 2 })).toBe("33.43");
|
|
306
|
+
expect(new BigIntArithmetics(999.999).toCurrency("$")).toBe("$1,000");
|
|
307
|
+
expect(new BigIntArithmetics(0.0000000000000000000000000000001).toCurrency("", { decimal: 8 })).toBe("0");
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("zero value", () => {
|
|
311
|
+
expect(new BigIntArithmetics(0).toCurrency("$")).toBe("$0");
|
|
312
|
+
expect(new BigIntArithmetics(0).toCurrency("")).toBe("0");
|
|
287
313
|
});
|
|
288
314
|
|
|
289
|
-
test("
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
expect(result).toContain("1");
|
|
315
|
+
test("custom decimal separator for small values", () => {
|
|
316
|
+
expect(new BigIntArithmetics(0.015072).toCurrency("€", { currencyPosition: "end", decimalSeparator: "," })).toBe(
|
|
317
|
+
"0,015072€",
|
|
318
|
+
);
|
|
294
319
|
});
|
|
295
320
|
});
|
|
296
321
|
|
|
@@ -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
|
+
});
|