infrastructure-upgrade/lib/v3-core/contracts/test/SqrtPriceMathEchidnaTest.sol
T-Hax 735546619e
init
Signed-off-by: T-Hax <>
2023-04-08 18:46:18 +00:00

233 lines
7.4 KiB
Solidity

// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.7.6;
import '../libraries/FullMath.sol';
import '../libraries/SqrtPriceMath.sol';
import '../libraries/FixedPoint96.sol';
contract SqrtPriceMathEchidnaTest {
function mulDivRoundingUpInvariants(
uint256 x,
uint256 y,
uint256 z
) external pure {
require(z > 0);
uint256 notRoundedUp = FullMath.mulDiv(x, y, z);
uint256 roundedUp = FullMath.mulDivRoundingUp(x, y, z);
assert(roundedUp >= notRoundedUp);
assert(roundedUp - notRoundedUp < 2);
if (roundedUp - notRoundedUp == 1) {
assert(mulmod(x, y, z) > 0);
} else {
assert(mulmod(x, y, z) == 0);
}
}
function getNextSqrtPriceFromInputInvariants(
uint160 sqrtP,
uint128 liquidity,
uint256 amountIn,
bool zeroForOne
) external pure {
uint160 sqrtQ = SqrtPriceMath.getNextSqrtPriceFromInput(sqrtP, liquidity, amountIn, zeroForOne);
if (zeroForOne) {
assert(sqrtQ <= sqrtP);
assert(amountIn >= SqrtPriceMath.getAmount0Delta(sqrtQ, sqrtP, liquidity, true));
} else {
assert(sqrtQ >= sqrtP);
assert(amountIn >= SqrtPriceMath.getAmount1Delta(sqrtP, sqrtQ, liquidity, true));
}
}
function getNextSqrtPriceFromOutputInvariants(
uint160 sqrtP,
uint128 liquidity,
uint256 amountOut,
bool zeroForOne
) external pure {
uint160 sqrtQ = SqrtPriceMath.getNextSqrtPriceFromOutput(sqrtP, liquidity, amountOut, zeroForOne);
if (zeroForOne) {
assert(sqrtQ <= sqrtP);
assert(amountOut <= SqrtPriceMath.getAmount1Delta(sqrtQ, sqrtP, liquidity, false));
} else {
assert(sqrtQ > 0); // this has to be true, otherwise we need another require
assert(sqrtQ >= sqrtP);
assert(amountOut <= SqrtPriceMath.getAmount0Delta(sqrtP, sqrtQ, liquidity, false));
}
}
function getNextSqrtPriceFromAmount0RoundingUpInvariants(
uint160 sqrtPX96,
uint128 liquidity,
uint256 amount,
bool add
) external pure {
require(sqrtPX96 > 0);
require(liquidity > 0);
uint160 sqrtQX96 = SqrtPriceMath.getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amount, add);
if (add) {
assert(sqrtQX96 <= sqrtPX96);
} else {
assert(sqrtQX96 >= sqrtPX96);
}
if (amount == 0) {
assert(sqrtPX96 == sqrtQX96);
}
}
function getNextSqrtPriceFromAmount1RoundingDownInvariants(
uint160 sqrtPX96,
uint128 liquidity,
uint256 amount,
bool add
) external pure {
require(sqrtPX96 > 0);
require(liquidity > 0);
uint160 sqrtQX96 = SqrtPriceMath.getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amount, add);
if (add) {
assert(sqrtQX96 >= sqrtPX96);
} else {
assert(sqrtQX96 <= sqrtPX96);
}
if (amount == 0) {
assert(sqrtPX96 == sqrtQX96);
}
}
function getAmount0DeltaInvariants(
uint160 sqrtP,
uint160 sqrtQ,
uint128 liquidity
) external pure {
require(sqrtP > 0 && sqrtQ > 0);
uint256 amount0Down = SqrtPriceMath.getAmount0Delta(sqrtQ, sqrtP, liquidity, false);
assert(amount0Down == SqrtPriceMath.getAmount0Delta(sqrtP, sqrtQ, liquidity, false));
uint256 amount0Up = SqrtPriceMath.getAmount0Delta(sqrtQ, sqrtP, liquidity, true);
assert(amount0Up == SqrtPriceMath.getAmount0Delta(sqrtP, sqrtQ, liquidity, true));
assert(amount0Down <= amount0Up);
// diff is 0 or 1
assert(amount0Up - amount0Down < 2);
}
// ensure that chained division is always equal to the full-precision case for
// liquidity * (sqrt(P) - sqrt(Q)) / (sqrt(P) * sqrt(Q))
function getAmount0DeltaEquivalency(
uint160 sqrtP,
uint160 sqrtQ,
uint128 liquidity,
bool roundUp
) external pure {
require(sqrtP >= sqrtQ);
require(sqrtP > 0 && sqrtQ > 0);
require((sqrtP * sqrtQ) / sqrtP == sqrtQ);
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
uint256 numerator2 = sqrtP - sqrtQ;
uint256 denominator = uint256(sqrtP) * sqrtQ;
uint256 safeResult =
roundUp
? FullMath.mulDivRoundingUp(numerator1, numerator2, denominator)
: FullMath.mulDiv(numerator1, numerator2, denominator);
uint256 fullResult = SqrtPriceMath.getAmount0Delta(sqrtQ, sqrtP, liquidity, roundUp);
assert(safeResult == fullResult);
}
function getAmount1DeltaInvariants(
uint160 sqrtP,
uint160 sqrtQ,
uint128 liquidity
) external pure {
require(sqrtP > 0 && sqrtQ > 0);
uint256 amount1Down = SqrtPriceMath.getAmount1Delta(sqrtP, sqrtQ, liquidity, false);
assert(amount1Down == SqrtPriceMath.getAmount1Delta(sqrtQ, sqrtP, liquidity, false));
uint256 amount1Up = SqrtPriceMath.getAmount1Delta(sqrtP, sqrtQ, liquidity, true);
assert(amount1Up == SqrtPriceMath.getAmount1Delta(sqrtQ, sqrtP, liquidity, true));
assert(amount1Down <= amount1Up);
// diff is 0 or 1
assert(amount1Up - amount1Down < 2);
}
function getAmount0DeltaSignedInvariants(
uint160 sqrtP,
uint160 sqrtQ,
int128 liquidity
) external pure {
require(sqrtP > 0 && sqrtQ > 0);
int256 amount0 = SqrtPriceMath.getAmount0Delta(sqrtQ, sqrtP, liquidity);
if (liquidity < 0) assert(amount0 <= 0);
if (liquidity > 0) {
if (sqrtP == sqrtQ) assert(amount0 == 0);
else assert(amount0 > 0);
}
if (liquidity == 0) assert(amount0 == 0);
}
function getAmount1DeltaSignedInvariants(
uint160 sqrtP,
uint160 sqrtQ,
int128 liquidity
) external pure {
require(sqrtP > 0 && sqrtQ > 0);
int256 amount1 = SqrtPriceMath.getAmount1Delta(sqrtP, sqrtQ, liquidity);
if (liquidity < 0) assert(amount1 <= 0);
if (liquidity > 0) {
if (sqrtP == sqrtQ) assert(amount1 == 0);
else assert(amount1 > 0);
}
if (liquidity == 0) assert(amount1 == 0);
}
function getOutOfRangeMintInvariants(
uint160 sqrtA,
uint160 sqrtB,
int128 liquidity
) external pure {
require(sqrtA > 0 && sqrtB > 0);
require(liquidity > 0);
int256 amount0 = SqrtPriceMath.getAmount0Delta(sqrtA, sqrtB, liquidity);
int256 amount1 = SqrtPriceMath.getAmount1Delta(sqrtA, sqrtB, liquidity);
if (sqrtA == sqrtB) {
assert(amount0 == 0);
assert(amount1 == 0);
} else {
assert(amount0 > 0);
assert(amount1 > 0);
}
}
function getInRangeMintInvariants(
uint160 sqrtLower,
uint160 sqrtCurrent,
uint160 sqrtUpper,
int128 liquidity
) external pure {
require(sqrtLower > 0);
require(sqrtLower < sqrtUpper);
require(sqrtLower <= sqrtCurrent && sqrtCurrent <= sqrtUpper);
require(liquidity > 0);
int256 amount0 = SqrtPriceMath.getAmount0Delta(sqrtCurrent, sqrtUpper, liquidity);
int256 amount1 = SqrtPriceMath.getAmount1Delta(sqrtLower, sqrtCurrent, liquidity);
assert(amount0 > 0 || amount1 > 0);
}
}