@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.
@@ -5,7 +5,7 @@ import { AssetValue, getMinAmountByChain } from "../assetValue";
5
5
 
6
6
  describe("AssetValue", () => {
7
7
  describe("creation", () => {
8
- test("regres cases", () => {
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("assets creation", () => {
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 string", async () => {
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 string with multiple dashes", async () => {
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.todo("creates AssetValue with _ symbol", async () => {
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
- decimal: 8,
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: "XWBTC-resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75",
622
- ticker: "XWBTC",
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 if string is not in `@swapkit/tokens` lists", async () => {
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 if string is not in `@swapkit/tokens` lists with multiple dashes", async () => {
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 avax string with address from `@swapkit/tokens` lists", async () => {
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 if string is not in `@swapkit/tokens` lists", async () => {
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 avax string with address from `@swapkit/tokens` lists", async () => {
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("handles different currency symbols", () => {
263
+ test("currency symbols €, £, ¥", () => {
264
264
  const num = new BigIntArithmetics(1234.56);
265
- expect(num.toCurrency("€")).toContain("€");
266
- expect(num.toCurrency("£")).toContain("£");
267
- expect(num.toCurrency("¥")).toContain("¥");
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("handles currency position", () => {
270
+ test("currency position start and end", () => {
271
271
  const num = new BigIntArithmetics(1234.56);
272
- expect(num.toCurrency("€", { currencyPosition: "start" })).toMatch(/^€/);
273
- expect(num.toCurrency("€", { currencyPosition: "end" })).toMatch(/€$/);
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("handles custom separators", () => {
276
+ test("european format with custom separators", () => {
277
277
  const num = new BigIntArithmetics(1234567.89);
278
- const result = num.toCurrency("$", { decimalSeparator: ",", thousandSeparator: " " });
279
- expect(result).toContain(" ");
280
- expect(result).toContain(",");
278
+ expect(num.toCurrency("", { currencyPosition: "end", decimalSeparator: ",", thousandSeparator: "." })).toBe(
279
+ "1.234.567,89€",
280
+ );
281
281
  });
282
282
 
283
- test("handles zero with currency", () => {
284
- const num = new BigIntArithmetics(0);
285
- expect(num.toCurrency()).toContain("$");
286
- expect(num.toCurrency()).toContain("0");
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("handles custom decimal places", () => {
290
- const num = new BigIntArithmetics(1234.56789);
291
- const result = num.toCurrency("$", { decimal: 4 });
292
- expect(result).toContain("$");
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
+ });