@paraswap/dex-lib 2.16.3 → 2.16.4-balancer-v2-buy

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.
Files changed (77) hide show
  1. package/.idea/aws.xml +17 -0
  2. package/.idea/codeStyles/Project.xml +19 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  5. package/.idea/misc.xml +6 -0
  6. package/.idea/modules.xml +8 -0
  7. package/.idea/paraswap-dex-lib.iml +9 -0
  8. package/.idea/vcs.xml +6 -0
  9. package/build/config.js +5 -5
  10. package/build/dex/balancer-v2/balancer-v2.d.ts +9 -14
  11. package/build/dex/balancer-v2/balancer-v2.js +19 -16
  12. package/build/dex/balancer-v2/balancer-v2.js.map +1 -1
  13. package/build/dex/balancer-v2/config.d.ts +2 -7
  14. package/build/dex/balancer-v2/config.js +20 -30
  15. package/build/dex/balancer-v2/config.js.map +1 -1
  16. package/build/dex/balancer-v2/pools/balancer-v2-pool.d.ts +25 -0
  17. package/build/dex/balancer-v2/pools/balancer-v2-pool.js +107 -0
  18. package/build/dex/balancer-v2/pools/balancer-v2-pool.js.map +1 -0
  19. package/build/dex/balancer-v2/pools/linear/LinearMath.d.ts +20 -0
  20. package/build/dex/balancer-v2/pools/linear/LinearMath.js +186 -0
  21. package/build/dex/balancer-v2/pools/linear/LinearMath.js.map +1 -0
  22. package/build/dex/balancer-v2/pools/linear/LinearPool.d.ts +51 -0
  23. package/build/dex/balancer-v2/pools/linear/LinearPool.js +477 -0
  24. package/build/dex/balancer-v2/pools/linear/LinearPool.js.map +1 -0
  25. package/build/dex/balancer-v2/pools/phantom-stable/PhantomStableMath.d.ts +10 -0
  26. package/build/dex/balancer-v2/pools/phantom-stable/PhantomStableMath.js +314 -0
  27. package/build/dex/balancer-v2/pools/phantom-stable/PhantomStableMath.js.map +1 -0
  28. package/build/dex/balancer-v2/pools/phantom-stable/PhantomStablePool.d.ts +50 -0
  29. package/build/dex/balancer-v2/pools/phantom-stable/PhantomStablePool.js +367 -0
  30. package/build/dex/balancer-v2/pools/phantom-stable/PhantomStablePool.js.map +1 -0
  31. package/build/dex/balancer-v2/pools/stable/StableMath.d.ts +7 -0
  32. package/build/dex/balancer-v2/pools/stable/StableMath.js +111 -0
  33. package/build/dex/balancer-v2/pools/stable/StableMath.js.map +1 -0
  34. package/build/dex/balancer-v2/pools/stable/StablePool.d.ts +30 -0
  35. package/build/dex/balancer-v2/pools/stable/StablePool.js +129 -0
  36. package/build/dex/balancer-v2/pools/stable/StablePool.js.map +1 -0
  37. package/build/dex/balancer-v2/pools/weighted/WeightedMath.d.ts +6 -0
  38. package/build/dex/balancer-v2/pools/weighted/WeightedMath.js +61 -0
  39. package/build/dex/balancer-v2/pools/weighted/WeightedMath.js.map +1 -0
  40. package/build/dex/balancer-v2/pools/weighted/WeightedPool.d.ts +30 -0
  41. package/build/dex/balancer-v2/pools/weighted/WeightedPool.js +112 -0
  42. package/build/dex/balancer-v2/pools/weighted/WeightedPool.js.map +1 -0
  43. package/build/dex/balancer-v2/types.d.ts +1 -0
  44. package/build/dex/balancer-v2/types.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/config.ts +5 -5
  47. package/src/dex/balancer-v2/balancer-v2-e2e.test.ts +204 -224
  48. package/src/dex/balancer-v2/balancer-v2.ts +41 -29
  49. package/src/dex/balancer-v2/config.ts +23 -35
  50. package/src/dex/balancer-v2/pools/balancer-v2-pool.ts +274 -0
  51. package/src/dex/balancer-v2/{LinearMath.ts → pools/linear/LinearMath.ts} +81 -23
  52. package/src/dex/balancer-v2/{LinearPool.ts → pools/linear/LinearPool.ts} +241 -5
  53. package/src/dex/balancer-v2/{StableMath.ts → pools/phantom-stable/PhantomStableMath.ts} +101 -21
  54. package/src/dex/balancer-v2/{PhantomStablePool.ts → pools/phantom-stable/PhantomStablePool.ts} +165 -11
  55. package/src/dex/balancer-v2/pools/stable/StableMath.ts +204 -0
  56. package/src/dex/balancer-v2/pools/stable/StablePool.ts +221 -0
  57. package/src/dex/balancer-v2/pools/weighted/WeightedMath.ts +84 -0
  58. package/src/dex/balancer-v2/pools/weighted/WeightedPool.ts +189 -0
  59. package/src/dex/balancer-v2/types.ts +1 -0
  60. package/tests/constants-e2e.ts +9 -4
  61. package/build/abi/DirectSwap.json +0 -970
  62. package/build/dex/test-dex/config.d.ts +0 -4
  63. package/build/dex/test-dex/config.js +0 -15
  64. package/build/dex/test-dex/config.js.map +0 -1
  65. package/build/dex/test-dex/test-dex-pool.d.ts +0 -39
  66. package/build/dex/test-dex/test-dex-pool.js +0 -63
  67. package/build/dex/test-dex/test-dex-pool.js.map +0 -1
  68. package/build/dex/test-dex/test-dex.d.ts +0 -37
  69. package/build/dex/test-dex/test-dex.js +0 -126
  70. package/build/dex/test-dex/test-dex.js.map +0 -1
  71. package/build/dex/test-dex/types.d.ts +0 -6
  72. package/build/dex/test-dex/types.js +0 -3
  73. package/build/dex/test-dex/types.js.map +0 -1
  74. package/build/dex/woo-fi-v2/woo-fi-math.d.ts +0 -16
  75. package/build/dex/woo-fi-v2/woo-fi-math.js +0 -137
  76. package/build/dex/woo-fi-v2/woo-fi-math.js.map +0 -1
  77. package/src/dex/balancer-v2/balancer-v2-pool.ts +0 -744
@@ -1,11 +1,11 @@
1
1
  import { Interface } from '@ethersproject/abi';
2
2
  import { BigNumber } from '@ethersproject/bignumber';
3
- import { isSameAddress, decodeThrowError } from './utils';
3
+ import { isSameAddress, decodeThrowError } from '../../utils';
4
4
  import * as LinearMath from './LinearMath';
5
- import { BasePool } from './balancer-v2-pool';
6
- import { callData, SubgraphPoolBase, PoolState, TokenState } from './types';
7
- import LinearPoolABI from '../../abi/balancer-v2/linearPoolAbi.json';
8
- import { SwapSide } from '../../constants';
5
+ import { BasePool } from '../balancer-v2-pool';
6
+ import { callData, SubgraphPoolBase, PoolState, TokenState } from '../../types';
7
+ import LinearPoolABI from '../../../../abi/balancer-v2/linearPoolAbi.json';
8
+ import { SwapSide } from '../../../../constants';
9
9
  import { keyBy } from 'lodash';
10
10
 
11
11
  export enum PairTypes {
@@ -30,6 +30,7 @@ type LinearPoolPairData = {
30
30
  mainIndex: number;
31
31
  lowerTarget: bigint;
32
32
  upperTarget: bigint;
33
+ rate: bigint;
33
34
  };
34
35
 
35
36
  /*
@@ -79,9 +80,223 @@ export class LinearPool extends BasePool {
79
80
  poolPairData.swapFee,
80
81
  poolPairData.lowerTarget,
81
82
  poolPairData.upperTarget,
83
+ poolPairData.rate,
82
84
  );
83
85
  }
84
86
 
87
+ onBuy(amounts: bigint[], poolPairData: LinearPoolPairData): bigint[] {
88
+ return this._swapGivenOut(
89
+ amounts,
90
+ poolPairData.tokens,
91
+ poolPairData.balances,
92
+ poolPairData.indexIn,
93
+ poolPairData.indexOut,
94
+ poolPairData.bptIndex,
95
+ poolPairData.wrappedIndex,
96
+ poolPairData.mainIndex,
97
+ poolPairData.scalingFactors,
98
+ poolPairData.swapFee,
99
+ poolPairData.lowerTarget,
100
+ poolPairData.upperTarget,
101
+ poolPairData.rate,
102
+ );
103
+ }
104
+
105
+ _swapGivenOut(
106
+ tokenAmountsOut: bigint[],
107
+ tokens: string[],
108
+ balances: bigint[],
109
+ indexIn: number,
110
+ indexOut: number,
111
+ bptIndex: number,
112
+ wrappedIndex: number,
113
+ mainIndex: number,
114
+ scalingFactors: bigint[],
115
+ swapFeePercentage: bigint,
116
+ lowerTarget: bigint,
117
+ upperTarget: bigint,
118
+ rate: bigint,
119
+ ): bigint[] {
120
+ let pairType: PairTypes;
121
+ if (isSameAddress(tokens[indexIn], tokens[bptIndex])) {
122
+ if (isSameAddress(tokens[indexOut], tokens[wrappedIndex]))
123
+ pairType = PairTypes.BptToWrappedToken;
124
+ else pairType = PairTypes.BptToMainToken;
125
+ } else if (isSameAddress(tokens[indexOut], tokens[bptIndex])) {
126
+ if (isSameAddress(tokens[indexIn], tokens[wrappedIndex]))
127
+ pairType = PairTypes.WrappedTokenToBpt;
128
+ else pairType = PairTypes.MainTokenToBpt;
129
+ } else {
130
+ if (isSameAddress(tokens[indexIn], tokens[wrappedIndex]))
131
+ pairType = PairTypes.WrappedTokenToMainToken;
132
+ else pairType = PairTypes.MainTokenToWrappedToken;
133
+ }
134
+
135
+ const balancesUpscaled = this._upscaleArray(balances, scalingFactors);
136
+ const tokenAmountsOutScaled = tokenAmountsOut.map(a =>
137
+ this._upscale(a, scalingFactors[indexOut]),
138
+ );
139
+
140
+ // VirtualBPTSupply must be used for the maths
141
+ const virtualBptSupply = this.MAX_TOKEN_BALANCE.sub(
142
+ balances[bptIndex],
143
+ ).toBigInt();
144
+
145
+ const amountsIn = this._onSwapGivenOut(
146
+ tokenAmountsOutScaled,
147
+ balancesUpscaled[mainIndex],
148
+ balancesUpscaled[wrappedIndex],
149
+ swapFeePercentage,
150
+ lowerTarget,
151
+ upperTarget,
152
+ virtualBptSupply,
153
+ pairType,
154
+ rate,
155
+ );
156
+
157
+ return amountsIn.map(a => this._downscaleUp(a, scalingFactors[indexIn]));
158
+ }
159
+
160
+ _onSwapGivenOut(
161
+ tokenAmountsIn: bigint[],
162
+ mainBalance: bigint,
163
+ wrappedBalance: bigint,
164
+ fee: bigint,
165
+ lowerTarget: bigint,
166
+ upperTarget: bigint,
167
+ virtualBptSupply: bigint,
168
+ pairType: PairTypes,
169
+ rate: bigint,
170
+ ): bigint[] {
171
+ const amountsIn: bigint[] = [];
172
+
173
+ switch (pairType) {
174
+ case PairTypes.BptToMainToken:
175
+ tokenAmountsIn.forEach(amountIn => {
176
+ let amt: bigint;
177
+ try {
178
+ amt = LinearMath._calcBptInPerMainOut(
179
+ amountIn,
180
+ mainBalance,
181
+ wrappedBalance,
182
+ virtualBptSupply,
183
+ {
184
+ rate,
185
+ fee: fee,
186
+ lowerTarget: lowerTarget,
187
+ upperTarget: upperTarget,
188
+ },
189
+ );
190
+ } catch (err) {
191
+ amt = 0n;
192
+ }
193
+ amountsIn.push(amt);
194
+ });
195
+ break;
196
+ case PairTypes.MainTokenToBpt:
197
+ tokenAmountsIn.forEach(amountIn => {
198
+ let amt: bigint;
199
+ try {
200
+ amt = LinearMath._calcMainInPerBptOut(
201
+ amountIn,
202
+ mainBalance,
203
+ wrappedBalance,
204
+ virtualBptSupply,
205
+ {
206
+ rate,
207
+ fee: fee,
208
+ lowerTarget: lowerTarget,
209
+ upperTarget: upperTarget,
210
+ },
211
+ );
212
+ } catch (err) {
213
+ amt = 0n;
214
+ }
215
+ amountsIn.push(amt);
216
+ });
217
+ break;
218
+ case PairTypes.MainTokenToWrappedToken:
219
+ tokenAmountsIn.forEach(amountIn => {
220
+ let amt: bigint;
221
+ try {
222
+ amt = LinearMath._calcMainInPerWrappedOut(amountIn, mainBalance, {
223
+ rate,
224
+ fee: fee,
225
+ lowerTarget: lowerTarget,
226
+ upperTarget: upperTarget,
227
+ });
228
+ } catch (err) {
229
+ amt = 0n;
230
+ }
231
+ amountsIn.push(amt);
232
+ });
233
+ break;
234
+ case PairTypes.WrappedTokenToMainToken:
235
+ tokenAmountsIn.forEach(amountIn => {
236
+ let amt: bigint;
237
+ try {
238
+ amt = LinearMath._calcWrappedInPerMainOut(amountIn, mainBalance, {
239
+ rate,
240
+ fee: fee,
241
+ lowerTarget: lowerTarget,
242
+ upperTarget: upperTarget,
243
+ });
244
+ } catch (err) {
245
+ amt = 0n;
246
+ }
247
+ amountsIn.push(amt);
248
+ });
249
+ break;
250
+ case PairTypes.BptToWrappedToken:
251
+ tokenAmountsIn.forEach(amountIn => {
252
+ let amt: bigint;
253
+ try {
254
+ amt = LinearMath._calcBptInPerWrappedOut(
255
+ amountIn,
256
+ mainBalance,
257
+ wrappedBalance,
258
+ virtualBptSupply,
259
+ {
260
+ rate,
261
+ fee: fee,
262
+ lowerTarget: lowerTarget,
263
+ upperTarget: upperTarget,
264
+ },
265
+ );
266
+ } catch (err) {
267
+ amt = 0n;
268
+ }
269
+ amountsIn.push(amt);
270
+ });
271
+ break;
272
+ case PairTypes.WrappedTokenToBpt:
273
+ tokenAmountsIn.forEach(amountIn => {
274
+ let amt: bigint;
275
+ try {
276
+ amt = LinearMath._calcWrappedInPerBptOut(
277
+ amountIn,
278
+ mainBalance,
279
+ wrappedBalance,
280
+ virtualBptSupply,
281
+ {
282
+ rate,
283
+ fee: fee,
284
+ lowerTarget: lowerTarget,
285
+ upperTarget: upperTarget,
286
+ },
287
+ );
288
+ } catch (err) {
289
+ amt = 0n;
290
+ }
291
+ amountsIn.push(amt);
292
+ });
293
+ break;
294
+ default:
295
+ amountsIn.push(0n);
296
+ }
297
+ return amountsIn;
298
+ }
299
+
85
300
  _swapGivenIn(
86
301
  tokenAmountsIn: bigint[],
87
302
  tokens: string[],
@@ -95,6 +310,7 @@ export class LinearPool extends BasePool {
95
310
  swapFeePercentage: bigint,
96
311
  lowerTarget: bigint,
97
312
  upperTarget: bigint,
313
+ rate: bigint,
98
314
  ): bigint[] {
99
315
  /*
100
316
  Linear pools allow trading between:
@@ -136,6 +352,7 @@ export class LinearPool extends BasePool {
136
352
  upperTarget,
137
353
  virtualBptSupply,
138
354
  pairType,
355
+ rate,
139
356
  );
140
357
 
141
358
  // amountOut tokens are exiting the Pool, so we round down.
@@ -159,6 +376,7 @@ export class LinearPool extends BasePool {
159
376
  upperTarget: bigint,
160
377
  virtualBptSupply: bigint,
161
378
  pairType: PairTypes,
379
+ rate: bigint,
162
380
  ): bigint[] {
163
381
  const amountsOut: bigint[] = [];
164
382
 
@@ -173,6 +391,7 @@ export class LinearPool extends BasePool {
173
391
  wrappedBalance,
174
392
  virtualBptSupply,
175
393
  {
394
+ rate,
176
395
  fee: fee,
177
396
  lowerTarget: lowerTarget,
178
397
  upperTarget: upperTarget,
@@ -194,6 +413,7 @@ export class LinearPool extends BasePool {
194
413
  wrappedBalance,
195
414
  virtualBptSupply,
196
415
  {
416
+ rate,
197
417
  fee: fee,
198
418
  lowerTarget: lowerTarget,
199
419
  upperTarget: upperTarget,
@@ -210,6 +430,7 @@ export class LinearPool extends BasePool {
210
430
  let amt: bigint;
211
431
  try {
212
432
  amt = LinearMath._calcWrappedOutPerMainIn(amountIn, mainBalance, {
433
+ rate,
213
434
  fee: fee,
214
435
  lowerTarget: lowerTarget,
215
436
  upperTarget: upperTarget,
@@ -225,6 +446,7 @@ export class LinearPool extends BasePool {
225
446
  let amt: bigint;
226
447
  try {
227
448
  amt = LinearMath._calcMainOutPerWrappedIn(amountIn, mainBalance, {
449
+ rate,
228
450
  fee: fee,
229
451
  lowerTarget: lowerTarget,
230
452
  upperTarget: upperTarget,
@@ -245,6 +467,7 @@ export class LinearPool extends BasePool {
245
467
  wrappedBalance,
246
468
  virtualBptSupply,
247
469
  {
470
+ rate,
248
471
  fee: fee,
249
472
  lowerTarget: lowerTarget,
250
473
  upperTarget: upperTarget,
@@ -266,6 +489,7 @@ export class LinearPool extends BasePool {
266
489
  wrappedBalance,
267
490
  virtualBptSupply,
268
491
  {
492
+ rate,
269
493
  fee: fee,
270
494
  lowerTarget: lowerTarget,
271
495
  upperTarget: upperTarget,
@@ -317,6 +541,7 @@ export class LinearPool extends BasePool {
317
541
  indexOut,
318
542
  scalingFactors,
319
543
  bptIndex,
544
+ rate: poolState.rate!,
320
545
  swapFee: poolState.swapFee,
321
546
  amp: poolState.amp || 0n,
322
547
  wrappedIndex: poolState.wrappedIndex || 0,
@@ -352,6 +577,10 @@ export class LinearPool extends BasePool {
352
577
  target: pool.address,
353
578
  callData: this.poolInterface.encodeFunctionData('getTargets'),
354
579
  });
580
+ poolCallData.push({
581
+ target: pool.address,
582
+ callData: this.poolInterface.encodeFunctionData('getRate'),
583
+ });
355
584
  return poolCallData;
356
585
  }
357
586
 
@@ -391,6 +620,12 @@ export class LinearPool extends BasePool {
391
620
  data[startIndex++],
392
621
  pool.address,
393
622
  );
623
+ const rate = decodeThrowError(
624
+ this.poolInterface,
625
+ 'getRate',
626
+ data[startIndex++],
627
+ pool.address,
628
+ )[0];
394
629
 
395
630
  const bptIndex = pool.tokens.findIndex(
396
631
  t => t.address.toLowerCase() === pool.address.toLowerCase(),
@@ -404,6 +639,7 @@ export class LinearPool extends BasePool {
404
639
 
405
640
  const poolState: PoolState = {
406
641
  swapFee: BigInt(swapFee.toString()),
642
+ rate: BigInt(rate.toString()),
407
643
  mainIndex: Number(pool.mainIndex),
408
644
  wrappedIndex: Number(pool.wrappedIndex),
409
645
  bptIndex,
@@ -1,5 +1,5 @@
1
- import { BI_POWS } from '../../bigint-constants';
2
- import { MathSol } from './balancer-v2-math';
1
+ import { BI_POWS } from '../../../../bigint-constants';
2
+ import { MathSol } from '../../balancer-v2-math';
3
3
 
4
4
  const AMP_PRECISION = BI_POWS[3];
5
5
 
@@ -9,15 +9,15 @@ export function _calculateInvariant(
9
9
  roundUp: boolean,
10
10
  ): bigint {
11
11
  /**********************************************************************************************
12
- // invariant //
13
- // D = invariant D^(n+1) //
14
- // A = amplification coefficient A n^n S + D = A D n^n + ----------- //
15
- // S = sum of balances n^n P //
16
- // P = product of balances //
17
- // n = number of tokens //
18
- *********x************************************************************************************/
12
+ // invariant //
13
+ // D = invariant D^(n+1) //
14
+ // A = amplification coefficient A n^n S + D = A D n^n + ----------- //
15
+ // S = sum of balances n^n P //
16
+ // P = product of balances //
17
+ // n = number of tokens //
18
+ *********x************************************************************************************/
19
19
 
20
- // We support rounding up or down.
20
+ // We support rounding up or down.
21
21
 
22
22
  let sum = 0n;
23
23
  const numTokens = balances.length;
@@ -44,18 +44,18 @@ export function _calculateInvariant(
44
44
  prevInvariant = invariant;
45
45
  invariant = MathSol.div(
46
46
  MathSol.mul(MathSol.mul(BigInt(numTokens), invariant), invariant) +
47
- MathSol.div(
48
- MathSol.mul(MathSol.mul(ampTimesTotal, sum), P_D),
49
- AMP_PRECISION,
50
- roundUp,
51
- ),
47
+ MathSol.div(
48
+ MathSol.mul(MathSol.mul(ampTimesTotal, sum), P_D),
49
+ AMP_PRECISION,
50
+ roundUp,
51
+ ),
52
52
  MathSol.mul(BigInt(numTokens + 1), invariant) +
53
- // No need to use checked arithmetic for the amp precision, the amp is guaranteed to be at least 1
54
- MathSol.div(
55
- MathSol.mul(ampTimesTotal - AMP_PRECISION, P_D),
56
- AMP_PRECISION,
57
- !roundUp,
58
- ),
53
+ // No need to use checked arithmetic for the amp precision, the amp is guaranteed to be at least 1
54
+ MathSol.div(
55
+ MathSol.mul(ampTimesTotal - AMP_PRECISION, P_D),
56
+ AMP_PRECISION,
57
+ !roundUp,
58
+ ),
59
59
  roundUp,
60
60
  );
61
61
 
@@ -81,6 +81,17 @@ export function _calcOutGivenIn(
81
81
  amountIn: bigint,
82
82
  invariant?: bigint,
83
83
  ): bigint {
84
+ /**************************************************************************************************************
85
+ // outGivenIn token x for y - polynomial equation to solve //
86
+ // ay = amount out to calculate //
87
+ // by = balance token out //
88
+ // y = by - ay (finalBalanceOut) //
89
+ // D = invariant D D^(n+1) //
90
+ // A = amplification coefficient y^2 + ( S - ---------- - D) * y - ------------- = 0 //
91
+ // n = number of tokens (A * n^n) A * n^2n * P //
92
+ // S = sum of final balances but y //
93
+ // P = product of final balances but y //
94
+ **************************************************************************************************************/
84
95
  balances = [...balances];
85
96
  // Given that we need to have a greater final balance out, the invariant needs to be rounded up
86
97
  if (!invariant) invariant = _calculateInvariant(amp, balances, true);
@@ -105,6 +116,19 @@ export function _calcInGivenOut(
105
116
  fee: bigint,
106
117
  invariant?: bigint,
107
118
  ): bigint {
119
+ /**************************************************************************************************************
120
+ // inGivenOut token x for y - polynomial equation to solve //
121
+ // ax = amount in to calculate //
122
+ // bx = balance token in //
123
+ // x = bx + ax (finalBalanceIn) //
124
+ // D = invariant D D^(n+1) //
125
+ // A = amplification coefficient x^2 + ( S - ---------- - D) * x - ------------- = 0 //
126
+ // n = number of tokens (A * n^n) A * n^2n * P //
127
+ // S = sum of final balances but x //
128
+ // P = product of final balances but x //
129
+ **************************************************************************************************************/
130
+
131
+ // Given that we need to have a greater final balance in, the invariant needs to be rounded up
108
132
  balances = [...balances];
109
133
  if (!invariant) invariant = _calculateInvariant(amp, balances, true);
110
134
  balances[tokenIndexOut] = MathSol.sub(balances[tokenIndexOut], amountOut);
@@ -120,6 +144,7 @@ export function _calcInGivenOut(
120
144
  MathSol.sub(finalBalanceIn, balances[tokenIndexIn]),
121
145
  1n,
122
146
  );
147
+
123
148
  amountIn = addFee(amountIn, fee);
124
149
  return amountIn;
125
150
  }
@@ -195,6 +220,61 @@ export function _calcBptOutGivenExactTokensIn(
195
220
  }
196
221
  }
197
222
 
223
+ export function _calcTokenInGivenExactBptOut(
224
+ amp: bigint,
225
+ balances: bigint[],
226
+ tokenIndexIn: number,
227
+ bptAmountOut: bigint,
228
+ bptTotalSupply: bigint,
229
+ fee: bigint,
230
+ invariant?: bigint,
231
+ ): bigint {
232
+ if (!invariant) invariant = _calculateInvariant(amp, balances, true);
233
+
234
+ const newInvariant = MathSol.mulUpFixed(
235
+ MathSol.divUpFixed(
236
+ MathSol.add(bptTotalSupply, bptAmountOut),
237
+ bptTotalSupply
238
+ ),
239
+ invariant
240
+ );
241
+
242
+ const newBalanceTokenIndex =
243
+ _getTokenBalanceGivenInvariantAndAllOtherBalances(
244
+ amp,
245
+ balances,
246
+ newInvariant,
247
+ tokenIndexIn
248
+ );
249
+ const amountInWithoutFee = MathSol.sub(
250
+ newBalanceTokenIndex,
251
+ balances[tokenIndexIn]
252
+ );
253
+
254
+ let sumBalances = BigInt(0);
255
+ for (let i = 0; i < balances.length; i++) {
256
+ sumBalances = MathSol.add(sumBalances, balances[i]);
257
+ }
258
+
259
+ // We can now compute how much extra balance is being deposited
260
+ // and used in virtual swaps, and charge swap fees accordingly.
261
+ const currentWeight = MathSol.divDownFixed(
262
+ balances[tokenIndexIn],
263
+ sumBalances
264
+ );
265
+ const taxablePercentage = MathSol.complementFixed(currentWeight);
266
+ const taxableAmount = MathSol.mulUpFixed(
267
+ amountInWithoutFee,
268
+ taxablePercentage
269
+ );
270
+ const nonTaxableAmount = MathSol.sub(amountInWithoutFee, taxableAmount);
271
+
272
+ return MathSol.add(
273
+ nonTaxableAmount,
274
+ MathSol.divUpFixed(taxableAmount, MathSol.sub(MathSol.ONE, fee))
275
+ );
276
+ }
277
+
198
278
  /*
199
279
  Flow of calculations:
200
280
  amountsTokenOut -> amountsOutProportional ->