UNPKG

@pancakeswap/v3-sdk

Version:

⚒️ An SDK for building applications on top of Pancakeswap V3

1,222 lines (1,205 loc) 221 kB
'use strict'; var sdk = require('@pancakeswap/sdk'); var invariant9 = require('tiny-invariant'); var chains = require('@pancakeswap/chains'); var swapSdkCore = require('@pancakeswap/swap-sdk-core'); var viem = require('viem'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var invariant9__default = /*#__PURE__*/_interopDefault(invariant9); // src/entities/pool.ts var FACTORY_ADDRESS = "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865"; var FACTORY_ADDRESSES = { [chains.ChainId.ETHEREUM]: FACTORY_ADDRESS, [chains.ChainId.GOERLI]: FACTORY_ADDRESS, [chains.ChainId.BSC]: FACTORY_ADDRESS, [chains.ChainId.BSC_TESTNET]: FACTORY_ADDRESS, [chains.ChainId.ARBITRUM_ONE]: FACTORY_ADDRESS, [chains.ChainId.ARBITRUM_GOERLI]: "0xBA40c83026213F9cbc79998752721a0312bdB74a", [chains.ChainId.POLYGON_ZKEVM]: FACTORY_ADDRESS, [chains.ChainId.POLYGON_ZKEVM_TESTNET]: "0x2430dbd123BC40f8Be6110065a448C1aA0619Cb1", [chains.ChainId.ZKSYNC]: "0x1BB72E0CbbEA93c08f535fc7856E0338D7F7a8aB", [chains.ChainId.ZKSYNC_TESTNET]: "0x48e6Bc3f2546E63908cd09b04E2B3f78e57B6292", [chains.ChainId.LINEA]: FACTORY_ADDRESS, [chains.ChainId.LINEA_TESTNET]: "0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E", [chains.ChainId.OPBNB]: FACTORY_ADDRESS, [chains.ChainId.OPBNB_TESTNET]: "0x0F81fD8DaC20A21029B496D8F8E08385201B8ca0", [chains.ChainId.BASE]: FACTORY_ADDRESS, [chains.ChainId.BASE_TESTNET]: "0x618f16159d489AA7761168F0200b7705dee9e2C0", [chains.ChainId.SCROLL_SEPOLIA]: "0x5A6919Dfd2C761788608b0D1bd1239961ADCB08B", [chains.ChainId.SEPOLIA]: FACTORY_ADDRESS, [chains.ChainId.BASE_SEPOLIA]: FACTORY_ADDRESS, [chains.ChainId.ARBITRUM_SEPOLIA]: FACTORY_ADDRESS, [chains.ChainId.MONAD_TESTNET]: "0x3b7838D96Fc18AD1972aFa17574686be79C50040" }; var DEPLOYER_ADDRESS = "0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9"; var DEPLOYER_ADDRESSES = { [chains.ChainId.ETHEREUM]: DEPLOYER_ADDRESS, [chains.ChainId.GOERLI]: DEPLOYER_ADDRESS, [chains.ChainId.BSC]: DEPLOYER_ADDRESS, [chains.ChainId.BSC_TESTNET]: DEPLOYER_ADDRESS, [chains.ChainId.ARBITRUM_ONE]: DEPLOYER_ADDRESS, [chains.ChainId.ARBITRUM_GOERLI]: "0xbC465fbf687e4184103b67Ed86557A8155FA4343", [chains.ChainId.POLYGON_ZKEVM]: DEPLOYER_ADDRESS, [chains.ChainId.POLYGON_ZKEVM_TESTNET]: "0x86808Be3f426C9B4c8C706bCDe29dBC036A1259B", [chains.ChainId.ZKSYNC]: "0x7f71382044A6a62595D5D357fE75CA8199123aD6", [chains.ChainId.ZKSYNC_TESTNET]: "0xaC20647b8e9d1C4cb199104485518c136817b380", [chains.ChainId.LINEA]: DEPLOYER_ADDRESS, [chains.ChainId.LINEA_TESTNET]: "0xdAecee3C08e953Bd5f89A5Cc90ac560413d709E3", [chains.ChainId.OPBNB]: DEPLOYER_ADDRESS, [chains.ChainId.OPBNB_TESTNET]: "0xD55CAFAB2Ffa1139Be46bc5C0b8259c620050dFC", [chains.ChainId.BASE]: DEPLOYER_ADDRESS, [chains.ChainId.BASE_TESTNET]: "0x5A6919Dfd2C761788608b0D1bd1239961ADCB08B", [chains.ChainId.SCROLL_SEPOLIA]: "0xC259d1D3476558630d83b0b60c105ae958382792", [chains.ChainId.SEPOLIA]: DEPLOYER_ADDRESS, [chains.ChainId.BASE_SEPOLIA]: DEPLOYER_ADDRESS, [chains.ChainId.ARBITRUM_SEPOLIA]: DEPLOYER_ADDRESS, [chains.ChainId.MONAD_TESTNET]: "0x2c63B2dC63D7e1f47294a0902da68B5E80f0d604" }; var ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; var POOL_INIT_CODE_HASH = "0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2"; var POOL_INIT_CODE_HASHES = { [chains.ChainId.ETHEREUM]: POOL_INIT_CODE_HASH, [chains.ChainId.GOERLI]: POOL_INIT_CODE_HASH, [chains.ChainId.BSC]: POOL_INIT_CODE_HASH, [chains.ChainId.BSC_TESTNET]: POOL_INIT_CODE_HASH, [chains.ChainId.ARBITRUM_ONE]: POOL_INIT_CODE_HASH, [chains.ChainId.ARBITRUM_GOERLI]: POOL_INIT_CODE_HASH, [chains.ChainId.POLYGON_ZKEVM]: POOL_INIT_CODE_HASH, [chains.ChainId.POLYGON_ZKEVM_TESTNET]: POOL_INIT_CODE_HASH, [chains.ChainId.ZKSYNC]: "0x01001487a7c45b21c52a0bc0558bf48d897d14792f1d0cc82733c8271d069178", [chains.ChainId.ZKSYNC_TESTNET]: "0x01001487a7c45b21c52a0bc0558bf48d897d14792f1d0cc82733c8271d069178", [chains.ChainId.LINEA]: POOL_INIT_CODE_HASH, [chains.ChainId.LINEA_TESTNET]: POOL_INIT_CODE_HASH, [chains.ChainId.OPBNB]: POOL_INIT_CODE_HASH, [chains.ChainId.OPBNB_TESTNET]: POOL_INIT_CODE_HASH, [chains.ChainId.BASE]: POOL_INIT_CODE_HASH, [chains.ChainId.BASE_TESTNET]: POOL_INIT_CODE_HASH, [chains.ChainId.SCROLL_SEPOLIA]: POOL_INIT_CODE_HASH, [chains.ChainId.SEPOLIA]: POOL_INIT_CODE_HASH, [chains.ChainId.ARBITRUM_SEPOLIA]: POOL_INIT_CODE_HASH, [chains.ChainId.BASE_SEPOLIA]: POOL_INIT_CODE_HASH, [chains.ChainId.MONAD_TESTNET]: "0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2" }; var NFT_POSITION_MANAGER_ADDRESS = "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364"; var NFT_POSITION_MANAGER_ADDRESSES = { [chains.ChainId.ETHEREUM]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.GOERLI]: "0x427bF5b37357632377eCbEC9de3626C71A5396c1", [chains.ChainId.BSC]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.BSC_TESTNET]: "0x427bF5b37357632377eCbEC9de3626C71A5396c1", [chains.ChainId.ZKSYNC_TESTNET]: "0xF84697CfE7c88F846e4ba5dAe14A6A8f67deF5c2", [chains.ChainId.ZKSYNC]: "0xa815e2eD7f7d5B0c49fda367F249232a1B9D2883", [chains.ChainId.POLYGON_ZKEVM]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.POLYGON_ZKEVM_TESTNET]: "0x1f489dd5B559E976AE74303F939Cfd0aF1b62C2B", [chains.ChainId.ARBITRUM_ONE]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.LINEA]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.LINEA_TESTNET]: "0xacFa791C833120c769Fd3066c940B7D30Cd8BC73", [chains.ChainId.ARBITRUM_GOERLI]: "0xb10120961f7504766976A89E29802Fa00553da5b", [chains.ChainId.OPBNB]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.OPBNB_TESTNET]: "0x9d4277f1D41CCB30C0e91f7d1bBA2A739E19032C", [chains.ChainId.BASE]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.BASE_TESTNET]: "0x0F81fD8DaC20A21029B496D8F8E08385201B8ca0", [chains.ChainId.SCROLL_SEPOLIA]: "0x0F81fD8DaC20A21029B496D8F8E08385201B8ca0", [chains.ChainId.SEPOLIA]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.ARBITRUM_SEPOLIA]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.BASE_SEPOLIA]: NFT_POSITION_MANAGER_ADDRESS, [chains.ChainId.MONAD_TESTNET]: "0x075A0Ba7bc4cdFBBdc9d8De5f228C834246e5AFc" }; var FeeAmount = /* @__PURE__ */ ((FeeAmount4) => { FeeAmount4[FeeAmount4["LOWEST"] = 100] = "LOWEST"; FeeAmount4[FeeAmount4["LOW"] = 500] = "LOW"; FeeAmount4[FeeAmount4["MEDIUM"] = 2500] = "MEDIUM"; FeeAmount4[FeeAmount4["HIGH"] = 1e4] = "HIGH"; return FeeAmount4; })(FeeAmount || {}); var TICK_SPACINGS = { [100 /* LOWEST */]: 1, [500 /* LOW */]: 10, [2500 /* MEDIUM */]: 50, [1e4 /* HIGH */]: 200 }; var NEGATIVE_ONE = BigInt(-1); var ZERO = 0n; var ONE = 1n; var Q96 = 2n ** 96n; var Q192 = Q96 ** 2n; var MAX_FEE = 10n ** 6n; var ONE_HUNDRED_PERCENT = new swapSdkCore.Percent("1"); var ZERO_PERCENT = new swapSdkCore.Percent("0"); var Q128 = 2n ** 128n; function getCreate2Address(from_, salt_, initCodeHash) { const from = viem.toBytes(viem.getAddress(from_)); const salt = viem.pad(viem.isBytes(salt_) ? salt_ : viem.toBytes(salt_), { size: 32 }); return viem.getAddress(viem.slice(viem.keccak256(viem.concat([viem.toBytes("0xff"), from, salt, viem.toBytes(initCodeHash)])), 12)); } var EMPTY_INPU_HASH = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; var ZKSYNC_PREFIX = "0x2020dba91b30cc0006188af794c2fb30dd8520db7e2c088b7fc7c103c00ca494"; function getCreate2AddressZkSync(from, salt, initCodeHash) { return viem.getAddress( `0x${viem.keccak256(viem.concat([ZKSYNC_PREFIX, viem.pad(from, { size: 32 }), salt, initCodeHash, EMPTY_INPU_HASH])).slice(26)}` ); } function computePoolAddress({ deployerAddress, tokenA, tokenB, fee, initCodeHashManualOverride }) { const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]; const salt = viem.keccak256( viem.encodeAbiParameters(viem.parseAbiParameters(["address, address, uint24"]), [token0.address, token1.address, fee]) ); if (token0.chainId === chains.ChainId.ZKSYNC || token0.chainId === chains.ChainId.ZKSYNC_TESTNET) { return getCreate2AddressZkSync( deployerAddress, salt, initCodeHashManualOverride ?? POOL_INIT_CODE_HASHES[token0.chainId] ); } return getCreate2Address( deployerAddress, salt, initCodeHashManualOverride ?? POOL_INIT_CODE_HASHES[token0.chainId] ); } // src/utils/liquidityMath.ts var LiquidityMath = class { /** * Cannot be constructed. */ constructor() { } static addDelta(x, y) { if (y < ZERO) { return x - y * NEGATIVE_ONE; } return x + y; } }; // src/utils/fullMath.ts var FullMath = class { /** * Cannot be constructed. */ constructor() { } static mulDivRoundingUp(a, b, denominator) { const product = a * b; let result = product / denominator; if (product % denominator !== ZERO) result = result + ONE; return result; } }; var MaxUint160 = 2n ** 160n - ONE; function multiplyIn256(x, y) { const product = x * y; return product & swapSdkCore.MaxUint256; } function addIn256(x, y) { const sum = x + y; return sum & swapSdkCore.MaxUint256; } var SqrtPriceMath = class { /** * Cannot be constructed. */ constructor() { } static getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, liquidity, roundUp) { if (sqrtRatioAX96 > sqrtRatioBX96) { [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]; } const numerator1 = liquidity << 96n; const numerator2 = sqrtRatioBX96 - sqrtRatioAX96; return roundUp ? FullMath.mulDivRoundingUp(FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96), ONE, sqrtRatioAX96) : numerator1 * numerator2 / sqrtRatioBX96 / sqrtRatioAX96; } static getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, liquidity, roundUp) { if (sqrtRatioAX96 > sqrtRatioBX96) { [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]; } return roundUp ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96) : liquidity * (sqrtRatioBX96 - sqrtRatioAX96) / Q96; } static getNextSqrtPriceFromInput(sqrtPX96, liquidity, amountIn, zeroForOne) { invariant9__default.default(sqrtPX96 > ZERO); invariant9__default.default(liquidity > ZERO); return zeroForOne ? this.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) : this.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true); } static getNextSqrtPriceFromOutput(sqrtPX96, liquidity, amountOut, zeroForOne) { invariant9__default.default(sqrtPX96 > ZERO); invariant9__default.default(liquidity > ZERO); return zeroForOne ? this.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) : this.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false); } static getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amount, add) { if (amount === ZERO) return sqrtPX96; const numerator1 = liquidity << 96n; if (add) { const product2 = multiplyIn256(amount, sqrtPX96); if (product2 / amount === sqrtPX96) { const denominator2 = addIn256(numerator1, product2); if (denominator2 >= numerator1) { return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator2); } } return FullMath.mulDivRoundingUp(numerator1, ONE, numerator1 / sqrtPX96 + amount); } const product = multiplyIn256(amount, sqrtPX96); invariant9__default.default(product / amount === sqrtPX96); invariant9__default.default(numerator1 > product); const denominator = numerator1 - product; return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator); } static getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amount, add) { if (add) { const quotient2 = amount <= MaxUint160 ? (amount << 96n) / liquidity : amount * Q96 / liquidity; return sqrtPX96 + quotient2; } const quotient = FullMath.mulDivRoundingUp(amount, Q96, liquidity); invariant9__default.default(sqrtPX96 > quotient); return sqrtPX96 - quotient; } }; // src/utils/swapMath.ts var SwapMath = class { /** * Cannot be constructed. */ constructor() { } static computeSwapStep(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, amountRemaining, feePips) { const returnValues = {}; const zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96; const exactIn = amountRemaining >= ZERO; if (exactIn) { const amountRemainingLessFee = amountRemaining * (MAX_FEE - BigInt(feePips)) / MAX_FEE; returnValues.amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true); if (amountRemainingLessFee >= returnValues.amountIn) { returnValues.sqrtRatioNextX96 = sqrtRatioTargetX96; } else { returnValues.sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput( sqrtRatioCurrentX96, liquidity, amountRemainingLessFee, zeroForOne ); } } else { returnValues.amountOut = zeroForOne ? SqrtPriceMath.getAmount1Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false) : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false); if (amountRemaining * NEGATIVE_ONE >= returnValues.amountOut) { returnValues.sqrtRatioNextX96 = sqrtRatioTargetX96; } else { returnValues.sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput( sqrtRatioCurrentX96, liquidity, amountRemaining * NEGATIVE_ONE, zeroForOne ); } } const max = sqrtRatioTargetX96 === returnValues.sqrtRatioNextX96; if (zeroForOne) { returnValues.amountIn = max && exactIn ? returnValues.amountIn : SqrtPriceMath.getAmount0Delta(returnValues.sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true); returnValues.amountOut = max && !exactIn ? returnValues.amountOut : SqrtPriceMath.getAmount1Delta(returnValues.sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false); } else { returnValues.amountIn = max && exactIn ? returnValues.amountIn : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, returnValues.sqrtRatioNextX96, liquidity, true); returnValues.amountOut = max && !exactIn ? returnValues.amountOut : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, returnValues.sqrtRatioNextX96, liquidity, false); } if (!exactIn && returnValues.amountOut > amountRemaining * NEGATIVE_ONE) { returnValues.amountOut = amountRemaining * NEGATIVE_ONE; } if (exactIn && returnValues.sqrtRatioNextX96 !== sqrtRatioTargetX96) { returnValues.feeAmount = amountRemaining - returnValues.amountIn; } else { returnValues.feeAmount = FullMath.mulDivRoundingUp( returnValues.amountIn, BigInt(feePips), MAX_FEE - BigInt(feePips) ); } return [returnValues.sqrtRatioNextX96, returnValues.amountIn, returnValues.amountOut, returnValues.feeAmount]; } }; var TWO = 2n; var POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow) => [pow, TWO ** BigInt(pow)]); function mostSignificantBit(x) { invariant9__default.default(x > ZERO, "ZERO"); invariant9__default.default(x <= swapSdkCore.MaxUint256, "MAX"); let msb = 0; for (const [power, min] of POWERS_OF_2) { if (x >= min) { x = x >> BigInt(power); msb += power; } } return msb; } // src/utils/tickMath.ts function mulShift(val, mulBy) { return val * BigInt(mulBy) >> 128n; } var Q32 = 2n ** 32n; var _TickMath = class { /** * Cannot be constructed. */ constructor() { } /** * Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as sqrt(1.0001)^tick * @param tick the tick for which to compute the sqrt ratio */ static getSqrtRatioAtTick(tick) { invariant9__default.default(tick >= _TickMath.MIN_TICK && tick <= _TickMath.MAX_TICK && Number.isInteger(tick), "TICK"); const absTick = tick < 0 ? tick * -1 : tick; let ratio = (absTick & 1) != 0 ? BigInt("0xfffcb933bd6fad37aa2d162d1a594001") : BigInt("0x100000000000000000000000000000000"); if ((absTick & 2) != 0) ratio = mulShift(ratio, "0xfff97272373d413259a46990580e213a"); if ((absTick & 4) != 0) ratio = mulShift(ratio, "0xfff2e50f5f656932ef12357cf3c7fdcc"); if ((absTick & 8) != 0) ratio = mulShift(ratio, "0xffe5caca7e10e4e61c3624eaa0941cd0"); if ((absTick & 16) != 0) ratio = mulShift(ratio, "0xffcb9843d60f6159c9db58835c926644"); if ((absTick & 32) != 0) ratio = mulShift(ratio, "0xff973b41fa98c081472e6896dfb254c0"); if ((absTick & 64) != 0) ratio = mulShift(ratio, "0xff2ea16466c96a3843ec78b326b52861"); if ((absTick & 128) != 0) ratio = mulShift(ratio, "0xfe5dee046a99a2a811c461f1969c3053"); if ((absTick & 256) != 0) ratio = mulShift(ratio, "0xfcbe86c7900a88aedcffc83b479aa3a4"); if ((absTick & 512) != 0) ratio = mulShift(ratio, "0xf987a7253ac413176f2b074cf7815e54"); if ((absTick & 1024) != 0) ratio = mulShift(ratio, "0xf3392b0822b70005940c7a398e4b70f3"); if ((absTick & 2048) != 0) ratio = mulShift(ratio, "0xe7159475a2c29b7443b29c7fa6e889d9"); if ((absTick & 4096) != 0) ratio = mulShift(ratio, "0xd097f3bdfd2022b8845ad8f792aa5825"); if ((absTick & 8192) != 0) ratio = mulShift(ratio, "0xa9f746462d870fdf8a65dc1f90e061e5"); if ((absTick & 16384) != 0) ratio = mulShift(ratio, "0x70d869a156d2a1b890bb3df62baf32f7"); if ((absTick & 32768) != 0) ratio = mulShift(ratio, "0x31be135f97d08fd981231505542fcfa6"); if ((absTick & 65536) != 0) ratio = mulShift(ratio, "0x9aa508b5b7a84e1c677de54f3e99bc9"); if ((absTick & 131072) != 0) ratio = mulShift(ratio, "0x5d6af8dedb81196699c329225ee604"); if ((absTick & 262144) != 0) ratio = mulShift(ratio, "0x2216e584f5fa1ea926041bedfe98"); if ((absTick & 524288) != 0) ratio = mulShift(ratio, "0x48a170391f7dc42444e8fa2"); if (tick > 0) ratio = swapSdkCore.MaxUint256 / ratio; return ratio % Q32 > ZERO ? ratio / Q32 + ONE : ratio / Q32; } /** * Returns the tick corresponding to a given sqrt ratio, s.t. #getSqrtRatioAtTick(tick) <= sqrtRatioX96 * and #getSqrtRatioAtTick(tick + 1) > sqrtRatioX96 * @param sqrtRatioX96 the sqrt ratio as a Q64.96 for which to compute the tick */ static getTickAtSqrtRatio(sqrtRatioX96) { invariant9__default.default(sqrtRatioX96 >= _TickMath.MIN_SQRT_RATIO && sqrtRatioX96 < _TickMath.MAX_SQRT_RATIO, "SQRT_RATIO"); const sqrtRatioX128 = sqrtRatioX96 << 32n; const msb = mostSignificantBit(sqrtRatioX128); let r; if (BigInt(msb) >= 128n) { r = sqrtRatioX128 >> BigInt(msb - 127); } else { r = sqrtRatioX128 << BigInt(127 - msb); } let log_2 = BigInt(msb) - 128n << 64n; for (let i = 0; i < 14; i++) { r = r * r >> 127n; const f = r >> 128n; log_2 = log_2 | f << BigInt(63 - i); r = r >> f; } const log_sqrt10001 = log_2 * 255738958999603826347141n; const tickLow = Number(log_sqrt10001 - 3402992956809132418596140100660247210n >> 128n); const tickHigh = Number(log_sqrt10001 + 291339464771989622907027621153398088495n >> 128n); return tickLow === tickHigh ? tickLow : _TickMath.getSqrtRatioAtTick(tickHigh) <= sqrtRatioX96 ? tickHigh : tickLow; } }; var TickMath = _TickMath; /** * The minimum tick that can be used on any pool. */ // eslint-disable-next-line @typescript-eslint/no-inferrable-types TickMath.MIN_TICK = -887272; /** * The maximum tick that can be used on any pool. */ TickMath.MAX_TICK = -_TickMath.MIN_TICK; /** * The sqrt ratio corresponding to the minimum tick that could be used on any pool. */ TickMath.MIN_SQRT_RATIO = 4295128739n; /** * The sqrt ratio corresponding to the maximum tick that could be used on any pool. */ TickMath.MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342n; // src/entities/tickDataProvider.ts var _NoTickDataProvider = class { async getTick(_tick) { throw new Error(_NoTickDataProvider.ERROR_MESSAGE); } async nextInitializedTickWithinOneWord(_tick, _lte, _tickSpacing) { throw new Error(_NoTickDataProvider.ERROR_MESSAGE); } }; var NoTickDataProvider = _NoTickDataProvider; NoTickDataProvider.ERROR_MESSAGE = "No tick data provider was given"; // src/utils/isSorted.ts function isSorted(list, comparator) { for (let i = 0; i < list.length - 1; i++) { if (comparator(list[i], list[i + 1]) > 0) { return false; } } return true; } // src/utils/tickList.ts function tickComparator(a, b) { return a.index - b.index; } var TickList = class { /** * Cannot be constructed */ constructor() { } static validateList(ticks, tickSpacing) { invariant9__default.default(tickSpacing > 0, "TICK_SPACING_NONZERO"); invariant9__default.default( ticks.every(({ index }) => index % tickSpacing === 0), "TICK_SPACING" ); invariant9__default.default(ticks.reduce((accumulator, { liquidityNet }) => accumulator + liquidityNet, ZERO) === ZERO, "ZERO_NET"); invariant9__default.default(isSorted(ticks, tickComparator), "SORTED"); } static isBelowSmallest(ticks, tick) { invariant9__default.default(ticks.length > 0, "LENGTH"); return tick < ticks[0].index; } static isAtOrAboveLargest(ticks, tick) { invariant9__default.default(ticks.length > 0, "LENGTH"); return tick >= ticks[ticks.length - 1].index; } static getTick(ticks, index) { const tick = ticks[this.binarySearch(ticks, index)]; invariant9__default.default(tick.index === index, "NOT_CONTAINED"); return tick; } /** * Finds the largest tick in the list of ticks that is less than or equal to tick * @param ticks list of ticks * @param tick tick to find the largest tick that is less than or equal to tick * @private */ static binarySearch(ticks, tick) { invariant9__default.default(!this.isBelowSmallest(ticks, tick), "BELOW_SMALLEST"); let l = 0; let r = ticks.length - 1; let i; while (true) { i = Math.floor((l + r) / 2); if (ticks[i].index <= tick && (i === ticks.length - 1 || ticks[i + 1].index > tick)) { return i; } if (ticks[i].index < tick) { l = i + 1; } else { r = i - 1; } } } static nextInitializedTick(ticks, tick, lte) { if (lte) { invariant9__default.default(!TickList.isBelowSmallest(ticks, tick), "BELOW_SMALLEST"); if (TickList.isAtOrAboveLargest(ticks, tick)) { return ticks[ticks.length - 1]; } const index2 = this.binarySearch(ticks, tick); return ticks[index2]; } invariant9__default.default(!this.isAtOrAboveLargest(ticks, tick), "AT_OR_ABOVE_LARGEST"); if (this.isBelowSmallest(ticks, tick)) { return ticks[0]; } const index = this.binarySearch(ticks, tick); return ticks[index + 1]; } static nextInitializedTickWithinOneWord(ticks, tick, lte, tickSpacing) { const compressed = Math.floor(tick / tickSpacing); if (lte) { const wordPos2 = compressed >> 8; const minimum = (wordPos2 << 8) * tickSpacing; if (TickList.isBelowSmallest(ticks, tick)) { return [minimum, false]; } const { index: index2 } = TickList.nextInitializedTick(ticks, tick, lte); const nextInitializedTick2 = Math.max(minimum, index2); return [nextInitializedTick2, nextInitializedTick2 === index2]; } const wordPos = compressed + 1 >> 8; const maximum = ((wordPos + 1 << 8) - 1) * tickSpacing; if (this.isAtOrAboveLargest(ticks, tick)) { return [maximum, false]; } const { index } = this.nextInitializedTick(ticks, tick, lte); const nextInitializedTick = Math.min(maximum, index); return [nextInitializedTick, nextInitializedTick === index]; } static countInitializedTicksCrossed(ticks, tickBefore, tickAfter) { if (tickBefore === tickAfter) { return 0; } const beforeIndex = this.binarySearch(ticks, tickBefore); const afterIndex = this.binarySearch(ticks, tickAfter); return Math.abs(beforeIndex - afterIndex); } }; var Tick = class { constructor({ index, liquidityGross, liquidityNet }) { invariant9__default.default(index >= TickMath.MIN_TICK && index <= TickMath.MAX_TICK, "TICK"); this.index = index; this.liquidityGross = BigInt(liquidityGross); this.liquidityNet = BigInt(liquidityNet); } }; // src/entities/tickListDataProvider.ts var TickListDataProvider = class { constructor(ticks) { const ticksMapped = ticks.map((t) => t instanceof Tick ? t : new Tick(t)); this.ticks = ticksMapped; } async getTick(tick) { return TickList.getTick(this.ticks, tick); } async nextInitializedTickWithinOneWord(tick, lte, tickSpacing) { return TickList.nextInitializedTickWithinOneWord(this.ticks, tick, lte, tickSpacing); } }; // src/entities/pool.ts var NO_TICK_DATA_PROVIDER_DEFAULT = new NoTickDataProvider(); var Pool = class { static getAddress(tokenA, tokenB, fee, initCodeHashManualOverride, deployerAddressOverride) { return computePoolAddress({ deployerAddress: deployerAddressOverride ?? DEPLOYER_ADDRESSES[tokenA.chainId], fee, tokenA, tokenB, initCodeHashManualOverride }); } /** * Construct a pool * @param tokenA One of the tokens in the pool * @param tokenB The other token in the pool * @param fee The fee in hundredths of a bips of the input amount of every swap that is collected by the pool * @param sqrtRatioX96 The sqrt of the current ratio of amounts of token1 to token0 * @param liquidity The current value of in range liquidity * @param tickCurrent The current tick of the pool * @param ticks The current state of the pool ticks or a data provider that can return tick data */ constructor(tokenA, tokenB, fee, sqrtRatioX96, liquidity, tickCurrent, ticks = NO_TICK_DATA_PROVIDER_DEFAULT) { invariant9__default.default(Number.isInteger(fee) && fee < 1e6, "FEE"); [this.token0, this.token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]; this.fee = fee; this.sqrtRatioX96 = BigInt(sqrtRatioX96); this.liquidity = BigInt(liquidity); this.tickCurrent = tickCurrent; this.tickDataProvider = Array.isArray(ticks) ? new TickListDataProvider(ticks) : ticks; } /** * Returns true if the token is either token0 or token1 * @param token The token to check * @returns True if token is either token0 or token */ involvesToken(token) { return token.equals(this.token0) || token.equals(this.token1); } /** * Returns the current mid price of the pool in terms of token0, i.e. the ratio of token1 over token0 */ get token0Price() { return this._token0Price ?? (this._token0Price = new sdk.Price(this.token0, this.token1, Q192, this.sqrtRatioX96 * this.sqrtRatioX96)); } /** * Returns the current mid price of the pool in terms of token1, i.e. the ratio of token0 over token1 */ get token1Price() { return this._token1Price ?? (this._token1Price = new sdk.Price(this.token1, this.token0, this.sqrtRatioX96 * this.sqrtRatioX96, Q192)); } /** * Return the price of the given token in terms of the other token in the pool. * @param token The token to return price of * @returns The price of the given token, in terms of the other. */ priceOf(token) { invariant9__default.default(this.involvesToken(token), "TOKEN"); return token.equals(this.token0) ? this.token0Price : this.token1Price; } /** * Returns the chain ID of the tokens in the pool. */ get chainId() { return this.token0.chainId; } /** * Given an input amount of a token, return the computed output amount, and a pool with state updated after the trade * @param inputAmount The input amount for which to quote the output amount * @param sqrtPriceLimitX96 The Q64.96 sqrt price limit * @returns The output amount and the pool with updated state */ async getOutputAmount(inputAmount, sqrtPriceLimitX96) { invariant9__default.default(this.involvesToken(inputAmount.currency), "TOKEN"); const zeroForOne = inputAmount.currency.equals(this.token0); const { amountCalculated: outputAmount, sqrtRatioX96, liquidity, tickCurrent } = await this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX96); const outputToken = zeroForOne ? this.token1 : this.token0; return [ sdk.CurrencyAmount.fromRawAmount(outputToken, outputAmount * NEGATIVE_ONE), new Pool(this.token0, this.token1, this.fee, sqrtRatioX96, liquidity, tickCurrent, this.tickDataProvider) ]; } /** * Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade * @param outputAmount the output amount for which to quote the input amount * @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 * @returns The input amount and the pool with updated state */ async getInputAmount(outputAmount, sqrtPriceLimitX96) { invariant9__default.default(outputAmount.currency.isToken && this.involvesToken(outputAmount.currency), "TOKEN"); const zeroForOne = outputAmount.currency.equals(this.token1); const { amountCalculated: inputAmount, sqrtRatioX96, liquidity, tickCurrent } = await this.swap(zeroForOne, outputAmount.quotient * NEGATIVE_ONE, sqrtPriceLimitX96); const inputToken = zeroForOne ? this.token0 : this.token1; return [ sdk.CurrencyAmount.fromRawAmount(inputToken, inputAmount), new Pool(this.token0, this.token1, this.fee, sqrtRatioX96, liquidity, tickCurrent, this.tickDataProvider) ]; } /** * Given a desired output amount of a token, return the computed input amount and a pool with state updated after the trade * @param outputAmount the output amount for which to quote the input amount * @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 * @returns The input amount and the pool with updated state */ async getInputAmountByExactOut(outputAmount, sqrtPriceLimitX96) { invariant9__default.default(outputAmount.currency.isToken && this.involvesToken(outputAmount.currency), "TOKEN"); const zeroForOne = outputAmount.currency.equals(this.token1); const { amountSpecifiedRemaining, amountCalculated: inputAmount, sqrtRatioX96, liquidity, tickCurrent } = await this.swap(zeroForOne, outputAmount.quotient * NEGATIVE_ONE, sqrtPriceLimitX96); invariant9__default.default(amountSpecifiedRemaining === 0n, "INSUFFICIENT_LIQUIDITY"); const inputToken = zeroForOne ? this.token0 : this.token1; return [ sdk.CurrencyAmount.fromRawAmount(inputToken, inputAmount), new Pool(this.token0, this.token1, this.fee, sqrtRatioX96, liquidity, tickCurrent, this.tickDataProvider) ]; } /** * Executes a swap * @param zeroForOne Whether the amount in is token0 or token1 * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) * @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 * @returns amountCalculated * @returns sqrtRatioX96 * @returns liquidity * @returns tickCurrent */ async swap(zeroForOne, amountSpecified, sqrtPriceLimitX96) { if (!sqrtPriceLimitX96) sqrtPriceLimitX96 = zeroForOne ? TickMath.MIN_SQRT_RATIO + ONE : TickMath.MAX_SQRT_RATIO - ONE; if (zeroForOne) { invariant9__default.default(sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO, "RATIO_MIN"); invariant9__default.default(sqrtPriceLimitX96 < this.sqrtRatioX96, "RATIO_CURRENT"); } else { invariant9__default.default(sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO, "RATIO_MAX"); invariant9__default.default(sqrtPriceLimitX96 > this.sqrtRatioX96, "RATIO_CURRENT"); } const exactInput = amountSpecified >= ZERO; const state = { amountSpecifiedRemaining: amountSpecified, amountCalculated: ZERO, sqrtPriceX96: this.sqrtRatioX96, tick: this.tickCurrent, liquidity: this.liquidity }; while (state.amountSpecifiedRemaining !== ZERO && state.sqrtPriceX96 != sqrtPriceLimitX96) { const step = {}; step.sqrtPriceStartX96 = state.sqrtPriceX96; [step.tickNext, step.initialized] = await this.tickDataProvider.nextInitializedTickWithinOneWord( state.tick, zeroForOne, this.tickSpacing ); if (step.tickNext < TickMath.MIN_TICK) { step.tickNext = TickMath.MIN_TICK; } else if (step.tickNext > TickMath.MAX_TICK) { step.tickNext = TickMath.MAX_TICK; } step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext); [state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount] = SwapMath.computeSwapStep( state.sqrtPriceX96, (zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96) ? sqrtPriceLimitX96 : step.sqrtPriceNextX96, state.liquidity, state.amountSpecifiedRemaining, this.fee ); if (exactInput) { state.amountSpecifiedRemaining = state.amountSpecifiedRemaining - (step.amountIn + step.feeAmount); state.amountCalculated = state.amountCalculated - step.amountOut; } else { state.amountSpecifiedRemaining = state.amountSpecifiedRemaining + step.amountOut; state.amountCalculated = state.amountCalculated + (step.amountIn + step.feeAmount); } if (state.sqrtPriceX96 === step.sqrtPriceNextX96) { if (step.initialized) { let liquidityNet = BigInt((await this.tickDataProvider.getTick(step.tickNext)).liquidityNet); if (zeroForOne) liquidityNet = liquidityNet * NEGATIVE_ONE; state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet); } state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext; } else if (state.sqrtPriceX96 !== step.sqrtPriceStartX96) { state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96); } } return { amountSpecifiedRemaining: state.amountSpecifiedRemaining, amountCalculated: state.amountCalculated, sqrtRatioX96: state.sqrtPriceX96, liquidity: state.liquidity, tickCurrent: state.tick }; } get tickSpacing() { return TICK_SPACINGS[this.fee]; } }; // src/utils/maxLiquidityForAmounts.ts function maxLiquidityForAmount0Imprecise(sqrtRatioAX96, sqrtRatioBX96, amount0) { if (sqrtRatioAX96 > sqrtRatioBX96) { [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]; } const intermediate = sqrtRatioAX96 * sqrtRatioBX96 / Q96; return BigInt(amount0) * intermediate / (sqrtRatioBX96 - sqrtRatioAX96); } function maxLiquidityForAmount0Precise(sqrtRatioAX96, sqrtRatioBX96, amount0) { if (sqrtRatioAX96 > sqrtRatioBX96) { [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]; } const numerator = BigInt(amount0) * sqrtRatioAX96 * sqrtRatioBX96; const denominator = Q96 * (sqrtRatioBX96 - sqrtRatioAX96); return numerator / denominator; } function maxLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) { [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]; } return BigInt(amount1) * Q96 / (sqrtRatioBX96 - sqrtRatioAX96); } function maxLiquidityForAmounts(sqrtRatioCurrentX96, sqrtRatioAX96, sqrtRatioBX96, amount0, amount1, useFullPrecision) { if (sqrtRatioAX96 > sqrtRatioBX96) { [sqrtRatioAX96, sqrtRatioBX96] = [sqrtRatioBX96, sqrtRatioAX96]; } const maxLiquidityForAmount0 = useFullPrecision ? maxLiquidityForAmount0Precise : maxLiquidityForAmount0Imprecise; if (sqrtRatioCurrentX96 <= sqrtRatioAX96) { return maxLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); } if (sqrtRatioCurrentX96 < sqrtRatioBX96) { const liquidity0 = maxLiquidityForAmount0(sqrtRatioCurrentX96, sqrtRatioBX96, amount0); const liquidity1 = maxLiquidityForAmount1(sqrtRatioAX96, sqrtRatioCurrentX96, amount1); return liquidity0 < liquidity1 ? liquidity0 : liquidity1; } return maxLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); } function encodeSqrtRatioX96(amount1, amount0) { const numerator = BigInt(amount1) << 192n; const denominator = BigInt(amount0); const ratioX192 = numerator / denominator; return swapSdkCore.sqrt(ratioX192); } // src/utils/priceTickConversions.ts function tickToPrice(baseToken, quoteToken, tick) { const sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick); const ratioX192 = sqrtRatioX96 * sqrtRatioX96; return swapSdkCore.isCurrencySorted(baseToken, quoteToken) ? new swapSdkCore.Price(baseToken, quoteToken, Q192, ratioX192) : new swapSdkCore.Price(baseToken, quoteToken, ratioX192, Q192); } function tickToPriceV2(baseToken, quoteToken, tick) { const sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick); const ratioX192 = sqrtRatioX96 * sqrtRatioX96; return swapSdkCore.sortCurrencies([baseToken, quoteToken])[0] === baseToken ? new swapSdkCore.Price(baseToken, quoteToken, Q192, ratioX192) : new swapSdkCore.Price(baseToken, quoteToken, ratioX192, Q192); } function priceToClosestTick(price) { const sorted = swapSdkCore.isCurrencySorted(price.baseCurrency, price.quoteCurrency); const sqrtRatioX96 = sorted ? encodeSqrtRatioX96(price.numerator, price.denominator) : encodeSqrtRatioX96(price.denominator, price.numerator); let tick = TickMath.getTickAtSqrtRatio(sqrtRatioX96); const nextTickPrice = tickToPrice(price.baseCurrency, price.quoteCurrency, tick + 1); if (sorted) { if (!price.lessThan(nextTickPrice)) { tick++; } } else if (!price.greaterThan(nextTickPrice)) { tick++; } return tick; } // src/utils/positionMath.ts function getToken0Amount(tickCurrent, tickLower, tickUpper, sqrtRatioX96, liquidity) { if (tickCurrent < tickLower) { return SqrtPriceMath.getAmount0Delta( TickMath.getSqrtRatioAtTick(tickLower), TickMath.getSqrtRatioAtTick(tickUpper), liquidity, false ); } if (tickCurrent < tickUpper) { return SqrtPriceMath.getAmount0Delta(sqrtRatioX96, TickMath.getSqrtRatioAtTick(tickUpper), liquidity, false); } return ZERO; } function getToken1Amount(tickCurrent, tickLower, tickUpper, sqrtRatioX96, liquidity) { if (tickCurrent < tickLower) { return ZERO; } if (tickCurrent < tickUpper) { return SqrtPriceMath.getAmount1Delta(TickMath.getSqrtRatioAtTick(tickLower), sqrtRatioX96, liquidity, false); } return SqrtPriceMath.getAmount1Delta( TickMath.getSqrtRatioAtTick(tickLower), TickMath.getSqrtRatioAtTick(tickUpper), liquidity, false ); } var PositionMath = { getToken0Amount, getToken1Amount }; // src/entities/position.ts var Position = class { /** * Constructs a position for a given pool with the given liquidity * @param pool For which pool the liquidity is assigned * @param liquidity The amount of liquidity that is in the position * @param tickLower The lower tick of the position * @param tickUpper The upper tick of the position */ constructor({ pool, liquidity, tickLower, tickUpper }) { // cached resuts for the getters this._token0Amount = null; this._token1Amount = null; this._mintAmounts = null; invariant9__default.default(tickLower < tickUpper, "TICK_ORDER"); invariant9__default.default(tickLower >= TickMath.MIN_TICK && tickLower % pool.tickSpacing === 0, "TICK_LOWER"); invariant9__default.default(tickUpper <= TickMath.MAX_TICK && tickUpper % pool.tickSpacing === 0, "TICK_UPPER"); this.pool = pool; this.tickLower = tickLower; this.tickUpper = tickUpper; this.liquidity = BigInt(liquidity); } /** * Returns the price of token0 at the lower tick */ get token0PriceLower() { return tickToPrice(this.pool.token0, this.pool.token1, this.tickLower); } /** * Returns the price of token0 at the upper tick */ get token0PriceUpper() { return tickToPrice(this.pool.token0, this.pool.token1, this.tickUpper); } /** * Returns the amount of token0 that this position's liquidity could be burned for at the current pool price */ get amount0() { if (this._token0Amount === null) { this._token0Amount = sdk.CurrencyAmount.fromRawAmount( this.pool.token0, PositionMath.getToken0Amount( this.pool.tickCurrent, this.tickLower, this.tickUpper, this.pool.sqrtRatioX96, this.liquidity ) ); } return this._token0Amount; } /** * Returns the amount of token1 that this position's liquidity could be burned for at the current pool price */ get amount1() { if (this._token1Amount === null) { this._token1Amount = sdk.CurrencyAmount.fromRawAmount( this.pool.token1, PositionMath.getToken1Amount( this.pool.tickCurrent, this.tickLower, this.tickUpper, this.pool.sqrtRatioX96, this.liquidity ) ); } return this._token1Amount; } /** * Returns the lower and upper sqrt ratios if the price 'slips' up to slippage tolerance percentage * @param slippageTolerance The amount by which the price can 'slip' before the transaction will revert * @returns The sqrt ratios after slippage */ ratiosAfterSlippage(slippageTolerance) { const priceLower = this.pool.token0Price.asFraction.multiply(new sdk.Percent(1).subtract(slippageTolerance)); const priceUpper = this.pool.token0Price.asFraction.multiply(slippageTolerance.add(1)); let sqrtRatioX96Lower = encodeSqrtRatioX96(priceLower.numerator, priceLower.denominator); if (sqrtRatioX96Lower <= TickMath.MIN_SQRT_RATIO) { sqrtRatioX96Lower = TickMath.MIN_SQRT_RATIO + 1n; } let sqrtRatioX96Upper = encodeSqrtRatioX96(priceUpper.numerator, priceUpper.denominator); if (sqrtRatioX96Upper >= TickMath.MAX_SQRT_RATIO) { sqrtRatioX96Upper = TickMath.MAX_SQRT_RATIO - 1n; } return { sqrtRatioX96Lower, sqrtRatioX96Upper }; } /** * Returns the minimum amounts that must be sent in order to safely mint the amount of liquidity held by the position * with the given slippage tolerance * @param slippageTolerance Tolerance of unfavorable slippage from the current price * @returns The amounts, with slippage */ mintAmountsWithSlippage(slippageTolerance) { const { sqrtRatioX96Upper, sqrtRatioX96Lower } = this.ratiosAfterSlippage(slippageTolerance); const poolLower = new Pool( this.pool.token0, this.pool.token1, this.pool.fee, sqrtRatioX96Lower, 0, TickMath.getTickAtSqrtRatio(sqrtRatioX96Lower) ); const poolUpper = new Pool( this.pool.token0, this.pool.token1, this.pool.fee, sqrtRatioX96Upper, 0, TickMath.getTickAtSqrtRatio(sqrtRatioX96Upper) ); const positionThatWillBeCreated = Position.fromAmounts({ pool: this.pool, tickLower: this.tickLower, tickUpper: this.tickUpper, ...this.mintAmounts, // the mint amounts are what will be passed as calldata useFullPrecision: false }); const { amount0 } = new Position({ pool: poolUpper, liquidity: positionThatWillBeCreated.liquidity, tickLower: this.tickLower, tickUpper: this.tickUpper }).mintAmounts; const { amount1 } = new Position({ pool: poolLower, liquidity: positionThatWillBeCreated.liquidity, tickLower: this.tickLower, tickUpper: this.tickUpper }).mintAmounts; return { amount0, amount1 }; } /** * Returns the minimum amounts that should be requested in order to safely burn the amount of liquidity held by the * position with the given slippage tolerance * @param slippageTolerance tolerance of unfavorable slippage from the current price * @returns The amounts, with slippage */ burnAmountsWithSlippage(slippageTolerance) { const { sqrtRatioX96Upper, sqrtRatioX96Lower } = this.ratiosAfterSlippage(slippageTolerance); const poolLower = new Pool( this.pool.token0, this.pool.token1, this.pool.fee, sqrtRatioX96Lower, 0, TickMath.getTickAtSqrtRatio(sqrtRatioX96Lower) ); const poolUpper = new Pool( this.pool.token0, this.pool.token1, this.pool.fee, sqrtRatioX96Upper, 0, TickMath.getTickAtSqrtRatio(sqrtRatioX96Upper) ); const { amount0 } = new Position({ pool: poolUpper, liquidity: this.liquidity, tickLower: this.tickLower, tickUpper: this.tickUpper }); const { amount1 } = new Position({ pool: poolLower, liquidity: this.liquidity, tickLower: this.tickLower, tickUpper: this.tickUpper }); return { amount0: amount0.quotient, amount1: amount1.quotient }; } /** * Returns the minimum amounts that must be sent in order to mint the amount of liquidity held by the position at * the current price for the pool */ get mintAmounts() { if (this._mintAmounts === null) { if (this.pool.tickCurrent < this.tickLower) { return { amount0: SqrtPriceMath.getAmount0Delta( TickMath.getSqrtRatioAtTick(this.tickLower), TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, true ), amount1: ZERO }; } if (this.pool.tickCurrent < this.tickUpper) { return { amount0: SqrtPriceMath.getAmount0Delta( this.pool.sqrtRatioX96, TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, true ), amount1: SqrtPriceMath.getAmount1Delta( TickMath.getSqrtRatioAtTick(this.tickLower), this.pool.sqrtRatioX96, this.liquidity, true ) }; } return { amount0: ZERO, amount1: SqrtPriceMath.getAmount1Delta( TickMath.getSqrtRatioAtTick(this.tickLower), TickMath.getSqrtRatioAtTick(this.tickUpper), this.liquidity, true ) }; } return this._mintAmounts; } /** * Computes the maximum amount of liquidity received for a given amount of token0, token1, * and the prices at the tick boundaries. * @param pool The pool for which the position should be created * @param tickLower The lower tick of the position * @param tickUpper The upper tick of the position * @param amount0 token0 amount * @param amount1 token1 amount * @param useFullPrecision If false, liquidity will be maximized according to what the router can calculate, * not what core can theoretically support * @returns The amount of liquidity for the position */ static fromAmounts({ pool, tickLower, tickUpper, amount0, amount1, useFullPrecision }) { const sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(tickLower); const sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(tickUpper); return new Position({ pool, tickLower, tickUpper, liquidity: maxLiquidityForAmounts( pool.sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, amount0, amount1, useFullPrecision ) }); } /** * Computes a position with the maximum amount of liquidity received for a given amount of token0, assuming an unlimited amount of token1 * @param pool The pool for which the position is created * @param tickLower The lower tick * @param tickUpper The upper tick * @param amount0 The desired amount of token0 * @param useFullPrecision If true, liquidity will be maximized according to what the router can calculate, * not what core can theoretically support * @returns The position */ static fromAmount0({ pool, tickLower, tickUpper, amount0, useFullPrecision }) { return Position.fromAmounts({ pool, tickLower, tickUpper, amount0, amount1: sdk.MaxUint256, useFullPrecision }); } /** * Computes a position with the maximum amount of liquidity received for a given amount of token1, assuming an unlimited amount of token0 * @param pool The pool for which the position is created * @param tickLower The lower tick * @param tickUpper The upper tick * @param amount1 The desired amount of token1 * @returns The position */ static fromAmount1({ pool, tickLower, tickUpper, amount1 }) { return Position.fromAmounts({ pool, tickLower, tickUpper, amount0: sdk.MaxUint256, amount1, useFullPrecision: true }); } }; var Route = class { /** * Creates an instance of route. * @param pools An array of `Pool` objects, ordered by the route the swap will take * @param input The input token * @param output The output token */ constructor(pools, input, output) { this._midPrice = null; invariant9__default.default(pools.length > 0, "POOLS"); const { chainId } = pools[0]; const allOnSameChain = pools.every((pool) => pool.chainId === chainId); invariant9__default.default(allOnSameChain, "CHAIN_IDS"); const