@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.
@@ -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);
@@ -222,10 +222,15 @@ export class BigIntArithmetics {
222
222
  { currencyPosition = "start", decimal = 2, decimalSeparator = ".", thousandSeparator = "," } = {},
223
223
  ) {
224
224
  const valueStr = this.getValue("string");
225
- const [int = "0", dec = ""] = valueStr.split(".");
225
+ const isNegative = valueStr.startsWith("-");
226
+ const absValueStr = isNegative ? valueStr.slice(1) : valueStr;
227
+ const [int = "0", dec = ""] = absValueStr.split(".");
228
+ const sign = isNegative ? "-" : "";
226
229
 
227
230
  if (int === "0" && dec) {
228
- const formatted = `${Number.parseFloat(`0.${dec}`)}`.replace(".", decimalSeparator);
231
+ const trimmedDec = dec.replace(/0+$/, "");
232
+ const formatted = trimmedDec ? `${sign}0${decimalSeparator}${trimmedDec}` : "0";
233
+
229
234
  return match(currencyPosition)
230
235
  .with("start", () => `${currency}${formatted}`)
231
236
  .with("end", () => `${formatted}${currency}`)
@@ -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 { derivationPathToString } from "../derivationPath";
5
+ import {
6
+ DerivationPath,
7
+ derivationPathToString,
8
+ getDerivationPathFor,
9
+ getWalletFormatFor,
10
+ updateDerivationPath,
11
+ } from "../derivationPath";
5
12
 
6
13
  describe("derivationPathToString", () => {
7
- test("should return the correct string for a full path", () => {
8
- const path = [1, 2, 3, 4, 5] as DerivationPathArray;
9
- expect(derivationPathToString(path)).toEqual("m/1'/2'/3'/4/5");
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("should return the correct string for a short path", () => {
13
- const path = [1, 2, 3, 4] as DerivationPathArray;
14
- expect(derivationPathToString(path)).toEqual("m/1'/2'/3'/4");
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
  });
@@ -0,0 +1,302 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ getAsymmetricAssetShare,
5
+ getAsymmetricAssetWithdrawAmount,
6
+ getAsymmetricRuneShare,
7
+ getAsymmetricRuneWithdrawAmount,
8
+ getEstimatedPoolShare,
9
+ getLiquiditySlippage,
10
+ getSymmetricPoolShare,
11
+ getSymmetricWithdraw,
12
+ } from "../liquidity";
13
+
14
+ describe("getAsymmetricRuneShare", () => {
15
+ test("calculates rune share for typical pool position", () => {
16
+ const result = getAsymmetricRuneShare({
17
+ liquidityUnits: "100000000",
18
+ poolUnits: "1000000000",
19
+ runeDepth: "500000000000",
20
+ });
21
+ expect(result.getValue("number")).toBeGreaterThan(0);
22
+ });
23
+
24
+ test("returns zero rune share for zero liquidity units", () => {
25
+ const result = getAsymmetricRuneShare({ liquidityUnits: "0", poolUnits: "1000000000", runeDepth: "500000000000" });
26
+ expect(result.getValue("number")).toBe(0);
27
+ });
28
+
29
+ test("returns full amount when owning all pool units", () => {
30
+ const result = getAsymmetricRuneShare({
31
+ liquidityUnits: "1000000000",
32
+ poolUnits: "1000000000",
33
+ runeDepth: "500000000000",
34
+ });
35
+ expect(result.getValue("string")).toBe("5000");
36
+ });
37
+ });
38
+
39
+ describe("getAsymmetricAssetShare", () => {
40
+ test("calculates asset share for typical pool position", () => {
41
+ const result = getAsymmetricAssetShare({
42
+ assetDepth: "200000000000",
43
+ liquidityUnits: "100000000",
44
+ poolUnits: "1000000000",
45
+ });
46
+ expect(result.getValue("number")).toBeGreaterThan(0);
47
+ });
48
+
49
+ test("returns zero asset share for zero liquidity units", () => {
50
+ const result = getAsymmetricAssetShare({
51
+ assetDepth: "200000000000",
52
+ liquidityUnits: "0",
53
+ poolUnits: "1000000000",
54
+ });
55
+ expect(result.getValue("number")).toBe(0);
56
+ });
57
+ });
58
+
59
+ describe("getAsymmetricRuneWithdrawAmount", () => {
60
+ test("calculates withdrawal amount for 50% withdrawal", () => {
61
+ const result = getAsymmetricRuneWithdrawAmount({
62
+ liquidityUnits: "100000000",
63
+ percent: 0.5,
64
+ poolUnits: "1000000000",
65
+ runeDepth: "500000000000",
66
+ });
67
+ expect(result.getValue("number")).toBeGreaterThan(0);
68
+ });
69
+
70
+ test("calculates full withdrawal for 100%", () => {
71
+ const full = getAsymmetricRuneWithdrawAmount({
72
+ liquidityUnits: "100000000",
73
+ percent: 1,
74
+ poolUnits: "1000000000",
75
+ runeDepth: "500000000000",
76
+ });
77
+ const half = getAsymmetricRuneWithdrawAmount({
78
+ liquidityUnits: "100000000",
79
+ percent: 0.5,
80
+ poolUnits: "1000000000",
81
+ runeDepth: "500000000000",
82
+ });
83
+ expect(full.getValue("number")).toBeCloseTo(half.getValue("number") * 2, 5);
84
+ });
85
+ });
86
+
87
+ describe("getAsymmetricAssetWithdrawAmount", () => {
88
+ test("calculates withdrawal for given percentage", () => {
89
+ const result = getAsymmetricAssetWithdrawAmount({
90
+ assetDepth: "200000000000",
91
+ liquidityUnits: "100000000",
92
+ percent: 0.25,
93
+ poolUnits: "1000000000",
94
+ });
95
+ expect(result.getValue("number")).toBeGreaterThan(0);
96
+ });
97
+ });
98
+
99
+ describe("getSymmetricPoolShare", () => {
100
+ test("returns both rune and asset amounts", () => {
101
+ const result = getSymmetricPoolShare({
102
+ assetDepth: "200000000000",
103
+ liquidityUnits: "100000000",
104
+ poolUnits: "1000000000",
105
+ runeDepth: "500000000000",
106
+ });
107
+ expect(result.runeAmount.getValue("number")).toBeGreaterThan(0);
108
+ expect(result.assetAmount.getValue("number")).toBeGreaterThan(0);
109
+ });
110
+
111
+ test("proportionally distributes based on liquidity units", () => {
112
+ const result10 = getSymmetricPoolShare({
113
+ assetDepth: "1000000000000",
114
+ liquidityUnits: "100000000",
115
+ poolUnits: "1000000000",
116
+ runeDepth: "1000000000000",
117
+ });
118
+ const result20 = getSymmetricPoolShare({
119
+ assetDepth: "1000000000000",
120
+ liquidityUnits: "200000000",
121
+ poolUnits: "1000000000",
122
+ runeDepth: "1000000000000",
123
+ });
124
+ expect(result20.runeAmount.getValue("number")).toBeCloseTo(result10.runeAmount.getValue("number") * 2, 5);
125
+ });
126
+ });
127
+
128
+ describe("getSymmetricWithdraw", () => {
129
+ test("applies percentage to both amounts", () => {
130
+ const result = getSymmetricWithdraw({
131
+ assetDepth: "200000000000",
132
+ liquidityUnits: "100000000",
133
+ percent: 0.5,
134
+ poolUnits: "1000000000",
135
+ runeDepth: "500000000000",
136
+ });
137
+ expect(result.runeAmount?.getValue("number")).toBeGreaterThan(0);
138
+ expect(result.assetAmount?.getValue("number")).toBeGreaterThan(0);
139
+ });
140
+
141
+ test("full withdrawal equals pool share", () => {
142
+ const params = {
143
+ assetDepth: "200000000000",
144
+ liquidityUnits: "100000000",
145
+ poolUnits: "1000000000",
146
+ runeDepth: "500000000000",
147
+ };
148
+ const share = getSymmetricPoolShare(params);
149
+ const withdraw = getSymmetricWithdraw({ ...params, percent: 1 });
150
+ expect(withdraw.runeAmount?.getValue("string")).toBe(share.runeAmount.getValue("string"));
151
+ });
152
+ });
153
+
154
+ describe("getEstimatedPoolShare", () => {
155
+ test("estimates pool share after adding liquidity", () => {
156
+ // Returns base value representation (with 8 decimals internally)
157
+ // For ~4.76% share, base value is 4761905 (0.04761905 * 10^8)
158
+ const result = getEstimatedPoolShare({
159
+ assetAmount: "10000000000",
160
+ assetDepth: "200000000000",
161
+ liquidityUnits: "0",
162
+ poolUnits: "1000000000",
163
+ runeAmount: "25000000000",
164
+ runeDepth: "500000000000",
165
+ });
166
+ expect(result).toBeGreaterThan(0);
167
+ // Base value for percentage < 100% is < 10^8
168
+ expect(result).toBeLessThan(100_000_000);
169
+ });
170
+
171
+ test("returns 0 when adding zero liquidity", () => {
172
+ const result = getEstimatedPoolShare({
173
+ assetAmount: "0",
174
+ assetDepth: "200000000000",
175
+ liquidityUnits: "0",
176
+ poolUnits: "1000000000",
177
+ runeAmount: "0",
178
+ runeDepth: "500000000000",
179
+ });
180
+ expect(result).toBe(0);
181
+ });
182
+ });
183
+
184
+ describe("getLiquiditySlippage", () => {
185
+ test("returns 0 when any amount is zero", () => {
186
+ expect(
187
+ getLiquiditySlippage({ assetAmount: "0", assetDepth: "200000000000", runeAmount: "100", runeDepth: "500" }),
188
+ ).toBe(0);
189
+ expect(getLiquiditySlippage({ assetAmount: "100", assetDepth: "0", runeAmount: "100", runeDepth: "500" })).toBe(0);
190
+ expect(getLiquiditySlippage({ assetAmount: "100", assetDepth: "200", runeAmount: "0", runeDepth: "500" })).toBe(0);
191
+ expect(getLiquiditySlippage({ assetAmount: "100", assetDepth: "200", runeAmount: "100", runeDepth: "0" })).toBe(0);
192
+ });
193
+
194
+ test("calculates slippage for balanced add", () => {
195
+ const result = getLiquiditySlippage({
196
+ assetAmount: "100000000",
197
+ assetDepth: "200000000000",
198
+ runeAmount: "250000000",
199
+ runeDepth: "500000000000",
200
+ });
201
+ expect(result).toBeGreaterThanOrEqual(0);
202
+ expect(result).toBeLessThan(1);
203
+ });
204
+
205
+ test("returns absolute value (no negatives)", () => {
206
+ const result = getLiquiditySlippage({
207
+ assetAmount: "1000000000",
208
+ assetDepth: "200000000000",
209
+ runeAmount: "100000000",
210
+ runeDepth: "500000000000",
211
+ });
212
+ expect(result).toBeGreaterThanOrEqual(0);
213
+ });
214
+ });
215
+
216
+ describe("edge cases", () => {
217
+ test("handles very large numbers without overflow", () => {
218
+ const result = getAsymmetricRuneShare({
219
+ liquidityUnits: "999999999999999999",
220
+ poolUnits: "9999999999999999999",
221
+ runeDepth: "99999999999999999999",
222
+ });
223
+ expect(result.getValue("number")).toBeGreaterThan(0);
224
+ });
225
+
226
+ test("getSymmetricPoolShare with equal depths", () => {
227
+ const result = getSymmetricPoolShare({
228
+ assetDepth: "1000000000000",
229
+ liquidityUnits: "500000000",
230
+ poolUnits: "1000000000",
231
+ runeDepth: "1000000000000",
232
+ });
233
+ // 50% of pool should get 50% of both depths
234
+ expect(result.runeAmount.getValue("string")).toBe(result.assetAmount.getValue("string"));
235
+ });
236
+
237
+ test("getEstimatedPoolShare with existing liquidity units", () => {
238
+ const result = getEstimatedPoolShare({
239
+ assetAmount: "10000000000",
240
+ assetDepth: "200000000000",
241
+ liquidityUnits: "50000000", // User already has some units
242
+ poolUnits: "1000000000",
243
+ runeAmount: "25000000000",
244
+ runeDepth: "500000000000",
245
+ });
246
+ expect(result).toBeGreaterThan(0);
247
+ });
248
+
249
+ test("handles single-sided liquidity add (only rune)", () => {
250
+ const result = getEstimatedPoolShare({
251
+ assetAmount: "0",
252
+ assetDepth: "200000000000",
253
+ liquidityUnits: "0",
254
+ poolUnits: "1000000000",
255
+ runeAmount: "25000000000",
256
+ runeDepth: "500000000000",
257
+ });
258
+ expect(result).toBeGreaterThan(0);
259
+ });
260
+
261
+ test("handles single-sided liquidity add (only asset)", () => {
262
+ const result = getEstimatedPoolShare({
263
+ assetAmount: "10000000000",
264
+ assetDepth: "200000000000",
265
+ liquidityUnits: "0",
266
+ poolUnits: "1000000000",
267
+ runeAmount: "0",
268
+ runeDepth: "500000000000",
269
+ });
270
+ expect(result).toBeGreaterThan(0);
271
+ });
272
+
273
+ test("getAsymmetricRuneWithdrawAmount with 0% withdrawal returns 0", () => {
274
+ const result = getAsymmetricRuneWithdrawAmount({
275
+ liquidityUnits: "100000000",
276
+ percent: 0,
277
+ poolUnits: "1000000000",
278
+ runeDepth: "500000000000",
279
+ });
280
+ expect(result.getValue("number")).toBe(0);
281
+ });
282
+
283
+ test("getLiquiditySlippage higher slippage for unbalanced add", () => {
284
+ // Balanced add (proportional to pool)
285
+ const balanced = getLiquiditySlippage({
286
+ assetAmount: "100000000",
287
+ assetDepth: "200000000000",
288
+ runeAmount: "250000000",
289
+ runeDepth: "500000000000",
290
+ });
291
+
292
+ // Unbalanced add (too much rune)
293
+ const unbalanced = getLiquiditySlippage({
294
+ assetAmount: "100000000",
295
+ assetDepth: "200000000000",
296
+ runeAmount: "1000000000", // Much higher rune
297
+ runeDepth: "500000000000",
298
+ });
299
+
300
+ expect(unbalanced).toBeGreaterThan(balanced);
301
+ });
302
+ });
@@ -25,7 +25,7 @@ describe("getMemoForLeaveAndBond", () => {
25
25
  });
26
26
 
27
27
  describe("getMemoForNameRegister", () => {
28
- test("returns correct memo for single side", () => {
28
+ test("returns correct memo for name registration", () => {
29
29
  const result = getMemoForNameRegister({
30
30
  address: "0xaasd123",
31
31
  chain: Chain.Ethereum,
@@ -37,7 +37,7 @@ describe("getMemoForNameRegister", () => {
37
37
  });
38
38
 
39
39
  describe("getMemoForNamePreferredAssetRegister", () => {
40
- test("returns correct memo for single side", () => {
40
+ test("returns correct memo for preferred asset registration", () => {
41
41
  const result = getMemoForNamePreferredAssetRegister({
42
42
  asset: "ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48",
43
43
  chain: Chain.Ethereum,
@@ -52,7 +52,7 @@ describe("getMemoForNamePreferredAssetRegister", () => {
52
52
  });
53
53
 
54
54
  describe("getMemoForDeposit", () => {
55
- test("returns correct memo for single side", () => {
55
+ test("returns correct memo for deposit", () => {
56
56
  const result = getMemoForDeposit({ chain: Chain.Ethereum, symbol: "ETH" });
57
57
  expect(result).toBe("+:ETH.ETH");
58
58
  });
@@ -69,21 +69,21 @@ describe("getMemoForDeposit", () => {
69
69
  });
70
70
 
71
71
  describe("getMemoForWithdraw", () => {
72
- test("returns correct memo for single side", () => {
72
+ test("returns correct memo for withdraw", () => {
73
73
  const result = getMemoForWithdraw({ basisPoints: 100, chain: Chain.Ethereum, symbol: "ETH", ticker: "ETH" });
74
74
  expect(result).toBe("-:ETH.ETH:100");
75
75
  });
76
76
  });
77
77
 
78
78
  describe("getMemoForRunePoolDeposit", () => {
79
- test("returns correct memo for single side", () => {
79
+ test("returns correct memo for rune pool deposit", () => {
80
80
  const result = getMemoForRunePoolDeposit();
81
81
  expect(result).toBe("POOL+");
82
82
  });
83
83
  });
84
84
 
85
85
  describe("getMemoForRunePoolWithdraw", () => {
86
- test("returns correct memo for single side", () => {
86
+ test("returns correct memo for rune pool withdraw", () => {
87
87
  const result = getMemoForRunePoolWithdraw({ basisPoints: 500 });
88
88
  expect(result).toBe("POOL-:500");
89
89
  });