@pancakeswap/v3-sdk 2.0.0 → 3.0.0
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/abi/MasterChefV3.d.ts +1222 -0
- package/dist/abi/MasterChefV3.d.ts.map +1 -0
- package/dist/abi/NonfungiblePositionManager.d.ts +962 -0
- package/dist/abi/NonfungiblePositionManager.d.ts.map +1 -0
- package/dist/abi/PeripheryPaymentsWithFee.d.ts +88 -0
- package/dist/abi/PeripheryPaymentsWithFee.d.ts.map +1 -0
- package/dist/abi/Quoter.d.ts +162 -0
- package/dist/abi/Quoter.d.ts.map +1 -0
- package/dist/abi/QuoterV2.d.ts +220 -0
- package/dist/abi/QuoterV2.d.ts.map +1 -0
- package/dist/abi/SelfPermit.d.ts +122 -0
- package/dist/abi/SelfPermit.d.ts.map +1 -0
- package/dist/abi/SwapRouter.d.ts +453 -0
- package/dist/abi/SwapRouter.d.ts.map +1 -0
- package/dist/abi/V3Staker.d.ts +547 -0
- package/dist/abi/V3Staker.d.ts.map +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/entities/pool.d.ts +2 -1
- package/dist/entities/pool.d.ts.map +1 -1
- package/dist/entities/tick.d.ts.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1447 -1359
- package/dist/index.mjs +1447 -1367
- package/dist/masterchefV3.d.ts +1228 -9
- package/dist/masterchefV3.d.ts.map +1 -1
- package/dist/multicall.d.ts +16 -3
- package/dist/multicall.d.ts.map +1 -1
- package/dist/nonfungiblePositionManager.d.ts +976 -10
- package/dist/nonfungiblePositionManager.d.ts.map +1 -1
- package/dist/payments.d.ts +95 -6
- package/dist/payments.d.ts.map +1 -1
- package/dist/quoter.d.ts +385 -4
- package/dist/quoter.d.ts.map +1 -1
- package/dist/selfPermit.d.ts +128 -8
- package/dist/selfPermit.d.ts.map +1 -1
- package/dist/staker.d.ts +549 -3
- package/dist/staker.d.ts.map +1 -1
- package/dist/swapRouter.d.ts +452 -2
- package/dist/swapRouter.d.ts.map +1 -1
- package/dist/utils/calldata.d.ts +4 -3
- package/dist/utils/calldata.d.ts.map +1 -1
- package/dist/utils/computePoolAddress.d.ts +4 -3
- package/dist/utils/computePoolAddress.d.ts.map +1 -1
- package/dist/utils/encodeRouteToPath.d.ts +3 -2
- package/dist/utils/encodeRouteToPath.d.ts.map +1 -1
- package/dist/utils/encodeSqrtRatioX96.d.ts +1 -1
- package/dist/utils/encodeSqrtRatioX96.d.ts.map +1 -1
- package/dist/utils/feeCalculator.d.ts +1 -1
- package/dist/utils/feeCalculator.d.ts.map +1 -1
- package/dist/utils/parseProtocolFees.d.ts +1 -1
- package/dist/utils/parseProtocolFees.d.ts.map +1 -1
- package/dist/utils/positionMath.d.ts.map +1 -1
- package/dist/utils/priceTickConversions.d.ts +1 -1
- package/dist/utils/priceTickConversions.d.ts.map +1 -1
- package/package.json +6 -15
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { ChainId,
|
|
2
|
-
import
|
|
3
|
-
import { Percent, Price as Price$1, Fraction as Fraction$1 } from '@pancakeswap/swap-sdk-core';
|
|
4
|
-
import {
|
|
5
|
-
import { getCreate2Address } from '@ethersproject/address';
|
|
6
|
-
import { keccak256, pack } from '@ethersproject/solidity';
|
|
1
|
+
import { ChainId, Price, CurrencyAmount, Percent as Percent$1, MaxUint256 as MaxUint256$1, TradeType, Fraction, sortedInsert, validateAndParseAddress, ZERO as ZERO$2, ONE as ONE$1 } from '@pancakeswap/sdk';
|
|
2
|
+
import invariant9 from 'tiny-invariant';
|
|
3
|
+
import { Percent, MaxUint256, sqrt, Price as Price$1, CurrencyAmount as CurrencyAmount$1, Fraction as Fraction$1, ZERO as ZERO$1, TradeType as TradeType$1 } from '@pancakeswap/swap-sdk-core';
|
|
4
|
+
import { keccak256, encodeAbiParameters, parseAbiParameters, encodePacked, encodeFunctionData, toBytes, getAddress, pad, isBytes, slice, concat } from 'viem';
|
|
7
5
|
|
|
8
6
|
// src/entities/pool.ts
|
|
9
7
|
var FACTORY_ADDRESS = "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865";
|
|
@@ -38,6 +36,13 @@ var MAX_FEE = 10n ** 6n;
|
|
|
38
36
|
var ONE_HUNDRED_PERCENT = new Percent("1");
|
|
39
37
|
var ZERO_PERCENT = new Percent("0");
|
|
40
38
|
var Q128 = 2n ** 128n;
|
|
39
|
+
function getCreate2Address(from_, salt_, initCodeHash) {
|
|
40
|
+
const from = toBytes(getAddress(from_));
|
|
41
|
+
const salt = pad(isBytes(salt_) ? salt_ : toBytes(salt_), {
|
|
42
|
+
size: 32
|
|
43
|
+
});
|
|
44
|
+
return getAddress(slice(keccak256(concat([toBytes("0xff"), from, salt, toBytes(initCodeHash)])), 12));
|
|
45
|
+
}
|
|
41
46
|
function computePoolAddress({
|
|
42
47
|
deployerAddress,
|
|
43
48
|
tokenA,
|
|
@@ -49,8 +54,7 @@ function computePoolAddress({
|
|
|
49
54
|
return getCreate2Address(
|
|
50
55
|
deployerAddress,
|
|
51
56
|
keccak256(
|
|
52
|
-
["
|
|
53
|
-
[defaultAbiCoder.encode(["address", "address", "uint24"], [token0.address, token1.address, fee])]
|
|
57
|
+
encodeAbiParameters(parseAbiParameters(["address, address, uint24"]), [token0.address, token1.address, fee])
|
|
54
58
|
),
|
|
55
59
|
initCodeHashManualOverride ?? POOL_INIT_CODE_HASH
|
|
56
60
|
);
|
|
@@ -118,13 +122,13 @@ var SqrtPriceMath = class {
|
|
|
118
122
|
return roundUp ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96) : liquidity * (sqrtRatioBX96 - sqrtRatioAX96) / Q96;
|
|
119
123
|
}
|
|
120
124
|
static getNextSqrtPriceFromInput(sqrtPX96, liquidity, amountIn, zeroForOne) {
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
invariant9(sqrtPX96 > ZERO);
|
|
126
|
+
invariant9(liquidity > ZERO);
|
|
123
127
|
return zeroForOne ? this.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) : this.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true);
|
|
124
128
|
}
|
|
125
129
|
static getNextSqrtPriceFromOutput(sqrtPX96, liquidity, amountOut, zeroForOne) {
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
invariant9(sqrtPX96 > ZERO);
|
|
131
|
+
invariant9(liquidity > ZERO);
|
|
128
132
|
return zeroForOne ? this.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) : this.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false);
|
|
129
133
|
}
|
|
130
134
|
static getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amount, add) {
|
|
@@ -142,8 +146,8 @@ var SqrtPriceMath = class {
|
|
|
142
146
|
return FullMath.mulDivRoundingUp(numerator1, ONE, numerator1 / sqrtPX96 + amount);
|
|
143
147
|
}
|
|
144
148
|
const product = multiplyIn256(amount, sqrtPX96);
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
invariant9(product / amount === sqrtPX96);
|
|
150
|
+
invariant9(numerator1 > product);
|
|
147
151
|
const denominator = numerator1 - product;
|
|
148
152
|
return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator);
|
|
149
153
|
}
|
|
@@ -153,7 +157,7 @@ var SqrtPriceMath = class {
|
|
|
153
157
|
return sqrtPX96 + quotient2;
|
|
154
158
|
}
|
|
155
159
|
const quotient = FullMath.mulDivRoundingUp(amount, Q96, liquidity);
|
|
156
|
-
|
|
160
|
+
invariant9(sqrtPX96 > quotient);
|
|
157
161
|
return sqrtPX96 - quotient;
|
|
158
162
|
}
|
|
159
163
|
};
|
|
@@ -221,8 +225,8 @@ var SwapMath = class {
|
|
|
221
225
|
var TWO = 2n;
|
|
222
226
|
var POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow) => [pow, TWO ** BigInt(pow)]);
|
|
223
227
|
function mostSignificantBit(x) {
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
invariant9(x > ZERO, "ZERO");
|
|
229
|
+
invariant9(x <= MaxUint256, "MAX");
|
|
226
230
|
let msb = 0;
|
|
227
231
|
for (const [power, min] of POWERS_OF_2) {
|
|
228
232
|
if (x >= min) {
|
|
@@ -249,7 +253,7 @@ var _TickMath = class {
|
|
|
249
253
|
* @param tick the tick for which to compute the sqrt ratio
|
|
250
254
|
*/
|
|
251
255
|
static getSqrtRatioAtTick(tick) {
|
|
252
|
-
|
|
256
|
+
invariant9(tick >= _TickMath.MIN_TICK && tick <= _TickMath.MAX_TICK && Number.isInteger(tick), "TICK");
|
|
253
257
|
const absTick = tick < 0 ? tick * -1 : tick;
|
|
254
258
|
let ratio = (absTick & 1) != 0 ? BigInt("0xfffcb933bd6fad37aa2d162d1a594001") : BigInt("0x100000000000000000000000000000000");
|
|
255
259
|
if ((absTick & 2) != 0)
|
|
@@ -300,7 +304,7 @@ var _TickMath = class {
|
|
|
300
304
|
* @param sqrtRatioX96 the sqrt ratio as a Q64.96 for which to compute the tick
|
|
301
305
|
*/
|
|
302
306
|
static getTickAtSqrtRatio(sqrtRatioX96) {
|
|
303
|
-
|
|
307
|
+
invariant9(sqrtRatioX96 >= _TickMath.MIN_SQRT_RATIO && sqrtRatioX96 < _TickMath.MAX_SQRT_RATIO, "SQRT_RATIO");
|
|
304
308
|
const sqrtRatioX128 = sqrtRatioX96 << 32n;
|
|
305
309
|
const msb = mostSignificantBit(sqrtRatioX128);
|
|
306
310
|
let r;
|
|
@@ -374,25 +378,25 @@ var TickList = class {
|
|
|
374
378
|
constructor() {
|
|
375
379
|
}
|
|
376
380
|
static validateList(ticks, tickSpacing) {
|
|
377
|
-
|
|
378
|
-
|
|
381
|
+
invariant9(tickSpacing > 0, "TICK_SPACING_NONZERO");
|
|
382
|
+
invariant9(
|
|
379
383
|
ticks.every(({ index }) => index % tickSpacing === 0),
|
|
380
384
|
"TICK_SPACING"
|
|
381
385
|
);
|
|
382
|
-
|
|
383
|
-
|
|
386
|
+
invariant9(ticks.reduce((accumulator, { liquidityNet }) => accumulator + liquidityNet, ZERO) === ZERO, "ZERO_NET");
|
|
387
|
+
invariant9(isSorted(ticks, tickComparator), "SORTED");
|
|
384
388
|
}
|
|
385
389
|
static isBelowSmallest(ticks, tick) {
|
|
386
|
-
|
|
390
|
+
invariant9(ticks.length > 0, "LENGTH");
|
|
387
391
|
return tick < ticks[0].index;
|
|
388
392
|
}
|
|
389
393
|
static isAtOrAboveLargest(ticks, tick) {
|
|
390
|
-
|
|
394
|
+
invariant9(ticks.length > 0, "LENGTH");
|
|
391
395
|
return tick >= ticks[ticks.length - 1].index;
|
|
392
396
|
}
|
|
393
397
|
static getTick(ticks, index) {
|
|
394
398
|
const tick = ticks[this.binarySearch(ticks, index)];
|
|
395
|
-
|
|
399
|
+
invariant9(tick.index === index, "NOT_CONTAINED");
|
|
396
400
|
return tick;
|
|
397
401
|
}
|
|
398
402
|
/**
|
|
@@ -402,7 +406,7 @@ var TickList = class {
|
|
|
402
406
|
* @private
|
|
403
407
|
*/
|
|
404
408
|
static binarySearch(ticks, tick) {
|
|
405
|
-
|
|
409
|
+
invariant9(!this.isBelowSmallest(ticks, tick), "BELOW_SMALLEST");
|
|
406
410
|
let l = 0;
|
|
407
411
|
let r = ticks.length - 1;
|
|
408
412
|
let i;
|
|
@@ -420,14 +424,14 @@ var TickList = class {
|
|
|
420
424
|
}
|
|
421
425
|
static nextInitializedTick(ticks, tick, lte) {
|
|
422
426
|
if (lte) {
|
|
423
|
-
|
|
427
|
+
invariant9(!TickList.isBelowSmallest(ticks, tick), "BELOW_SMALLEST");
|
|
424
428
|
if (TickList.isAtOrAboveLargest(ticks, tick)) {
|
|
425
429
|
return ticks[ticks.length - 1];
|
|
426
430
|
}
|
|
427
431
|
const index2 = this.binarySearch(ticks, tick);
|
|
428
432
|
return ticks[index2];
|
|
429
433
|
}
|
|
430
|
-
|
|
434
|
+
invariant9(!this.isAtOrAboveLargest(ticks, tick), "AT_OR_ABOVE_LARGEST");
|
|
431
435
|
if (this.isBelowSmallest(ticks, tick)) {
|
|
432
436
|
return ticks[0];
|
|
433
437
|
}
|
|
@@ -464,44 +468,219 @@ var TickList = class {
|
|
|
464
468
|
return Math.abs(beforeIndex - afterIndex);
|
|
465
469
|
}
|
|
466
470
|
};
|
|
471
|
+
var Tick = class {
|
|
472
|
+
constructor({ index, liquidityGross, liquidityNet }) {
|
|
473
|
+
invariant9(index >= TickMath.MIN_TICK && index <= TickMath.MAX_TICK, "TICK");
|
|
474
|
+
this.index = index;
|
|
475
|
+
this.liquidityGross = BigInt(liquidityGross);
|
|
476
|
+
this.liquidityNet = BigInt(liquidityNet);
|
|
477
|
+
}
|
|
478
|
+
};
|
|
467
479
|
|
|
468
|
-
// src/
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
hex = `0${hex}`;
|
|
480
|
+
// src/entities/tickListDataProvider.ts
|
|
481
|
+
var TickListDataProvider = class {
|
|
482
|
+
constructor(ticks) {
|
|
483
|
+
const ticksMapped = ticks.map((t) => t instanceof Tick ? t : new Tick(t));
|
|
484
|
+
this.ticks = ticksMapped;
|
|
474
485
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
486
|
+
async getTick(tick) {
|
|
487
|
+
return TickList.getTick(this.ticks, tick);
|
|
488
|
+
}
|
|
489
|
+
async nextInitializedTickWithinOneWord(tick, lte, tickSpacing) {
|
|
490
|
+
return TickList.nextInitializedTickWithinOneWord(this.ticks, tick, lte, tickSpacing);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
// src/entities/pool.ts
|
|
495
|
+
var NO_TICK_DATA_PROVIDER_DEFAULT = new NoTickDataProvider();
|
|
496
|
+
var Pool = class {
|
|
497
|
+
static getAddress(tokenA, tokenB, fee, initCodeHashManualOverride, deployerAddressOverride) {
|
|
498
|
+
return computePoolAddress({
|
|
499
|
+
deployerAddress: deployerAddressOverride ?? DEPLOYER_ADDRESSES[tokenA.chainId],
|
|
500
|
+
fee,
|
|
501
|
+
tokenA,
|
|
502
|
+
tokenB,
|
|
503
|
+
initCodeHashManualOverride
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Construct a pool
|
|
508
|
+
* @param tokenA One of the tokens in the pool
|
|
509
|
+
* @param tokenB The other token in the pool
|
|
510
|
+
* @param fee The fee in hundredths of a bips of the input amount of every swap that is collected by the pool
|
|
511
|
+
* @param sqrtRatioX96 The sqrt of the current ratio of amounts of token1 to token0
|
|
512
|
+
* @param liquidity The current value of in range liquidity
|
|
513
|
+
* @param tickCurrent The current tick of the pool
|
|
514
|
+
* @param ticks The current state of the pool ticks or a data provider that can return tick data
|
|
515
|
+
*/
|
|
516
|
+
constructor(tokenA, tokenB, fee, sqrtRatioX96, liquidity, tickCurrent, ticks = NO_TICK_DATA_PROVIDER_DEFAULT) {
|
|
517
|
+
invariant9(Number.isInteger(fee) && fee < 1e6, "FEE");
|
|
518
|
+
[this.token0, this.token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA];
|
|
519
|
+
this.fee = fee;
|
|
520
|
+
this.sqrtRatioX96 = BigInt(sqrtRatioX96);
|
|
521
|
+
this.liquidity = BigInt(liquidity);
|
|
522
|
+
this.tickCurrent = tickCurrent;
|
|
523
|
+
this.tickDataProvider = Array.isArray(ticks) ? new TickListDataProvider(ticks) : ticks;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Returns true if the token is either token0 or token1
|
|
527
|
+
* @param token The token to check
|
|
528
|
+
* @returns True if token is either token0 or token
|
|
529
|
+
*/
|
|
530
|
+
involvesToken(token) {
|
|
531
|
+
return token.equals(this.token0) || token.equals(this.token1);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Returns the current mid price of the pool in terms of token0, i.e. the ratio of token1 over token0
|
|
535
|
+
*/
|
|
536
|
+
get token0Price() {
|
|
537
|
+
return this._token0Price ?? (this._token0Price = new Price(this.token0, this.token1, Q192, this.sqrtRatioX96 * this.sqrtRatioX96));
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Returns the current mid price of the pool in terms of token1, i.e. the ratio of token0 over token1
|
|
541
|
+
*/
|
|
542
|
+
get token1Price() {
|
|
543
|
+
return this._token1Price ?? (this._token1Price = new Price(this.token1, this.token0, this.sqrtRatioX96 * this.sqrtRatioX96, Q192));
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Return the price of the given token in terms of the other token in the pool.
|
|
547
|
+
* @param token The token to return price of
|
|
548
|
+
* @returns The price of the given token, in terms of the other.
|
|
549
|
+
*/
|
|
550
|
+
priceOf(token) {
|
|
551
|
+
invariant9(this.involvesToken(token), "TOKEN");
|
|
552
|
+
return token.equals(this.token0) ? this.token0Price : this.token1Price;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Returns the chain ID of the tokens in the pool.
|
|
556
|
+
*/
|
|
557
|
+
get chainId() {
|
|
558
|
+
return this.token0.chainId;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Given an input amount of a token, return the computed output amount, and a pool with state updated after the trade
|
|
562
|
+
* @param inputAmount The input amount for which to quote the output amount
|
|
563
|
+
* @param sqrtPriceLimitX96 The Q64.96 sqrt price limit
|
|
564
|
+
* @returns The output amount and the pool with updated state
|
|
565
|
+
*/
|
|
566
|
+
async getOutputAmount(inputAmount, sqrtPriceLimitX96) {
|
|
567
|
+
invariant9(this.involvesToken(inputAmount.currency), "TOKEN");
|
|
568
|
+
const zeroForOne = inputAmount.currency.equals(this.token0);
|
|
569
|
+
const {
|
|
570
|
+
amountCalculated: outputAmount,
|
|
571
|
+
sqrtRatioX96,
|
|
572
|
+
liquidity,
|
|
573
|
+
tickCurrent
|
|
574
|
+
} = await this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX96);
|
|
575
|
+
const outputToken = zeroForOne ? this.token1 : this.token0;
|
|
576
|
+
return [
|
|
577
|
+
CurrencyAmount.fromRawAmount(outputToken, outputAmount * NEGATIVE_ONE),
|
|
578
|
+
new Pool(this.token0, this.token1, this.fee, sqrtRatioX96, liquidity, tickCurrent, this.tickDataProvider)
|
|
579
|
+
];
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade
|
|
583
|
+
* @param outputAmount the output amount for which to quote the input amount
|
|
584
|
+
* @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this value after the swap. If one for zero, the price cannot be greater than this value after the swap
|
|
585
|
+
* @returns The input amount and the pool with updated state
|
|
586
|
+
*/
|
|
587
|
+
async getInputAmount(outputAmount, sqrtPriceLimitX96) {
|
|
588
|
+
invariant9(outputAmount.currency.isToken && this.involvesToken(outputAmount.currency), "TOKEN");
|
|
589
|
+
const zeroForOne = outputAmount.currency.equals(this.token1);
|
|
590
|
+
const {
|
|
591
|
+
amountSpecifiedRemaining,
|
|
592
|
+
amountCalculated: inputAmount,
|
|
593
|
+
sqrtRatioX96,
|
|
594
|
+
liquidity,
|
|
595
|
+
tickCurrent
|
|
596
|
+
} = await this.swap(zeroForOne, outputAmount.quotient * NEGATIVE_ONE, sqrtPriceLimitX96);
|
|
597
|
+
invariant9(amountSpecifiedRemaining === ZERO, "INSUFICIENT_LIQUIDITY");
|
|
598
|
+
const inputToken = zeroForOne ? this.token0 : this.token1;
|
|
599
|
+
return [
|
|
600
|
+
CurrencyAmount.fromRawAmount(inputToken, inputAmount),
|
|
601
|
+
new Pool(this.token0, this.token1, this.fee, sqrtRatioX96, liquidity, tickCurrent, this.tickDataProvider)
|
|
602
|
+
];
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Executes a swap
|
|
606
|
+
* @param zeroForOne Whether the amount in is token0 or token1
|
|
607
|
+
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
|
|
608
|
+
* @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this value after the swap. If one for zero, the price cannot be greater than this value after the swap
|
|
609
|
+
* @returns amountCalculated
|
|
610
|
+
* @returns sqrtRatioX96
|
|
611
|
+
* @returns liquidity
|
|
612
|
+
* @returns tickCurrent
|
|
613
|
+
*/
|
|
614
|
+
async swap(zeroForOne, amountSpecified, sqrtPriceLimitX96) {
|
|
615
|
+
if (!sqrtPriceLimitX96)
|
|
616
|
+
sqrtPriceLimitX96 = zeroForOne ? TickMath.MIN_SQRT_RATIO + ONE : TickMath.MAX_SQRT_RATIO - ONE;
|
|
617
|
+
if (zeroForOne) {
|
|
618
|
+
invariant9(sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO, "RATIO_MIN");
|
|
619
|
+
invariant9(sqrtPriceLimitX96 < this.sqrtRatioX96, "RATIO_CURRENT");
|
|
620
|
+
} else {
|
|
621
|
+
invariant9(sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO, "RATIO_MAX");
|
|
622
|
+
invariant9(sqrtPriceLimitX96 > this.sqrtRatioX96, "RATIO_CURRENT");
|
|
623
|
+
}
|
|
624
|
+
const exactInput = amountSpecified >= ZERO;
|
|
625
|
+
const state = {
|
|
626
|
+
amountSpecifiedRemaining: amountSpecified,
|
|
627
|
+
amountCalculated: ZERO,
|
|
628
|
+
sqrtPriceX96: this.sqrtRatioX96,
|
|
629
|
+
tick: this.tickCurrent,
|
|
630
|
+
liquidity: this.liquidity
|
|
631
|
+
};
|
|
632
|
+
while (state.amountSpecifiedRemaining !== ZERO && state.sqrtPriceX96 != sqrtPriceLimitX96) {
|
|
633
|
+
const step = {};
|
|
634
|
+
step.sqrtPriceStartX96 = state.sqrtPriceX96;
|
|
635
|
+
[step.tickNext, step.initialized] = await this.tickDataProvider.nextInitializedTickWithinOneWord(
|
|
636
|
+
state.tick,
|
|
637
|
+
zeroForOne,
|
|
638
|
+
this.tickSpacing
|
|
639
|
+
);
|
|
640
|
+
if (step.tickNext < TickMath.MIN_TICK) {
|
|
641
|
+
step.tickNext = TickMath.MIN_TICK;
|
|
642
|
+
} else if (step.tickNext > TickMath.MAX_TICK) {
|
|
643
|
+
step.tickNext = TickMath.MAX_TICK;
|
|
488
644
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
645
|
+
step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
|
|
646
|
+
[state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount] = SwapMath.computeSwapStep(
|
|
647
|
+
state.sqrtPriceX96,
|
|
648
|
+
(zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96) ? sqrtPriceLimitX96 : step.sqrtPriceNextX96,
|
|
649
|
+
state.liquidity,
|
|
650
|
+
state.amountSpecifiedRemaining,
|
|
651
|
+
this.fee
|
|
652
|
+
);
|
|
653
|
+
if (exactInput) {
|
|
654
|
+
state.amountSpecifiedRemaining = state.amountSpecifiedRemaining - (step.amountIn + step.feeAmount);
|
|
655
|
+
state.amountCalculated = state.amountCalculated - step.amountOut;
|
|
656
|
+
} else {
|
|
657
|
+
state.amountSpecifiedRemaining = state.amountSpecifiedRemaining + step.amountOut;
|
|
658
|
+
state.amountCalculated = state.amountCalculated + (step.amountIn + step.feeAmount);
|
|
659
|
+
}
|
|
660
|
+
if (state.sqrtPriceX96 === step.sqrtPriceNextX96) {
|
|
661
|
+
if (step.initialized) {
|
|
662
|
+
let liquidityNet = BigInt((await this.tickDataProvider.getTick(step.tickNext)).liquidityNet);
|
|
663
|
+
if (zeroForOne)
|
|
664
|
+
liquidityNet = liquidityNet * NEGATIVE_ONE;
|
|
665
|
+
state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet);
|
|
666
|
+
}
|
|
667
|
+
state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
|
|
668
|
+
} else if (state.sqrtPriceX96 !== step.sqrtPriceStartX96) {
|
|
669
|
+
state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return {
|
|
673
|
+
amountSpecifiedRemaining: state.amountSpecifiedRemaining,
|
|
674
|
+
amountCalculated: state.amountCalculated,
|
|
675
|
+
sqrtRatioX96: state.sqrtPriceX96,
|
|
676
|
+
liquidity: state.liquidity,
|
|
677
|
+
tickCurrent: state.tick
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
get tickSpacing() {
|
|
681
|
+
return TICK_SPACINGS[this.fee];
|
|
682
|
+
}
|
|
683
|
+
};
|
|
505
684
|
|
|
506
685
|
// src/utils/maxLiquidityForAmounts.ts
|
|
507
686
|
function maxLiquidityForAmount0Imprecise(sqrtRatioAX96, sqrtRatioBX96, amount0) {
|
|
@@ -544,36 +723,18 @@ function maxLiquidityForAmounts(sqrtRatioCurrentX96, sqrtRatioAX96, sqrtRatioBX9
|
|
|
544
723
|
}
|
|
545
724
|
return maxLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);
|
|
546
725
|
}
|
|
547
|
-
function
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
if (rounded < TickMath.MIN_TICK)
|
|
553
|
-
return rounded + tickSpacing;
|
|
554
|
-
if (rounded > TickMath.MAX_TICK)
|
|
555
|
-
return rounded - tickSpacing;
|
|
556
|
-
return rounded;
|
|
726
|
+
function encodeSqrtRatioX96(amount1, amount0) {
|
|
727
|
+
const numerator = BigInt(amount1) << 192n;
|
|
728
|
+
const denominator = BigInt(amount0);
|
|
729
|
+
const ratioX192 = numerator / denominator;
|
|
730
|
+
return sqrt(ratioX192);
|
|
557
731
|
}
|
|
558
732
|
|
|
559
|
-
// src/utils/
|
|
560
|
-
var PositionLibrary = class {
|
|
561
|
-
/**
|
|
562
|
-
* Cannot be constructed.
|
|
563
|
-
*/
|
|
564
|
-
constructor() {
|
|
565
|
-
}
|
|
566
|
-
// replicates the portions of Position#update required to compute unaccounted fees
|
|
567
|
-
static getTokensOwed(feeGrowthInside0LastX128, feeGrowthInside1LastX128, liquidity, feeGrowthInside0X128, feeGrowthInside1X128) {
|
|
568
|
-
const tokensOwed0 = subIn256(feeGrowthInside0X128, feeGrowthInside0LastX128) * liquidity / Q128;
|
|
569
|
-
const tokensOwed1 = subIn256(feeGrowthInside1X128, feeGrowthInside1LastX128) * liquidity / Q128;
|
|
570
|
-
return [tokensOwed0, tokensOwed1];
|
|
571
|
-
}
|
|
572
|
-
};
|
|
733
|
+
// src/utils/priceTickConversions.ts
|
|
573
734
|
function tickToPrice(baseToken, quoteToken, tick) {
|
|
574
735
|
const sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);
|
|
575
736
|
const ratioX192 = sqrtRatioX96 * sqrtRatioX96;
|
|
576
|
-
return baseToken.sortsBefore(quoteToken) ? new Price(baseToken, quoteToken, Q192, ratioX192) : new Price(baseToken, quoteToken, ratioX192, Q192);
|
|
737
|
+
return baseToken.sortsBefore(quoteToken) ? new Price$1(baseToken, quoteToken, Q192, ratioX192) : new Price$1(baseToken, quoteToken, ratioX192, Q192);
|
|
577
738
|
}
|
|
578
739
|
function priceToClosestTick(price) {
|
|
579
740
|
const sorted = price.baseCurrency.sortsBefore(price.quoteCurrency);
|
|
@@ -590,47 +751,6 @@ function priceToClosestTick(price) {
|
|
|
590
751
|
return tick;
|
|
591
752
|
}
|
|
592
753
|
|
|
593
|
-
// src/utils/tickLibrary.ts
|
|
594
|
-
var Q256 = 2n ** 256n;
|
|
595
|
-
function subIn256(x, y) {
|
|
596
|
-
const difference = x - y;
|
|
597
|
-
if (difference < ZERO) {
|
|
598
|
-
return Q256 + difference;
|
|
599
|
-
}
|
|
600
|
-
return difference;
|
|
601
|
-
}
|
|
602
|
-
var TickLibrary = class {
|
|
603
|
-
/**
|
|
604
|
-
* Cannot be constructed.
|
|
605
|
-
*/
|
|
606
|
-
constructor() {
|
|
607
|
-
}
|
|
608
|
-
static getFeeGrowthInside(feeGrowthOutsideLower, feeGrowthOutsideUpper, tickLower, tickUpper, tickCurrent, feeGrowthGlobal0X128, feeGrowthGlobal1X128) {
|
|
609
|
-
let feeGrowthBelow0X128;
|
|
610
|
-
let feeGrowthBelow1X128;
|
|
611
|
-
if (tickCurrent >= tickLower) {
|
|
612
|
-
feeGrowthBelow0X128 = feeGrowthOutsideLower.feeGrowthOutside0X128;
|
|
613
|
-
feeGrowthBelow1X128 = feeGrowthOutsideLower.feeGrowthOutside1X128;
|
|
614
|
-
} else {
|
|
615
|
-
feeGrowthBelow0X128 = subIn256(feeGrowthGlobal0X128, feeGrowthOutsideLower.feeGrowthOutside0X128);
|
|
616
|
-
feeGrowthBelow1X128 = subIn256(feeGrowthGlobal1X128, feeGrowthOutsideLower.feeGrowthOutside1X128);
|
|
617
|
-
}
|
|
618
|
-
let feeGrowthAbove0X128;
|
|
619
|
-
let feeGrowthAbove1X128;
|
|
620
|
-
if (tickCurrent < tickUpper) {
|
|
621
|
-
feeGrowthAbove0X128 = feeGrowthOutsideUpper.feeGrowthOutside0X128;
|
|
622
|
-
feeGrowthAbove1X128 = feeGrowthOutsideUpper.feeGrowthOutside1X128;
|
|
623
|
-
} else {
|
|
624
|
-
feeGrowthAbove0X128 = subIn256(feeGrowthGlobal0X128, feeGrowthOutsideUpper.feeGrowthOutside0X128);
|
|
625
|
-
feeGrowthAbove1X128 = subIn256(feeGrowthGlobal1X128, feeGrowthOutsideUpper.feeGrowthOutside1X128);
|
|
626
|
-
}
|
|
627
|
-
return [
|
|
628
|
-
subIn256(subIn256(feeGrowthGlobal0X128, feeGrowthBelow0X128), feeGrowthAbove0X128),
|
|
629
|
-
subIn256(subIn256(feeGrowthGlobal1X128, feeGrowthBelow1X128), feeGrowthAbove1X128)
|
|
630
|
-
];
|
|
631
|
-
}
|
|
632
|
-
};
|
|
633
|
-
|
|
634
754
|
// src/utils/positionMath.ts
|
|
635
755
|
function getToken0Amount(tickCurrent, tickLower, tickUpper, sqrtRatioX96, liquidity) {
|
|
636
756
|
if (tickCurrent < tickLower) {
|
|
@@ -664,914 +784,514 @@ var PositionMath = {
|
|
|
664
784
|
getToken0Amount,
|
|
665
785
|
getToken1Amount
|
|
666
786
|
};
|
|
667
|
-
function parseNumberToFraction(num, precision = 6) {
|
|
668
|
-
const scalar = 10 ** precision;
|
|
669
|
-
return new Fraction$1(BigInt(Math.floor(num * scalar)), BigInt(scalar));
|
|
670
|
-
}
|
|
671
787
|
|
|
672
|
-
// src/
|
|
673
|
-
var
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
return getEstimatedLPFeeByAmounts({
|
|
694
|
-
...rest,
|
|
695
|
-
amountA: amount,
|
|
696
|
-
amountB: CurrencyAmount.fromRawAmount(currency, MaxUint256)
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
function getEstimatedLPFeeByAmountsWithProtocolFee(options) {
|
|
700
|
-
try {
|
|
701
|
-
return tryGetEstimatedLPFeeByAmounts(options);
|
|
702
|
-
} catch (e) {
|
|
703
|
-
console.error(e);
|
|
704
|
-
return new Fraction(ZERO$1);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
function getEstimatedLPFeeByAmounts({ protocolFee = ZERO_PERCENT, ...rest }) {
|
|
708
|
-
try {
|
|
709
|
-
const fee = tryGetEstimatedLPFeeByAmounts(rest);
|
|
710
|
-
return ONE_HUNDRED_PERCENT.subtract(protocolFee).multiply(fee).asFraction;
|
|
711
|
-
} catch (e) {
|
|
712
|
-
console.error(e);
|
|
713
|
-
return new Fraction(ZERO$1);
|
|
788
|
+
// src/entities/position.ts
|
|
789
|
+
var Position = class {
|
|
790
|
+
/**
|
|
791
|
+
* Constructs a position for a given pool with the given liquidity
|
|
792
|
+
* @param pool For which pool the liquidity is assigned
|
|
793
|
+
* @param liquidity The amount of liquidity that is in the position
|
|
794
|
+
* @param tickLower The lower tick of the position
|
|
795
|
+
* @param tickUpper The upper tick of the position
|
|
796
|
+
*/
|
|
797
|
+
constructor({ pool, liquidity, tickLower, tickUpper }) {
|
|
798
|
+
// cached resuts for the getters
|
|
799
|
+
this._token0Amount = null;
|
|
800
|
+
this._token1Amount = null;
|
|
801
|
+
this._mintAmounts = null;
|
|
802
|
+
invariant9(tickLower < tickUpper, "TICK_ORDER");
|
|
803
|
+
invariant9(tickLower >= TickMath.MIN_TICK && tickLower % pool.tickSpacing === 0, "TICK_LOWER");
|
|
804
|
+
invariant9(tickUpper <= TickMath.MAX_TICK && tickUpper % pool.tickSpacing === 0, "TICK_UPPER");
|
|
805
|
+
this.pool = pool;
|
|
806
|
+
this.tickLower = tickLower;
|
|
807
|
+
this.tickUpper = tickUpper;
|
|
808
|
+
this.liquidity = BigInt(liquidity);
|
|
714
809
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
sqrtRatioX96,
|
|
721
|
-
tickLower,
|
|
722
|
-
tickUpper,
|
|
723
|
-
mostActiveLiquidity,
|
|
724
|
-
fee,
|
|
725
|
-
insidePercentage = ONE_HUNDRED_PERCENT
|
|
726
|
-
}) {
|
|
727
|
-
invariant11(!Number.isNaN(fee) && fee >= 0, "INVALID_FEE");
|
|
728
|
-
const tickCurrent = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
729
|
-
if (tickCurrent < tickLower || tickCurrent > tickUpper) {
|
|
730
|
-
return new Fraction(ZERO$1);
|
|
810
|
+
/**
|
|
811
|
+
* Returns the price of token0 at the lower tick
|
|
812
|
+
*/
|
|
813
|
+
get token0PriceLower() {
|
|
814
|
+
return tickToPrice(this.pool.token0, this.pool.token1, this.tickLower);
|
|
731
815
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
sqrtRatioX96
|
|
738
|
-
});
|
|
739
|
-
return insidePercentage.multiply(parseNumberToFraction(volume24H).multiply(BigInt(fee)).multiply(liquidity)).divide(MAX_FEE * (liquidity + mostActiveLiquidity)).asFraction;
|
|
740
|
-
}
|
|
741
|
-
function getDependentAmount(options) {
|
|
742
|
-
const { currency, amount, sqrtRatioX96, tickLower, tickUpper } = options;
|
|
743
|
-
const currentTick = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
744
|
-
const liquidity = FeeCalculator.getLiquidityBySingleAmount(options);
|
|
745
|
-
const isToken0 = currency.wrapped.sortsBefore(amount.currency.wrapped);
|
|
746
|
-
const getTokenAmount = isToken0 ? PositionMath.getToken0Amount : PositionMath.getToken1Amount;
|
|
747
|
-
return CurrencyAmount.fromRawAmount(
|
|
748
|
-
currency,
|
|
749
|
-
getTokenAmount(currentTick, tickLower, tickUpper, sqrtRatioX96, liquidity)
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
function getLiquidityBySingleAmount({ amount, currency, ...rest }) {
|
|
753
|
-
return getLiquidityByAmountsAndPrice({
|
|
754
|
-
amountA: amount,
|
|
755
|
-
amountB: CurrencyAmount.fromRawAmount(currency, MaxUint256),
|
|
756
|
-
...rest
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
|
-
function getLiquidityByAmountsAndPrice({
|
|
760
|
-
amountA,
|
|
761
|
-
amountB,
|
|
762
|
-
tickUpper,
|
|
763
|
-
tickLower,
|
|
764
|
-
sqrtRatioX96
|
|
765
|
-
}) {
|
|
766
|
-
const isToken0 = amountA.currency.wrapped.sortsBefore(amountB.currency.wrapped);
|
|
767
|
-
const [inputAmount0, inputAmount1] = isToken0 ? [amountA.quotient, amountB.quotient] : [amountB.quotient, amountA.quotient];
|
|
768
|
-
const sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
|
769
|
-
const sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
|
770
|
-
return maxLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, inputAmount0, inputAmount1, true);
|
|
771
|
-
}
|
|
772
|
-
function getAmountsByLiquidityAndPrice(options) {
|
|
773
|
-
const { currencyA, currencyB, liquidity, sqrtRatioX96, tickLower, tickUpper } = options;
|
|
774
|
-
const currentTick = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
775
|
-
const isToken0 = currencyA.wrapped.sortsBefore(currencyB.wrapped);
|
|
776
|
-
const adjustedAmount0 = PositionMath.getToken0Amount(currentTick, tickLower, tickUpper, sqrtRatioX96, liquidity);
|
|
777
|
-
const adjustedAmount1 = PositionMath.getToken1Amount(currentTick, tickLower, tickUpper, sqrtRatioX96, liquidity);
|
|
778
|
-
return [
|
|
779
|
-
CurrencyAmount.fromRawAmount(currencyA, isToken0 ? adjustedAmount0 : adjustedAmount1),
|
|
780
|
-
CurrencyAmount.fromRawAmount(currencyB, isToken0 ? adjustedAmount1 : adjustedAmount0)
|
|
781
|
-
];
|
|
782
|
-
}
|
|
783
|
-
function getAmountsAtNewPrice({ newSqrtRatioX96, ...rest }) {
|
|
784
|
-
const { tickLower, tickUpper, amountA, amountB } = rest;
|
|
785
|
-
const liquidity = FeeCalculator.getLiquidityByAmountsAndPrice(rest);
|
|
786
|
-
return FeeCalculator.getAmountsByLiquidityAndPrice({
|
|
787
|
-
liquidity,
|
|
788
|
-
currencyA: amountA.currency,
|
|
789
|
-
currencyB: amountB.currency,
|
|
790
|
-
tickLower,
|
|
791
|
-
tickUpper,
|
|
792
|
-
sqrtRatioX96: newSqrtRatioX96
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
function getAverageLiquidity(ticks, tickSpacing, tickLower, tickUpper) {
|
|
796
|
-
invariant11(tickLower <= tickUpper, "INVALID_TICK_RANGE");
|
|
797
|
-
TickList.validateList(ticks, tickSpacing);
|
|
798
|
-
if (tickLower === tickUpper) {
|
|
799
|
-
return FeeCalculator.getLiquidityFromTick(ticks, tickLower);
|
|
816
|
+
/**
|
|
817
|
+
* Returns the price of token0 at the upper tick
|
|
818
|
+
*/
|
|
819
|
+
get token0PriceUpper() {
|
|
820
|
+
return tickToPrice(this.pool.token0, this.pool.token1, this.tickUpper);
|
|
800
821
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
822
|
+
/**
|
|
823
|
+
* Returns the amount of token0 that this position's liquidity could be burned for at the current pool price
|
|
824
|
+
*/
|
|
825
|
+
get amount0() {
|
|
826
|
+
if (this._token0Amount === null) {
|
|
827
|
+
this._token0Amount = CurrencyAmount.fromRawAmount(
|
|
828
|
+
this.pool.token0,
|
|
829
|
+
PositionMath.getToken0Amount(
|
|
830
|
+
this.pool.tickCurrent,
|
|
831
|
+
this.tickLower,
|
|
832
|
+
this.tickUpper,
|
|
833
|
+
this.pool.sqrtRatioX96,
|
|
834
|
+
this.liquidity
|
|
835
|
+
)
|
|
836
|
+
);
|
|
813
837
|
}
|
|
814
|
-
|
|
815
|
-
}
|
|
816
|
-
weightedL += getWeightedLFromLastTickTo(tickUpper);
|
|
817
|
-
return weightedL / BigInt(tickUpper - tickLower);
|
|
818
|
-
}
|
|
819
|
-
function getLiquidityFromSqrtRatioX96(ticks, sqrtRatioX96) {
|
|
820
|
-
const tick = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
821
|
-
return FeeCalculator.getLiquidityFromTick(ticks, tick);
|
|
822
|
-
}
|
|
823
|
-
function getLiquidityFromTick(ticks, tick) {
|
|
824
|
-
let liquidity = ZERO$1;
|
|
825
|
-
if (!ticks?.length)
|
|
826
|
-
return liquidity;
|
|
827
|
-
if (tick < ticks[0].index || tick > ticks[ticks.length - 1].index) {
|
|
828
|
-
return liquidity;
|
|
838
|
+
return this._token0Amount;
|
|
829
839
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
if (
|
|
835
|
-
|
|
840
|
+
/**
|
|
841
|
+
* Returns the amount of token1 that this position's liquidity could be burned for at the current pool price
|
|
842
|
+
*/
|
|
843
|
+
get amount1() {
|
|
844
|
+
if (this._token1Amount === null) {
|
|
845
|
+
this._token1Amount = CurrencyAmount.fromRawAmount(
|
|
846
|
+
this.pool.token1,
|
|
847
|
+
PositionMath.getToken1Amount(
|
|
848
|
+
this.pool.tickCurrent,
|
|
849
|
+
this.tickLower,
|
|
850
|
+
this.tickUpper,
|
|
851
|
+
this.pool.sqrtRatioX96,
|
|
852
|
+
this.liquidity
|
|
853
|
+
)
|
|
854
|
+
);
|
|
836
855
|
}
|
|
837
|
-
|
|
838
|
-
return liquidity;
|
|
839
|
-
}
|
|
840
|
-
var FEE_BASE = 10n ** 4n;
|
|
841
|
-
function parseProtocolFees(feeProtocol) {
|
|
842
|
-
const packed = Number(feeProtocol);
|
|
843
|
-
if (Number.isNaN(packed)) {
|
|
844
|
-
throw new Error(`Invalid fee protocol ${feeProtocol}`);
|
|
845
|
-
}
|
|
846
|
-
const token0ProtocolFee = packed % 2 ** 16;
|
|
847
|
-
const token1ProtocolFee = packed >> 16;
|
|
848
|
-
return [new Percent$1(token0ProtocolFee, FEE_BASE), new Percent$1(token1ProtocolFee, FEE_BASE)];
|
|
849
|
-
}
|
|
850
|
-
function sqrtRatioX96ToPrice(sqrtRatioX96, currencyA, currencyB) {
|
|
851
|
-
const ratioX192 = sqrtRatioX96 * sqrtRatioX96;
|
|
852
|
-
return currencyA.wrapped.sortsBefore(currencyB.wrapped) ? new Price$1(currencyA.wrapped, currencyB.wrapped, Q192, ratioX192) : new Price$1(currencyA.wrapped, currencyB.wrapped, ratioX192, Q192);
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
// src/entities/tick.ts
|
|
856
|
-
var Tick = class {
|
|
857
|
-
constructor({ index, liquidityGross, liquidityNet }) {
|
|
858
|
-
invariant11(index >= TickMath.MIN_TICK && index <= TickMath.MAX_TICK, "TICK");
|
|
859
|
-
this.index = index;
|
|
860
|
-
this.liquidityGross = BigInt(liquidityGross);
|
|
861
|
-
this.liquidityNet = BigInt(liquidityNet);
|
|
862
|
-
}
|
|
863
|
-
};
|
|
864
|
-
|
|
865
|
-
// src/entities/tickListDataProvider.ts
|
|
866
|
-
var TickListDataProvider = class {
|
|
867
|
-
constructor(ticks) {
|
|
868
|
-
const ticksMapped = ticks.map((t) => t instanceof Tick ? t : new Tick(t));
|
|
869
|
-
this.ticks = ticksMapped;
|
|
870
|
-
}
|
|
871
|
-
async getTick(tick) {
|
|
872
|
-
return TickList.getTick(this.ticks, tick);
|
|
873
|
-
}
|
|
874
|
-
async nextInitializedTickWithinOneWord(tick, lte, tickSpacing) {
|
|
875
|
-
return TickList.nextInitializedTickWithinOneWord(this.ticks, tick, lte, tickSpacing);
|
|
876
|
-
}
|
|
877
|
-
};
|
|
878
|
-
|
|
879
|
-
// src/entities/pool.ts
|
|
880
|
-
var NO_TICK_DATA_PROVIDER_DEFAULT = new NoTickDataProvider();
|
|
881
|
-
var Pool = class {
|
|
882
|
-
static getAddress(tokenA, tokenB, fee, initCodeHashManualOverride, deployerAddressOverride) {
|
|
883
|
-
return computePoolAddress({
|
|
884
|
-
deployerAddress: deployerAddressOverride ?? DEPLOYER_ADDRESSES[tokenA.chainId],
|
|
885
|
-
fee,
|
|
886
|
-
tokenA,
|
|
887
|
-
tokenB,
|
|
888
|
-
initCodeHashManualOverride
|
|
889
|
-
});
|
|
856
|
+
return this._token1Amount;
|
|
890
857
|
}
|
|
891
858
|
/**
|
|
892
|
-
*
|
|
893
|
-
* @param
|
|
894
|
-
* @
|
|
895
|
-
* @param fee The fee in hundredths of a bips of the input amount of every swap that is collected by the pool
|
|
896
|
-
* @param sqrtRatioX96 The sqrt of the current ratio of amounts of token1 to token0
|
|
897
|
-
* @param liquidity The current value of in range liquidity
|
|
898
|
-
* @param tickCurrent The current tick of the pool
|
|
899
|
-
* @param ticks The current state of the pool ticks or a data provider that can return tick data
|
|
859
|
+
* Returns the lower and upper sqrt ratios if the price 'slips' up to slippage tolerance percentage
|
|
860
|
+
* @param slippageTolerance The amount by which the price can 'slip' before the transaction will revert
|
|
861
|
+
* @returns The sqrt ratios after slippage
|
|
900
862
|
*/
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
863
|
+
ratiosAfterSlippage(slippageTolerance) {
|
|
864
|
+
const priceLower = this.pool.token0Price.asFraction.multiply(new Percent$1(1).subtract(slippageTolerance));
|
|
865
|
+
const priceUpper = this.pool.token0Price.asFraction.multiply(slippageTolerance.add(1));
|
|
866
|
+
let sqrtRatioX96Lower = encodeSqrtRatioX96(priceLower.numerator, priceLower.denominator);
|
|
867
|
+
if (sqrtRatioX96Lower <= TickMath.MIN_SQRT_RATIO) {
|
|
868
|
+
sqrtRatioX96Lower = TickMath.MIN_SQRT_RATIO + 1n;
|
|
869
|
+
}
|
|
870
|
+
let sqrtRatioX96Upper = encodeSqrtRatioX96(priceUpper.numerator, priceUpper.denominator);
|
|
871
|
+
if (sqrtRatioX96Upper >= TickMath.MAX_SQRT_RATIO) {
|
|
872
|
+
sqrtRatioX96Upper = TickMath.MAX_SQRT_RATIO - 1n;
|
|
873
|
+
}
|
|
874
|
+
return {
|
|
875
|
+
sqrtRatioX96Lower,
|
|
876
|
+
sqrtRatioX96Upper
|
|
877
|
+
};
|
|
909
878
|
}
|
|
910
879
|
/**
|
|
911
|
-
* Returns
|
|
912
|
-
*
|
|
913
|
-
* @
|
|
880
|
+
* Returns the minimum amounts that must be sent in order to safely mint the amount of liquidity held by the position
|
|
881
|
+
* with the given slippage tolerance
|
|
882
|
+
* @param slippageTolerance Tolerance of unfavorable slippage from the current price
|
|
883
|
+
* @returns The amounts, with slippage
|
|
914
884
|
*/
|
|
915
|
-
|
|
916
|
-
|
|
885
|
+
mintAmountsWithSlippage(slippageTolerance) {
|
|
886
|
+
const { sqrtRatioX96Upper, sqrtRatioX96Lower } = this.ratiosAfterSlippage(slippageTolerance);
|
|
887
|
+
const poolLower = new Pool(
|
|
888
|
+
this.pool.token0,
|
|
889
|
+
this.pool.token1,
|
|
890
|
+
this.pool.fee,
|
|
891
|
+
sqrtRatioX96Lower,
|
|
892
|
+
0,
|
|
893
|
+
TickMath.getTickAtSqrtRatio(sqrtRatioX96Lower)
|
|
894
|
+
);
|
|
895
|
+
const poolUpper = new Pool(
|
|
896
|
+
this.pool.token0,
|
|
897
|
+
this.pool.token1,
|
|
898
|
+
this.pool.fee,
|
|
899
|
+
sqrtRatioX96Upper,
|
|
900
|
+
0,
|
|
901
|
+
TickMath.getTickAtSqrtRatio(sqrtRatioX96Upper)
|
|
902
|
+
);
|
|
903
|
+
const positionThatWillBeCreated = Position.fromAmounts({
|
|
904
|
+
pool: this.pool,
|
|
905
|
+
tickLower: this.tickLower,
|
|
906
|
+
tickUpper: this.tickUpper,
|
|
907
|
+
...this.mintAmounts,
|
|
908
|
+
// the mint amounts are what will be passed as calldata
|
|
909
|
+
useFullPrecision: false
|
|
910
|
+
});
|
|
911
|
+
const { amount0 } = new Position({
|
|
912
|
+
pool: poolUpper,
|
|
913
|
+
liquidity: positionThatWillBeCreated.liquidity,
|
|
914
|
+
tickLower: this.tickLower,
|
|
915
|
+
tickUpper: this.tickUpper
|
|
916
|
+
}).mintAmounts;
|
|
917
|
+
const { amount1 } = new Position({
|
|
918
|
+
pool: poolLower,
|
|
919
|
+
liquidity: positionThatWillBeCreated.liquidity,
|
|
920
|
+
tickLower: this.tickLower,
|
|
921
|
+
tickUpper: this.tickUpper
|
|
922
|
+
}).mintAmounts;
|
|
923
|
+
return { amount0, amount1 };
|
|
917
924
|
}
|
|
918
925
|
/**
|
|
919
|
-
* Returns the
|
|
926
|
+
* Returns the minimum amounts that should be requested in order to safely burn the amount of liquidity held by the
|
|
927
|
+
* position with the given slippage tolerance
|
|
928
|
+
* @param slippageTolerance tolerance of unfavorable slippage from the current price
|
|
929
|
+
* @returns The amounts, with slippage
|
|
920
930
|
*/
|
|
921
|
-
|
|
922
|
-
|
|
931
|
+
burnAmountsWithSlippage(slippageTolerance) {
|
|
932
|
+
const { sqrtRatioX96Upper, sqrtRatioX96Lower } = this.ratiosAfterSlippage(slippageTolerance);
|
|
933
|
+
const poolLower = new Pool(
|
|
934
|
+
this.pool.token0,
|
|
935
|
+
this.pool.token1,
|
|
936
|
+
this.pool.fee,
|
|
937
|
+
sqrtRatioX96Lower,
|
|
938
|
+
0,
|
|
939
|
+
TickMath.getTickAtSqrtRatio(sqrtRatioX96Lower)
|
|
940
|
+
);
|
|
941
|
+
const poolUpper = new Pool(
|
|
942
|
+
this.pool.token0,
|
|
943
|
+
this.pool.token1,
|
|
944
|
+
this.pool.fee,
|
|
945
|
+
sqrtRatioX96Upper,
|
|
946
|
+
0,
|
|
947
|
+
TickMath.getTickAtSqrtRatio(sqrtRatioX96Upper)
|
|
948
|
+
);
|
|
949
|
+
const { amount0 } = new Position({
|
|
950
|
+
pool: poolUpper,
|
|
951
|
+
liquidity: this.liquidity,
|
|
952
|
+
tickLower: this.tickLower,
|
|
953
|
+
tickUpper: this.tickUpper
|
|
954
|
+
});
|
|
955
|
+
const { amount1 } = new Position({
|
|
956
|
+
pool: poolLower,
|
|
957
|
+
liquidity: this.liquidity,
|
|
958
|
+
tickLower: this.tickLower,
|
|
959
|
+
tickUpper: this.tickUpper
|
|
960
|
+
});
|
|
961
|
+
return { amount0: amount0.quotient, amount1: amount1.quotient };
|
|
923
962
|
}
|
|
924
963
|
/**
|
|
925
|
-
* Returns the
|
|
964
|
+
* Returns the minimum amounts that must be sent in order to mint the amount of liquidity held by the position at
|
|
965
|
+
* the current price for the pool
|
|
926
966
|
*/
|
|
927
|
-
get
|
|
928
|
-
|
|
967
|
+
get mintAmounts() {
|
|
968
|
+
if (this._mintAmounts === null) {
|
|
969
|
+
if (this.pool.tickCurrent < this.tickLower) {
|
|
970
|
+
return {
|
|
971
|
+
amount0: SqrtPriceMath.getAmount0Delta(
|
|
972
|
+
TickMath.getSqrtRatioAtTick(this.tickLower),
|
|
973
|
+
TickMath.getSqrtRatioAtTick(this.tickUpper),
|
|
974
|
+
this.liquidity,
|
|
975
|
+
true
|
|
976
|
+
),
|
|
977
|
+
amount1: ZERO
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
if (this.pool.tickCurrent < this.tickUpper) {
|
|
981
|
+
return {
|
|
982
|
+
amount0: SqrtPriceMath.getAmount0Delta(
|
|
983
|
+
this.pool.sqrtRatioX96,
|
|
984
|
+
TickMath.getSqrtRatioAtTick(this.tickUpper),
|
|
985
|
+
this.liquidity,
|
|
986
|
+
true
|
|
987
|
+
),
|
|
988
|
+
amount1: SqrtPriceMath.getAmount1Delta(
|
|
989
|
+
TickMath.getSqrtRatioAtTick(this.tickLower),
|
|
990
|
+
this.pool.sqrtRatioX96,
|
|
991
|
+
this.liquidity,
|
|
992
|
+
true
|
|
993
|
+
)
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
return {
|
|
997
|
+
amount0: ZERO,
|
|
998
|
+
amount1: SqrtPriceMath.getAmount1Delta(
|
|
999
|
+
TickMath.getSqrtRatioAtTick(this.tickLower),
|
|
1000
|
+
TickMath.getSqrtRatioAtTick(this.tickUpper),
|
|
1001
|
+
this.liquidity,
|
|
1002
|
+
true
|
|
1003
|
+
)
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
return this._mintAmounts;
|
|
929
1007
|
}
|
|
930
1008
|
/**
|
|
931
|
-
*
|
|
932
|
-
*
|
|
933
|
-
* @
|
|
1009
|
+
* Computes the maximum amount of liquidity received for a given amount of token0, token1,
|
|
1010
|
+
* and the prices at the tick boundaries.
|
|
1011
|
+
* @param pool The pool for which the position should be created
|
|
1012
|
+
* @param tickLower The lower tick of the position
|
|
1013
|
+
* @param tickUpper The upper tick of the position
|
|
1014
|
+
* @param amount0 token0 amount
|
|
1015
|
+
* @param amount1 token1 amount
|
|
1016
|
+
* @param useFullPrecision If false, liquidity will be maximized according to what the router can calculate,
|
|
1017
|
+
* not what core can theoretically support
|
|
1018
|
+
* @returns The amount of liquidity for the position
|
|
934
1019
|
*/
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1020
|
+
static fromAmounts({
|
|
1021
|
+
pool,
|
|
1022
|
+
tickLower,
|
|
1023
|
+
tickUpper,
|
|
1024
|
+
amount0,
|
|
1025
|
+
amount1,
|
|
1026
|
+
useFullPrecision
|
|
1027
|
+
}) {
|
|
1028
|
+
const sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
|
1029
|
+
const sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
|
1030
|
+
return new Position({
|
|
1031
|
+
pool,
|
|
1032
|
+
tickLower,
|
|
1033
|
+
tickUpper,
|
|
1034
|
+
liquidity: maxLiquidityForAmounts(
|
|
1035
|
+
pool.sqrtRatioX96,
|
|
1036
|
+
sqrtRatioAX96,
|
|
1037
|
+
sqrtRatioBX96,
|
|
1038
|
+
amount0,
|
|
1039
|
+
amount1,
|
|
1040
|
+
useFullPrecision
|
|
1041
|
+
)
|
|
1042
|
+
});
|
|
938
1043
|
}
|
|
939
1044
|
/**
|
|
940
|
-
*
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1045
|
+
* Computes a position with the maximum amount of liquidity received for a given amount of token0, assuming an unlimited amount of token1
|
|
1046
|
+
* @param pool The pool for which the position is created
|
|
1047
|
+
* @param tickLower The lower tick
|
|
1048
|
+
* @param tickUpper The upper tick
|
|
1049
|
+
* @param amount0 The desired amount of token0
|
|
1050
|
+
* @param useFullPrecision If true, liquidity will be maximized according to what the router can calculate,
|
|
1051
|
+
* not what core can theoretically support
|
|
1052
|
+
* @returns The position
|
|
1053
|
+
*/
|
|
1054
|
+
static fromAmount0({
|
|
1055
|
+
pool,
|
|
1056
|
+
tickLower,
|
|
1057
|
+
tickUpper,
|
|
1058
|
+
amount0,
|
|
1059
|
+
useFullPrecision
|
|
1060
|
+
}) {
|
|
1061
|
+
return Position.fromAmounts({ pool, tickLower, tickUpper, amount0, amount1: MaxUint256$1, useFullPrecision });
|
|
944
1062
|
}
|
|
945
1063
|
/**
|
|
946
|
-
*
|
|
947
|
-
* @param
|
|
948
|
-
* @param
|
|
949
|
-
* @
|
|
1064
|
+
* Computes a position with the maximum amount of liquidity received for a given amount of token1, assuming an unlimited amount of token0
|
|
1065
|
+
* @param pool The pool for which the position is created
|
|
1066
|
+
* @param tickLower The lower tick
|
|
1067
|
+
* @param tickUpper The upper tick
|
|
1068
|
+
* @param amount1 The desired amount of token1
|
|
1069
|
+
* @returns The position
|
|
950
1070
|
*/
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
tickCurrent
|
|
959
|
-
} = await this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX96);
|
|
960
|
-
const outputToken = zeroForOne ? this.token1 : this.token0;
|
|
961
|
-
return [
|
|
962
|
-
CurrencyAmount.fromRawAmount(outputToken, outputAmount * NEGATIVE_ONE),
|
|
963
|
-
new Pool(this.token0, this.token1, this.fee, sqrtRatioX96, liquidity, tickCurrent, this.tickDataProvider)
|
|
964
|
-
];
|
|
1071
|
+
static fromAmount1({
|
|
1072
|
+
pool,
|
|
1073
|
+
tickLower,
|
|
1074
|
+
tickUpper,
|
|
1075
|
+
amount1
|
|
1076
|
+
}) {
|
|
1077
|
+
return Position.fromAmounts({ pool, tickLower, tickUpper, amount0: MaxUint256$1, amount1, useFullPrecision: true });
|
|
965
1078
|
}
|
|
1079
|
+
};
|
|
1080
|
+
var Route = class {
|
|
966
1081
|
/**
|
|
967
|
-
*
|
|
968
|
-
* @param
|
|
969
|
-
* @param
|
|
970
|
-
* @
|
|
1082
|
+
* Creates an instance of route.
|
|
1083
|
+
* @param pools An array of `Pool` objects, ordered by the route the swap will take
|
|
1084
|
+
* @param input The input token
|
|
1085
|
+
* @param output The output token
|
|
971
1086
|
*/
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
const {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1087
|
+
constructor(pools, input, output) {
|
|
1088
|
+
this._midPrice = null;
|
|
1089
|
+
invariant9(pools.length > 0, "POOLS");
|
|
1090
|
+
const { chainId } = pools[0];
|
|
1091
|
+
const allOnSameChain = pools.every((pool) => pool.chainId === chainId);
|
|
1092
|
+
invariant9(allOnSameChain, "CHAIN_IDS");
|
|
1093
|
+
const wrappedInput = input.wrapped;
|
|
1094
|
+
invariant9(pools[0].involvesToken(wrappedInput), "INPUT");
|
|
1095
|
+
invariant9(pools[pools.length - 1].involvesToken(output.wrapped), "OUTPUT");
|
|
1096
|
+
const tokenPath = [wrappedInput];
|
|
1097
|
+
for (const [i, pool] of pools.entries()) {
|
|
1098
|
+
const currentInputToken = tokenPath[i];
|
|
1099
|
+
invariant9(currentInputToken.equals(pool.token0) || currentInputToken.equals(pool.token1), "PATH");
|
|
1100
|
+
const nextToken = currentInputToken.equals(pool.token0) ? pool.token1 : pool.token0;
|
|
1101
|
+
tokenPath.push(nextToken);
|
|
1102
|
+
}
|
|
1103
|
+
this.pools = pools;
|
|
1104
|
+
this.tokenPath = tokenPath;
|
|
1105
|
+
this.input = input;
|
|
1106
|
+
this.output = output ?? tokenPath[tokenPath.length - 1];
|
|
1107
|
+
}
|
|
1108
|
+
get chainId() {
|
|
1109
|
+
return this.pools[0].chainId;
|
|
988
1110
|
}
|
|
989
1111
|
/**
|
|
990
|
-
*
|
|
991
|
-
* @param zeroForOne Whether the amount in is token0 or token1
|
|
992
|
-
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
|
|
993
|
-
* @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this value after the swap. If one for zero, the price cannot be greater than this value after the swap
|
|
994
|
-
* @returns amountCalculated
|
|
995
|
-
* @returns sqrtRatioX96
|
|
996
|
-
* @returns liquidity
|
|
997
|
-
* @returns tickCurrent
|
|
1112
|
+
* Returns the mid price of the route
|
|
998
1113
|
*/
|
|
999
|
-
|
|
1000
|
-
if (
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
const step = {};
|
|
1019
|
-
step.sqrtPriceStartX96 = state.sqrtPriceX96;
|
|
1020
|
-
[step.tickNext, step.initialized] = await this.tickDataProvider.nextInitializedTickWithinOneWord(
|
|
1021
|
-
state.tick,
|
|
1022
|
-
zeroForOne,
|
|
1023
|
-
this.tickSpacing
|
|
1024
|
-
);
|
|
1025
|
-
if (step.tickNext < TickMath.MIN_TICK) {
|
|
1026
|
-
step.tickNext = TickMath.MIN_TICK;
|
|
1027
|
-
} else if (step.tickNext > TickMath.MAX_TICK) {
|
|
1028
|
-
step.tickNext = TickMath.MAX_TICK;
|
|
1029
|
-
}
|
|
1030
|
-
step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
|
|
1031
|
-
[state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount] = SwapMath.computeSwapStep(
|
|
1032
|
-
state.sqrtPriceX96,
|
|
1033
|
-
(zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96) ? sqrtPriceLimitX96 : step.sqrtPriceNextX96,
|
|
1034
|
-
state.liquidity,
|
|
1035
|
-
state.amountSpecifiedRemaining,
|
|
1036
|
-
this.fee
|
|
1037
|
-
);
|
|
1038
|
-
if (exactInput) {
|
|
1039
|
-
state.amountSpecifiedRemaining = state.amountSpecifiedRemaining - (step.amountIn + step.feeAmount);
|
|
1040
|
-
state.amountCalculated = state.amountCalculated - step.amountOut;
|
|
1041
|
-
} else {
|
|
1042
|
-
state.amountSpecifiedRemaining = state.amountSpecifiedRemaining + step.amountOut;
|
|
1043
|
-
state.amountCalculated = state.amountCalculated + (step.amountIn + step.feeAmount);
|
|
1044
|
-
}
|
|
1045
|
-
if (state.sqrtPriceX96 === step.sqrtPriceNextX96) {
|
|
1046
|
-
if (step.initialized) {
|
|
1047
|
-
let liquidityNet = BigInt((await this.tickDataProvider.getTick(step.tickNext)).liquidityNet);
|
|
1048
|
-
if (zeroForOne)
|
|
1049
|
-
liquidityNet = liquidityNet * NEGATIVE_ONE;
|
|
1050
|
-
state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet);
|
|
1051
|
-
}
|
|
1052
|
-
state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
|
|
1053
|
-
} else if (state.sqrtPriceX96 !== step.sqrtPriceStartX96) {
|
|
1054
|
-
state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
|
|
1114
|
+
get midPrice() {
|
|
1115
|
+
if (this._midPrice !== null)
|
|
1116
|
+
return this._midPrice;
|
|
1117
|
+
const { price } = this.pools.slice(1).reduce(
|
|
1118
|
+
({ nextInput, price: price2 }, pool) => {
|
|
1119
|
+
return nextInput.equals(pool.token0) ? {
|
|
1120
|
+
nextInput: pool.token1,
|
|
1121
|
+
price: price2.multiply(pool.token0Price)
|
|
1122
|
+
} : {
|
|
1123
|
+
nextInput: pool.token0,
|
|
1124
|
+
price: price2.multiply(pool.token1Price)
|
|
1125
|
+
};
|
|
1126
|
+
},
|
|
1127
|
+
this.pools[0].token0.equals(this.input.wrapped) ? {
|
|
1128
|
+
nextInput: this.pools[0].token1,
|
|
1129
|
+
price: this.pools[0].token0Price
|
|
1130
|
+
} : {
|
|
1131
|
+
nextInput: this.pools[0].token0,
|
|
1132
|
+
price: this.pools[0].token1Price
|
|
1055
1133
|
}
|
|
1134
|
+
);
|
|
1135
|
+
return this._midPrice = new Price$1(this.input, this.output, price.denominator, price.numerator);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
function tradeComparator(a, b) {
|
|
1139
|
+
invariant9(a.inputAmount.currency.equals(b.inputAmount.currency), "INPUT_CURRENCY");
|
|
1140
|
+
invariant9(a.outputAmount.currency.equals(b.outputAmount.currency), "OUTPUT_CURRENCY");
|
|
1141
|
+
if (a.outputAmount.equalTo(b.outputAmount)) {
|
|
1142
|
+
if (a.inputAmount.equalTo(b.inputAmount)) {
|
|
1143
|
+
const aHops = a.swaps.reduce((total, cur) => total + cur.route.tokenPath.length, 0);
|
|
1144
|
+
const bHops = b.swaps.reduce((total, cur) => total + cur.route.tokenPath.length, 0);
|
|
1145
|
+
return aHops - bHops;
|
|
1056
1146
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
liquidity: state.liquidity,
|
|
1062
|
-
tickCurrent: state.tick
|
|
1063
|
-
};
|
|
1147
|
+
if (a.inputAmount.lessThan(b.inputAmount)) {
|
|
1148
|
+
return -1;
|
|
1149
|
+
}
|
|
1150
|
+
return 1;
|
|
1064
1151
|
}
|
|
1065
|
-
|
|
1066
|
-
return
|
|
1152
|
+
if (a.outputAmount.lessThan(b.outputAmount)) {
|
|
1153
|
+
return 1;
|
|
1067
1154
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1155
|
+
return -1;
|
|
1156
|
+
}
|
|
1157
|
+
var Trade = class {
|
|
1070
1158
|
/**
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1159
|
+
* @deprecated Deprecated in favor of 'swaps' property. If the trade consists of multiple routes
|
|
1160
|
+
* this will return an error.
|
|
1161
|
+
*
|
|
1162
|
+
* When the trade consists of just a single route, this returns the route of the trade,
|
|
1163
|
+
* i.e. which pools the trade goes through.
|
|
1076
1164
|
*/
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
this.
|
|
1080
|
-
this._token1Amount = null;
|
|
1081
|
-
this._mintAmounts = null;
|
|
1082
|
-
invariant11(tickLower < tickUpper, "TICK_ORDER");
|
|
1083
|
-
invariant11(tickLower >= TickMath.MIN_TICK && tickLower % pool.tickSpacing === 0, "TICK_LOWER");
|
|
1084
|
-
invariant11(tickUpper <= TickMath.MAX_TICK && tickUpper % pool.tickSpacing === 0, "TICK_UPPER");
|
|
1085
|
-
this.pool = pool;
|
|
1086
|
-
this.tickLower = tickLower;
|
|
1087
|
-
this.tickUpper = tickUpper;
|
|
1088
|
-
this.liquidity = BigInt(liquidity);
|
|
1165
|
+
get route() {
|
|
1166
|
+
invariant9(this.swaps.length == 1, "MULTIPLE_ROUTES");
|
|
1167
|
+
return this.swaps[0].route;
|
|
1089
1168
|
}
|
|
1090
1169
|
/**
|
|
1091
|
-
*
|
|
1170
|
+
* The input amount for the trade assuming no slippage.
|
|
1092
1171
|
*/
|
|
1093
|
-
get
|
|
1094
|
-
|
|
1172
|
+
get inputAmount() {
|
|
1173
|
+
if (this._inputAmount) {
|
|
1174
|
+
return this._inputAmount;
|
|
1175
|
+
}
|
|
1176
|
+
const inputCurrency = this.swaps[0].inputAmount.currency;
|
|
1177
|
+
const totalInputFromRoutes = this.swaps.map(({ inputAmount }) => inputAmount).reduce((total, cur) => total.add(cur), CurrencyAmount.fromRawAmount(inputCurrency, 0));
|
|
1178
|
+
this._inputAmount = totalInputFromRoutes;
|
|
1179
|
+
return this._inputAmount;
|
|
1095
1180
|
}
|
|
1096
1181
|
/**
|
|
1097
|
-
*
|
|
1182
|
+
* The output amount for the trade assuming no slippage.
|
|
1098
1183
|
*/
|
|
1099
|
-
get
|
|
1100
|
-
|
|
1184
|
+
get outputAmount() {
|
|
1185
|
+
if (this._outputAmount) {
|
|
1186
|
+
return this._outputAmount;
|
|
1187
|
+
}
|
|
1188
|
+
const outputCurrency = this.swaps[0].outputAmount.currency;
|
|
1189
|
+
const totalOutputFromRoutes = this.swaps.map(({ outputAmount }) => outputAmount).reduce((total, cur) => total.add(cur), CurrencyAmount.fromRawAmount(outputCurrency, 0));
|
|
1190
|
+
this._outputAmount = totalOutputFromRoutes;
|
|
1191
|
+
return this._outputAmount;
|
|
1101
1192
|
}
|
|
1102
1193
|
/**
|
|
1103
|
-
*
|
|
1194
|
+
* The price expressed in terms of output amount/input amount.
|
|
1104
1195
|
*/
|
|
1105
|
-
get
|
|
1106
|
-
|
|
1107
|
-
this.
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
this.tickUpper,
|
|
1113
|
-
this.pool.sqrtRatioX96,
|
|
1114
|
-
this.liquidity
|
|
1115
|
-
)
|
|
1116
|
-
);
|
|
1117
|
-
}
|
|
1118
|
-
return this._token0Amount;
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* Returns the amount of token1 that this position's liquidity could be burned for at the current pool price
|
|
1122
|
-
*/
|
|
1123
|
-
get amount1() {
|
|
1124
|
-
if (this._token1Amount === null) {
|
|
1125
|
-
this._token1Amount = CurrencyAmount.fromRawAmount(
|
|
1126
|
-
this.pool.token1,
|
|
1127
|
-
PositionMath.getToken1Amount(
|
|
1128
|
-
this.pool.tickCurrent,
|
|
1129
|
-
this.tickLower,
|
|
1130
|
-
this.tickUpper,
|
|
1131
|
-
this.pool.sqrtRatioX96,
|
|
1132
|
-
this.liquidity
|
|
1133
|
-
)
|
|
1134
|
-
);
|
|
1135
|
-
}
|
|
1136
|
-
return this._token1Amount;
|
|
1196
|
+
get executionPrice() {
|
|
1197
|
+
return this._executionPrice ?? (this._executionPrice = new Price(
|
|
1198
|
+
this.inputAmount.currency,
|
|
1199
|
+
this.outputAmount.currency,
|
|
1200
|
+
this.inputAmount.quotient,
|
|
1201
|
+
this.outputAmount.quotient
|
|
1202
|
+
));
|
|
1137
1203
|
}
|
|
1138
1204
|
/**
|
|
1139
|
-
* Returns the
|
|
1140
|
-
* @param slippageTolerance The amount by which the price can 'slip' before the transaction will revert
|
|
1141
|
-
* @returns The sqrt ratios after slippage
|
|
1205
|
+
* Returns the percent difference between the route's mid price and the price impact
|
|
1142
1206
|
*/
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
let sqrtRatioX96Lower = encodeSqrtRatioX96(priceLower.numerator, priceLower.denominator);
|
|
1147
|
-
if (sqrtRatioX96Lower <= TickMath.MIN_SQRT_RATIO) {
|
|
1148
|
-
sqrtRatioX96Lower = TickMath.MIN_SQRT_RATIO + 1n;
|
|
1207
|
+
get priceImpact() {
|
|
1208
|
+
if (this._priceImpact) {
|
|
1209
|
+
return this._priceImpact;
|
|
1149
1210
|
}
|
|
1150
|
-
let
|
|
1151
|
-
|
|
1152
|
-
|
|
1211
|
+
let spotOutputAmount = CurrencyAmount.fromRawAmount(this.outputAmount.currency, 0);
|
|
1212
|
+
for (const { route, inputAmount } of this.swaps) {
|
|
1213
|
+
const { midPrice } = route;
|
|
1214
|
+
spotOutputAmount = spotOutputAmount.add(midPrice.quote(inputAmount));
|
|
1153
1215
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
};
|
|
1216
|
+
const priceImpact = spotOutputAmount.subtract(this.outputAmount).divide(spotOutputAmount);
|
|
1217
|
+
this._priceImpact = new Percent$1(priceImpact.numerator, priceImpact.denominator);
|
|
1218
|
+
return this._priceImpact;
|
|
1158
1219
|
}
|
|
1159
1220
|
/**
|
|
1160
|
-
*
|
|
1161
|
-
*
|
|
1162
|
-
* @
|
|
1163
|
-
* @
|
|
1221
|
+
* Constructs an exact in trade with the given amount in and route
|
|
1222
|
+
* @template TInput The input token, either Ether or an ERC-20
|
|
1223
|
+
* @template TOutput The output token, either Ether or an ERC-20
|
|
1224
|
+
* @param route The route of the exact in trade
|
|
1225
|
+
* @param amountIn The amount being passed in
|
|
1226
|
+
* @returns The exact in trade
|
|
1164
1227
|
*/
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
const poolLower = new Pool(
|
|
1168
|
-
this.pool.token0,
|
|
1169
|
-
this.pool.token1,
|
|
1170
|
-
this.pool.fee,
|
|
1171
|
-
sqrtRatioX96Lower,
|
|
1172
|
-
0,
|
|
1173
|
-
TickMath.getTickAtSqrtRatio(sqrtRatioX96Lower)
|
|
1174
|
-
);
|
|
1175
|
-
const poolUpper = new Pool(
|
|
1176
|
-
this.pool.token0,
|
|
1177
|
-
this.pool.token1,
|
|
1178
|
-
this.pool.fee,
|
|
1179
|
-
sqrtRatioX96Upper,
|
|
1180
|
-
0,
|
|
1181
|
-
TickMath.getTickAtSqrtRatio(sqrtRatioX96Upper)
|
|
1182
|
-
);
|
|
1183
|
-
const positionThatWillBeCreated = Position.fromAmounts({
|
|
1184
|
-
pool: this.pool,
|
|
1185
|
-
tickLower: this.tickLower,
|
|
1186
|
-
tickUpper: this.tickUpper,
|
|
1187
|
-
...this.mintAmounts,
|
|
1188
|
-
// the mint amounts are what will be passed as calldata
|
|
1189
|
-
useFullPrecision: false
|
|
1190
|
-
});
|
|
1191
|
-
const { amount0 } = new Position({
|
|
1192
|
-
pool: poolUpper,
|
|
1193
|
-
liquidity: positionThatWillBeCreated.liquidity,
|
|
1194
|
-
tickLower: this.tickLower,
|
|
1195
|
-
tickUpper: this.tickUpper
|
|
1196
|
-
}).mintAmounts;
|
|
1197
|
-
const { amount1 } = new Position({
|
|
1198
|
-
pool: poolLower,
|
|
1199
|
-
liquidity: positionThatWillBeCreated.liquidity,
|
|
1200
|
-
tickLower: this.tickLower,
|
|
1201
|
-
tickUpper: this.tickUpper
|
|
1202
|
-
}).mintAmounts;
|
|
1203
|
-
return { amount0, amount1 };
|
|
1228
|
+
static async exactIn(route, amountIn) {
|
|
1229
|
+
return Trade.fromRoute(route, amountIn, TradeType.EXACT_INPUT);
|
|
1204
1230
|
}
|
|
1205
1231
|
/**
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
* @
|
|
1209
|
-
* @
|
|
1232
|
+
* Constructs an exact out trade with the given amount out and route
|
|
1233
|
+
* @template TInput The input token, either Ether or an ERC-20
|
|
1234
|
+
* @template TOutput The output token, either Ether or an ERC-20
|
|
1235
|
+
* @param route The route of the exact out trade
|
|
1236
|
+
* @param amountOut The amount returned by the trade
|
|
1237
|
+
* @returns The exact out trade
|
|
1210
1238
|
*/
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
const poolLower = new Pool(
|
|
1214
|
-
this.pool.token0,
|
|
1215
|
-
this.pool.token1,
|
|
1216
|
-
this.pool.fee,
|
|
1217
|
-
sqrtRatioX96Lower,
|
|
1218
|
-
0,
|
|
1219
|
-
TickMath.getTickAtSqrtRatio(sqrtRatioX96Lower)
|
|
1220
|
-
);
|
|
1221
|
-
const poolUpper = new Pool(
|
|
1222
|
-
this.pool.token0,
|
|
1223
|
-
this.pool.token1,
|
|
1224
|
-
this.pool.fee,
|
|
1225
|
-
sqrtRatioX96Upper,
|
|
1226
|
-
0,
|
|
1227
|
-
TickMath.getTickAtSqrtRatio(sqrtRatioX96Upper)
|
|
1228
|
-
);
|
|
1229
|
-
const { amount0 } = new Position({
|
|
1230
|
-
pool: poolUpper,
|
|
1231
|
-
liquidity: this.liquidity,
|
|
1232
|
-
tickLower: this.tickLower,
|
|
1233
|
-
tickUpper: this.tickUpper
|
|
1234
|
-
});
|
|
1235
|
-
const { amount1 } = new Position({
|
|
1236
|
-
pool: poolLower,
|
|
1237
|
-
liquidity: this.liquidity,
|
|
1238
|
-
tickLower: this.tickLower,
|
|
1239
|
-
tickUpper: this.tickUpper
|
|
1240
|
-
});
|
|
1241
|
-
return { amount0: amount0.quotient, amount1: amount1.quotient };
|
|
1239
|
+
static async exactOut(route, amountOut) {
|
|
1240
|
+
return Trade.fromRoute(route, amountOut, TradeType.EXACT_OUTPUT);
|
|
1242
1241
|
}
|
|
1243
1242
|
/**
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1243
|
+
* Constructs a trade by simulating swaps through the given route
|
|
1244
|
+
* @template TInput The input token, either Ether or an ERC-20.
|
|
1245
|
+
* @template TOutput The output token, either Ether or an ERC-20.
|
|
1246
|
+
* @template TTradeType The type of the trade, either exact in or exact out.
|
|
1247
|
+
* @param route route to swap through
|
|
1248
|
+
* @param amount the amount specified, either input or output, depending on tradeType
|
|
1249
|
+
* @param tradeType whether the trade is an exact input or exact output swap
|
|
1250
|
+
* @returns The route
|
|
1246
1251
|
*/
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
};
|
|
1252
|
+
static async fromRoute(route, amount, tradeType) {
|
|
1253
|
+
const amounts = new Array(route.tokenPath.length);
|
|
1254
|
+
let inputAmount;
|
|
1255
|
+
let outputAmount;
|
|
1256
|
+
if (tradeType === TradeType.EXACT_INPUT) {
|
|
1257
|
+
invariant9(amount.currency.equals(route.input), "INPUT");
|
|
1258
|
+
amounts[0] = amount.wrapped;
|
|
1259
|
+
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
1260
|
+
const pool = route.pools[i];
|
|
1261
|
+
const [outputAmount2] = await pool.getOutputAmount(amounts[i]);
|
|
1262
|
+
amounts[i + 1] = outputAmount2;
|
|
1259
1263
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
)
|
|
1274
|
-
};
|
|
1264
|
+
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
|
|
1265
|
+
outputAmount = CurrencyAmount.fromFractionalAmount(
|
|
1266
|
+
route.output,
|
|
1267
|
+
amounts[amounts.length - 1].numerator,
|
|
1268
|
+
amounts[amounts.length - 1].denominator
|
|
1269
|
+
);
|
|
1270
|
+
} else {
|
|
1271
|
+
invariant9(amount.currency.equals(route.output), "OUTPUT");
|
|
1272
|
+
amounts[amounts.length - 1] = amount.wrapped;
|
|
1273
|
+
for (let i = route.tokenPath.length - 1; i > 0; i--) {
|
|
1274
|
+
const pool = route.pools[i - 1];
|
|
1275
|
+
const [inputAmount2] = await pool.getInputAmount(amounts[i]);
|
|
1276
|
+
amounts[i - 1] = inputAmount2;
|
|
1275
1277
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
amount1: SqrtPriceMath.getAmount1Delta(
|
|
1279
|
-
TickMath.getSqrtRatioAtTick(this.tickLower),
|
|
1280
|
-
TickMath.getSqrtRatioAtTick(this.tickUpper),
|
|
1281
|
-
this.liquidity,
|
|
1282
|
-
true
|
|
1283
|
-
)
|
|
1284
|
-
};
|
|
1278
|
+
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amounts[0].numerator, amounts[0].denominator);
|
|
1279
|
+
outputAmount = CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator);
|
|
1285
1280
|
}
|
|
1286
|
-
return
|
|
1281
|
+
return new Trade({
|
|
1282
|
+
routes: [{ inputAmount, outputAmount, route }],
|
|
1283
|
+
tradeType
|
|
1284
|
+
});
|
|
1287
1285
|
}
|
|
1288
1286
|
/**
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
* @
|
|
1292
|
-
* @
|
|
1293
|
-
* @
|
|
1294
|
-
* @param
|
|
1295
|
-
* @param
|
|
1296
|
-
* @
|
|
1297
|
-
* not what core can theoretically support
|
|
1298
|
-
* @returns The amount of liquidity for the position
|
|
1299
|
-
*/
|
|
1300
|
-
static fromAmounts({
|
|
1301
|
-
pool,
|
|
1302
|
-
tickLower,
|
|
1303
|
-
tickUpper,
|
|
1304
|
-
amount0,
|
|
1305
|
-
amount1,
|
|
1306
|
-
useFullPrecision
|
|
1307
|
-
}) {
|
|
1308
|
-
const sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
|
1309
|
-
const sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
|
1310
|
-
return new Position({
|
|
1311
|
-
pool,
|
|
1312
|
-
tickLower,
|
|
1313
|
-
tickUpper,
|
|
1314
|
-
liquidity: maxLiquidityForAmounts(
|
|
1315
|
-
pool.sqrtRatioX96,
|
|
1316
|
-
sqrtRatioAX96,
|
|
1317
|
-
sqrtRatioBX96,
|
|
1318
|
-
amount0,
|
|
1319
|
-
amount1,
|
|
1320
|
-
useFullPrecision
|
|
1321
|
-
)
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
/**
|
|
1325
|
-
* Computes a position with the maximum amount of liquidity received for a given amount of token0, assuming an unlimited amount of token1
|
|
1326
|
-
* @param pool The pool for which the position is created
|
|
1327
|
-
* @param tickLower The lower tick
|
|
1328
|
-
* @param tickUpper The upper tick
|
|
1329
|
-
* @param amount0 The desired amount of token0
|
|
1330
|
-
* @param useFullPrecision If true, liquidity will be maximized according to what the router can calculate,
|
|
1331
|
-
* not what core can theoretically support
|
|
1332
|
-
* @returns The position
|
|
1333
|
-
*/
|
|
1334
|
-
static fromAmount0({
|
|
1335
|
-
pool,
|
|
1336
|
-
tickLower,
|
|
1337
|
-
tickUpper,
|
|
1338
|
-
amount0,
|
|
1339
|
-
useFullPrecision
|
|
1340
|
-
}) {
|
|
1341
|
-
return Position.fromAmounts({ pool, tickLower, tickUpper, amount0, amount1: MaxUint256, useFullPrecision });
|
|
1342
|
-
}
|
|
1343
|
-
/**
|
|
1344
|
-
* Computes a position with the maximum amount of liquidity received for a given amount of token1, assuming an unlimited amount of token0
|
|
1345
|
-
* @param pool The pool for which the position is created
|
|
1346
|
-
* @param tickLower The lower tick
|
|
1347
|
-
* @param tickUpper The upper tick
|
|
1348
|
-
* @param amount1 The desired amount of token1
|
|
1349
|
-
* @returns The position
|
|
1350
|
-
*/
|
|
1351
|
-
static fromAmount1({
|
|
1352
|
-
pool,
|
|
1353
|
-
tickLower,
|
|
1354
|
-
tickUpper,
|
|
1355
|
-
amount1
|
|
1356
|
-
}) {
|
|
1357
|
-
return Position.fromAmounts({ pool, tickLower, tickUpper, amount0: MaxUint256, amount1, useFullPrecision: true });
|
|
1358
|
-
}
|
|
1359
|
-
};
|
|
1360
|
-
var Route = class {
|
|
1361
|
-
/**
|
|
1362
|
-
* Creates an instance of route.
|
|
1363
|
-
* @param pools An array of `Pool` objects, ordered by the route the swap will take
|
|
1364
|
-
* @param input The input token
|
|
1365
|
-
* @param output The output token
|
|
1366
|
-
*/
|
|
1367
|
-
constructor(pools, input, output) {
|
|
1368
|
-
this._midPrice = null;
|
|
1369
|
-
invariant11(pools.length > 0, "POOLS");
|
|
1370
|
-
const { chainId } = pools[0];
|
|
1371
|
-
const allOnSameChain = pools.every((pool) => pool.chainId === chainId);
|
|
1372
|
-
invariant11(allOnSameChain, "CHAIN_IDS");
|
|
1373
|
-
const wrappedInput = input.wrapped;
|
|
1374
|
-
invariant11(pools[0].involvesToken(wrappedInput), "INPUT");
|
|
1375
|
-
invariant11(pools[pools.length - 1].involvesToken(output.wrapped), "OUTPUT");
|
|
1376
|
-
const tokenPath = [wrappedInput];
|
|
1377
|
-
for (const [i, pool] of pools.entries()) {
|
|
1378
|
-
const currentInputToken = tokenPath[i];
|
|
1379
|
-
invariant11(currentInputToken.equals(pool.token0) || currentInputToken.equals(pool.token1), "PATH");
|
|
1380
|
-
const nextToken = currentInputToken.equals(pool.token0) ? pool.token1 : pool.token0;
|
|
1381
|
-
tokenPath.push(nextToken);
|
|
1382
|
-
}
|
|
1383
|
-
this.pools = pools;
|
|
1384
|
-
this.tokenPath = tokenPath;
|
|
1385
|
-
this.input = input;
|
|
1386
|
-
this.output = output ?? tokenPath[tokenPath.length - 1];
|
|
1387
|
-
}
|
|
1388
|
-
get chainId() {
|
|
1389
|
-
return this.pools[0].chainId;
|
|
1390
|
-
}
|
|
1391
|
-
/**
|
|
1392
|
-
* Returns the mid price of the route
|
|
1393
|
-
*/
|
|
1394
|
-
get midPrice() {
|
|
1395
|
-
if (this._midPrice !== null)
|
|
1396
|
-
return this._midPrice;
|
|
1397
|
-
const { price } = this.pools.slice(1).reduce(
|
|
1398
|
-
({ nextInput, price: price2 }, pool) => {
|
|
1399
|
-
return nextInput.equals(pool.token0) ? {
|
|
1400
|
-
nextInput: pool.token1,
|
|
1401
|
-
price: price2.multiply(pool.token0Price)
|
|
1402
|
-
} : {
|
|
1403
|
-
nextInput: pool.token0,
|
|
1404
|
-
price: price2.multiply(pool.token1Price)
|
|
1405
|
-
};
|
|
1406
|
-
},
|
|
1407
|
-
this.pools[0].token0.equals(this.input.wrapped) ? {
|
|
1408
|
-
nextInput: this.pools[0].token1,
|
|
1409
|
-
price: this.pools[0].token0Price
|
|
1410
|
-
} : {
|
|
1411
|
-
nextInput: this.pools[0].token0,
|
|
1412
|
-
price: this.pools[0].token1Price
|
|
1413
|
-
}
|
|
1414
|
-
);
|
|
1415
|
-
return this._midPrice = new Price$1(this.input, this.output, price.denominator, price.numerator);
|
|
1416
|
-
}
|
|
1417
|
-
};
|
|
1418
|
-
function tradeComparator(a, b) {
|
|
1419
|
-
invariant11(a.inputAmount.currency.equals(b.inputAmount.currency), "INPUT_CURRENCY");
|
|
1420
|
-
invariant11(a.outputAmount.currency.equals(b.outputAmount.currency), "OUTPUT_CURRENCY");
|
|
1421
|
-
if (a.outputAmount.equalTo(b.outputAmount)) {
|
|
1422
|
-
if (a.inputAmount.equalTo(b.inputAmount)) {
|
|
1423
|
-
const aHops = a.swaps.reduce((total, cur) => total + cur.route.tokenPath.length, 0);
|
|
1424
|
-
const bHops = b.swaps.reduce((total, cur) => total + cur.route.tokenPath.length, 0);
|
|
1425
|
-
return aHops - bHops;
|
|
1426
|
-
}
|
|
1427
|
-
if (a.inputAmount.lessThan(b.inputAmount)) {
|
|
1428
|
-
return -1;
|
|
1429
|
-
}
|
|
1430
|
-
return 1;
|
|
1431
|
-
}
|
|
1432
|
-
if (a.outputAmount.lessThan(b.outputAmount)) {
|
|
1433
|
-
return 1;
|
|
1434
|
-
}
|
|
1435
|
-
return -1;
|
|
1436
|
-
}
|
|
1437
|
-
var Trade = class {
|
|
1438
|
-
/**
|
|
1439
|
-
* @deprecated Deprecated in favor of 'swaps' property. If the trade consists of multiple routes
|
|
1440
|
-
* this will return an error.
|
|
1441
|
-
*
|
|
1442
|
-
* When the trade consists of just a single route, this returns the route of the trade,
|
|
1443
|
-
* i.e. which pools the trade goes through.
|
|
1444
|
-
*/
|
|
1445
|
-
get route() {
|
|
1446
|
-
invariant11(this.swaps.length == 1, "MULTIPLE_ROUTES");
|
|
1447
|
-
return this.swaps[0].route;
|
|
1448
|
-
}
|
|
1449
|
-
/**
|
|
1450
|
-
* The input amount for the trade assuming no slippage.
|
|
1451
|
-
*/
|
|
1452
|
-
get inputAmount() {
|
|
1453
|
-
if (this._inputAmount) {
|
|
1454
|
-
return this._inputAmount;
|
|
1455
|
-
}
|
|
1456
|
-
const inputCurrency = this.swaps[0].inputAmount.currency;
|
|
1457
|
-
const totalInputFromRoutes = this.swaps.map(({ inputAmount }) => inputAmount).reduce((total, cur) => total.add(cur), CurrencyAmount.fromRawAmount(inputCurrency, 0));
|
|
1458
|
-
this._inputAmount = totalInputFromRoutes;
|
|
1459
|
-
return this._inputAmount;
|
|
1460
|
-
}
|
|
1461
|
-
/**
|
|
1462
|
-
* The output amount for the trade assuming no slippage.
|
|
1463
|
-
*/
|
|
1464
|
-
get outputAmount() {
|
|
1465
|
-
if (this._outputAmount) {
|
|
1466
|
-
return this._outputAmount;
|
|
1467
|
-
}
|
|
1468
|
-
const outputCurrency = this.swaps[0].outputAmount.currency;
|
|
1469
|
-
const totalOutputFromRoutes = this.swaps.map(({ outputAmount }) => outputAmount).reduce((total, cur) => total.add(cur), CurrencyAmount.fromRawAmount(outputCurrency, 0));
|
|
1470
|
-
this._outputAmount = totalOutputFromRoutes;
|
|
1471
|
-
return this._outputAmount;
|
|
1472
|
-
}
|
|
1473
|
-
/**
|
|
1474
|
-
* The price expressed in terms of output amount/input amount.
|
|
1475
|
-
*/
|
|
1476
|
-
get executionPrice() {
|
|
1477
|
-
return this._executionPrice ?? (this._executionPrice = new Price(
|
|
1478
|
-
this.inputAmount.currency,
|
|
1479
|
-
this.outputAmount.currency,
|
|
1480
|
-
this.inputAmount.quotient,
|
|
1481
|
-
this.outputAmount.quotient
|
|
1482
|
-
));
|
|
1483
|
-
}
|
|
1484
|
-
/**
|
|
1485
|
-
* Returns the percent difference between the route's mid price and the price impact
|
|
1486
|
-
*/
|
|
1487
|
-
get priceImpact() {
|
|
1488
|
-
if (this._priceImpact) {
|
|
1489
|
-
return this._priceImpact;
|
|
1490
|
-
}
|
|
1491
|
-
let spotOutputAmount = CurrencyAmount.fromRawAmount(this.outputAmount.currency, 0);
|
|
1492
|
-
for (const { route, inputAmount } of this.swaps) {
|
|
1493
|
-
const { midPrice } = route;
|
|
1494
|
-
spotOutputAmount = spotOutputAmount.add(midPrice.quote(inputAmount));
|
|
1495
|
-
}
|
|
1496
|
-
const priceImpact = spotOutputAmount.subtract(this.outputAmount).divide(spotOutputAmount);
|
|
1497
|
-
this._priceImpact = new Percent$1(priceImpact.numerator, priceImpact.denominator);
|
|
1498
|
-
return this._priceImpact;
|
|
1499
|
-
}
|
|
1500
|
-
/**
|
|
1501
|
-
* Constructs an exact in trade with the given amount in and route
|
|
1502
|
-
* @template TInput The input token, either Ether or an ERC-20
|
|
1503
|
-
* @template TOutput The output token, either Ether or an ERC-20
|
|
1504
|
-
* @param route The route of the exact in trade
|
|
1505
|
-
* @param amountIn The amount being passed in
|
|
1506
|
-
* @returns The exact in trade
|
|
1507
|
-
*/
|
|
1508
|
-
static async exactIn(route, amountIn) {
|
|
1509
|
-
return Trade.fromRoute(route, amountIn, TradeType.EXACT_INPUT);
|
|
1510
|
-
}
|
|
1511
|
-
/**
|
|
1512
|
-
* Constructs an exact out trade with the given amount out and route
|
|
1513
|
-
* @template TInput The input token, either Ether or an ERC-20
|
|
1514
|
-
* @template TOutput The output token, either Ether or an ERC-20
|
|
1515
|
-
* @param route The route of the exact out trade
|
|
1516
|
-
* @param amountOut The amount returned by the trade
|
|
1517
|
-
* @returns The exact out trade
|
|
1518
|
-
*/
|
|
1519
|
-
static async exactOut(route, amountOut) {
|
|
1520
|
-
return Trade.fromRoute(route, amountOut, TradeType.EXACT_OUTPUT);
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* Constructs a trade by simulating swaps through the given route
|
|
1524
|
-
* @template TInput The input token, either Ether or an ERC-20.
|
|
1525
|
-
* @template TOutput The output token, either Ether or an ERC-20.
|
|
1526
|
-
* @template TTradeType The type of the trade, either exact in or exact out.
|
|
1527
|
-
* @param route route to swap through
|
|
1528
|
-
* @param amount the amount specified, either input or output, depending on tradeType
|
|
1529
|
-
* @param tradeType whether the trade is an exact input or exact output swap
|
|
1530
|
-
* @returns The route
|
|
1531
|
-
*/
|
|
1532
|
-
static async fromRoute(route, amount, tradeType) {
|
|
1533
|
-
const amounts = new Array(route.tokenPath.length);
|
|
1534
|
-
let inputAmount;
|
|
1535
|
-
let outputAmount;
|
|
1536
|
-
if (tradeType === TradeType.EXACT_INPUT) {
|
|
1537
|
-
invariant11(amount.currency.equals(route.input), "INPUT");
|
|
1538
|
-
amounts[0] = amount.wrapped;
|
|
1539
|
-
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
1540
|
-
const pool = route.pools[i];
|
|
1541
|
-
const [outputAmount2] = await pool.getOutputAmount(amounts[i]);
|
|
1542
|
-
amounts[i + 1] = outputAmount2;
|
|
1543
|
-
}
|
|
1544
|
-
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
|
|
1545
|
-
outputAmount = CurrencyAmount.fromFractionalAmount(
|
|
1546
|
-
route.output,
|
|
1547
|
-
amounts[amounts.length - 1].numerator,
|
|
1548
|
-
amounts[amounts.length - 1].denominator
|
|
1549
|
-
);
|
|
1550
|
-
} else {
|
|
1551
|
-
invariant11(amount.currency.equals(route.output), "OUTPUT");
|
|
1552
|
-
amounts[amounts.length - 1] = amount.wrapped;
|
|
1553
|
-
for (let i = route.tokenPath.length - 1; i > 0; i--) {
|
|
1554
|
-
const pool = route.pools[i - 1];
|
|
1555
|
-
const [inputAmount2] = await pool.getInputAmount(amounts[i]);
|
|
1556
|
-
amounts[i - 1] = inputAmount2;
|
|
1557
|
-
}
|
|
1558
|
-
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amounts[0].numerator, amounts[0].denominator);
|
|
1559
|
-
outputAmount = CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator);
|
|
1560
|
-
}
|
|
1561
|
-
return new Trade({
|
|
1562
|
-
routes: [{ inputAmount, outputAmount, route }],
|
|
1563
|
-
tradeType
|
|
1564
|
-
});
|
|
1565
|
-
}
|
|
1566
|
-
/**
|
|
1567
|
-
* Constructs a trade from routes by simulating swaps
|
|
1568
|
-
*
|
|
1569
|
-
* @template TInput The input token, either Ether or an ERC-20.
|
|
1570
|
-
* @template TOutput The output token, either Ether or an ERC-20.
|
|
1571
|
-
* @template TTradeType The type of the trade, either exact in or exact out.
|
|
1572
|
-
* @param routes the routes to swap through and how much of the amount should be routed through each
|
|
1573
|
-
* @param tradeType whether the trade is an exact input or exact output swap
|
|
1574
|
-
* @returns The trade
|
|
1287
|
+
* Constructs a trade from routes by simulating swaps
|
|
1288
|
+
*
|
|
1289
|
+
* @template TInput The input token, either Ether or an ERC-20.
|
|
1290
|
+
* @template TOutput The output token, either Ether or an ERC-20.
|
|
1291
|
+
* @template TTradeType The type of the trade, either exact in or exact out.
|
|
1292
|
+
* @param routes the routes to swap through and how much of the amount should be routed through each
|
|
1293
|
+
* @param tradeType whether the trade is an exact input or exact output swap
|
|
1294
|
+
* @returns The trade
|
|
1575
1295
|
*/
|
|
1576
1296
|
static async fromRoutes(routes, tradeType) {
|
|
1577
1297
|
const populatedRoutes = [];
|
|
@@ -1580,7 +1300,7 @@ var Trade = class {
|
|
|
1580
1300
|
let inputAmount;
|
|
1581
1301
|
let outputAmount;
|
|
1582
1302
|
if (tradeType === TradeType.EXACT_INPUT) {
|
|
1583
|
-
|
|
1303
|
+
invariant9(amount.currency.equals(route.input), "INPUT");
|
|
1584
1304
|
inputAmount = CurrencyAmount.fromFractionalAmount(route.input, amount.numerator, amount.denominator);
|
|
1585
1305
|
amounts[0] = CurrencyAmount.fromFractionalAmount(route.input.wrapped, amount.numerator, amount.denominator);
|
|
1586
1306
|
for (let i = 0; i < route.tokenPath.length - 1; i++) {
|
|
@@ -1594,7 +1314,7 @@ var Trade = class {
|
|
|
1594
1314
|
amounts[amounts.length - 1].denominator
|
|
1595
1315
|
);
|
|
1596
1316
|
} else {
|
|
1597
|
-
|
|
1317
|
+
invariant9(amount.currency.equals(route.output), "OUTPUT");
|
|
1598
1318
|
outputAmount = CurrencyAmount.fromFractionalAmount(route.output, amount.numerator, amount.denominator);
|
|
1599
1319
|
amounts[amounts.length - 1] = CurrencyAmount.fromFractionalAmount(
|
|
1600
1320
|
route.output.wrapped,
|
|
@@ -1659,11 +1379,11 @@ var Trade = class {
|
|
|
1659
1379
|
}) {
|
|
1660
1380
|
const inputCurrency = routes[0].inputAmount.currency;
|
|
1661
1381
|
const outputCurrency = routes[0].outputAmount.currency;
|
|
1662
|
-
|
|
1382
|
+
invariant9(
|
|
1663
1383
|
routes.every(({ route }) => inputCurrency.wrapped.equals(route.input.wrapped)),
|
|
1664
1384
|
"INPUT_CURRENCY_MATCH"
|
|
1665
1385
|
);
|
|
1666
|
-
|
|
1386
|
+
invariant9(
|
|
1667
1387
|
routes.every(({ route }) => outputCurrency.wrapped.equals(route.output.wrapped)),
|
|
1668
1388
|
"OUTPUT_CURRENCY_MATCH"
|
|
1669
1389
|
);
|
|
@@ -1674,7 +1394,7 @@ var Trade = class {
|
|
|
1674
1394
|
poolAddressSet.add(Pool.getAddress(pool.token0, pool.token1, pool.fee));
|
|
1675
1395
|
}
|
|
1676
1396
|
}
|
|
1677
|
-
|
|
1397
|
+
invariant9(numPools == poolAddressSet.size, "POOLS_DUPLICATED");
|
|
1678
1398
|
this.swaps = routes;
|
|
1679
1399
|
this.tradeType = tradeType;
|
|
1680
1400
|
}
|
|
@@ -1684,169 +1404,459 @@ var Trade = class {
|
|
|
1684
1404
|
* @returns The amount out
|
|
1685
1405
|
*/
|
|
1686
1406
|
minimumAmountOut(slippageTolerance, amountOut = this.outputAmount) {
|
|
1687
|
-
|
|
1407
|
+
invariant9(!slippageTolerance.lessThan(ZERO), "SLIPPAGE_TOLERANCE");
|
|
1688
1408
|
if (this.tradeType === TradeType.EXACT_OUTPUT) {
|
|
1689
1409
|
return amountOut;
|
|
1690
1410
|
}
|
|
1691
1411
|
const slippageAdjustedAmountOut = new Fraction(ONE).add(slippageTolerance).invert().multiply(amountOut.quotient).quotient;
|
|
1692
1412
|
return CurrencyAmount.fromRawAmount(amountOut.currency, slippageAdjustedAmountOut);
|
|
1693
1413
|
}
|
|
1694
|
-
/**
|
|
1695
|
-
* Get the maximum amount in that can be spent via this trade for the given slippage tolerance
|
|
1696
|
-
* @param slippageTolerance The tolerance of unfavorable slippage from the execution price of this trade
|
|
1697
|
-
* @returns The amount in
|
|
1698
|
-
*/
|
|
1699
|
-
maximumAmountIn(slippageTolerance, amountIn = this.inputAmount) {
|
|
1700
|
-
|
|
1701
|
-
if (this.tradeType === TradeType.EXACT_INPUT) {
|
|
1702
|
-
return amountIn;
|
|
1414
|
+
/**
|
|
1415
|
+
* Get the maximum amount in that can be spent via this trade for the given slippage tolerance
|
|
1416
|
+
* @param slippageTolerance The tolerance of unfavorable slippage from the execution price of this trade
|
|
1417
|
+
* @returns The amount in
|
|
1418
|
+
*/
|
|
1419
|
+
maximumAmountIn(slippageTolerance, amountIn = this.inputAmount) {
|
|
1420
|
+
invariant9(!slippageTolerance.lessThan(ZERO), "SLIPPAGE_TOLERANCE");
|
|
1421
|
+
if (this.tradeType === TradeType.EXACT_INPUT) {
|
|
1422
|
+
return amountIn;
|
|
1423
|
+
}
|
|
1424
|
+
const slippageAdjustedAmountIn = new Fraction(ONE).add(slippageTolerance).multiply(amountIn.quotient).quotient;
|
|
1425
|
+
return CurrencyAmount.fromRawAmount(amountIn.currency, slippageAdjustedAmountIn);
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Return the execution price after accounting for slippage tolerance
|
|
1429
|
+
* @param slippageTolerance the allowed tolerated slippage
|
|
1430
|
+
* @returns The execution price
|
|
1431
|
+
*/
|
|
1432
|
+
worstExecutionPrice(slippageTolerance) {
|
|
1433
|
+
return new Price(
|
|
1434
|
+
this.inputAmount.currency,
|
|
1435
|
+
this.outputAmount.currency,
|
|
1436
|
+
this.maximumAmountIn(slippageTolerance).quotient,
|
|
1437
|
+
this.minimumAmountOut(slippageTolerance).quotient
|
|
1438
|
+
);
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Given a list of pools, and a fixed amount in, returns the top `maxNumResults` trades that go from an input token
|
|
1442
|
+
* amount to an output token, making at most `maxHops` hops.
|
|
1443
|
+
* Note this does not consider aggregation, as routes are linear. It's possible a better route exists by splitting
|
|
1444
|
+
* the amount in among multiple routes.
|
|
1445
|
+
* @param pools the pools to consider in finding the best trade
|
|
1446
|
+
* @param nextAmountIn exact amount of input currency to spend
|
|
1447
|
+
* @param currencyOut the desired currency out
|
|
1448
|
+
* @param maxNumResults maximum number of results to return
|
|
1449
|
+
* @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pool
|
|
1450
|
+
* @param currentPools used in recursion; the current list of pools
|
|
1451
|
+
* @param currencyAmountIn used in recursion; the original value of the currencyAmountIn parameter
|
|
1452
|
+
* @param bestTrades used in recursion; the current list of best trades
|
|
1453
|
+
* @returns The exact in trade
|
|
1454
|
+
*/
|
|
1455
|
+
static async bestTradeExactIn(pools, currencyAmountIn, currencyOut, { maxNumResults = 3, maxHops = 3 } = {}, currentPools = [], nextAmountIn = currencyAmountIn, bestTrades = []) {
|
|
1456
|
+
invariant9(pools.length > 0, "POOLS");
|
|
1457
|
+
invariant9(maxHops > 0, "MAX_HOPS");
|
|
1458
|
+
invariant9(currencyAmountIn === nextAmountIn || currentPools.length > 0, "INVALID_RECURSION");
|
|
1459
|
+
const amountIn = nextAmountIn.wrapped;
|
|
1460
|
+
const tokenOut = currencyOut.wrapped;
|
|
1461
|
+
for (let i = 0; i < pools.length; i++) {
|
|
1462
|
+
const pool = pools[i];
|
|
1463
|
+
if (!pool.token0.equals(amountIn.currency) && !pool.token1.equals(amountIn.currency))
|
|
1464
|
+
continue;
|
|
1465
|
+
let amountOut;
|
|
1466
|
+
try {
|
|
1467
|
+
const [result] = await pool.getOutputAmount(amountIn);
|
|
1468
|
+
amountOut = result;
|
|
1469
|
+
} catch (error) {
|
|
1470
|
+
if (error.isInsufficientInputAmountError) {
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
throw error;
|
|
1474
|
+
}
|
|
1475
|
+
if (amountOut.currency.isToken && amountOut.currency.equals(tokenOut)) {
|
|
1476
|
+
sortedInsert(
|
|
1477
|
+
bestTrades,
|
|
1478
|
+
await Trade.fromRoute(
|
|
1479
|
+
new Route([...currentPools, pool], currencyAmountIn.currency, currencyOut),
|
|
1480
|
+
currencyAmountIn,
|
|
1481
|
+
TradeType.EXACT_INPUT
|
|
1482
|
+
),
|
|
1483
|
+
maxNumResults,
|
|
1484
|
+
tradeComparator
|
|
1485
|
+
);
|
|
1486
|
+
} else if (maxHops > 1 && pools.length > 1) {
|
|
1487
|
+
const poolsExcludingThisPool = pools.slice(0, i).concat(pools.slice(i + 1, pools.length));
|
|
1488
|
+
await Trade.bestTradeExactIn(
|
|
1489
|
+
poolsExcludingThisPool,
|
|
1490
|
+
currencyAmountIn,
|
|
1491
|
+
currencyOut,
|
|
1492
|
+
{
|
|
1493
|
+
maxNumResults,
|
|
1494
|
+
maxHops: maxHops - 1
|
|
1495
|
+
},
|
|
1496
|
+
[...currentPools, pool],
|
|
1497
|
+
amountOut,
|
|
1498
|
+
bestTrades
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
return bestTrades;
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* similar to the above method but instead targets a fixed output amount
|
|
1506
|
+
* given a list of pools, and a fixed amount out, returns the top `maxNumResults` trades that go from an input token
|
|
1507
|
+
* to an output token amount, making at most `maxHops` hops
|
|
1508
|
+
* note this does not consider aggregation, as routes are linear. it's possible a better route exists by splitting
|
|
1509
|
+
* the amount in among multiple routes.
|
|
1510
|
+
* @param pools the pools to consider in finding the best trade
|
|
1511
|
+
* @param currencyIn the currency to spend
|
|
1512
|
+
* @param currencyAmountOut the desired currency amount out
|
|
1513
|
+
* @param nextAmountOut the exact amount of currency out
|
|
1514
|
+
* @param maxNumResults maximum number of results to return
|
|
1515
|
+
* @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pool
|
|
1516
|
+
* @param currentPools used in recursion; the current list of pools
|
|
1517
|
+
* @param bestTrades used in recursion; the current list of best trades
|
|
1518
|
+
* @returns The exact out trade
|
|
1519
|
+
*/
|
|
1520
|
+
static async bestTradeExactOut(pools, currencyIn, currencyAmountOut, { maxNumResults = 3, maxHops = 3 } = {}, currentPools = [], nextAmountOut = currencyAmountOut, bestTrades = []) {
|
|
1521
|
+
invariant9(pools.length > 0, "POOLS");
|
|
1522
|
+
invariant9(maxHops > 0, "MAX_HOPS");
|
|
1523
|
+
invariant9(currencyAmountOut === nextAmountOut || currentPools.length > 0, "INVALID_RECURSION");
|
|
1524
|
+
const amountOut = nextAmountOut.wrapped;
|
|
1525
|
+
const tokenIn = currencyIn.wrapped;
|
|
1526
|
+
for (let i = 0; i < pools.length; i++) {
|
|
1527
|
+
const pool = pools[i];
|
|
1528
|
+
if (!pool.token0.equals(amountOut.currency) && !pool.token1.equals(amountOut.currency))
|
|
1529
|
+
continue;
|
|
1530
|
+
let amountIn;
|
|
1531
|
+
try {
|
|
1532
|
+
const [result] = await pool.getInputAmount(amountOut);
|
|
1533
|
+
amountIn = result;
|
|
1534
|
+
} catch (error) {
|
|
1535
|
+
if (error.isInsufficientReservesError) {
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
throw error;
|
|
1539
|
+
}
|
|
1540
|
+
if (amountIn.currency.equals(tokenIn)) {
|
|
1541
|
+
sortedInsert(
|
|
1542
|
+
bestTrades,
|
|
1543
|
+
await Trade.fromRoute(
|
|
1544
|
+
new Route([pool, ...currentPools], currencyIn, currencyAmountOut.currency),
|
|
1545
|
+
currencyAmountOut,
|
|
1546
|
+
TradeType.EXACT_OUTPUT
|
|
1547
|
+
),
|
|
1548
|
+
maxNumResults,
|
|
1549
|
+
tradeComparator
|
|
1550
|
+
);
|
|
1551
|
+
} else if (maxHops > 1 && pools.length > 1) {
|
|
1552
|
+
const poolsExcludingThisPool = pools.slice(0, i).concat(pools.slice(i + 1, pools.length));
|
|
1553
|
+
await Trade.bestTradeExactOut(
|
|
1554
|
+
poolsExcludingThisPool,
|
|
1555
|
+
currencyIn,
|
|
1556
|
+
currencyAmountOut,
|
|
1557
|
+
{
|
|
1558
|
+
maxNumResults,
|
|
1559
|
+
maxHops: maxHops - 1
|
|
1560
|
+
},
|
|
1561
|
+
[pool, ...currentPools],
|
|
1562
|
+
amountIn,
|
|
1563
|
+
bestTrades
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
return bestTrades;
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
// src/utils/calldata.ts
|
|
1572
|
+
function toHex(bigintIsh) {
|
|
1573
|
+
const bigInt = BigInt(bigintIsh);
|
|
1574
|
+
let hex = bigInt.toString(16);
|
|
1575
|
+
if (hex.length % 2 !== 0) {
|
|
1576
|
+
hex = `0${hex}`;
|
|
1577
|
+
}
|
|
1578
|
+
return `0x${hex}`;
|
|
1579
|
+
}
|
|
1580
|
+
function encodeRouteToPath(route, exactOutput) {
|
|
1581
|
+
const firstInputToken = route.input.wrapped;
|
|
1582
|
+
const { path, types } = route.pools.reduce(
|
|
1583
|
+
({ inputToken, path: path2, types: types2 }, pool, index) => {
|
|
1584
|
+
const outputToken = pool.token0.equals(inputToken) ? pool.token1 : pool.token0;
|
|
1585
|
+
if (index === 0) {
|
|
1586
|
+
return {
|
|
1587
|
+
inputToken: outputToken,
|
|
1588
|
+
types: ["address", "uint24", "address"],
|
|
1589
|
+
path: [inputToken.address, pool.fee, outputToken.address]
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
return {
|
|
1593
|
+
inputToken: outputToken,
|
|
1594
|
+
types: [...types2, "uint24", "address"],
|
|
1595
|
+
path: [...path2, pool.fee, outputToken.address]
|
|
1596
|
+
};
|
|
1597
|
+
},
|
|
1598
|
+
{ inputToken: firstInputToken, path: [], types: [] }
|
|
1599
|
+
);
|
|
1600
|
+
return exactOutput ? encodePacked(types.reverse(), path.reverse()) : encodePacked(types, path);
|
|
1601
|
+
}
|
|
1602
|
+
function nearestUsableTick(tick, tickSpacing) {
|
|
1603
|
+
invariant9(Number.isInteger(tick) && Number.isInteger(tickSpacing), "INTEGERS");
|
|
1604
|
+
invariant9(tickSpacing > 0, "TICK_SPACING");
|
|
1605
|
+
invariant9(tick >= TickMath.MIN_TICK && tick <= TickMath.MAX_TICK, "TICK_BOUND");
|
|
1606
|
+
const rounded = Math.round(tick / tickSpacing) * tickSpacing;
|
|
1607
|
+
if (rounded < TickMath.MIN_TICK)
|
|
1608
|
+
return rounded + tickSpacing;
|
|
1609
|
+
if (rounded > TickMath.MAX_TICK)
|
|
1610
|
+
return rounded - tickSpacing;
|
|
1611
|
+
return rounded;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// src/utils/position.ts
|
|
1615
|
+
var PositionLibrary = class {
|
|
1616
|
+
/**
|
|
1617
|
+
* Cannot be constructed.
|
|
1618
|
+
*/
|
|
1619
|
+
constructor() {
|
|
1620
|
+
}
|
|
1621
|
+
// replicates the portions of Position#update required to compute unaccounted fees
|
|
1622
|
+
static getTokensOwed(feeGrowthInside0LastX128, feeGrowthInside1LastX128, liquidity, feeGrowthInside0X128, feeGrowthInside1X128) {
|
|
1623
|
+
const tokensOwed0 = subIn256(feeGrowthInside0X128, feeGrowthInside0LastX128) * liquidity / Q128;
|
|
1624
|
+
const tokensOwed1 = subIn256(feeGrowthInside1X128, feeGrowthInside1LastX128) * liquidity / Q128;
|
|
1625
|
+
return [tokensOwed0, tokensOwed1];
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
1628
|
+
|
|
1629
|
+
// src/utils/tickLibrary.ts
|
|
1630
|
+
var Q256 = 2n ** 256n;
|
|
1631
|
+
function subIn256(x, y) {
|
|
1632
|
+
const difference = x - y;
|
|
1633
|
+
if (difference < ZERO) {
|
|
1634
|
+
return Q256 + difference;
|
|
1635
|
+
}
|
|
1636
|
+
return difference;
|
|
1637
|
+
}
|
|
1638
|
+
var TickLibrary = class {
|
|
1639
|
+
/**
|
|
1640
|
+
* Cannot be constructed.
|
|
1641
|
+
*/
|
|
1642
|
+
constructor() {
|
|
1643
|
+
}
|
|
1644
|
+
static getFeeGrowthInside(feeGrowthOutsideLower, feeGrowthOutsideUpper, tickLower, tickUpper, tickCurrent, feeGrowthGlobal0X128, feeGrowthGlobal1X128) {
|
|
1645
|
+
let feeGrowthBelow0X128;
|
|
1646
|
+
let feeGrowthBelow1X128;
|
|
1647
|
+
if (tickCurrent >= tickLower) {
|
|
1648
|
+
feeGrowthBelow0X128 = feeGrowthOutsideLower.feeGrowthOutside0X128;
|
|
1649
|
+
feeGrowthBelow1X128 = feeGrowthOutsideLower.feeGrowthOutside1X128;
|
|
1650
|
+
} else {
|
|
1651
|
+
feeGrowthBelow0X128 = subIn256(feeGrowthGlobal0X128, feeGrowthOutsideLower.feeGrowthOutside0X128);
|
|
1652
|
+
feeGrowthBelow1X128 = subIn256(feeGrowthGlobal1X128, feeGrowthOutsideLower.feeGrowthOutside1X128);
|
|
1653
|
+
}
|
|
1654
|
+
let feeGrowthAbove0X128;
|
|
1655
|
+
let feeGrowthAbove1X128;
|
|
1656
|
+
if (tickCurrent < tickUpper) {
|
|
1657
|
+
feeGrowthAbove0X128 = feeGrowthOutsideUpper.feeGrowthOutside0X128;
|
|
1658
|
+
feeGrowthAbove1X128 = feeGrowthOutsideUpper.feeGrowthOutside1X128;
|
|
1659
|
+
} else {
|
|
1660
|
+
feeGrowthAbove0X128 = subIn256(feeGrowthGlobal0X128, feeGrowthOutsideUpper.feeGrowthOutside0X128);
|
|
1661
|
+
feeGrowthAbove1X128 = subIn256(feeGrowthGlobal1X128, feeGrowthOutsideUpper.feeGrowthOutside1X128);
|
|
1662
|
+
}
|
|
1663
|
+
return [
|
|
1664
|
+
subIn256(subIn256(feeGrowthGlobal0X128, feeGrowthBelow0X128), feeGrowthAbove0X128),
|
|
1665
|
+
subIn256(subIn256(feeGrowthGlobal1X128, feeGrowthBelow1X128), feeGrowthAbove1X128)
|
|
1666
|
+
];
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
function parseNumberToFraction(num, precision = 6) {
|
|
1670
|
+
if (Number.isNaN(num) || !Number.isFinite(num)) {
|
|
1671
|
+
return void 0;
|
|
1672
|
+
}
|
|
1673
|
+
const scalar = 10 ** precision;
|
|
1674
|
+
return new Fraction$1(BigInt(Math.floor(num * scalar)), BigInt(scalar));
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
// src/utils/feeCalculator.ts
|
|
1678
|
+
var FeeCalculator = {
|
|
1679
|
+
getEstimatedLPFee,
|
|
1680
|
+
getEstimatedLPFeeByAmounts,
|
|
1681
|
+
getLiquidityFromTick,
|
|
1682
|
+
getLiquidityFromSqrtRatioX96,
|
|
1683
|
+
getAverageLiquidity,
|
|
1684
|
+
getLiquidityBySingleAmount,
|
|
1685
|
+
getDependentAmount,
|
|
1686
|
+
getLiquidityByAmountsAndPrice,
|
|
1687
|
+
getAmountsByLiquidityAndPrice,
|
|
1688
|
+
getAmountsAtNewPrice
|
|
1689
|
+
};
|
|
1690
|
+
function getEstimatedLPFeeWithProtocolFee({ amount, currency, ...rest }) {
|
|
1691
|
+
return getEstimatedLPFeeByAmountsWithProtocolFee({
|
|
1692
|
+
...rest,
|
|
1693
|
+
amountA: amount,
|
|
1694
|
+
amountB: CurrencyAmount$1.fromRawAmount(currency, MaxUint256)
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
function getEstimatedLPFee({ amount, currency, ...rest }) {
|
|
1698
|
+
return getEstimatedLPFeeByAmounts({
|
|
1699
|
+
...rest,
|
|
1700
|
+
amountA: amount,
|
|
1701
|
+
amountB: CurrencyAmount$1.fromRawAmount(currency, MaxUint256)
|
|
1702
|
+
});
|
|
1703
|
+
}
|
|
1704
|
+
function getEstimatedLPFeeByAmountsWithProtocolFee(options) {
|
|
1705
|
+
try {
|
|
1706
|
+
return tryGetEstimatedLPFeeByAmounts(options);
|
|
1707
|
+
} catch (e) {
|
|
1708
|
+
console.error(e);
|
|
1709
|
+
return new Fraction$1(ZERO$1);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
function getEstimatedLPFeeByAmounts({ protocolFee = ZERO_PERCENT, ...rest }) {
|
|
1713
|
+
try {
|
|
1714
|
+
const fee = tryGetEstimatedLPFeeByAmounts(rest);
|
|
1715
|
+
return ONE_HUNDRED_PERCENT.subtract(protocolFee).multiply(fee).asFraction;
|
|
1716
|
+
} catch (e) {
|
|
1717
|
+
console.error(e);
|
|
1718
|
+
return new Fraction$1(ZERO$1);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
function tryGetEstimatedLPFeeByAmounts({
|
|
1722
|
+
amountA,
|
|
1723
|
+
amountB,
|
|
1724
|
+
volume24H,
|
|
1725
|
+
sqrtRatioX96,
|
|
1726
|
+
tickLower,
|
|
1727
|
+
tickUpper,
|
|
1728
|
+
mostActiveLiquidity,
|
|
1729
|
+
fee,
|
|
1730
|
+
insidePercentage = ONE_HUNDRED_PERCENT
|
|
1731
|
+
}) {
|
|
1732
|
+
invariant9(!Number.isNaN(fee) && fee >= 0, "INVALID_FEE");
|
|
1733
|
+
const tickCurrent = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
1734
|
+
if (tickCurrent < tickLower || tickCurrent > tickUpper) {
|
|
1735
|
+
return new Fraction$1(ZERO$1);
|
|
1736
|
+
}
|
|
1737
|
+
const liquidity = FeeCalculator.getLiquidityByAmountsAndPrice({
|
|
1738
|
+
amountA,
|
|
1739
|
+
amountB,
|
|
1740
|
+
tickUpper,
|
|
1741
|
+
tickLower,
|
|
1742
|
+
sqrtRatioX96
|
|
1743
|
+
});
|
|
1744
|
+
const volumeInFraction = parseNumberToFraction(volume24H) || new Fraction$1(ZERO$1);
|
|
1745
|
+
return insidePercentage.multiply(volumeInFraction.multiply(BigInt(fee)).multiply(liquidity)).divide(MAX_FEE * (liquidity + mostActiveLiquidity)).asFraction;
|
|
1746
|
+
}
|
|
1747
|
+
function getDependentAmount(options) {
|
|
1748
|
+
const { currency, amount, sqrtRatioX96, tickLower, tickUpper } = options;
|
|
1749
|
+
const currentTick = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
1750
|
+
const liquidity = FeeCalculator.getLiquidityBySingleAmount(options);
|
|
1751
|
+
const isToken0 = currency.wrapped.sortsBefore(amount.currency.wrapped);
|
|
1752
|
+
const getTokenAmount = isToken0 ? PositionMath.getToken0Amount : PositionMath.getToken1Amount;
|
|
1753
|
+
return CurrencyAmount$1.fromRawAmount(
|
|
1754
|
+
currency,
|
|
1755
|
+
getTokenAmount(currentTick, tickLower, tickUpper, sqrtRatioX96, liquidity)
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
function getLiquidityBySingleAmount({ amount, currency, ...rest }) {
|
|
1759
|
+
return getLiquidityByAmountsAndPrice({
|
|
1760
|
+
amountA: amount,
|
|
1761
|
+
amountB: CurrencyAmount$1.fromRawAmount(currency, MaxUint256),
|
|
1762
|
+
...rest
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
function getLiquidityByAmountsAndPrice({
|
|
1766
|
+
amountA,
|
|
1767
|
+
amountB,
|
|
1768
|
+
tickUpper,
|
|
1769
|
+
tickLower,
|
|
1770
|
+
sqrtRatioX96
|
|
1771
|
+
}) {
|
|
1772
|
+
const isToken0 = amountA.currency.wrapped.address !== amountB.currency.wrapped.address ? amountA.currency.wrapped.sortsBefore(amountB.currency.wrapped) : true;
|
|
1773
|
+
const [inputAmount0, inputAmount1] = isToken0 ? [amountA.quotient, amountB.quotient] : [amountB.quotient, amountA.quotient];
|
|
1774
|
+
const sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower);
|
|
1775
|
+
const sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper);
|
|
1776
|
+
return maxLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, inputAmount0, inputAmount1, true);
|
|
1777
|
+
}
|
|
1778
|
+
function getAmountsByLiquidityAndPrice(options) {
|
|
1779
|
+
const { currencyA, currencyB, liquidity, sqrtRatioX96, tickLower, tickUpper } = options;
|
|
1780
|
+
const currentTick = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
1781
|
+
const isToken0 = currencyA.wrapped.sortsBefore(currencyB.wrapped);
|
|
1782
|
+
const adjustedAmount0 = PositionMath.getToken0Amount(currentTick, tickLower, tickUpper, sqrtRatioX96, liquidity);
|
|
1783
|
+
const adjustedAmount1 = PositionMath.getToken1Amount(currentTick, tickLower, tickUpper, sqrtRatioX96, liquidity);
|
|
1784
|
+
return [
|
|
1785
|
+
CurrencyAmount$1.fromRawAmount(currencyA, isToken0 ? adjustedAmount0 : adjustedAmount1),
|
|
1786
|
+
CurrencyAmount$1.fromRawAmount(currencyB, isToken0 ? adjustedAmount1 : adjustedAmount0)
|
|
1787
|
+
];
|
|
1788
|
+
}
|
|
1789
|
+
function getAmountsAtNewPrice({ newSqrtRatioX96, ...rest }) {
|
|
1790
|
+
const { tickLower, tickUpper, amountA, amountB } = rest;
|
|
1791
|
+
const liquidity = FeeCalculator.getLiquidityByAmountsAndPrice(rest);
|
|
1792
|
+
return FeeCalculator.getAmountsByLiquidityAndPrice({
|
|
1793
|
+
liquidity,
|
|
1794
|
+
currencyA: amountA.currency,
|
|
1795
|
+
currencyB: amountB.currency,
|
|
1796
|
+
tickLower,
|
|
1797
|
+
tickUpper,
|
|
1798
|
+
sqrtRatioX96: newSqrtRatioX96
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
function getAverageLiquidity(ticks, tickSpacing, tickLower, tickUpper) {
|
|
1802
|
+
invariant9(tickLower <= tickUpper, "INVALID_TICK_RANGE");
|
|
1803
|
+
TickList.validateList(ticks, tickSpacing);
|
|
1804
|
+
if (tickLower === tickUpper) {
|
|
1805
|
+
return FeeCalculator.getLiquidityFromTick(ticks, tickLower);
|
|
1806
|
+
}
|
|
1807
|
+
const lowerOutOfBound = tickLower < ticks[0].index;
|
|
1808
|
+
let lastTick = lowerOutOfBound ? new Tick({ index: TickMath.MIN_TICK, liquidityNet: ZERO$1, liquidityGross: ZERO$1 }) : TickList.nextInitializedTick(ticks, tickLower, true);
|
|
1809
|
+
let currentTick = TickList.nextInitializedTick(ticks, tickLower, false);
|
|
1810
|
+
let currentL = lowerOutOfBound ? ZERO$1 : FeeCalculator.getLiquidityFromTick(ticks, currentTick.index);
|
|
1811
|
+
let weightedL = ZERO$1;
|
|
1812
|
+
const getWeightedLFromLastTickTo = (toTick) => currentL * BigInt(toTick - Math.max(lastTick.index, tickLower));
|
|
1813
|
+
while (currentTick.index < tickUpper) {
|
|
1814
|
+
weightedL += getWeightedLFromLastTickTo(currentTick.index);
|
|
1815
|
+
currentL += currentTick.liquidityNet;
|
|
1816
|
+
lastTick = currentTick;
|
|
1817
|
+
if (currentTick.index === ticks[ticks.length - 1].index) {
|
|
1818
|
+
break;
|
|
1703
1819
|
}
|
|
1704
|
-
|
|
1705
|
-
return CurrencyAmount.fromRawAmount(amountIn.currency, slippageAdjustedAmountIn);
|
|
1820
|
+
currentTick = TickList.nextInitializedTick(ticks, currentTick.index, false);
|
|
1706
1821
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1822
|
+
weightedL += getWeightedLFromLastTickTo(tickUpper);
|
|
1823
|
+
return weightedL / BigInt(tickUpper - tickLower);
|
|
1824
|
+
}
|
|
1825
|
+
function getLiquidityFromSqrtRatioX96(ticks, sqrtRatioX96) {
|
|
1826
|
+
const tick = TickMath.getTickAtSqrtRatio(sqrtRatioX96);
|
|
1827
|
+
return FeeCalculator.getLiquidityFromTick(ticks, tick);
|
|
1828
|
+
}
|
|
1829
|
+
function getLiquidityFromTick(ticks, tick) {
|
|
1830
|
+
let liquidity = ZERO$1;
|
|
1831
|
+
if (!ticks?.length)
|
|
1832
|
+
return liquidity;
|
|
1833
|
+
if (tick < ticks[0].index || tick > ticks[ticks.length - 1].index) {
|
|
1834
|
+
return liquidity;
|
|
1719
1835
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
* @param nextAmountIn exact amount of input currency to spend
|
|
1727
|
-
* @param currencyOut the desired currency out
|
|
1728
|
-
* @param maxNumResults maximum number of results to return
|
|
1729
|
-
* @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pool
|
|
1730
|
-
* @param currentPools used in recursion; the current list of pools
|
|
1731
|
-
* @param currencyAmountIn used in recursion; the original value of the currencyAmountIn parameter
|
|
1732
|
-
* @param bestTrades used in recursion; the current list of best trades
|
|
1733
|
-
* @returns The exact in trade
|
|
1734
|
-
*/
|
|
1735
|
-
static async bestTradeExactIn(pools, currencyAmountIn, currencyOut, { maxNumResults = 3, maxHops = 3 } = {}, currentPools = [], nextAmountIn = currencyAmountIn, bestTrades = []) {
|
|
1736
|
-
invariant11(pools.length > 0, "POOLS");
|
|
1737
|
-
invariant11(maxHops > 0, "MAX_HOPS");
|
|
1738
|
-
invariant11(currencyAmountIn === nextAmountIn || currentPools.length > 0, "INVALID_RECURSION");
|
|
1739
|
-
const amountIn = nextAmountIn.wrapped;
|
|
1740
|
-
const tokenOut = currencyOut.wrapped;
|
|
1741
|
-
for (let i = 0; i < pools.length; i++) {
|
|
1742
|
-
const pool = pools[i];
|
|
1743
|
-
if (!pool.token0.equals(amountIn.currency) && !pool.token1.equals(amountIn.currency))
|
|
1744
|
-
continue;
|
|
1745
|
-
let amountOut;
|
|
1746
|
-
try {
|
|
1747
|
-
const [result] = await pool.getOutputAmount(amountIn);
|
|
1748
|
-
amountOut = result;
|
|
1749
|
-
} catch (error) {
|
|
1750
|
-
if (error.isInsufficientInputAmountError) {
|
|
1751
|
-
continue;
|
|
1752
|
-
}
|
|
1753
|
-
throw error;
|
|
1754
|
-
}
|
|
1755
|
-
if (amountOut.currency.isToken && amountOut.currency.equals(tokenOut)) {
|
|
1756
|
-
sortedInsert(
|
|
1757
|
-
bestTrades,
|
|
1758
|
-
await Trade.fromRoute(
|
|
1759
|
-
new Route([...currentPools, pool], currencyAmountIn.currency, currencyOut),
|
|
1760
|
-
currencyAmountIn,
|
|
1761
|
-
TradeType.EXACT_INPUT
|
|
1762
|
-
),
|
|
1763
|
-
maxNumResults,
|
|
1764
|
-
tradeComparator
|
|
1765
|
-
);
|
|
1766
|
-
} else if (maxHops > 1 && pools.length > 1) {
|
|
1767
|
-
const poolsExcludingThisPool = pools.slice(0, i).concat(pools.slice(i + 1, pools.length));
|
|
1768
|
-
await Trade.bestTradeExactIn(
|
|
1769
|
-
poolsExcludingThisPool,
|
|
1770
|
-
currencyAmountIn,
|
|
1771
|
-
currencyOut,
|
|
1772
|
-
{
|
|
1773
|
-
maxNumResults,
|
|
1774
|
-
maxHops: maxHops - 1
|
|
1775
|
-
},
|
|
1776
|
-
[...currentPools, pool],
|
|
1777
|
-
amountOut,
|
|
1778
|
-
bestTrades
|
|
1779
|
-
);
|
|
1780
|
-
}
|
|
1836
|
+
for (let i = 0; i < ticks.length - 1; ++i) {
|
|
1837
|
+
liquidity += ticks[i].liquidityNet;
|
|
1838
|
+
const lowerTick = ticks[i].index;
|
|
1839
|
+
const upperTick = ticks[i + 1]?.index;
|
|
1840
|
+
if (lowerTick <= tick && tick <= upperTick) {
|
|
1841
|
+
break;
|
|
1781
1842
|
}
|
|
1782
|
-
return bestTrades;
|
|
1783
1843
|
}
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
* @param currencyIn the currency to spend
|
|
1792
|
-
* @param currencyAmountOut the desired currency amount out
|
|
1793
|
-
* @param nextAmountOut the exact amount of currency out
|
|
1794
|
-
* @param maxNumResults maximum number of results to return
|
|
1795
|
-
* @param maxHops maximum number of hops a returned trade can make, e.g. 1 hop goes through a single pool
|
|
1796
|
-
* @param currentPools used in recursion; the current list of pools
|
|
1797
|
-
* @param bestTrades used in recursion; the current list of best trades
|
|
1798
|
-
* @returns The exact out trade
|
|
1799
|
-
*/
|
|
1800
|
-
static async bestTradeExactOut(pools, currencyIn, currencyAmountOut, { maxNumResults = 3, maxHops = 3 } = {}, currentPools = [], nextAmountOut = currencyAmountOut, bestTrades = []) {
|
|
1801
|
-
invariant11(pools.length > 0, "POOLS");
|
|
1802
|
-
invariant11(maxHops > 0, "MAX_HOPS");
|
|
1803
|
-
invariant11(currencyAmountOut === nextAmountOut || currentPools.length > 0, "INVALID_RECURSION");
|
|
1804
|
-
const amountOut = nextAmountOut.wrapped;
|
|
1805
|
-
const tokenIn = currencyIn.wrapped;
|
|
1806
|
-
for (let i = 0; i < pools.length; i++) {
|
|
1807
|
-
const pool = pools[i];
|
|
1808
|
-
if (!pool.token0.equals(amountOut.currency) && !pool.token1.equals(amountOut.currency))
|
|
1809
|
-
continue;
|
|
1810
|
-
let amountIn;
|
|
1811
|
-
try {
|
|
1812
|
-
const [result] = await pool.getInputAmount(amountOut);
|
|
1813
|
-
amountIn = result;
|
|
1814
|
-
} catch (error) {
|
|
1815
|
-
if (error.isInsufficientReservesError) {
|
|
1816
|
-
continue;
|
|
1817
|
-
}
|
|
1818
|
-
throw error;
|
|
1819
|
-
}
|
|
1820
|
-
if (amountIn.currency.equals(tokenIn)) {
|
|
1821
|
-
sortedInsert(
|
|
1822
|
-
bestTrades,
|
|
1823
|
-
await Trade.fromRoute(
|
|
1824
|
-
new Route([pool, ...currentPools], currencyIn, currencyAmountOut.currency),
|
|
1825
|
-
currencyAmountOut,
|
|
1826
|
-
TradeType.EXACT_OUTPUT
|
|
1827
|
-
),
|
|
1828
|
-
maxNumResults,
|
|
1829
|
-
tradeComparator
|
|
1830
|
-
);
|
|
1831
|
-
} else if (maxHops > 1 && pools.length > 1) {
|
|
1832
|
-
const poolsExcludingThisPool = pools.slice(0, i).concat(pools.slice(i + 1, pools.length));
|
|
1833
|
-
await Trade.bestTradeExactOut(
|
|
1834
|
-
poolsExcludingThisPool,
|
|
1835
|
-
currencyIn,
|
|
1836
|
-
currencyAmountOut,
|
|
1837
|
-
{
|
|
1838
|
-
maxNumResults,
|
|
1839
|
-
maxHops: maxHops - 1
|
|
1840
|
-
},
|
|
1841
|
-
[pool, ...currentPools],
|
|
1842
|
-
amountIn,
|
|
1843
|
-
bestTrades
|
|
1844
|
-
);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
return bestTrades;
|
|
1844
|
+
return liquidity;
|
|
1845
|
+
}
|
|
1846
|
+
var FEE_BASE = 10n ** 4n;
|
|
1847
|
+
function parseProtocolFees(feeProtocol) {
|
|
1848
|
+
const packed = Number(feeProtocol);
|
|
1849
|
+
if (Number.isNaN(packed)) {
|
|
1850
|
+
throw new Error(`Invalid fee protocol ${feeProtocol}`);
|
|
1848
1851
|
}
|
|
1849
|
-
|
|
1852
|
+
const token0ProtocolFee = packed % 2 ** 16;
|
|
1853
|
+
const token1ProtocolFee = packed >> 16;
|
|
1854
|
+
return [new Percent(token0ProtocolFee, FEE_BASE), new Percent(token1ProtocolFee, FEE_BASE)];
|
|
1855
|
+
}
|
|
1856
|
+
function sqrtRatioX96ToPrice(sqrtRatioX96, currencyA, currencyB) {
|
|
1857
|
+
const ratioX192 = sqrtRatioX96 * sqrtRatioX96;
|
|
1858
|
+
return currencyA.wrapped.sortsBefore(currencyB.wrapped) ? new Price$1(currencyA.wrapped, currencyB.wrapped, Q192, ratioX192) : new Price$1(currencyA.wrapped, currencyB.wrapped, ratioX192, Q192);
|
|
1859
|
+
}
|
|
1850
1860
|
var IMulticall = [
|
|
1851
1861
|
{
|
|
1852
1862
|
inputs: [
|
|
@@ -1878,14 +1888,14 @@ var _Multicall = class {
|
|
|
1878
1888
|
if (!Array.isArray(calldatas)) {
|
|
1879
1889
|
calldatas = [calldatas];
|
|
1880
1890
|
}
|
|
1881
|
-
return calldatas.length === 1 ? calldatas[0] : _Multicall.
|
|
1891
|
+
return calldatas.length === 1 ? calldatas[0] : encodeFunctionData({ abi: _Multicall.ABI, functionName: "multicall", args: [calldatas] });
|
|
1882
1892
|
}
|
|
1883
1893
|
};
|
|
1884
1894
|
var Multicall = _Multicall;
|
|
1885
|
-
Multicall.
|
|
1895
|
+
Multicall.ABI = IMulticall;
|
|
1886
1896
|
|
|
1887
|
-
// src/abi/NonfungiblePositionManager.
|
|
1888
|
-
var
|
|
1897
|
+
// src/abi/NonfungiblePositionManager.ts
|
|
1898
|
+
var nonfungiblePositionManagerABI = [
|
|
1889
1899
|
{
|
|
1890
1900
|
inputs: [
|
|
1891
1901
|
{ internalType: "address", name: "_deployer", type: "address" },
|
|
@@ -2391,8 +2401,8 @@ var NonfungiblePositionManager_default = [
|
|
|
2391
2401
|
{ stateMutability: "payable", type: "receive" }
|
|
2392
2402
|
];
|
|
2393
2403
|
|
|
2394
|
-
// src/abi/SelfPermit.
|
|
2395
|
-
var
|
|
2404
|
+
// src/abi/SelfPermit.ts
|
|
2405
|
+
var selfPermitABI = [
|
|
2396
2406
|
{
|
|
2397
2407
|
inputs: [
|
|
2398
2408
|
{
|
|
@@ -2558,28 +2568,22 @@ var _SelfPermit = class {
|
|
|
2558
2568
|
constructor() {
|
|
2559
2569
|
}
|
|
2560
2570
|
static encodePermit(token, options) {
|
|
2561
|
-
return isAllowedPermit(options) ?
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
toHex(options.amount),
|
|
2571
|
-
toHex(options.deadline),
|
|
2572
|
-
options.v,
|
|
2573
|
-
options.r,
|
|
2574
|
-
options.s
|
|
2575
|
-
]);
|
|
2571
|
+
return isAllowedPermit(options) ? encodeFunctionData({
|
|
2572
|
+
abi: _SelfPermit.ABI,
|
|
2573
|
+
functionName: "selfPermitAllowed",
|
|
2574
|
+
args: [token.address, BigInt(options.nonce), BigInt(options.expiry), options.v, options.r, options.s]
|
|
2575
|
+
}) : encodeFunctionData({
|
|
2576
|
+
abi: _SelfPermit.ABI,
|
|
2577
|
+
functionName: "selfPermit",
|
|
2578
|
+
args: [token.address, BigInt(options.amount), BigInt(options.deadline), options.v, options.r, options.s]
|
|
2579
|
+
});
|
|
2576
2580
|
}
|
|
2577
2581
|
};
|
|
2578
2582
|
var SelfPermit = _SelfPermit;
|
|
2579
|
-
SelfPermit.
|
|
2583
|
+
SelfPermit.ABI = selfPermitABI;
|
|
2580
2584
|
|
|
2581
|
-
// src/abi/
|
|
2582
|
-
var
|
|
2585
|
+
// src/abi/PeripheryPaymentsWithFee.ts
|
|
2586
|
+
var peripheryPaymentsWithFeeABI = [
|
|
2583
2587
|
{
|
|
2584
2588
|
inputs: [],
|
|
2585
2589
|
name: "refundETH",
|
|
@@ -2699,46 +2703,47 @@ var _Payments = class {
|
|
|
2699
2703
|
constructor() {
|
|
2700
2704
|
}
|
|
2701
2705
|
static encodeFeeBips(fee) {
|
|
2702
|
-
return
|
|
2706
|
+
return fee.multiply(1e4).quotient;
|
|
2703
2707
|
}
|
|
2704
2708
|
static encodeUnwrapWETH9(amountMinimum, recipient, feeOptions) {
|
|
2705
2709
|
recipient = validateAndParseAddress(recipient);
|
|
2706
2710
|
if (feeOptions) {
|
|
2707
2711
|
const feeBips = this.encodeFeeBips(feeOptions.fee);
|
|
2708
2712
|
const feeRecipient = validateAndParseAddress(feeOptions.recipient);
|
|
2709
|
-
return
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
feeBips,
|
|
2713
|
-
|
|
2714
|
-
]);
|
|
2713
|
+
return encodeFunctionData({
|
|
2714
|
+
abi: _Payments.ABI,
|
|
2715
|
+
functionName: "unwrapWETH9WithFee",
|
|
2716
|
+
args: [amountMinimum, recipient, feeBips, feeRecipient]
|
|
2717
|
+
});
|
|
2715
2718
|
}
|
|
2716
|
-
return _Payments.
|
|
2719
|
+
return encodeFunctionData({ abi: _Payments.ABI, functionName: "unwrapWETH9", args: [amountMinimum, recipient] });
|
|
2717
2720
|
}
|
|
2718
2721
|
static encodeSweepToken(token, amountMinimum, recipient, feeOptions) {
|
|
2719
2722
|
recipient = validateAndParseAddress(recipient);
|
|
2720
2723
|
if (feeOptions) {
|
|
2721
2724
|
const feeBips = this.encodeFeeBips(feeOptions.fee);
|
|
2722
2725
|
const feeRecipient = validateAndParseAddress(feeOptions.recipient);
|
|
2723
|
-
return
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
recipient,
|
|
2727
|
-
|
|
2728
|
-
feeRecipient
|
|
2729
|
-
]);
|
|
2726
|
+
return encodeFunctionData({
|
|
2727
|
+
abi: _Payments.ABI,
|
|
2728
|
+
functionName: "sweepTokenWithFee",
|
|
2729
|
+
args: [token.address, amountMinimum, recipient, feeBips, feeRecipient]
|
|
2730
|
+
});
|
|
2730
2731
|
}
|
|
2731
|
-
return
|
|
2732
|
+
return encodeFunctionData({
|
|
2733
|
+
abi: _Payments.ABI,
|
|
2734
|
+
functionName: "sweepToken",
|
|
2735
|
+
args: [token.address, amountMinimum, recipient]
|
|
2736
|
+
});
|
|
2732
2737
|
}
|
|
2733
2738
|
static encodeRefundETH() {
|
|
2734
|
-
return _Payments.
|
|
2739
|
+
return encodeFunctionData({ abi: _Payments.ABI, functionName: "refundETH" });
|
|
2735
2740
|
}
|
|
2736
2741
|
};
|
|
2737
2742
|
var Payments = _Payments;
|
|
2738
|
-
Payments.
|
|
2743
|
+
Payments.ABI = peripheryPaymentsWithFeeABI;
|
|
2739
2744
|
|
|
2740
2745
|
// src/nonfungiblePositionManager.ts
|
|
2741
|
-
var MaxUint128 =
|
|
2746
|
+
var MaxUint128 = 2n ** 128n - 1n;
|
|
2742
2747
|
function isMint(options) {
|
|
2743
2748
|
return Object.keys(options).some((k) => k === "recipient");
|
|
2744
2749
|
}
|
|
@@ -2750,12 +2755,11 @@ var _NonfungiblePositionManager = class {
|
|
|
2750
2755
|
constructor() {
|
|
2751
2756
|
}
|
|
2752
2757
|
static encodeCreate(pool) {
|
|
2753
|
-
return
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
pool.fee,
|
|
2757
|
-
|
|
2758
|
-
]);
|
|
2758
|
+
return encodeFunctionData({
|
|
2759
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2760
|
+
functionName: "createAndInitializePoolIfNecessary",
|
|
2761
|
+
args: [pool.token0.address, pool.token1.address, pool.fee, pool.sqrtRatioX96]
|
|
2762
|
+
});
|
|
2759
2763
|
}
|
|
2760
2764
|
static createCallParameters(pool) {
|
|
2761
2765
|
return {
|
|
@@ -2764,13 +2768,13 @@ var _NonfungiblePositionManager = class {
|
|
|
2764
2768
|
};
|
|
2765
2769
|
}
|
|
2766
2770
|
static addCallParameters(position, options) {
|
|
2767
|
-
|
|
2771
|
+
invariant9(position.liquidity > ZERO, "ZERO_LIQUIDITY");
|
|
2768
2772
|
const calldatas = [];
|
|
2769
2773
|
const { amount0: amount0Desired, amount1: amount1Desired } = position.mintAmounts;
|
|
2770
2774
|
const minimumAmounts = position.mintAmountsWithSlippage(options.slippageTolerance);
|
|
2771
|
-
const amount0Min =
|
|
2772
|
-
const amount1Min =
|
|
2773
|
-
const deadline =
|
|
2775
|
+
const amount0Min = minimumAmounts.amount0;
|
|
2776
|
+
const amount1Min = minimumAmounts.amount1;
|
|
2777
|
+
const deadline = BigInt(options.deadline);
|
|
2774
2778
|
if (isMint(options) && options.createPool) {
|
|
2775
2779
|
calldatas.push(this.encodeCreate(position.pool));
|
|
2776
2780
|
}
|
|
@@ -2783,40 +2787,48 @@ var _NonfungiblePositionManager = class {
|
|
|
2783
2787
|
if (isMint(options)) {
|
|
2784
2788
|
const recipient = validateAndParseAddress(options.recipient);
|
|
2785
2789
|
calldatas.push(
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2790
|
+
encodeFunctionData({
|
|
2791
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2792
|
+
functionName: "mint",
|
|
2793
|
+
args: [
|
|
2794
|
+
{
|
|
2795
|
+
token0: position.pool.token0.address,
|
|
2796
|
+
token1: position.pool.token1.address,
|
|
2797
|
+
fee: position.pool.fee,
|
|
2798
|
+
tickLower: position.tickLower,
|
|
2799
|
+
tickUpper: position.tickUpper,
|
|
2800
|
+
amount0Desired,
|
|
2801
|
+
amount1Desired,
|
|
2802
|
+
amount0Min,
|
|
2803
|
+
amount1Min,
|
|
2804
|
+
recipient,
|
|
2805
|
+
deadline
|
|
2806
|
+
}
|
|
2807
|
+
]
|
|
2808
|
+
})
|
|
2801
2809
|
);
|
|
2802
2810
|
} else {
|
|
2803
2811
|
calldatas.push(
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2812
|
+
encodeFunctionData({
|
|
2813
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2814
|
+
functionName: "increaseLiquidity",
|
|
2815
|
+
args: [
|
|
2816
|
+
{
|
|
2817
|
+
tokenId: BigInt(options.tokenId),
|
|
2818
|
+
amount0Desired,
|
|
2819
|
+
amount1Desired,
|
|
2820
|
+
amount0Min,
|
|
2821
|
+
amount1Min,
|
|
2822
|
+
deadline
|
|
2823
|
+
}
|
|
2824
|
+
]
|
|
2825
|
+
})
|
|
2814
2826
|
);
|
|
2815
2827
|
}
|
|
2816
2828
|
let value = toHex(0);
|
|
2817
2829
|
if (options.useNative) {
|
|
2818
2830
|
const { wrapped } = options.useNative;
|
|
2819
|
-
|
|
2831
|
+
invariant9(position.pool.token0.equals(wrapped) || position.pool.token1.equals(wrapped), "NO_WETH");
|
|
2820
2832
|
const wrappedValue = position.pool.token0.equals(wrapped) ? amount0Desired : amount1Desired;
|
|
2821
2833
|
if (wrappedValue > ZERO) {
|
|
2822
2834
|
calldatas.push(Payments.encodeRefundETH());
|
|
@@ -2830,18 +2842,22 @@ var _NonfungiblePositionManager = class {
|
|
|
2830
2842
|
}
|
|
2831
2843
|
static encodeCollect(options) {
|
|
2832
2844
|
const calldatas = [];
|
|
2833
|
-
const tokenId =
|
|
2845
|
+
const tokenId = BigInt(options.tokenId);
|
|
2834
2846
|
const involvesETH = options.expectedCurrencyOwed0.currency.isNative || options.expectedCurrencyOwed1.currency.isNative;
|
|
2835
2847
|
const recipient = validateAndParseAddress(options.recipient);
|
|
2836
2848
|
calldatas.push(
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2849
|
+
encodeFunctionData({
|
|
2850
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2851
|
+
functionName: "collect",
|
|
2852
|
+
args: [
|
|
2853
|
+
{
|
|
2854
|
+
tokenId,
|
|
2855
|
+
recipient: involvesETH ? ADDRESS_ZERO : recipient,
|
|
2856
|
+
amount0Max: MaxUint128,
|
|
2857
|
+
amount1Max: MaxUint128
|
|
2858
|
+
}
|
|
2859
|
+
]
|
|
2860
|
+
})
|
|
2845
2861
|
);
|
|
2846
2862
|
if (involvesETH) {
|
|
2847
2863
|
const ethAmount = options.expectedCurrencyOwed0.currency.isNative ? options.expectedCurrencyOwed0.quotient : options.expectedCurrencyOwed1.quotient;
|
|
@@ -2867,40 +2883,48 @@ var _NonfungiblePositionManager = class {
|
|
|
2867
2883
|
*/
|
|
2868
2884
|
static removeCallParameters(position, options) {
|
|
2869
2885
|
const calldatas = [];
|
|
2870
|
-
const deadline =
|
|
2871
|
-
const tokenId =
|
|
2886
|
+
const deadline = BigInt(options.deadline);
|
|
2887
|
+
const tokenId = BigInt(options.tokenId);
|
|
2872
2888
|
const partialPosition = new Position({
|
|
2873
2889
|
pool: position.pool,
|
|
2874
2890
|
liquidity: options.liquidityPercentage.multiply(position.liquidity).quotient,
|
|
2875
2891
|
tickLower: position.tickLower,
|
|
2876
2892
|
tickUpper: position.tickUpper
|
|
2877
2893
|
});
|
|
2878
|
-
|
|
2894
|
+
invariant9(partialPosition.liquidity > ZERO, "ZERO_LIQUIDITY");
|
|
2879
2895
|
const { amount0: amount0Min, amount1: amount1Min } = partialPosition.burnAmountsWithSlippage(
|
|
2880
2896
|
options.slippageTolerance
|
|
2881
2897
|
);
|
|
2882
2898
|
if (options.permit) {
|
|
2883
2899
|
calldatas.push(
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2900
|
+
encodeFunctionData({
|
|
2901
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2902
|
+
functionName: "permit",
|
|
2903
|
+
args: [
|
|
2904
|
+
validateAndParseAddress(options.permit.spender),
|
|
2905
|
+
tokenId,
|
|
2906
|
+
BigInt(options.permit.deadline),
|
|
2907
|
+
options.permit.v,
|
|
2908
|
+
options.permit.r,
|
|
2909
|
+
options.permit.s
|
|
2910
|
+
]
|
|
2911
|
+
})
|
|
2892
2912
|
);
|
|
2893
2913
|
}
|
|
2894
2914
|
calldatas.push(
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2915
|
+
encodeFunctionData({
|
|
2916
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2917
|
+
functionName: "decreaseLiquidity",
|
|
2918
|
+
args: [
|
|
2919
|
+
{
|
|
2920
|
+
tokenId,
|
|
2921
|
+
liquidity: partialPosition.liquidity,
|
|
2922
|
+
amount0Min,
|
|
2923
|
+
amount1Min,
|
|
2924
|
+
deadline
|
|
2925
|
+
}
|
|
2926
|
+
]
|
|
2927
|
+
})
|
|
2904
2928
|
);
|
|
2905
2929
|
const { expectedCurrencyOwed0, expectedCurrencyOwed1, ...rest } = options.collectOptions;
|
|
2906
2930
|
calldatas.push(
|
|
@@ -2918,10 +2942,12 @@ var _NonfungiblePositionManager = class {
|
|
|
2918
2942
|
);
|
|
2919
2943
|
if (options.liquidityPercentage.equalTo(ONE)) {
|
|
2920
2944
|
if (options.burnToken) {
|
|
2921
|
-
calldatas.push(
|
|
2945
|
+
calldatas.push(
|
|
2946
|
+
encodeFunctionData({ abi: _NonfungiblePositionManager.ABI, functionName: "burn", args: [tokenId] })
|
|
2947
|
+
);
|
|
2922
2948
|
}
|
|
2923
2949
|
} else {
|
|
2924
|
-
|
|
2950
|
+
invariant9(options.burnToken !== true, "CANNOT_BURN");
|
|
2925
2951
|
}
|
|
2926
2952
|
return {
|
|
2927
2953
|
calldata: Multicall.encodeMulticall(calldatas),
|
|
@@ -2933,16 +2959,17 @@ var _NonfungiblePositionManager = class {
|
|
|
2933
2959
|
const sender = validateAndParseAddress(options.sender);
|
|
2934
2960
|
let calldata;
|
|
2935
2961
|
if (options.data) {
|
|
2936
|
-
calldata =
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2962
|
+
calldata = encodeFunctionData({
|
|
2963
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2964
|
+
functionName: "safeTransferFrom",
|
|
2965
|
+
args: [sender, recipient, BigInt(options.tokenId), options.data]
|
|
2966
|
+
});
|
|
2940
2967
|
} else {
|
|
2941
|
-
calldata =
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2968
|
+
calldata = encodeFunctionData({
|
|
2969
|
+
abi: _NonfungiblePositionManager.ABI,
|
|
2970
|
+
functionName: "safeTransferFrom",
|
|
2971
|
+
args: [sender, recipient, BigInt(options.tokenId)]
|
|
2972
|
+
});
|
|
2946
2973
|
}
|
|
2947
2974
|
return {
|
|
2948
2975
|
calldata,
|
|
@@ -2951,10 +2978,10 @@ var _NonfungiblePositionManager = class {
|
|
|
2951
2978
|
}
|
|
2952
2979
|
};
|
|
2953
2980
|
var NonfungiblePositionManager = _NonfungiblePositionManager;
|
|
2954
|
-
NonfungiblePositionManager.
|
|
2981
|
+
NonfungiblePositionManager.ABI = nonfungiblePositionManagerABI;
|
|
2955
2982
|
|
|
2956
|
-
// src/abi/Quoter.
|
|
2957
|
-
var
|
|
2983
|
+
// src/abi/Quoter.ts
|
|
2984
|
+
var quoterABI = [
|
|
2958
2985
|
{
|
|
2959
2986
|
inputs: [
|
|
2960
2987
|
{
|
|
@@ -3166,8 +3193,8 @@ var Quoter_default = [
|
|
|
3166
3193
|
}
|
|
3167
3194
|
];
|
|
3168
3195
|
|
|
3169
|
-
// src/abi/QuoterV2.
|
|
3170
|
-
var
|
|
3196
|
+
// src/abi/QuoterV2.ts
|
|
3197
|
+
var quoterV2ABI = [
|
|
3171
3198
|
{
|
|
3172
3199
|
inputs: [
|
|
3173
3200
|
{
|
|
@@ -3468,19 +3495,19 @@ var SwapQuoter = class {
|
|
|
3468
3495
|
*/
|
|
3469
3496
|
static quoteCallParameters(route, amount, tradeType, options = {}) {
|
|
3470
3497
|
const singleHop = route.pools.length === 1;
|
|
3471
|
-
const quoteAmount =
|
|
3498
|
+
const quoteAmount = amount.quotient;
|
|
3472
3499
|
let calldata;
|
|
3473
|
-
const
|
|
3500
|
+
const swapAbi = options.useQuoterV2 ? this.V2ABI : this.V1ABI;
|
|
3474
3501
|
if (singleHop) {
|
|
3475
3502
|
const baseQuoteParams = {
|
|
3476
3503
|
tokenIn: route.tokenPath[0].address,
|
|
3477
3504
|
tokenOut: route.tokenPath[1].address,
|
|
3478
3505
|
fee: route.pools[0].fee,
|
|
3479
|
-
sqrtPriceLimitX96:
|
|
3506
|
+
sqrtPriceLimitX96: BigInt(options?.sqrtPriceLimitX96 ?? 0)
|
|
3480
3507
|
};
|
|
3481
3508
|
const v2QuoteParams = {
|
|
3482
3509
|
...baseQuoteParams,
|
|
3483
|
-
...tradeType
|
|
3510
|
+
...tradeType === TradeType$1.EXACT_INPUT ? { amountIn: quoteAmount } : { amount: quoteAmount }
|
|
3484
3511
|
};
|
|
3485
3512
|
const v1QuoteParams = [
|
|
3486
3513
|
baseQuoteParams.tokenIn,
|
|
@@ -3489,16 +3516,31 @@ var SwapQuoter = class {
|
|
|
3489
3516
|
quoteAmount,
|
|
3490
3517
|
baseQuoteParams.sqrtPriceLimitX96
|
|
3491
3518
|
];
|
|
3492
|
-
const tradeTypeFunctionName = tradeType === TradeType.EXACT_INPUT ? "quoteExactInputSingle" : "quoteExactOutputSingle";
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3519
|
+
const tradeTypeFunctionName = tradeType === TradeType$1.EXACT_INPUT ? "quoteExactInputSingle" : "quoteExactOutputSingle";
|
|
3520
|
+
if (options.useQuoterV2) {
|
|
3521
|
+
calldata = encodeFunctionData({
|
|
3522
|
+
abi: this.V2ABI,
|
|
3523
|
+
functionName: tradeTypeFunctionName,
|
|
3524
|
+
// @ts-ignore // FIXME
|
|
3525
|
+
args: [v2QuoteParams]
|
|
3526
|
+
});
|
|
3527
|
+
} else {
|
|
3528
|
+
calldata = encodeFunctionData({
|
|
3529
|
+
abi: this.V1ABI,
|
|
3530
|
+
functionName: tradeTypeFunctionName,
|
|
3531
|
+
args: v1QuoteParams
|
|
3532
|
+
});
|
|
3533
|
+
}
|
|
3497
3534
|
} else {
|
|
3498
|
-
|
|
3499
|
-
const path = encodeRouteToPath(route, tradeType === TradeType.EXACT_OUTPUT);
|
|
3500
|
-
const tradeTypeFunctionName = tradeType === TradeType.EXACT_INPUT ? "quoteExactInput" : "quoteExactOutput";
|
|
3501
|
-
calldata =
|
|
3535
|
+
invariant9(options?.sqrtPriceLimitX96 === void 0, "MULTIHOP_PRICE_LIMIT");
|
|
3536
|
+
const path = encodeRouteToPath(route, tradeType === TradeType$1.EXACT_OUTPUT);
|
|
3537
|
+
const tradeTypeFunctionName = tradeType === TradeType$1.EXACT_INPUT ? "quoteExactInput" : "quoteExactOutput";
|
|
3538
|
+
calldata = encodeFunctionData({
|
|
3539
|
+
// @ts-ignore
|
|
3540
|
+
abi: swapAbi,
|
|
3541
|
+
functionName: tradeTypeFunctionName,
|
|
3542
|
+
args: [path, quoteAmount]
|
|
3543
|
+
});
|
|
3502
3544
|
}
|
|
3503
3545
|
return {
|
|
3504
3546
|
calldata,
|
|
@@ -3506,11 +3548,11 @@ var SwapQuoter = class {
|
|
|
3506
3548
|
};
|
|
3507
3549
|
}
|
|
3508
3550
|
};
|
|
3509
|
-
SwapQuoter.
|
|
3510
|
-
SwapQuoter.
|
|
3551
|
+
SwapQuoter.V1ABI = quoterABI;
|
|
3552
|
+
SwapQuoter.V2ABI = quoterV2ABI;
|
|
3511
3553
|
|
|
3512
|
-
// src/abi/V3Staker.
|
|
3513
|
-
var
|
|
3554
|
+
// src/abi/V3Staker.ts
|
|
3555
|
+
var v3StakerABI = [
|
|
3514
3556
|
{
|
|
3515
3557
|
inputs: [
|
|
3516
3558
|
{
|
|
@@ -4230,15 +4272,20 @@ var _Staker = class {
|
|
|
4230
4272
|
static encodeClaim(incentiveKey, options) {
|
|
4231
4273
|
const calldatas = [];
|
|
4232
4274
|
calldatas.push(
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4275
|
+
encodeFunctionData({
|
|
4276
|
+
abi: _Staker.ABI,
|
|
4277
|
+
functionName: "unstakeToken",
|
|
4278
|
+
args: [this._encodeIncentiveKey(incentiveKey), BigInt(options.tokenId)]
|
|
4279
|
+
})
|
|
4237
4280
|
);
|
|
4238
4281
|
const recipient = validateAndParseAddress(options.recipient);
|
|
4239
4282
|
const amount = options.amount ?? 0;
|
|
4240
4283
|
calldatas.push(
|
|
4241
|
-
|
|
4284
|
+
encodeFunctionData({
|
|
4285
|
+
abi: _Staker.ABI,
|
|
4286
|
+
functionName: "claimReward",
|
|
4287
|
+
args: [incentiveKey.rewardToken.address, recipient, BigInt(amount)]
|
|
4288
|
+
})
|
|
4242
4289
|
);
|
|
4243
4290
|
return calldatas;
|
|
4244
4291
|
}
|
|
@@ -4258,10 +4305,11 @@ var _Staker = class {
|
|
|
4258
4305
|
const incentiveKey = incentiveKeys[i];
|
|
4259
4306
|
calldatas = calldatas.concat(this.encodeClaim(incentiveKey, options));
|
|
4260
4307
|
calldatas.push(
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4308
|
+
encodeFunctionData({
|
|
4309
|
+
abi: _Staker.ABI,
|
|
4310
|
+
functionName: "stakeToken",
|
|
4311
|
+
args: [this._encodeIncentiveKey(incentiveKey), BigInt(options.tokenId)]
|
|
4312
|
+
})
|
|
4265
4313
|
);
|
|
4266
4314
|
}
|
|
4267
4315
|
return {
|
|
@@ -4289,11 +4337,11 @@ var _Staker = class {
|
|
|
4289
4337
|
}
|
|
4290
4338
|
const owner = validateAndParseAddress(withdrawOptions.owner);
|
|
4291
4339
|
calldatas.push(
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4340
|
+
encodeFunctionData({
|
|
4341
|
+
abi: _Staker.ABI,
|
|
4342
|
+
functionName: "withdrawToken",
|
|
4343
|
+
args: [BigInt(withdrawOptions.tokenId), owner, toHex(0)]
|
|
4344
|
+
})
|
|
4297
4345
|
);
|
|
4298
4346
|
return {
|
|
4299
4347
|
calldata: Multicall.encodeMulticall(calldatas),
|
|
@@ -4314,16 +4362,18 @@ var _Staker = class {
|
|
|
4314
4362
|
const incentiveKey = incentiveKeys[i];
|
|
4315
4363
|
keys.push(this._encodeIncentiveKey(incentiveKey));
|
|
4316
4364
|
}
|
|
4317
|
-
data =
|
|
4365
|
+
data = encodeAbiParameters(parseAbiParameters([`${_Staker.INCENTIVE_KEY_ABI}[]`]), [keys]);
|
|
4318
4366
|
} else {
|
|
4319
|
-
data =
|
|
4367
|
+
data = encodeAbiParameters(parseAbiParameters(_Staker.INCENTIVE_KEY_ABI), [
|
|
4368
|
+
this._encodeIncentiveKey(incentiveKeys[0])
|
|
4369
|
+
]);
|
|
4320
4370
|
}
|
|
4321
4371
|
return data;
|
|
4322
4372
|
}
|
|
4323
4373
|
/**
|
|
4324
4374
|
*
|
|
4325
4375
|
* @param incentiveKey An `IncentiveKey` which represents a unique staking program.
|
|
4326
|
-
* @returns An encoded IncentiveKey to be read by
|
|
4376
|
+
* @returns An encoded IncentiveKey to be read by viem
|
|
4327
4377
|
*/
|
|
4328
4378
|
static _encodeIncentiveKey(incentiveKey) {
|
|
4329
4379
|
const { token0, token1, fee } = incentiveKey.pool;
|
|
@@ -4331,18 +4381,18 @@ var _Staker = class {
|
|
|
4331
4381
|
return {
|
|
4332
4382
|
rewardToken: incentiveKey.rewardToken.address,
|
|
4333
4383
|
pool: Pool.getAddress(token0, token1, fee),
|
|
4334
|
-
startTime:
|
|
4335
|
-
endTime:
|
|
4384
|
+
startTime: BigInt(incentiveKey.startTime),
|
|
4385
|
+
endTime: BigInt(incentiveKey.endTime),
|
|
4336
4386
|
refundee
|
|
4337
4387
|
};
|
|
4338
4388
|
}
|
|
4339
4389
|
};
|
|
4340
4390
|
var Staker = _Staker;
|
|
4341
|
-
Staker.
|
|
4391
|
+
Staker.ABI = v3StakerABI;
|
|
4342
4392
|
Staker.INCENTIVE_KEY_ABI = "tuple(address rewardToken, address pool, uint256 startTime, uint256 endTime, address refundee)";
|
|
4343
4393
|
|
|
4344
|
-
// src/abi/SwapRouter.
|
|
4345
|
-
var
|
|
4394
|
+
// src/abi/SwapRouter.ts
|
|
4395
|
+
var swapRouterABI = [
|
|
4346
4396
|
{
|
|
4347
4397
|
inputs: [
|
|
4348
4398
|
{
|
|
@@ -4945,11 +4995,11 @@ var _SwapRouter = class {
|
|
|
4945
4995
|
const sampleTrade = trades[0];
|
|
4946
4996
|
const tokenIn = sampleTrade.inputAmount.currency.wrapped;
|
|
4947
4997
|
const tokenOut = sampleTrade.outputAmount.currency.wrapped;
|
|
4948
|
-
|
|
4998
|
+
invariant9(
|
|
4949
4999
|
trades.every((trade) => trade.inputAmount.currency.wrapped.equals(tokenIn)),
|
|
4950
5000
|
"TOKEN_IN_DIFF"
|
|
4951
5001
|
);
|
|
4952
|
-
|
|
5002
|
+
invariant9(
|
|
4953
5003
|
trades.every((trade) => trade.outputAmount.currency.wrapped.equals(tokenOut)),
|
|
4954
5004
|
"TOKEN_OUT_DIFF"
|
|
4955
5005
|
);
|
|
@@ -4966,15 +5016,15 @@ var _SwapRouter = class {
|
|
|
4966
5016
|
const routerMustCustody = outputIsNative || !!options.fee;
|
|
4967
5017
|
const totalValue = inputIsNative ? trades.reduce((sum, trade) => sum.add(trade.maximumAmountIn(options.slippageTolerance)), ZERO_IN) : ZERO_IN;
|
|
4968
5018
|
if (options.inputTokenPermit) {
|
|
4969
|
-
|
|
5019
|
+
invariant9(sampleTrade.inputAmount.currency.isToken, "NON_TOKEN_PERMIT");
|
|
4970
5020
|
calldatas.push(SelfPermit.encodePermit(sampleTrade.inputAmount.currency, options.inputTokenPermit));
|
|
4971
5021
|
}
|
|
4972
5022
|
const recipient = validateAndParseAddress(options.recipient);
|
|
4973
|
-
const deadline =
|
|
5023
|
+
const deadline = BigInt(options.deadline);
|
|
4974
5024
|
for (const trade of trades) {
|
|
4975
5025
|
for (const { route, inputAmount, outputAmount } of trade.swaps) {
|
|
4976
|
-
const amountIn =
|
|
4977
|
-
const amountOut =
|
|
5026
|
+
const amountIn = BigInt(trade.maximumAmountIn(options.slippageTolerance, inputAmount).quotient);
|
|
5027
|
+
const amountOut = BigInt(trade.minimumAmountOut(options.slippageTolerance, outputAmount).quotient);
|
|
4978
5028
|
const singleHop = route.pools.length === 1;
|
|
4979
5029
|
if (singleHop) {
|
|
4980
5030
|
if (trade.tradeType === TradeType.EXACT_INPUT) {
|
|
@@ -4986,9 +5036,15 @@ var _SwapRouter = class {
|
|
|
4986
5036
|
deadline,
|
|
4987
5037
|
amountIn,
|
|
4988
5038
|
amountOutMinimum: amountOut,
|
|
4989
|
-
sqrtPriceLimitX96:
|
|
5039
|
+
sqrtPriceLimitX96: BigInt(options.sqrtPriceLimitX96 ?? 0)
|
|
4990
5040
|
};
|
|
4991
|
-
calldatas.push(
|
|
5041
|
+
calldatas.push(
|
|
5042
|
+
encodeFunctionData({
|
|
5043
|
+
abi: _SwapRouter.ABI,
|
|
5044
|
+
functionName: "exactInputSingle",
|
|
5045
|
+
args: [exactInputSingleParams]
|
|
5046
|
+
})
|
|
5047
|
+
);
|
|
4992
5048
|
} else {
|
|
4993
5049
|
const exactOutputSingleParams = {
|
|
4994
5050
|
tokenIn: route.tokenPath[0].address,
|
|
@@ -4998,12 +5054,18 @@ var _SwapRouter = class {
|
|
|
4998
5054
|
deadline,
|
|
4999
5055
|
amountOut,
|
|
5000
5056
|
amountInMaximum: amountIn,
|
|
5001
|
-
sqrtPriceLimitX96:
|
|
5057
|
+
sqrtPriceLimitX96: BigInt(options.sqrtPriceLimitX96 ?? 0)
|
|
5002
5058
|
};
|
|
5003
|
-
calldatas.push(
|
|
5059
|
+
calldatas.push(
|
|
5060
|
+
encodeFunctionData({
|
|
5061
|
+
abi: _SwapRouter.ABI,
|
|
5062
|
+
functionName: "exactOutputSingle",
|
|
5063
|
+
args: [exactOutputSingleParams]
|
|
5064
|
+
})
|
|
5065
|
+
);
|
|
5004
5066
|
}
|
|
5005
5067
|
} else {
|
|
5006
|
-
|
|
5068
|
+
invariant9(options.sqrtPriceLimitX96 === void 0, "MULTIHOP_PRICE_LIMIT");
|
|
5007
5069
|
const path = encodeRouteToPath(route, trade.tradeType === TradeType.EXACT_OUTPUT);
|
|
5008
5070
|
if (trade.tradeType === TradeType.EXACT_INPUT) {
|
|
5009
5071
|
const exactInputParams = {
|
|
@@ -5013,7 +5075,9 @@ var _SwapRouter = class {
|
|
|
5013
5075
|
amountIn,
|
|
5014
5076
|
amountOutMinimum: amountOut
|
|
5015
5077
|
};
|
|
5016
|
-
calldatas.push(
|
|
5078
|
+
calldatas.push(
|
|
5079
|
+
encodeFunctionData({ abi: _SwapRouter.ABI, functionName: "exactInput", args: [exactInputParams] })
|
|
5080
|
+
);
|
|
5017
5081
|
} else {
|
|
5018
5082
|
const exactOutputParams = {
|
|
5019
5083
|
path,
|
|
@@ -5022,7 +5086,9 @@ var _SwapRouter = class {
|
|
|
5022
5086
|
amountOut,
|
|
5023
5087
|
amountInMaximum: amountIn
|
|
5024
5088
|
};
|
|
5025
|
-
calldatas.push(
|
|
5089
|
+
calldatas.push(
|
|
5090
|
+
encodeFunctionData({ abi: _SwapRouter.ABI, functionName: "exactOutput", args: [exactOutputParams] })
|
|
5091
|
+
);
|
|
5026
5092
|
}
|
|
5027
5093
|
}
|
|
5028
5094
|
}
|
|
@@ -5055,10 +5121,11 @@ var _SwapRouter = class {
|
|
|
5055
5121
|
}
|
|
5056
5122
|
};
|
|
5057
5123
|
var SwapRouter = _SwapRouter;
|
|
5058
|
-
|
|
5124
|
+
// public static INTERFACE: Interface = new Interface(ISwapRouter)
|
|
5125
|
+
SwapRouter.ABI = swapRouterABI;
|
|
5059
5126
|
|
|
5060
|
-
// src/abi/MasterChefV3.
|
|
5061
|
-
var
|
|
5127
|
+
// src/abi/MasterChefV3.ts
|
|
5128
|
+
var masterChefV3ABI = [
|
|
5062
5129
|
{
|
|
5063
5130
|
inputs: [
|
|
5064
5131
|
{ internalType: "contract IERC20", name: "_CAKE", type: "address" },
|
|
@@ -5746,14 +5813,14 @@ var _MasterChefV3 = class {
|
|
|
5746
5813
|
// Copy from NonfungiblePositionManager
|
|
5747
5814
|
// Only support increaseLiquidity
|
|
5748
5815
|
static addCallParameters(position, options) {
|
|
5749
|
-
|
|
5816
|
+
invariant9(position.liquidity > ZERO$2, "ZERO_LIQUIDITY");
|
|
5750
5817
|
const calldatas = [];
|
|
5751
5818
|
const { amount0: amount0Desired, amount1: amount1Desired } = position.mintAmounts;
|
|
5752
5819
|
const minimumAmounts = position.mintAmountsWithSlippage(options.slippageTolerance);
|
|
5753
|
-
const amount0Min =
|
|
5754
|
-
const amount1Min =
|
|
5755
|
-
const deadline =
|
|
5756
|
-
|
|
5820
|
+
const amount0Min = BigInt(minimumAmounts.amount0);
|
|
5821
|
+
const amount1Min = BigInt(minimumAmounts.amount1);
|
|
5822
|
+
const deadline = BigInt(options.deadline);
|
|
5823
|
+
invariant9(!isMint(options), "NO_MINT_SUPPORT");
|
|
5757
5824
|
if (options.token0Permit) {
|
|
5758
5825
|
calldatas.push(SelfPermit.encodePermit(position.pool.token0, options.token0Permit));
|
|
5759
5826
|
}
|
|
@@ -5761,21 +5828,25 @@ var _MasterChefV3 = class {
|
|
|
5761
5828
|
calldatas.push(SelfPermit.encodePermit(position.pool.token1, options.token1Permit));
|
|
5762
5829
|
}
|
|
5763
5830
|
calldatas.push(
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5831
|
+
encodeFunctionData({
|
|
5832
|
+
abi: _MasterChefV3.ABI,
|
|
5833
|
+
functionName: "increaseLiquidity",
|
|
5834
|
+
args: [
|
|
5835
|
+
{
|
|
5836
|
+
tokenId: BigInt(options.tokenId),
|
|
5837
|
+
amount0Desired,
|
|
5838
|
+
amount1Desired,
|
|
5839
|
+
amount0Min,
|
|
5840
|
+
amount1Min,
|
|
5841
|
+
deadline
|
|
5842
|
+
}
|
|
5843
|
+
]
|
|
5844
|
+
})
|
|
5774
5845
|
);
|
|
5775
5846
|
let value = toHex(0);
|
|
5776
5847
|
if (options.useNative) {
|
|
5777
5848
|
const { wrapped } = options.useNative;
|
|
5778
|
-
|
|
5849
|
+
invariant9(position.pool.token0.equals(wrapped) || position.pool.token1.equals(wrapped), "NO_WETH");
|
|
5779
5850
|
const wrappedValue = position.pool.token0.equals(wrapped) ? amount0Desired : amount1Desired;
|
|
5780
5851
|
value = toHex(wrappedValue);
|
|
5781
5852
|
}
|
|
@@ -5787,18 +5858,22 @@ var _MasterChefV3 = class {
|
|
|
5787
5858
|
// Copy from NonfungiblePositionManager
|
|
5788
5859
|
static encodeCollect(options) {
|
|
5789
5860
|
const calldatas = [];
|
|
5790
|
-
const tokenId =
|
|
5861
|
+
const tokenId = BigInt(options.tokenId);
|
|
5791
5862
|
const involvesETH = options.expectedCurrencyOwed0.currency.isNative || options.expectedCurrencyOwed1.currency.isNative;
|
|
5792
5863
|
const recipient = validateAndParseAddress(options.recipient);
|
|
5793
5864
|
calldatas.push(
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5865
|
+
encodeFunctionData({
|
|
5866
|
+
abi: _MasterChefV3.ABI,
|
|
5867
|
+
functionName: "collect",
|
|
5868
|
+
args: [
|
|
5869
|
+
{
|
|
5870
|
+
tokenId,
|
|
5871
|
+
recipient: involvesETH ? ADDRESS_ZERO : recipient,
|
|
5872
|
+
amount0Max: MaxUint128,
|
|
5873
|
+
amount1Max: MaxUint128
|
|
5874
|
+
}
|
|
5875
|
+
]
|
|
5876
|
+
})
|
|
5802
5877
|
);
|
|
5803
5878
|
if (involvesETH) {
|
|
5804
5879
|
const ethAmount = options.expectedCurrencyOwed0.currency.isNative ? options.expectedCurrencyOwed0.quotient : options.expectedCurrencyOwed1.quotient;
|
|
@@ -5818,40 +5893,35 @@ var _MasterChefV3 = class {
|
|
|
5818
5893
|
}
|
|
5819
5894
|
static removeCallParameters(position, options) {
|
|
5820
5895
|
const calldatas = [];
|
|
5821
|
-
const deadline =
|
|
5822
|
-
const tokenId =
|
|
5896
|
+
const deadline = BigInt(options.deadline);
|
|
5897
|
+
const tokenId = BigInt(options.tokenId);
|
|
5823
5898
|
const partialPosition = new Position({
|
|
5824
5899
|
pool: position.pool,
|
|
5825
5900
|
liquidity: options.liquidityPercentage.multiply(position.liquidity).quotient,
|
|
5826
5901
|
tickLower: position.tickLower,
|
|
5827
5902
|
tickUpper: position.tickUpper
|
|
5828
5903
|
});
|
|
5829
|
-
|
|
5904
|
+
invariant9(partialPosition.liquidity > ZERO$2, "ZERO_LIQUIDITY");
|
|
5830
5905
|
const { amount0: amount0Min, amount1: amount1Min } = partialPosition.burnAmountsWithSlippage(
|
|
5831
5906
|
options.slippageTolerance
|
|
5832
5907
|
);
|
|
5833
5908
|
if (options.permit) {
|
|
5834
|
-
|
|
5835
|
-
_MasterChefV3.INTERFACE.encodeFunctionData("permit", [
|
|
5836
|
-
validateAndParseAddress(options.permit.spender),
|
|
5837
|
-
tokenId,
|
|
5838
|
-
toHex(options.permit.deadline),
|
|
5839
|
-
options.permit.v,
|
|
5840
|
-
options.permit.r,
|
|
5841
|
-
options.permit.s
|
|
5842
|
-
])
|
|
5843
|
-
);
|
|
5909
|
+
throw new Error("NOT_IMPLEMENTED");
|
|
5844
5910
|
}
|
|
5845
5911
|
calldatas.push(
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5912
|
+
encodeFunctionData({
|
|
5913
|
+
abi: _MasterChefV3.ABI,
|
|
5914
|
+
functionName: "decreaseLiquidity",
|
|
5915
|
+
args: [
|
|
5916
|
+
{
|
|
5917
|
+
tokenId,
|
|
5918
|
+
liquidity: partialPosition.liquidity,
|
|
5919
|
+
amount0Min,
|
|
5920
|
+
amount1Min,
|
|
5921
|
+
deadline
|
|
5922
|
+
}
|
|
5923
|
+
]
|
|
5924
|
+
})
|
|
5855
5925
|
);
|
|
5856
5926
|
const { expectedCurrencyOwed0, expectedCurrencyOwed1, ...rest } = options.collectOptions;
|
|
5857
5927
|
calldatas.push(
|
|
@@ -5870,26 +5940,28 @@ var _MasterChefV3 = class {
|
|
|
5870
5940
|
if (rest?.recipient) {
|
|
5871
5941
|
if (options.liquidityPercentage.equalTo(ONE$1)) {
|
|
5872
5942
|
calldatas.push(
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5943
|
+
encodeFunctionData({
|
|
5944
|
+
abi: _MasterChefV3.ABI,
|
|
5945
|
+
functionName: "withdraw",
|
|
5946
|
+
args: [tokenId, validateAndParseAddress(rest?.recipient)]
|
|
5947
|
+
})
|
|
5877
5948
|
);
|
|
5878
5949
|
} else {
|
|
5879
5950
|
calldatas.push(
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5951
|
+
encodeFunctionData({
|
|
5952
|
+
abi: _MasterChefV3.ABI,
|
|
5953
|
+
functionName: "harvest",
|
|
5954
|
+
args: [tokenId, validateAndParseAddress(rest?.recipient)]
|
|
5955
|
+
})
|
|
5884
5956
|
);
|
|
5885
5957
|
}
|
|
5886
5958
|
}
|
|
5887
5959
|
if (options.liquidityPercentage.equalTo(ONE$1)) {
|
|
5888
5960
|
if (options.burnToken) {
|
|
5889
|
-
calldatas.push(_MasterChefV3.
|
|
5961
|
+
calldatas.push(encodeFunctionData({ abi: _MasterChefV3.ABI, functionName: "burn", args: [tokenId] }));
|
|
5890
5962
|
}
|
|
5891
5963
|
} else {
|
|
5892
|
-
|
|
5964
|
+
invariant9(options.burnToken !== true, "CANNOT_BURN");
|
|
5893
5965
|
}
|
|
5894
5966
|
return {
|
|
5895
5967
|
calldata: Multicall.encodeMulticall(calldatas),
|
|
@@ -5915,7 +5987,11 @@ var _MasterChefV3 = class {
|
|
|
5915
5987
|
const { tokenId, to } = options;
|
|
5916
5988
|
const calldatas = [];
|
|
5917
5989
|
calldatas.push(
|
|
5918
|
-
|
|
5990
|
+
encodeFunctionData({
|
|
5991
|
+
abi: _MasterChefV3.ABI,
|
|
5992
|
+
functionName: "harvest",
|
|
5993
|
+
args: [BigInt(tokenId), validateAndParseAddress(to)]
|
|
5994
|
+
})
|
|
5919
5995
|
);
|
|
5920
5996
|
return calldatas;
|
|
5921
5997
|
}
|
|
@@ -5923,7 +5999,11 @@ var _MasterChefV3 = class {
|
|
|
5923
5999
|
const { tokenId, to } = options;
|
|
5924
6000
|
const calldatas = [];
|
|
5925
6001
|
calldatas.push(
|
|
5926
|
-
|
|
6002
|
+
encodeFunctionData({
|
|
6003
|
+
abi: _MasterChefV3.ABI,
|
|
6004
|
+
functionName: "withdraw",
|
|
6005
|
+
args: [BigInt(tokenId), validateAndParseAddress(to)]
|
|
6006
|
+
})
|
|
5927
6007
|
);
|
|
5928
6008
|
return {
|
|
5929
6009
|
calldata: Multicall.encodeMulticall(calldatas),
|
|
@@ -5932,6 +6012,6 @@ var _MasterChefV3 = class {
|
|
|
5932
6012
|
}
|
|
5933
6013
|
};
|
|
5934
6014
|
var MasterChefV3 = _MasterChefV3;
|
|
5935
|
-
MasterChefV3.
|
|
6015
|
+
MasterChefV3.ABI = masterChefV3ABI;
|
|
5936
6016
|
|
|
5937
|
-
export { ADDRESS_ZERO, DEPLOYER_ADDRESS, DEPLOYER_ADDRESSES, FACTORY_ADDRESS, FeeAmount, FeeCalculator, FullMath, LiquidityMath, MasterChefV3, MaxUint128, Multicall, NoTickDataProvider, NonfungiblePositionManager, POOL_INIT_CODE_HASH, Payments, Pool, Position, PositionLibrary, PositionMath, Route, SelfPermit, SqrtPriceMath, Staker, SwapMath, SwapQuoter, SwapRouter, TICK_SPACINGS, Tick, TickLibrary, TickList, TickListDataProvider, TickMath, Trade, computePoolAddress, encodeRouteToPath, encodeSqrtRatioX96, getAmountsAtNewPrice, getAmountsByLiquidityAndPrice, getAverageLiquidity, getDependentAmount, getEstimatedLPFee, getEstimatedLPFeeByAmounts, getEstimatedLPFeeByAmountsWithProtocolFee, getEstimatedLPFeeWithProtocolFee, getLiquidityByAmountsAndPrice, getLiquidityBySingleAmount, getLiquidityFromSqrtRatioX96, getLiquidityFromTick, isMint, isSorted, maxLiquidityForAmounts, mostSignificantBit, nearestUsableTick, parseProtocolFees, priceToClosestTick, sqrtRatioX96ToPrice, subIn256, tickToPrice, toHex, tradeComparator };
|
|
6017
|
+
export { ADDRESS_ZERO, DEPLOYER_ADDRESS, DEPLOYER_ADDRESSES, FACTORY_ADDRESS, FeeAmount, FeeCalculator, FullMath, LiquidityMath, MasterChefV3, MaxUint128, Multicall, NoTickDataProvider, NonfungiblePositionManager, POOL_INIT_CODE_HASH, Payments, Pool, Position, PositionLibrary, PositionMath, Route, SelfPermit, SqrtPriceMath, Staker, SwapMath, SwapQuoter, SwapRouter, TICK_SPACINGS, Tick, TickLibrary, TickList, TickListDataProvider, TickMath, Trade, computePoolAddress, encodeRouteToPath, encodeSqrtRatioX96, getAmountsAtNewPrice, getAmountsByLiquidityAndPrice, getAverageLiquidity, getDependentAmount, getEstimatedLPFee, getEstimatedLPFeeByAmounts, getEstimatedLPFeeByAmountsWithProtocolFee, getEstimatedLPFeeWithProtocolFee, getLiquidityByAmountsAndPrice, getLiquidityBySingleAmount, getLiquidityFromSqrtRatioX96, getLiquidityFromTick, isMint, isSorted, masterChefV3ABI, maxLiquidityForAmounts, mostSignificantBit, nearestUsableTick, nonfungiblePositionManagerABI, parseProtocolFees, peripheryPaymentsWithFeeABI, priceToClosestTick, quoterABI, quoterV2ABI, selfPermitABI, sqrtRatioX96ToPrice, subIn256, swapRouterABI, tickToPrice, toHex, tradeComparator, v3StakerABI };
|