feat(libraries): add sqrt-price delta math
This commit is contained in:
1 parent
72e670cd72
commit
7a1aff4521
1 file changed
+147
@@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.36;
|
||||
|
||||
import {FullMath} from "./FullMath.sol";
|
||||
import {UnsafeMath} from "./UnsafeMath.sol";
|
||||
import {FixedPoint96} from "./FixedPoint96.sol";
|
||||
import {SafeCast} from "./SafeCast.sol";
|
||||
|
||||
/// @title Sqrt-price and token amount deltas along the constant-product curve.
|
||||
library SqrtPriceMath {
|
||||
using SafeCast for uint256;
|
||||
|
||||
function getNextSqrtPriceFromAmount0RoundingUp(uint160 sqrtPX96, uint128 liquidity, uint256 amount, bool add)
|
||||
internal
|
||||
pure
|
||||
returns (uint160)
|
||||
{
|
||||
if (amount == 0) return sqrtPX96;
|
||||
uint256 numerator1 = uint256(liquidity) << FixedPoint96.resolution;
|
||||
|
||||
unchecked {
|
||||
if (add) {
|
||||
uint256 product = amount * sqrtPX96;
|
||||
if (product / amount == sqrtPX96) {
|
||||
uint256 denominator = numerator1 + product;
|
||||
if (denominator >= numerator1) {
|
||||
return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160();
|
||||
}
|
||||
}
|
||||
return uint160(UnsafeMath.divRoundingUp(numerator1, numerator1 / sqrtPX96 + amount));
|
||||
} else {
|
||||
uint256 product = amount * sqrtPX96;
|
||||
require(product / amount == sqrtPX96 && numerator1 > product, "SqrtPriceMath: A0");
|
||||
uint256 denominator = numerator1 - product;
|
||||
return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNextSqrtPriceFromAmount1RoundingDown(uint160 sqrtPX96, uint128 liquidity, uint256 amount, bool add)
|
||||
internal
|
||||
pure
|
||||
returns (uint160)
|
||||
{
|
||||
unchecked {
|
||||
if (add) {
|
||||
uint256 quotient =
|
||||
(amount <= type(uint160).max
|
||||
? (amount << FixedPoint96.resolution) / liquidity
|
||||
: FullMath.mulDiv(amount, FixedPoint96.q96, liquidity));
|
||||
return (uint256(sqrtPX96) + quotient).toUint160();
|
||||
} else {
|
||||
uint256 quotient =
|
||||
(amount <= type(uint160).max
|
||||
? UnsafeMath.divRoundingUp(amount << FixedPoint96.resolution, liquidity)
|
||||
: FullMath.mulDivRoundingUp(amount, FixedPoint96.q96, liquidity));
|
||||
require(sqrtPX96 > quotient, "SqrtPriceMath: A1");
|
||||
return uint160(sqrtPX96 - quotient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNextSqrtPriceFromInput(uint160 sqrtPX96, uint128 liquidity, uint256 amountIn, bool zeroForOne)
|
||||
internal
|
||||
pure
|
||||
returns (uint160 sqrtQX96)
|
||||
{
|
||||
require(sqrtPX96 > 0, "SqrtPriceMath: PRICE");
|
||||
require(liquidity > 0, "SqrtPriceMath: LIQ");
|
||||
|
||||
return zeroForOne
|
||||
? getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true)
|
||||
: getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true);
|
||||
}
|
||||
|
||||
function getNextSqrtPriceFromOutput(uint160 sqrtPX96, uint128 liquidity, uint256 amountOut, bool zeroForOne)
|
||||
internal
|
||||
pure
|
||||
returns (uint160 sqrtQX96)
|
||||
{
|
||||
require(sqrtPX96 > 0, "SqrtPriceMath: PRICE");
|
||||
require(liquidity > 0, "SqrtPriceMath: LIQ");
|
||||
|
||||
return zeroForOne
|
||||
? getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false)
|
||||
: getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false);
|
||||
}
|
||||
|
||||
function getAmount0Delta(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity, bool roundUp)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 amount0)
|
||||
{
|
||||
unchecked {
|
||||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
|
||||
|
||||
uint256 numerator1 = uint256(liquidity) << FixedPoint96.resolution;
|
||||
uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96;
|
||||
|
||||
require(sqrtRatioAX96 > 0, "SqrtPriceMath: A0Z");
|
||||
|
||||
return roundUp
|
||||
? UnsafeMath.divRoundingUp(
|
||||
FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96), sqrtRatioAX96
|
||||
)
|
||||
: FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96;
|
||||
}
|
||||
}
|
||||
|
||||
function getAmount1Delta(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity, bool roundUp)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 amount1)
|
||||
{
|
||||
unchecked {
|
||||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
|
||||
|
||||
return roundUp
|
||||
? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.q96)
|
||||
: FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.q96);
|
||||
}
|
||||
}
|
||||
|
||||
function getAmount0Delta(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, int128 liquidity)
|
||||
internal
|
||||
pure
|
||||
returns (int256 amount0)
|
||||
{
|
||||
unchecked {
|
||||
return liquidity < 0
|
||||
? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256()
|
||||
: getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
|
||||
}
|
||||
}
|
||||
|
||||
function getAmount1Delta(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, int128 liquidity)
|
||||
internal
|
||||
pure
|
||||
returns (int256 amount1)
|
||||
{
|
||||
unchecked {
|
||||
return liquidity < 0
|
||||
? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256()
|
||||
: getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user