@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
|
@@ -2,37 +2,119 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
import { Chain } from "@swapkit/types";
|
|
3
3
|
|
|
4
4
|
import { findAssetBy } from "../asset";
|
|
5
|
-
import { getTHORNameCost } from "../others";
|
|
5
|
+
import { getChainIdentifier, getMAYANameCost, getTHORNameCost, warnOnce, wrapWithThrow } from "../others";
|
|
6
6
|
|
|
7
7
|
describe("getTHORNameCost", () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
[10, 20],
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
for (const [years = 0, expected = 10] of costCases) {
|
|
17
|
-
test(`returns correct ${expected} cost for ${years} years`, () => {
|
|
18
|
-
const result = getTHORNameCost(years);
|
|
19
|
-
expect(result).toBe(expected);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
8
|
+
test("returns 10 + numberOfYears", () => {
|
|
9
|
+
expect(getTHORNameCost(0)).toBe(10);
|
|
10
|
+
expect(getTHORNameCost(1)).toBe(11);
|
|
11
|
+
expect(getTHORNameCost(5)).toBe(15);
|
|
12
|
+
expect(getTHORNameCost(10)).toBe(20);
|
|
22
13
|
});
|
|
23
14
|
|
|
24
|
-
test("throws
|
|
15
|
+
test("throws for negative years in THORName cost", () => {
|
|
25
16
|
expect(() => getTHORNameCost(-1)).toThrow("helpers_invalid_number_of_years");
|
|
17
|
+
expect(() => getTHORNameCost(-100)).toThrow("helpers_invalid_number_of_years");
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("getMAYANameCost", () => {
|
|
22
|
+
test("returns 10 + (numberOfYears * 1.0512)", () => {
|
|
23
|
+
expect(getMAYANameCost(0)).toBe(10);
|
|
24
|
+
expect(getMAYANameCost(1)).toBe(11.0512);
|
|
25
|
+
expect(getMAYANameCost(5)).toBeCloseTo(15.256, 3);
|
|
26
|
+
expect(getMAYANameCost(10)).toBeCloseTo(20.512, 3);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("throws for negative years in MAYAName cost", () => {
|
|
30
|
+
expect(() => getMAYANameCost(-1)).toThrow("helpers_invalid_number_of_years");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("getChainIdentifier", () => {
|
|
35
|
+
test("returns CHAIN.RUNE for THORChain", () => {
|
|
36
|
+
expect(getChainIdentifier(Chain.THORChain)).toBe("THOR.RUNE");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("returns CHAIN.ATOM for Cosmos", () => {
|
|
40
|
+
expect(getChainIdentifier(Chain.Cosmos)).toBe("GAIA.ATOM");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("returns CHAIN only for BinanceSmartChain", () => {
|
|
44
|
+
expect(getChainIdentifier(Chain.BinanceSmartChain)).toBe("BSC");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("returns CHAIN.CHAIN for other chains", () => {
|
|
48
|
+
expect(getChainIdentifier(Chain.Bitcoin)).toBe("BTC.BTC");
|
|
49
|
+
expect(getChainIdentifier(Chain.Ethereum)).toBe("ETH.ETH");
|
|
50
|
+
expect(getChainIdentifier(Chain.Avalanche)).toBe("AVAX.AVAX");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("wrapWithThrow", () => {
|
|
55
|
+
test("returns function result on success", () => {
|
|
56
|
+
expect(wrapWithThrow(() => 42)).toBe(42);
|
|
57
|
+
expect(wrapWithThrow(() => "hello")).toBe("hello");
|
|
58
|
+
expect(wrapWithThrow(() => ({ a: 1 }))).toEqual({ a: 1 });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("returns undefined on error without errorKey", () => {
|
|
62
|
+
expect(
|
|
63
|
+
wrapWithThrow(() => {
|
|
64
|
+
throw new Error("test");
|
|
65
|
+
}),
|
|
66
|
+
).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("throws SwapKitError when errorKey provided", () => {
|
|
70
|
+
expect(() =>
|
|
71
|
+
wrapWithThrow(() => {
|
|
72
|
+
throw new Error("test");
|
|
73
|
+
}, "helpers_invalid_identifier"),
|
|
74
|
+
).toThrow("helpers_invalid_identifier");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("warnOnce", () => {
|
|
79
|
+
// Note: warnOnce skips console.warn in test environment (NODE_ENV=test)
|
|
80
|
+
// We test the behavior by calling the function multiple times and observing
|
|
81
|
+
// that the function doesn't throw and handles repeated calls gracefully
|
|
82
|
+
|
|
83
|
+
test("does not throw when condition is false", () => {
|
|
84
|
+
expect(() => warnOnce({ condition: false, id: "test_false_condition", warning: "should not warn" })).not.toThrow();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("does not throw when condition is true", () => {
|
|
88
|
+
const uniqueId = `test_warns_${Date.now()}`;
|
|
89
|
+
expect(() => warnOnce({ condition: true, id: uniqueId, warning: "test warning message" })).not.toThrow();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("handles repeated calls with same id without throwing", () => {
|
|
93
|
+
const uniqueId = `test_once_${Date.now()}`;
|
|
94
|
+
expect(() => {
|
|
95
|
+
warnOnce({ condition: true, id: uniqueId, warning: "first warn" });
|
|
96
|
+
warnOnce({ condition: true, id: uniqueId, warning: "second warn" });
|
|
97
|
+
warnOnce({ condition: true, id: uniqueId, warning: "third warn" });
|
|
98
|
+
}).not.toThrow();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("handles multiple different ids without throwing", () => {
|
|
102
|
+
const uniqueId1 = `test_different_1_${Date.now()}`;
|
|
103
|
+
const uniqueId2 = `test_different_2_${Date.now()}`;
|
|
104
|
+
expect(() => {
|
|
105
|
+
warnOnce({ condition: true, id: uniqueId1, warning: "warn 1" });
|
|
106
|
+
warnOnce({ condition: true, id: uniqueId2, warning: "warn 2" });
|
|
107
|
+
}).not.toThrow();
|
|
26
108
|
});
|
|
27
109
|
});
|
|
28
110
|
|
|
29
111
|
describe("getAssetBy", () => {
|
|
30
|
-
test("find asset by identifier", async () => {
|
|
112
|
+
test("find ETH asset by identifier", async () => {
|
|
31
113
|
const assetByIdentifier = await findAssetBy({ identifier: "ETH.ETH" });
|
|
32
114
|
expect(assetByIdentifier).toBe("ETH.ETH");
|
|
33
115
|
});
|
|
34
116
|
|
|
35
|
-
test("find
|
|
117
|
+
test("find ETH token by chain and contract", async () => {
|
|
36
118
|
const assetByChainAndContract = await findAssetBy({
|
|
37
119
|
chain: Chain.Ethereum,
|
|
38
120
|
contract: "0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48",
|
|
@@ -48,12 +130,12 @@ describe("getAssetBy", () => {
|
|
|
48
130
|
});
|
|
49
131
|
|
|
50
132
|
describe(Chain.Radix, () => {
|
|
51
|
-
test("find
|
|
133
|
+
test("find Radix XRD by identifier", async () => {
|
|
52
134
|
const assetByChainAndContract = await findAssetBy({ identifier: "XRD.XRD" });
|
|
53
135
|
expect(assetByChainAndContract?.toUpperCase()).toBe("XRD.XRD".toUpperCase());
|
|
54
136
|
});
|
|
55
137
|
|
|
56
|
-
test("find
|
|
138
|
+
test("find Radix token by chain and contract", async () => {
|
|
57
139
|
const assetByChainAndContract = await findAssetBy({
|
|
58
140
|
chain: Chain.Radix,
|
|
59
141
|
contract: "resource_rdx1t580qxc7upat7lww4l2c4jckacafjeudxj5wpjrrct0p3e82sq4y75",
|
|
@@ -65,12 +147,12 @@ describe("getAssetBy", () => {
|
|
|
65
147
|
});
|
|
66
148
|
|
|
67
149
|
describe(Chain.Solana, () => {
|
|
68
|
-
test("find
|
|
150
|
+
test("find Solana SOL by identifier", async () => {
|
|
69
151
|
const assetByChainAndContract = await findAssetBy({ identifier: "SOL.SOL" });
|
|
70
152
|
expect(assetByChainAndContract?.toUpperCase()).toBe("SOL.SOL".toUpperCase());
|
|
71
153
|
});
|
|
72
154
|
|
|
73
|
-
test("find
|
|
155
|
+
test("find Solana token by chain and contract", async () => {
|
|
74
156
|
const assetByChainAndContract = await findAssetBy({
|
|
75
157
|
chain: Chain.Solana,
|
|
76
158
|
contract: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
@@ -1,24 +1,84 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { validateTNS } from "../validators";
|
|
2
|
+
import { validateIdentifier, validateTNS } from "../validators";
|
|
3
3
|
|
|
4
4
|
describe("validateTNS", () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
5
|
+
test("valid names with alphanumeric and allowed special chars", () => {
|
|
6
|
+
expect(validateTNS("validname")).toBe(true);
|
|
7
|
+
expect(validateTNS("valid-name")).toBe(true);
|
|
8
|
+
expect(validateTNS("valid_name")).toBe(true);
|
|
9
|
+
expect(validateTNS("valid+name")).toBe(true);
|
|
10
|
+
expect(validateTNS("name123")).toBe(true);
|
|
11
|
+
expect(validateTNS("UPPERCASE")).toBe(true);
|
|
12
|
+
expect(validateTNS("MixedCase123")).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("invalid names exceeding 30 characters", () => {
|
|
16
|
+
expect(validateTNS("toolongname123456789012345678901")).toBe(false);
|
|
17
|
+
expect(validateTNS("a".repeat(31))).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("invalid names with disallowed characters", () => {
|
|
21
|
+
expect(validateTNS("invalid@name")).toBe(false);
|
|
22
|
+
expect(validateTNS("invalid!name")).toBe(false);
|
|
23
|
+
expect(validateTNS("invalid#name")).toBe(false);
|
|
24
|
+
expect(validateTNS("invalid$name")).toBe(false);
|
|
25
|
+
expect(validateTNS("invalid%name")).toBe(false);
|
|
26
|
+
expect(validateTNS("name with space")).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("edge cases", () => {
|
|
30
|
+
expect(validateTNS("a")).toBe(true);
|
|
31
|
+
expect(validateTNS("a".repeat(30))).toBe(true);
|
|
32
|
+
expect(validateTNS("")).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("validateIdentifier", () => {
|
|
37
|
+
test("valid chain.ticker format", () => {
|
|
38
|
+
expect(validateIdentifier("BTC.BTC")).toBe(true);
|
|
39
|
+
expect(validateIdentifier("ETH.ETH")).toBe(true);
|
|
40
|
+
expect(validateIdentifier("AVAX.USDC-0x123")).toBe(true);
|
|
41
|
+
expect(validateIdentifier("eth.eth")).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("valid synth format with /", () => {
|
|
45
|
+
expect(validateIdentifier("ETH/ETH")).toBe(true);
|
|
46
|
+
expect(validateIdentifier("BTC/BTC")).toBe(true);
|
|
47
|
+
expect(validateIdentifier("THOR.ETH/ETH")).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("valid trade asset format with ~", () => {
|
|
51
|
+
expect(validateIdentifier("THOR.ETH~ETH")).toBe(true);
|
|
52
|
+
expect(validateIdentifier("THOR.BTC~BTC")).toBe(true);
|
|
53
|
+
expect(validateIdentifier("THOR.ETH~USDC-0xa5f2211b9b8170f694421f2046281775e8468044")).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("valid NEAR address formats", () => {
|
|
57
|
+
expect(validateIdentifier("NEAR.wNEAR-wrap.near")).toBe(true);
|
|
58
|
+
expect(validateIdentifier("NEAR.USDC-17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1")).toBe(true);
|
|
59
|
+
expect(validateIdentifier("NEAR.ETH-eth.bridge.near")).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("valid Maya synth format", () => {
|
|
63
|
+
expect(validateIdentifier("MAYA.ETH/ETH")).toBe(true);
|
|
64
|
+
expect(validateIdentifier("MAYA.BTC/BTC")).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("throws for invalid chain", () => {
|
|
68
|
+
expect(() => validateIdentifier("INVALID.TOKEN")).toThrow("helpers_invalid_identifier");
|
|
69
|
+
expect(() => validateIdentifier("XXX.YYY")).toThrow("helpers_invalid_identifier");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("throws for empty or malformed identifier", () => {
|
|
73
|
+
expect(() => validateIdentifier("")).toThrow("helpers_invalid_identifier");
|
|
74
|
+
expect(() => validateIdentifier("NOCHAIN")).toThrow("helpers_invalid_identifier");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("accepts identifier with only chain (validates chain exists)", () => {
|
|
78
|
+
// The validateIdentifier function only checks if the chain part is valid
|
|
79
|
+
// It doesn't enforce the full <Chain>.<Ticker> format
|
|
80
|
+
expect(validateIdentifier("ETH")).toBe(true);
|
|
81
|
+
expect(validateIdentifier("ETH.")).toBe(true);
|
|
82
|
+
expect(validateIdentifier("BTC")).toBe(true);
|
|
83
|
+
});
|
|
24
84
|
});
|