@sundaeswap/math 0.0.1

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.
@@ -0,0 +1,649 @@
1
+ import { test, describe, it, expect } from "bun:test";
2
+ import { Fraction, TFractionLike } from "@sundaeswap/fraction";
3
+ import { AssetAmount } from "@sundaeswap/asset";
4
+ import {
5
+ getSwapOutput,
6
+ getSwapInput,
7
+ TPair,
8
+ TRatioDirection,
9
+ IRatioCalculationAsset,
10
+ IRatioCalculationResult,
11
+ getSwapRatio,
12
+ } from "../ConstantProductPool.js";
13
+ import { getFirstLp } from "../ConstantProductPool.js";
14
+ import { calculateLiquidity } from "../ConstantProductPool.js";
15
+
16
+ describe("getSwapOutput", () => {
17
+ const zeroThreePct = new Fraction(3, 1000);
18
+ const onePct = new Fraction(1, 100);
19
+ const zeroPct = Fraction.ZERO;
20
+
21
+ test("throws if any of the arguments are negative", () => {
22
+ expect(() => getSwapOutput(-1n, 10n, 10n, Fraction.ZERO)).toThrow();
23
+ expect(() => getSwapOutput(1n, -10n, 10n, Fraction.ZERO)).toThrow();
24
+ expect(() => getSwapOutput(1n, 10n, -10n, Fraction.ZERO)).toThrow();
25
+ expect(() =>
26
+ getSwapOutput(1n, 1n, 1n, Fraction.asFraction(-0.1)),
27
+ ).toThrow();
28
+ });
29
+
30
+ test("throws if fee is greater than or equal 1", () => {
31
+ expect(() =>
32
+ getSwapOutput(1n, 10n, 10n, Fraction.asFraction(1)),
33
+ ).not.toThrow();
34
+ expect(() =>
35
+ getSwapOutput(1n, 10n, 10n, Fraction.asFraction(1.132)),
36
+ ).toThrow();
37
+ });
38
+
39
+ test("rounds up for non-fractional assets", () => {
40
+ expect(getSwapOutput(83n, 10000n, 500n, zeroThreePct).output).toEqual(4n);
41
+ expect(getSwapOutput(83n, 10000n, 500n, zeroThreePct, true).output).toEqual(
42
+ 5n,
43
+ );
44
+ });
45
+
46
+ test.each([
47
+ // Ideal, 0% pool
48
+ {
49
+ id: 1,
50
+ input: 1n,
51
+ inReserve: [1n, 1n],
52
+ fee: zeroPct,
53
+ out: 0n,
54
+ outReserve: [2n, 1n],
55
+ lpFee: 0n,
56
+ impact: new Fraction(0n, 0n),
57
+ },
58
+ {
59
+ id: 2,
60
+ input: 1n,
61
+ inReserve: [1n, 2n],
62
+ fee: zeroPct,
63
+ out: 1n,
64
+ outReserve: [2n, 1n],
65
+ lpFee: 0n,
66
+ impact: new Fraction(1n, 2n),
67
+ },
68
+ {
69
+ id: 3,
70
+ input: 100n,
71
+ inReserve: [1n, 2n],
72
+ fee: zeroPct,
73
+ out: 1n,
74
+ outReserve: [101n, 1n],
75
+ lpFee: 0n,
76
+ impact: Fraction.asFraction("0.995"),
77
+ },
78
+ {
79
+ id: 4,
80
+ input: 100n,
81
+ inReserve: [1n, 100n],
82
+ fee: zeroPct,
83
+ out: 99n,
84
+ outReserve: [101n, 1n],
85
+ lpFee: 0n,
86
+ impact: Fraction.asFraction("0.9901"),
87
+ },
88
+ {
89
+ id: 5,
90
+ input: 100n,
91
+ inReserve: [100n, 100n],
92
+ fee: zeroPct,
93
+ out: 50n,
94
+ outReserve: [200n, 50n],
95
+ lpFee: 0n,
96
+ impact: new Fraction(5000n, 10000n),
97
+ },
98
+ {
99
+ id: 6,
100
+ input: 50n,
101
+ inReserve: [100n, 100n],
102
+ fee: zeroPct,
103
+ out: 33n,
104
+ outReserve: [150n, 67n],
105
+ lpFee: 0n,
106
+ impact: new Fraction(1700n, 5000n),
107
+ },
108
+
109
+ // Simple boundary cases
110
+ {
111
+ id: 7,
112
+ input: 1n,
113
+ inReserve: [1n, 1n],
114
+ fee: zeroThreePct,
115
+ out: 0n,
116
+ outReserve: [2n, 1n],
117
+ lpFee: 0n,
118
+ impact: new Fraction(0n, 0n),
119
+ },
120
+ {
121
+ id: 8,
122
+ input: 1n,
123
+ inReserve: [1n, 2n],
124
+ fee: zeroThreePct,
125
+ out: 0n,
126
+ outReserve: [2n, 2n],
127
+ lpFee: 0n,
128
+ impact: Fraction.asFraction("0.5"),
129
+ },
130
+ {
131
+ id: 9,
132
+ input: 1n,
133
+ inReserve: [1n, 3n],
134
+ fee: zeroThreePct,
135
+ out: 1n,
136
+ outReserve: [2n, 2n],
137
+ lpFee: 0n,
138
+ impact: new Fraction(2, 3),
139
+ },
140
+ {
141
+ id: 10,
142
+ input: 100n,
143
+ inReserve: [1n, 2n],
144
+ fee: zeroThreePct,
145
+ out: 1n,
146
+ outReserve: [101n, 1n],
147
+ lpFee: 0n,
148
+ impact: Fraction.asFraction("0.995"),
149
+ },
150
+ {
151
+ id: 11,
152
+ input: 100n,
153
+ inReserve: [1n, 100n],
154
+ fee: zeroThreePct,
155
+ out: 99n,
156
+ outReserve: [101n, 1n],
157
+ lpFee: 0n,
158
+ impact: Fraction.asFraction("0.9901"),
159
+ },
160
+ {
161
+ id: 12,
162
+ input: 100n,
163
+ inReserve: [100n, 100n],
164
+ fee: zeroThreePct,
165
+ out: 49n,
166
+ outReserve: [200n, 51n],
167
+ lpFee: 0n,
168
+ impact: new Fraction(5100n, 10000n),
169
+ },
170
+ {
171
+ id: 13,
172
+ input: 50n,
173
+ inReserve: [100n, 100n],
174
+ fee: zeroThreePct,
175
+ out: 33n,
176
+ outReserve: [150n, 67n],
177
+ lpFee: 0n,
178
+ impact: new Fraction(1700n, 5000n),
179
+ },
180
+
181
+ // Real world examples
182
+ {
183
+ id: 14,
184
+ input: 1291591603n,
185
+ inReserve: [5753371381n, 672426600000n],
186
+ fee: onePct,
187
+ out: 122271016729n,
188
+ outReserve: [7044962984n, 550155583271n],
189
+ lpFee: 12915916n,
190
+ impact: new Fraction(156344976337673367251n, 859815544712074200000n),
191
+ },
192
+ {
193
+ id: 15,
194
+ input: 1000000n,
195
+ inReserve: [3696260028076n, 77871393827281n],
196
+ fee: zeroThreePct,
197
+ out: 21004409n,
198
+ outReserve: [3696261028076n, 77871372822872n],
199
+ lpFee: 3000n,
200
+ impact: new Fraction(22245739369916n, 77637779645799157000n),
201
+ },
202
+ ] as {
203
+ input: bigint;
204
+ inReserve: TPair;
205
+ fee: TFractionLike;
206
+ out: bigint;
207
+ outReserve: TPair;
208
+ lpFee: bigint;
209
+ impact: Fraction;
210
+ id: number;
211
+ }[])(
212
+ "gets the correct swap output, given different inputs (%#)",
213
+ ({ input, inReserve, fee, out, outReserve, lpFee, impact }) => {
214
+ const actual = getSwapOutput(input, ...inReserve, fee);
215
+ expect(actual.output).toBe(out);
216
+ expect(actual.inputLpFee).toBe(lpFee);
217
+ expect(actual.nextInputReserve).toBe(outReserve[0]);
218
+ expect(actual.nextInputReserve).toBe(input + inReserve[0]);
219
+ expect(actual.nextOutputReserve).toBe(outReserve[1]);
220
+ expect(actual.nextOutputReserve + actual.output).toBe(inReserve[1]);
221
+ expect(actual.priceImpact).toStrictEqual(impact);
222
+ },
223
+ );
224
+ });
225
+
226
+ describe("getSwapInput", () => {
227
+ const fivePct = new Fraction(5, 100);
228
+ const threePct = new Fraction(3, 100);
229
+ const onePct = new Fraction(1, 100);
230
+ const zeroPct = Fraction.ZERO;
231
+
232
+ test("throws if any of the arguments are negative", () => {
233
+ expect(() => getSwapInput(-1n, 10n, 10n, Fraction.ZERO)).toThrow();
234
+ expect(() => getSwapInput(1n, -10n, 10n, Fraction.ZERO)).toThrow();
235
+ expect(() => getSwapInput(1n, 10n, -10n, Fraction.ZERO)).toThrow();
236
+ expect(() =>
237
+ getSwapInput(1n, 10n, 10n, Fraction.asFraction(-0.1)),
238
+ ).toThrow();
239
+ });
240
+
241
+ test("throws if fee is greater than or equal 1", () => {
242
+ expect(() => getSwapInput(1n, 10n, 10n, Fraction.asFraction(1))).toThrow();
243
+ expect(() =>
244
+ getSwapInput(1n, 10n, 10n, Fraction.asFraction(1.132)),
245
+ ).toThrow();
246
+ });
247
+
248
+ test("throws if output is greater than or equal to output reserve", () => {
249
+ expect(() =>
250
+ getSwapInput(10n, 10n, 10n, Fraction.asFraction(0.1)),
251
+ ).toThrow();
252
+ expect(() => getSwapInput(1n, 1n, 1n, Fraction.asFraction(0.1))).toThrow();
253
+ expect(() => getSwapInput(10n, 1n, 1n, Fraction.asFraction(0.1))).toThrow();
254
+ });
255
+
256
+ test.each([
257
+ // Ideal 0% fee pool
258
+ {
259
+ input: 1n,
260
+ reserves: [1n, 2n],
261
+ fee: zeroPct,
262
+ impact: new Fraction(3n, 4n),
263
+ },
264
+ {
265
+ input: 100n,
266
+ reserves: [1n, 2n],
267
+ fee: zeroPct,
268
+ impact: new Fraction(3n, 4n),
269
+ },
270
+ {
271
+ input: 100n,
272
+ reserves: [1n, 100n],
273
+ fee: zeroPct,
274
+ impact: new Fraction(9901n, 10000n),
275
+ },
276
+ {
277
+ input: 100n,
278
+ reserves: [100n, 100n],
279
+ fee: zeroPct,
280
+ impact: new Fraction(5100n, 10100n),
281
+ },
282
+ {
283
+ input: 50n,
284
+ reserves: [100n, 100n],
285
+ fee: zeroPct,
286
+ impact: new Fraction(1700n, 5000n),
287
+ },
288
+
289
+ // Simple boundary cases
290
+ {
291
+ input: 1n,
292
+ reserves: [1n, 3n],
293
+ fee: threePct,
294
+ impact: new Fraction(2n, 3n),
295
+ },
296
+ {
297
+ input: 100n,
298
+ reserves: [1n, 2n],
299
+ fee: threePct,
300
+ impact: new Fraction(3n, 4n),
301
+ },
302
+ {
303
+ input: 100n,
304
+ reserves: [1n, 100n],
305
+ fee: threePct,
306
+ impact: new Fraction(4902n, 5000n),
307
+ },
308
+ {
309
+ input: 100n,
310
+ reserves: [100n, 100n],
311
+ fee: threePct,
312
+ impact: new Fraction(4800n, 9700n),
313
+ },
314
+ {
315
+ input: 50n,
316
+ reserves: [100n, 100n],
317
+ fee: threePct,
318
+ impact: new Fraction(1600n, 4800n),
319
+ },
320
+
321
+ // Real world examples
322
+ {
323
+ input: 5n,
324
+ reserves: [84159832107n, 123172010729n],
325
+ fee: fivePct,
326
+ impact: new Fraction(110901061003n, 615860053645n),
327
+ },
328
+ {
329
+ input: 100n,
330
+ reserves: [84159832107n, 123172010729n],
331
+ fee: fivePct,
332
+ impact: new Fraction(3124356382n, 11701341019255n),
333
+ },
334
+ {
335
+ input: 1291591603n,
336
+ reserves: [5753371381n, 672426600000n],
337
+ fee: onePct,
338
+ impact: new Fraction(156344976337673367251n, 859815544712074200000n),
339
+ },
340
+ ] as {
341
+ input: bigint;
342
+ reserves: TPair;
343
+ fee: TFractionLike;
344
+ impact: Fraction;
345
+ }[])(
346
+ "gets the correct swap input, given different swap outputs (%#)",
347
+ ({ input, reserves, fee, impact }) => {
348
+ const outcome = getSwapOutput(input, ...reserves, fee);
349
+ const actual = getSwapInput(outcome.output, ...reserves, fee);
350
+ const outcomeForActual = getSwapOutput(actual.input, ...reserves, fee);
351
+ expect(outcome.output).toBe(outcomeForActual.output);
352
+ expect(actual.inputLpFee).toBe(outcomeForActual.inputLpFee);
353
+ expect(actual.nextInputReserve).toBe(outcomeForActual.nextInputReserve);
354
+ expect(actual.nextOutputReserve).toBe(outcomeForActual.nextOutputReserve);
355
+ expect(actual.priceImpact).toEqual(outcomeForActual.priceImpact);
356
+ expect(actual.priceImpact).toStrictEqual(impact);
357
+ },
358
+ );
359
+ });
360
+
361
+ describe("calculateLiquidity", () => {
362
+ test.each([
363
+ {
364
+ a: 1n,
365
+ b: 2n,
366
+ reserves: [1n, 2n],
367
+ totalLp: getFirstLp(1n, 2n),
368
+ generatedLp: 1n,
369
+ nextTotalLp: 2n,
370
+ shareAfterDeposit: new Fraction(1n, 2n),
371
+ aChange: 0n,
372
+ bChange: 0n,
373
+ },
374
+ {
375
+ a: 1n,
376
+ b: 100n,
377
+ reserves: [1n, 100n],
378
+ totalLp: getFirstLp(1n, 100n),
379
+ generatedLp: 10n,
380
+ nextTotalLp: 20n,
381
+ shareAfterDeposit: new Fraction(10n, 20n),
382
+ aChange: 0n,
383
+ bChange: 0n,
384
+ },
385
+ {
386
+ a: 2n,
387
+ b: 200n,
388
+ reserves: [1n, 100n],
389
+ totalLp: getFirstLp(1n, 100n),
390
+ generatedLp: 20n,
391
+ nextTotalLp: 30n,
392
+ shareAfterDeposit: new Fraction(20n, 30n),
393
+ aChange: 0n,
394
+ bChange: 0n,
395
+ },
396
+ // Too much of token a
397
+ {
398
+ a: 5n,
399
+ b: 250n,
400
+ reserves: [1n, 100n],
401
+ totalLp: getFirstLp(1n, 100n),
402
+ generatedLp: 20n,
403
+ nextTotalLp: 30n,
404
+ shareAfterDeposit: new Fraction(20n, 30n),
405
+ aChange: 3n,
406
+ bChange: 0n,
407
+ },
408
+
409
+ // Too much of token b
410
+ {
411
+ a: 3n,
412
+ b: 200n,
413
+ reserves: [1n, 100n],
414
+ totalLp: getFirstLp(1n, 100n),
415
+ generatedLp: 20n,
416
+ nextTotalLp: 30n,
417
+ shareAfterDeposit: new Fraction(20n, 30n),
418
+ aChange: 1n,
419
+ bChange: 0n,
420
+ },
421
+
422
+ // Real world examples
423
+ {
424
+ a: 100947000n,
425
+ b: 151611403n,
426
+ reserves: [9993743829n, 15009515148n],
427
+ totalLp: 12247448713n,
428
+ generatedLp: 123711715n,
429
+ nextTotalLp: 12371160428n,
430
+ shareAfterDeposit: new Fraction(123711715n, 12371160428n),
431
+ aChange: 1n,
432
+ bChange: 0n,
433
+ },
434
+ {
435
+ a: 1291591603n,
436
+ b: 150955064896n,
437
+ reserves: [5753371381n, 672426600000n],
438
+ totalLp: getFirstLp(5753371381n, 672426600000n),
439
+ generatedLp: 13963247972n,
440
+ nextTotalLp: 76162282982n,
441
+ shareAfterDeposit: new Fraction(13963247972n, 76162282982n),
442
+ aChange: 1n,
443
+ bChange: 0n,
444
+ },
445
+ {
446
+ a: 5000000n,
447
+ b: 1869359n,
448
+ reserves: [684236468144n, 256584648756n],
449
+ totalLp: getFirstLp(684236468144n, 256584648756n),
450
+ generatedLp: 3052674n,
451
+ nextTotalLp: 419007317383n,
452
+ shareAfterDeposit: new Fraction(3052674n, 419007317383n),
453
+ aChange: 14965n,
454
+ bChange: 0n,
455
+ },
456
+ ] as {
457
+ a: bigint;
458
+ b: bigint;
459
+ reserves: TPair;
460
+ totalLp: bigint;
461
+ nextTotalLp: bigint;
462
+ generatedLp: bigint;
463
+ requiredB: bigint;
464
+ shareAfterDeposit: Fraction;
465
+ aChange: bigint;
466
+ bChange: bigint;
467
+ }[])(
468
+ "gets the right liquidity, given different inputs (%#)",
469
+ ({ a, b, reserves, totalLp, ...expectedResult }) => {
470
+ const actualResult = calculateLiquidity(a, b, ...reserves, totalLp);
471
+ expect(actualResult.generatedLp).toBe(expectedResult.generatedLp);
472
+ expect(actualResult.nextTotalLp).toBe(expectedResult.nextTotalLp);
473
+ expect(actualResult.aChange).toBe(expectedResult.aChange);
474
+ expect(actualResult.bChange).toBe(expectedResult.bChange);
475
+ expect(actualResult.shareAfterDeposit).toStrictEqual(
476
+ expectedResult.shareAfterDeposit,
477
+ );
478
+ },
479
+ );
480
+
481
+ it("should throw an error when the requiredB amount is less than 1", () => {
482
+ const zeroError = new Error("Cannot use a deposit asset amount of 0");
483
+ expect(() =>
484
+ calculateLiquidity(2n, 0n, 100n, 1n, getFirstLp(100n, 1n)),
485
+ ).toThrowError(zeroError);
486
+ expect(() =>
487
+ calculateLiquidity(0n, 2n, 100n, 1n, getFirstLp(100n, 1n)),
488
+ ).toThrowError(zeroError);
489
+ });
490
+ });
491
+
492
+ describe("getSwapRatio", () => {
493
+ const testCases: {
494
+ direction: TRatioDirection;
495
+ assets: [IRatioCalculationAsset, IRatioCalculationAsset];
496
+ expectedOutput: IRatioCalculationResult;
497
+ }[] = [
498
+ {
499
+ direction: "A_PER_B",
500
+ assets: [
501
+ { quantity: 100n, decimals: 0, assetId: "ada.lovelace" },
502
+ {
503
+ quantity: 200n,
504
+ decimals: 0,
505
+ assetId:
506
+ "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77.53554e444145",
507
+ },
508
+ ],
509
+ expectedOutput: {
510
+ calculatedAmount: new AssetAmount(0n),
511
+ ratioAsFraction: new Fraction(1n, 2n),
512
+ display: "0",
513
+ isDivisible: false,
514
+ belowMinimumRatio: false,
515
+ },
516
+ },
517
+ {
518
+ direction: "A_PER_B",
519
+ assets: [
520
+ {
521
+ quantity: 200n,
522
+ decimals: 0,
523
+ assetId:
524
+ "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77.53554e444145",
525
+ },
526
+ { quantity: 100n, decimals: 0, assetId: "ada.lovelace" },
527
+ ],
528
+ expectedOutput: {
529
+ calculatedAmount: new AssetAmount(0n),
530
+ ratioAsFraction: new Fraction(1n, 2n),
531
+ display: "0",
532
+ isDivisible: false,
533
+ belowMinimumRatio: false,
534
+ },
535
+ },
536
+ {
537
+ direction: "B_PER_A",
538
+ assets: [
539
+ {
540
+ quantity: 200n,
541
+ decimals: 0,
542
+ assetId:
543
+ "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77.53554e444145",
544
+ },
545
+ { quantity: 100n, decimals: 0, assetId: "ada.lovelace" },
546
+ ],
547
+ expectedOutput: {
548
+ calculatedAmount: new AssetAmount(2n),
549
+ ratioAsFraction: new Fraction(2n, 1n),
550
+ display: "2",
551
+ isDivisible: false,
552
+ belowMinimumRatio: false,
553
+ },
554
+ },
555
+ {
556
+ direction: "A_PER_B",
557
+ assets: [
558
+ { quantity: 100n, decimals: 0, assetId: "A" },
559
+ { quantity: 2000000n, decimals: 6, assetId: "B" },
560
+ ],
561
+ expectedOutput: {
562
+ calculatedAmount: new AssetAmount(50n),
563
+ ratioAsFraction: new Fraction(1n, 20000n),
564
+ display: "50",
565
+ isDivisible: false,
566
+ belowMinimumRatio: false,
567
+ },
568
+ },
569
+ {
570
+ direction: "B_PER_A",
571
+ assets: [
572
+ { quantity: 100n, decimals: 0, assetId: "A" },
573
+ { quantity: 2000000n, decimals: 6, assetId: "B" },
574
+ ],
575
+ expectedOutput: {
576
+ calculatedAmount: new AssetAmount(20000n, 6),
577
+ ratioAsFraction: new Fraction(20000n, 1n),
578
+ display: "0.02",
579
+ isDivisible: true,
580
+ belowMinimumRatio: false,
581
+ },
582
+ },
583
+ {
584
+ direction: "A_PER_B",
585
+ assets: [
586
+ { quantity: 1000000n, decimals: 6, assetId: "A" },
587
+ { quantity: 200n, decimals: 0, assetId: "B" },
588
+ ],
589
+ expectedOutput: {
590
+ calculatedAmount: new AssetAmount(5000n, 6),
591
+ ratioAsFraction: new Fraction(5000n, 1n),
592
+ display: "0.005",
593
+ isDivisible: true,
594
+ belowMinimumRatio: false,
595
+ },
596
+ },
597
+ {
598
+ direction: "B_PER_A",
599
+ assets: [
600
+ { quantity: 1000000n, decimals: 6, assetId: "A" },
601
+ { quantity: 200n, decimals: 0, assetId: "B" },
602
+ ],
603
+ expectedOutput: {
604
+ calculatedAmount: new AssetAmount(200n),
605
+ ratioAsFraction: new Fraction(1n, 5000n),
606
+ display: "200",
607
+ isDivisible: false,
608
+ belowMinimumRatio: false,
609
+ },
610
+ },
611
+ {
612
+ direction: "A_PER_B",
613
+ assets: [
614
+ { quantity: 0n, decimals: 6, assetId: "A" },
615
+ { quantity: 1n, decimals: 0, assetId: "B" },
616
+ ],
617
+ expectedOutput: {
618
+ calculatedAmount: new AssetAmount(0n),
619
+ ratioAsFraction: new Fraction(0n, 0n),
620
+ display: "0",
621
+ isDivisible: true,
622
+ belowMinimumRatio: true,
623
+ },
624
+ },
625
+ ];
626
+
627
+ test.each(testCases)(
628
+ "given a direction and assets asset pair, returns expected output (%#)",
629
+ ({ direction, expectedOutput, assets }) => {
630
+ const {
631
+ calculatedAmount,
632
+ ratioAsFraction,
633
+ display,
634
+ isDivisible,
635
+ belowMinimumRatio,
636
+ } = getSwapRatio(direction, assets);
637
+ expect(calculatedAmount.amount).toEqual(
638
+ expectedOutput.calculatedAmount.amount,
639
+ );
640
+ expect(calculatedAmount.value.toString()).toEqual(
641
+ expectedOutput.calculatedAmount.value.toString(),
642
+ );
643
+ expect(ratioAsFraction).toEqual(expectedOutput.ratioAsFraction);
644
+ expect(display).toEqual(expectedOutput.display);
645
+ expect(isDivisible).toEqual(expectedOutput.isDivisible);
646
+ expect(belowMinimumRatio).toEqual(expectedOutput.belowMinimumRatio);
647
+ },
648
+ );
649
+ });
@@ -0,0 +1 @@
1
+ export * as ConstantProductPool from "./ConstantProductPool.js";
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./@types/index.js";