mirror of
				https://github.com/Instadapp/dsa-connectors.git
				synced 2024-07-29 22:37:00 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			228 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| // SPDX-License-Identifier: BUSL-1.1
 | |
| pragma solidity >=0.5.0;
 | |
| 
 | |
| import './LowGasSafeMath.sol';
 | |
| import './SafeCast.sol';
 | |
| 
 | |
| import './FullMath.sol';
 | |
| import './UnsafeMath.sol';
 | |
| import './FixedPoint96.sol';
 | |
| 
 | |
| /// @title Functions based on Q64.96 sqrt price and liquidity
 | |
| /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas
 | |
| library SqrtPriceMath {
 | |
|     using LowGasSafeMath for uint256;
 | |
|     using SafeCast for uint256;
 | |
| 
 | |
|     /// @notice Gets the next sqrt price given a delta of token0
 | |
|     /// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least
 | |
|     /// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the
 | |
|     /// price less in order to not send too much output.
 | |
|     /// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96),
 | |
|     /// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount).
 | |
|     /// @param sqrtPX96 The starting price, i.e. before accounting for the token0 delta
 | |
|     /// @param liquidity The amount of usable liquidity
 | |
|     /// @param amount How much of token0 to add or remove from virtual reserves
 | |
|     /// @param add Whether to add or remove the amount of token0
 | |
|     /// @return The price after adding or removing amount, depending on add
 | |
|     function getNextSqrtPriceFromAmount0RoundingUp(
 | |
|         uint160 sqrtPX96,
 | |
|         uint128 liquidity,
 | |
|         uint256 amount,
 | |
|         bool add
 | |
|     ) internal pure returns (uint160) {
 | |
|         // we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price
 | |
|         if (amount == 0) return sqrtPX96;
 | |
|         uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
 | |
| 
 | |
|         if (add) {
 | |
|             uint256 product;
 | |
|             if ((product = amount * sqrtPX96) / amount == sqrtPX96) {
 | |
|                 uint256 denominator = numerator1 + product;
 | |
|                 if (denominator >= numerator1)
 | |
|                     // always fits in 160 bits
 | |
|                     return uint160(FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator));
 | |
|             }
 | |
| 
 | |
|             return uint160(UnsafeMath.divRoundingUp(numerator1, (numerator1 / sqrtPX96).add(amount)));
 | |
|         } else {
 | |
|             uint256 product;
 | |
|             // if the product overflows, we know the denominator underflows
 | |
|             // in addition, we must check that the denominator does not underflow
 | |
|             require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);
 | |
|             uint256 denominator = numerator1 - product;
 | |
|             return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @notice Gets the next sqrt price given a delta of token1
 | |
|     /// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least
 | |
|     /// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the
 | |
|     /// price less in order to not send too much output.
 | |
|     /// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity
 | |
|     /// @param sqrtPX96 The starting price, i.e., before accounting for the token1 delta
 | |
|     /// @param liquidity The amount of usable liquidity
 | |
|     /// @param amount How much of token1 to add, or remove, from virtual reserves
 | |
|     /// @param add Whether to add, or remove, the amount of token1
 | |
|     /// @return The price after adding or removing `amount`
 | |
|     function getNextSqrtPriceFromAmount1RoundingDown(
 | |
|         uint160 sqrtPX96,
 | |
|         uint128 liquidity,
 | |
|         uint256 amount,
 | |
|         bool add
 | |
|     ) internal pure returns (uint160) {
 | |
|         // if we're adding (subtracting), rounding down requires rounding the quotient down (up)
 | |
|         // in both cases, avoid a mulDiv for most inputs
 | |
|         if (add) {
 | |
|             uint256 quotient =
 | |
|                 (
 | |
|                     amount <= type(uint160).max
 | |
|                         ? (amount << FixedPoint96.RESOLUTION) / liquidity
 | |
|                         : FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity)
 | |
|                 );
 | |
| 
 | |
|             return uint256(sqrtPX96).add(quotient).toUint160();
 | |
|         } else {
 | |
|             uint256 quotient =
 | |
|                 (
 | |
|                     amount <= type(uint160).max
 | |
|                         ? UnsafeMath.divRoundingUp(amount << FixedPoint96.RESOLUTION, liquidity)
 | |
|                         : FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, liquidity)
 | |
|                 );
 | |
| 
 | |
|             require(sqrtPX96 > quotient);
 | |
|             // always fits 160 bits
 | |
|             return uint160(sqrtPX96 - quotient);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// @notice Gets the next sqrt price given an input amount of token0 or token1
 | |
|     /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds
 | |
|     /// @param sqrtPX96 The starting price, i.e., before accounting for the input amount
 | |
|     /// @param liquidity The amount of usable liquidity
 | |
|     /// @param amountIn How much of token0, or token1, is being swapped in
 | |
|     /// @param zeroForOne Whether the amount in is token0 or token1
 | |
|     /// @return sqrtQX96 The price after adding the input amount to token0 or token1
 | |
|     function getNextSqrtPriceFromInput(
 | |
|         uint160 sqrtPX96,
 | |
|         uint128 liquidity,
 | |
|         uint256 amountIn,
 | |
|         bool zeroForOne
 | |
|     ) internal pure returns (uint160 sqrtQX96) {
 | |
|         require(sqrtPX96 > 0);
 | |
|         require(liquidity > 0);
 | |
| 
 | |
|         // round to make sure that we don't pass the target price
 | |
|         return
 | |
|             zeroForOne
 | |
|                 ? getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true)
 | |
|                 : getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true);
 | |
|     }
 | |
| 
 | |
|     /// @notice Gets the next sqrt price given an output amount of token0 or token1
 | |
|     /// @dev Throws if price or liquidity are 0 or the next price is out of bounds
 | |
|     /// @param sqrtPX96 The starting price before accounting for the output amount
 | |
|     /// @param liquidity The amount of usable liquidity
 | |
|     /// @param amountOut How much of token0, or token1, is being swapped out
 | |
|     /// @param zeroForOne Whether the amount out is token0 or token1
 | |
|     /// @return sqrtQX96 The price after removing the output amount of token0 or token1
 | |
|     function getNextSqrtPriceFromOutput(
 | |
|         uint160 sqrtPX96,
 | |
|         uint128 liquidity,
 | |
|         uint256 amountOut,
 | |
|         bool zeroForOne
 | |
|     ) internal pure returns (uint160 sqrtQX96) {
 | |
|         require(sqrtPX96 > 0);
 | |
|         require(liquidity > 0);
 | |
| 
 | |
|         // round to make sure that we pass the target price
 | |
|         return
 | |
|             zeroForOne
 | |
|                 ? getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false)
 | |
|                 : getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false);
 | |
|     }
 | |
| 
 | |
|     /// @notice Gets the amount0 delta between two prices
 | |
|     /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
 | |
|     /// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
 | |
|     /// @param sqrtRatioAX96 A sqrt price
 | |
|     /// @param sqrtRatioBX96 Another sqrt price
 | |
|     /// @param liquidity The amount of usable liquidity
 | |
|     /// @param roundUp Whether to round the amount up or down
 | |
|     /// @return amount0 Amount of token0 required to cover a position of size liquidity between the two passed prices
 | |
|     function getAmount0Delta(
 | |
|         uint160 sqrtRatioAX96,
 | |
|         uint160 sqrtRatioBX96,
 | |
|         uint128 liquidity,
 | |
|         bool roundUp
 | |
|     ) internal pure returns (uint256 amount0) {
 | |
|         if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
 | |
| 
 | |
|         uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
 | |
|         uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96;
 | |
| 
 | |
|         require(sqrtRatioAX96 > 0);
 | |
| 
 | |
|         return
 | |
|             roundUp
 | |
|                 ? UnsafeMath.divRoundingUp(
 | |
|                     FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96),
 | |
|                     sqrtRatioAX96
 | |
|                 )
 | |
|                 : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96;
 | |
|     }
 | |
| 
 | |
|     /// @notice Gets the amount1 delta between two prices
 | |
|     /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
 | |
|     /// @param sqrtRatioAX96 A sqrt price
 | |
|     /// @param sqrtRatioBX96 Another sqrt price
 | |
|     /// @param liquidity The amount of usable liquidity
 | |
|     /// @param roundUp Whether to round the amount up, or down
 | |
|     /// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices
 | |
|     function getAmount1Delta(
 | |
|         uint160 sqrtRatioAX96,
 | |
|         uint160 sqrtRatioBX96,
 | |
|         uint128 liquidity,
 | |
|         bool roundUp
 | |
|     ) internal pure returns (uint256 amount1) {
 | |
|         if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
 | |
| 
 | |
|         return
 | |
|             roundUp
 | |
|                 ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96)
 | |
|                 : FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96);
 | |
|     }
 | |
| 
 | |
|     /// @notice Helper that gets signed token0 delta
 | |
|     /// @param sqrtRatioAX96 A sqrt price
 | |
|     /// @param sqrtRatioBX96 Another sqrt price
 | |
|     /// @param liquidity The change in liquidity for which to compute the amount0 delta
 | |
|     /// @return amount0 Amount of token0 corresponding to the passed liquidityDelta between the two prices
 | |
|     function getAmount0Delta(
 | |
|         uint160 sqrtRatioAX96,
 | |
|         uint160 sqrtRatioBX96,
 | |
|         int128 liquidity
 | |
|     ) internal pure returns (int256 amount0) {
 | |
|         return
 | |
|             liquidity < 0
 | |
|                 ? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256()
 | |
|                 : getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
 | |
|     }
 | |
| 
 | |
|     /// @notice Helper that gets signed token1 delta
 | |
|     /// @param sqrtRatioAX96 A sqrt price
 | |
|     /// @param sqrtRatioBX96 Another sqrt price
 | |
|     /// @param liquidity The change in liquidity for which to compute the amount1 delta
 | |
|     /// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices
 | |
|     function getAmount1Delta(
 | |
|         uint160 sqrtRatioAX96,
 | |
|         uint160 sqrtRatioBX96,
 | |
|         int128 liquidity
 | |
|     ) internal pure returns (int256 amount1) {
 | |
|         return
 | |
|             liquidity < 0
 | |
|                 ? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256()
 | |
|                 : getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
 | |
|     }
 | |
| }
 | 
