@sundaeswap/math 0.1.1 → 0.2.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.
@@ -1,4 +1,4 @@
1
- import { AssetAmount } from "@sundaeswap/asset";
1
+ import { AssetAmount, IAssetAmountMetadata } from "@sundaeswap/asset";
2
2
  import { Fraction, type TFractionLike } from "@sundaeswap/fraction";
3
3
  import { sqrt } from "@sundaeswap/bigint-math";
4
4
  import { SharedPoolMath } from "./index.js";
@@ -138,7 +138,7 @@ export const getTokensForLp = (
138
138
  export type TSwapOutcome = {
139
139
  input: bigint;
140
140
  output: bigint;
141
- inputLpFee: bigint;
141
+ lpFee: AssetAmount<IAssetAmountMetadata>;
142
142
  nextInputReserve: bigint;
143
143
  nextOutputReserve: bigint;
144
144
  priceImpact: Fraction;
@@ -157,6 +157,7 @@ export type TSwapOutcome = {
157
157
  * @returns The swap details
158
158
  */
159
159
  export const getSwapOutput = (
160
+ inputMetadata: IAssetAmountMetadata,
160
161
  input: bigint,
161
162
  inputReserve: bigint,
162
163
  outputReserve: bigint,
@@ -197,7 +198,7 @@ export const getSwapOutput = (
197
198
  return {
198
199
  input,
199
200
  output: safeOutput,
200
- inputLpFee,
201
+ lpFee: new AssetAmount(inputLpFee, inputMetadata),
201
202
  nextInputReserve,
202
203
  nextOutputReserve,
203
204
  priceImpact,
@@ -218,6 +219,7 @@ export const getSwapOutput = (
218
219
  * @returns The swap details
219
220
  */
220
221
  export const getSwapInput = (
222
+ inputMetadata: IAssetAmountMetadata,
221
223
  output: bigint,
222
224
  inputReserve: bigint,
223
225
  outputReserve: bigint,
@@ -254,7 +256,7 @@ export const getSwapInput = (
254
256
  return {
255
257
  input,
256
258
  output,
257
- inputLpFee,
259
+ lpFee: new AssetAmount(inputLpFee, inputMetadata),
258
260
  nextInputReserve,
259
261
  nextOutputReserve,
260
262
  priceImpact,
@@ -1,3 +1,4 @@
1
+ import { AssetAmount, IAssetAmountMetadata } from "@sundaeswap/asset";
1
2
  import { SharedPoolMath } from "./index.js";
2
3
  import { Fraction, type TFractionLike } from "@sundaeswap/fraction";
3
4
 
@@ -290,9 +291,9 @@ export type TSwapOutcome = {
290
291
  /** The amount of output tokens received (after all fees) */
291
292
  output: bigint;
292
293
  /** The portion of fees that goes to liquidity providers */
293
- outputLpFee: bigint;
294
+ lpFee: AssetAmount<IAssetAmountMetadata>;
294
295
  /** The portion of fees that goes to the protocol */
295
- outputProtocolFee: bigint;
296
+ protocolFee: AssetAmount<IAssetAmountMetadata>;
296
297
  /** The input asset reserve amount after the swap */
297
298
  nextInputReserve: bigint;
298
299
  /** The output asset reserve amount after the swap (excluding protocol fees) */
@@ -329,6 +330,7 @@ export type TSwapOutcome = {
329
330
  * @throws {Error} If combined fee is greater than or equal to 1.
330
331
  */
331
332
  export const getSwapOutput = (
333
+ outputMetadata: IAssetAmountMetadata,
332
334
  input: bigint,
333
335
  inputReserve: bigint,
334
336
  outputReserve: bigint,
@@ -384,8 +386,8 @@ export const getSwapOutput = (
384
386
  return {
385
387
  input,
386
388
  output: safeOutput,
387
- outputLpFee: totalLpFee,
388
- outputProtocolFee: totalProtocolFee,
389
+ lpFee: new AssetAmount(totalLpFee, outputMetadata),
390
+ protocolFee: new AssetAmount(totalProtocolFee, outputMetadata),
389
391
  nextInputReserve,
390
392
  nextOutputReserve,
391
393
  nextSumInvariant: getSumInvariant(laf, nextInputReserve, nextOutputReserve),
@@ -450,6 +452,7 @@ export function getPrice(
450
452
  * @throws {Error} If combined fee is greater than or equal to 1.
451
453
  */
452
454
  export const getSwapInput = (
455
+ outputMetadata: IAssetAmountMetadata,
453
456
  output: bigint,
454
457
  inputReserve: bigint,
455
458
  outputReserve: bigint,
@@ -517,8 +520,8 @@ export const getSwapInput = (
517
520
  return {
518
521
  input,
519
522
  output,
520
- outputLpFee: totalLpFee,
521
- outputProtocolFee: totalProtocolFee,
523
+ lpFee: new AssetAmount(totalLpFee, outputMetadata),
524
+ protocolFee: new AssetAmount(totalProtocolFee, outputMetadata),
522
525
  nextInputReserve,
523
526
  nextOutputReserve,
524
527
  priceImpact,
@@ -1,6 +1,6 @@
1
1
  import { test, describe, it, expect } from "bun:test";
2
2
  import { Fraction, TFractionLike } from "@sundaeswap/fraction";
3
- import { AssetAmount } from "@sundaeswap/asset";
3
+ import { AssetAmount, IAssetAmountMetadata } from "@sundaeswap/asset";
4
4
  import {
5
5
  getSwapOutput,
6
6
  getSwapInput,
@@ -15,34 +15,41 @@ import {
15
15
  TRatioDirection,
16
16
  } from "../SharedPoolMath.js";
17
17
 
18
+ const usdc: IAssetAmountMetadata = {
19
+ assetId: "99b071ce8580d6a3a11b4902145adb8bfd0d2a03935af8cf66403e15.55534443",
20
+ decimals: 6,
21
+ };
22
+
18
23
  describe("getSwapOutput", () => {
19
24
  const zeroThreePct = new Fraction(3, 1000);
20
25
  const onePct = new Fraction(1, 100);
21
26
  const zeroPct = Fraction.ZERO;
22
27
 
23
28
  test("throws if any of the arguments are negative", () => {
24
- expect(() => getSwapOutput(-1n, 10n, 10n, Fraction.ZERO)).toThrow();
25
- expect(() => getSwapOutput(1n, -10n, 10n, Fraction.ZERO)).toThrow();
26
- expect(() => getSwapOutput(1n, 10n, -10n, Fraction.ZERO)).toThrow();
29
+ expect(() => getSwapOutput(usdc, -1n, 10n, 10n, Fraction.ZERO)).toThrow();
30
+ expect(() => getSwapOutput(usdc, 1n, -10n, 10n, Fraction.ZERO)).toThrow();
31
+ expect(() => getSwapOutput(usdc, 1n, 10n, -10n, Fraction.ZERO)).toThrow();
27
32
  expect(() =>
28
- getSwapOutput(1n, 1n, 1n, Fraction.asFraction(-0.1)),
33
+ getSwapOutput(usdc, 1n, 1n, 1n, Fraction.asFraction(-0.1)),
29
34
  ).toThrow();
30
35
  });
31
36
 
32
37
  test("throws if fee is greater than or equal 1", () => {
33
38
  expect(() =>
34
- getSwapOutput(1n, 10n, 10n, Fraction.asFraction(1)),
39
+ getSwapOutput(usdc, 1n, 10n, 10n, Fraction.asFraction(1)),
35
40
  ).not.toThrow();
36
41
  expect(() =>
37
- getSwapOutput(1n, 10n, 10n, Fraction.asFraction(1.132)),
42
+ getSwapOutput(usdc, 1n, 10n, 10n, Fraction.asFraction(1.132)),
38
43
  ).toThrow();
39
44
  });
40
45
 
41
46
  test("rounds up for non-fractional assets", () => {
42
- expect(getSwapOutput(83n, 10000n, 500n, zeroThreePct).output).toEqual(4n);
43
- expect(getSwapOutput(83n, 10000n, 500n, zeroThreePct, true).output).toEqual(
44
- 5n,
47
+ expect(getSwapOutput(usdc, 83n, 10000n, 500n, zeroThreePct).output).toEqual(
48
+ 4n,
45
49
  );
50
+ expect(
51
+ getSwapOutput(usdc, 83n, 10000n, 500n, zeroThreePct, true).output,
52
+ ).toEqual(5n);
46
53
  });
47
54
 
48
55
  test.each([
@@ -213,9 +220,9 @@ describe("getSwapOutput", () => {
213
220
  }[])(
214
221
  "gets the correct swap output, given different inputs (%#)",
215
222
  ({ input, inReserve, fee, out, outReserve, lpFee, impact }) => {
216
- const actual = getSwapOutput(input, ...inReserve, fee);
223
+ const actual = getSwapOutput(usdc, input, ...inReserve, fee);
217
224
  expect(actual.output).toBe(out);
218
- expect(actual.inputLpFee).toBe(lpFee);
225
+ expect(actual.lpFee.amount).toBe(lpFee);
219
226
  expect(actual.nextInputReserve).toBe(outReserve[0]);
220
227
  expect(actual.nextInputReserve).toBe(input + inReserve[0]);
221
228
  expect(actual.nextOutputReserve).toBe(outReserve[1]);
@@ -232,27 +239,33 @@ describe("getSwapInput", () => {
232
239
  const zeroPct = Fraction.ZERO;
233
240
 
234
241
  test("throws if any of the arguments are negative", () => {
235
- expect(() => getSwapInput(-1n, 10n, 10n, Fraction.ZERO)).toThrow();
236
- expect(() => getSwapInput(1n, -10n, 10n, Fraction.ZERO)).toThrow();
237
- expect(() => getSwapInput(1n, 10n, -10n, Fraction.ZERO)).toThrow();
242
+ expect(() => getSwapInput(usdc, -1n, 10n, 10n, Fraction.ZERO)).toThrow();
243
+ expect(() => getSwapInput(usdc, 1n, -10n, 10n, Fraction.ZERO)).toThrow();
244
+ expect(() => getSwapInput(usdc, 1n, 10n, -10n, Fraction.ZERO)).toThrow();
238
245
  expect(() =>
239
- getSwapInput(1n, 10n, 10n, Fraction.asFraction(-0.1)),
246
+ getSwapInput(usdc, 1n, 10n, 10n, Fraction.asFraction(-0.1)),
240
247
  ).toThrow();
241
248
  });
242
249
 
243
250
  test("throws if fee is greater than or equal 1", () => {
244
- expect(() => getSwapInput(1n, 10n, 10n, Fraction.asFraction(1))).toThrow();
245
251
  expect(() =>
246
- getSwapInput(1n, 10n, 10n, Fraction.asFraction(1.132)),
252
+ getSwapInput(usdc, 1n, 10n, 10n, Fraction.asFraction(1)),
253
+ ).toThrow();
254
+ expect(() =>
255
+ getSwapInput(usdc, 1n, 10n, 10n, Fraction.asFraction(1.132)),
247
256
  ).toThrow();
248
257
  });
249
258
 
250
259
  test("throws if output is greater than or equal to output reserve", () => {
251
260
  expect(() =>
252
- getSwapInput(10n, 10n, 10n, Fraction.asFraction(0.1)),
261
+ getSwapInput(usdc, 10n, 10n, 10n, Fraction.asFraction(0.1)),
262
+ ).toThrow();
263
+ expect(() =>
264
+ getSwapInput(usdc, 1n, 1n, 1n, Fraction.asFraction(0.1)),
265
+ ).toThrow();
266
+ expect(() =>
267
+ getSwapInput(usdc, 10n, 1n, 1n, Fraction.asFraction(0.1)),
253
268
  ).toThrow();
254
- expect(() => getSwapInput(1n, 1n, 1n, Fraction.asFraction(0.1))).toThrow();
255
- expect(() => getSwapInput(10n, 1n, 1n, Fraction.asFraction(0.1))).toThrow();
256
269
  });
257
270
 
258
271
  test.each([
@@ -347,11 +360,16 @@ describe("getSwapInput", () => {
347
360
  }[])(
348
361
  "gets the correct swap input, given different swap outputs (%#)",
349
362
  ({ input, reserves, fee, impact }) => {
350
- const outcome = getSwapOutput(input, ...reserves, fee);
351
- const actual = getSwapInput(outcome.output, ...reserves, fee);
352
- const outcomeForActual = getSwapOutput(actual.input, ...reserves, fee);
363
+ const outcome = getSwapOutput(usdc, input, ...reserves, fee);
364
+ const actual = getSwapInput(usdc, outcome.output, ...reserves, fee);
365
+ const outcomeForActual = getSwapOutput(
366
+ usdc,
367
+ actual.input,
368
+ ...reserves,
369
+ fee,
370
+ );
353
371
  expect(outcome.output).toBe(outcomeForActual.output);
354
- expect(actual.inputLpFee).toBe(outcomeForActual.inputLpFee);
372
+ expect(actual.lpFee.amount).toBe(outcomeForActual.lpFee.amount);
355
373
  expect(actual.nextInputReserve).toBe(outcomeForActual.nextInputReserve);
356
374
  expect(actual.nextOutputReserve).toBe(outcomeForActual.nextOutputReserve);
357
375
  expect(actual.priceImpact).toEqual(outcomeForActual.priceImpact);
@@ -9,6 +9,12 @@ import {
9
9
  } from "../StableSwapsPool.js";
10
10
  import { TPair } from "../SharedPoolMath.js";
11
11
  import { Fraction, type TFractionLike } from "@sundaeswap/fraction";
12
+ import { IAssetAmountMetadata } from "@sundaeswap/asset";
13
+
14
+ const usdc: IAssetAmountMetadata = {
15
+ assetId: "99b071ce8580d6a3a11b4902145adb8bfd0d2a03935af8cf66403e15.55534443",
16
+ decimals: 6,
17
+ };
12
18
 
13
19
  describe("liquidityInvariant()", () => {
14
20
  test("Should be true for normal balanced case", () => {
@@ -99,7 +105,7 @@ describe("getPrice()", () => {
99
105
  });
100
106
  });
101
107
 
102
- describe("getSwapOutput()", () => {
108
+ describe("getSwapOutput(usdc,)", () => {
103
109
  const zeroThreePct = new Fraction(3, 1000);
104
110
  const onePct = new Fraction(1, 100);
105
111
  const zeroPct = Fraction.ZERO;
@@ -107,25 +113,42 @@ describe("getSwapOutput()", () => {
107
113
 
108
114
  test("throws if any of the arguments are negative", () => {
109
115
  expect(() =>
110
- getSwapOutput(-1n, 10n, 10n, Fraction.ZERO, Fraction.ZERO, laf),
116
+ getSwapOutput(usdc, -1n, 10n, 10n, Fraction.ZERO, Fraction.ZERO, laf),
111
117
  ).toThrow();
112
118
  expect(() =>
113
- getSwapOutput(1n, -10n, 10n, Fraction.ZERO, Fraction.ZERO, laf),
119
+ getSwapOutput(usdc, 1n, -10n, 10n, Fraction.ZERO, Fraction.ZERO, laf),
114
120
  ).toThrow();
115
121
  expect(() =>
116
- getSwapOutput(1n, 10n, -10n, Fraction.ZERO, Fraction.ZERO, laf),
122
+ getSwapOutput(usdc, 1n, 10n, -10n, Fraction.ZERO, Fraction.ZERO, laf),
117
123
  ).toThrow();
118
124
  expect(() =>
119
- getSwapOutput(1n, 1n, 1n, Fraction.asFraction(-0.1), Fraction.ZERO, laf),
125
+ getSwapOutput(
126
+ usdc,
127
+ 1n,
128
+ 1n,
129
+ 1n,
130
+ Fraction.asFraction(-0.1),
131
+ Fraction.ZERO,
132
+ laf,
133
+ ),
120
134
  ).toThrow();
121
135
  expect(() =>
122
- getSwapOutput(1n, 1n, 1n, Fraction.ZERO, Fraction.asFraction(-0.1), laf),
136
+ getSwapOutput(
137
+ usdc,
138
+ 1n,
139
+ 1n,
140
+ 1n,
141
+ Fraction.ZERO,
142
+ Fraction.asFraction(-0.1),
143
+ laf,
144
+ ),
123
145
  ).toThrow();
124
146
  });
125
147
 
126
148
  test("throws if combined fee is greater than 1", () => {
127
149
  expect(() =>
128
150
  getSwapOutput(
151
+ usdc,
129
152
  1n,
130
153
  10000n,
131
154
  10000n,
@@ -136,6 +159,7 @@ describe("getSwapOutput()", () => {
136
159
  ).not.toThrow();
137
160
  expect(() =>
138
161
  getSwapOutput(
162
+ usdc,
139
163
  1n,
140
164
  10000n,
141
165
  10000n,
@@ -148,11 +172,20 @@ describe("getSwapOutput()", () => {
148
172
 
149
173
  test("rounds up for non-fractional assets", () => {
150
174
  expect(
151
- getSwapOutput(83n, 10000n, 500n, zeroThreePct, zeroThreePct, laf).output,
175
+ getSwapOutput(usdc, 83n, 10000n, 500n, zeroThreePct, zeroThreePct, laf)
176
+ .output,
152
177
  ).toEqual(79n);
153
178
  expect(
154
- getSwapOutput(83n, 10000n, 500n, zeroThreePct, zeroThreePct, laf, true)
155
- .output,
179
+ getSwapOutput(
180
+ usdc,
181
+ 83n,
182
+ 10000n,
183
+ 500n,
184
+ zeroThreePct,
185
+ zeroThreePct,
186
+ laf,
187
+ true,
188
+ ).output,
156
189
  ).toEqual(80n);
157
190
  });
158
191
 
@@ -323,14 +356,14 @@ describe("getSwapOutput()", () => {
323
356
  }[])(
324
357
  "gets the correct swap output, given different inputs (%#)",
325
358
  ({ input, inReserve, fee, out, outReserve, lpFee, impact }) => {
326
- const actual = getSwapOutput(input, ...inReserve, fee, fee, laf);
359
+ const actual = getSwapOutput(usdc, input, ...inReserve, fee, fee, laf);
327
360
  expect(actual.output).toBe(out);
328
- expect(actual.outputLpFee).toBe(lpFee);
361
+ expect(actual.lpFee.amount).toBe(lpFee);
329
362
  expect(actual.nextInputReserve).toBe(outReserve[0]);
330
363
  expect(actual.nextInputReserve).toBe(input + inReserve[0]);
331
364
  expect(actual.nextOutputReserve).toBe(outReserve[1]);
332
365
  expect(
333
- actual.nextOutputReserve + actual.output + actual.outputProtocolFee,
366
+ actual.nextOutputReserve + actual.output + actual.protocolFee.amount,
334
367
  ).toBe(inReserve[1]);
335
368
  expect(actual.priceImpact.toPrecision(6)).toStrictEqual(impact);
336
369
  },
@@ -345,16 +378,17 @@ describe("getSwapInput", () => {
345
378
 
346
379
  test("throws if any of the arguments are negative", () => {
347
380
  expect(() =>
348
- getSwapInput(-1n, 10n, 10n, Fraction.ZERO, Fraction.ZERO, 1000n),
381
+ getSwapInput(usdc, -1n, 10n, 10n, Fraction.ZERO, Fraction.ZERO, 1000n),
349
382
  ).toThrow();
350
383
  expect(() =>
351
- getSwapInput(1n, -10n, 10n, Fraction.ZERO, Fraction.ZERO, 1000n),
384
+ getSwapInput(usdc, 1n, -10n, 10n, Fraction.ZERO, Fraction.ZERO, 1000n),
352
385
  ).toThrow();
353
386
  expect(() =>
354
- getSwapInput(1n, 10n, -10n, Fraction.ZERO, Fraction.ZERO, 1000n),
387
+ getSwapInput(usdc, 1n, 10n, -10n, Fraction.ZERO, Fraction.ZERO, 1000n),
355
388
  ).toThrow();
356
389
  expect(() =>
357
390
  getSwapInput(
391
+ usdc,
358
392
  1n,
359
393
  10n,
360
394
  10n,
@@ -367,10 +401,19 @@ describe("getSwapInput", () => {
367
401
 
368
402
  test("throws if fee is greater than or equal 1", () => {
369
403
  expect(() =>
370
- getSwapInput(1n, 10n, 10n, Fraction.asFraction(1), Fraction.ZERO, 1000n),
404
+ getSwapInput(
405
+ usdc,
406
+ 1n,
407
+ 10n,
408
+ 10n,
409
+ Fraction.asFraction(1),
410
+ Fraction.ZERO,
411
+ 1000n,
412
+ ),
371
413
  ).toThrow();
372
414
  expect(() =>
373
415
  getSwapInput(
416
+ usdc,
374
417
  1n,
375
418
  10n,
376
419
  10n,
@@ -384,6 +427,7 @@ describe("getSwapInput", () => {
384
427
  test("throws if output is greater than or equal to output reserve", () => {
385
428
  expect(() =>
386
429
  getSwapInput(
430
+ usdc,
387
431
  10n,
388
432
  10n,
389
433
  10n,
@@ -393,10 +437,26 @@ describe("getSwapInput", () => {
393
437
  ),
394
438
  ).toThrow();
395
439
  expect(() =>
396
- getSwapInput(1n, 1n, 1n, Fraction.asFraction(0.1), Fraction.ZERO, 1000n),
440
+ getSwapInput(
441
+ usdc,
442
+ 1n,
443
+ 1n,
444
+ 1n,
445
+ Fraction.asFraction(0.1),
446
+ Fraction.ZERO,
447
+ 1000n,
448
+ ),
397
449
  ).toThrow();
398
450
  expect(() =>
399
- getSwapInput(10n, 1n, 1n, Fraction.asFraction(0.1), Fraction.ZERO, 1000n),
451
+ getSwapInput(
452
+ usdc,
453
+ 10n,
454
+ 1n,
455
+ 1n,
456
+ Fraction.asFraction(0.1),
457
+ Fraction.ZERO,
458
+ 1000n,
459
+ ),
400
460
  ).toThrow();
401
461
  });
402
462
 
@@ -487,6 +547,7 @@ describe("getSwapInput", () => {
487
547
  "gets the correct swap input, given different swap outputs (%#)",
488
548
  ({ input, reserves, fee, impact }) => {
489
549
  const outcome = getSwapOutput(
550
+ usdc,
490
551
  input,
491
552
  ...reserves,
492
553
  fee,
@@ -494,6 +555,7 @@ describe("getSwapInput", () => {
494
555
  1000n,
495
556
  );
496
557
  const actual = getSwapInput(
558
+ usdc,
497
559
  outcome.output,
498
560
  ...reserves,
499
561
  fee,
@@ -501,6 +563,7 @@ describe("getSwapInput", () => {
501
563
  1000n,
502
564
  );
503
565
  const outcomeForActual = getSwapOutput(
566
+ usdc,
504
567
  actual.input,
505
568
  ...reserves,
506
569
  fee,
@@ -508,7 +571,7 @@ describe("getSwapInput", () => {
508
571
  1000n,
509
572
  );
510
573
  expect(outcome.output).toBe(outcomeForActual.output);
511
- expect(actual.outputLpFee).toBe(outcomeForActual.outputLpFee);
574
+ expect(actual.lpFee.amount).toBe(outcomeForActual.lpFee.amount);
512
575
  expect(actual.nextInputReserve).toBe(outcomeForActual.nextInputReserve);
513
576
  expect(actual.nextOutputReserve).toBe(outcomeForActual.nextOutputReserve);
514
577
  expect(actual.priceImpact).toEqual(outcomeForActual.priceImpact);