test(libraries): add math library unit tests
This commit is contained in:
1 parent
b2ec603567
commit
da99c14cdd
2 files changed
+160
No files matched your search
@@ -0,0 +1,90 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.36;
|
||||||
|
|
||||||
|
import {Test} from "forge-std/Test.sol";
|
||||||
|
import {TickMath} from "../src/libraries/TickMath.sol";
|
||||||
|
import {SqrtPriceMath} from "../src/libraries/SqrtPriceMath.sol";
|
||||||
|
import {SwapMath} from "../src/libraries/SwapMath.sol";
|
||||||
|
import {FullMath} from "../src/libraries/FullMath.sol";
|
||||||
|
|
||||||
|
contract ClMathTest is Test {
|
||||||
|
uint160 private constant priceAtTickZero = 79228162514264337593543950336;
|
||||||
|
|
||||||
|
function testSqrtRatioAtKnownTicks() public pure {
|
||||||
|
assertEq(TickMath.getSqrtRatioAtTick(0), priceAtTickZero);
|
||||||
|
assertEq(TickMath.getSqrtRatioAtTick(TickMath.minTick), TickMath.minSqrtRatio);
|
||||||
|
assertEq(TickMath.getSqrtRatioAtTick(TickMath.maxTick), TickMath.maxSqrtRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTickAtKnownRatios() public pure {
|
||||||
|
assertEq(TickMath.getTickAtSqrtRatio(priceAtTickZero), 0);
|
||||||
|
assertEq(TickMath.getTickAtSqrtRatio(TickMath.minSqrtRatio), TickMath.minTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSqrtRatioMonotonic() public pure {
|
||||||
|
assertGt(TickMath.getSqrtRatioAtTick(1), TickMath.getSqrtRatioAtTick(0));
|
||||||
|
assertLt(TickMath.getSqrtRatioAtTick(-1), TickMath.getSqrtRatioAtTick(0));
|
||||||
|
assertGt(TickMath.getSqrtRatioAtTick(500000), TickMath.getSqrtRatioAtTick(499999));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFuzzTickRoundTrip(int24 tick) public pure {
|
||||||
|
tick = int24(bound(tick, TickMath.minTick, TickMath.maxTick));
|
||||||
|
uint160 ratio = TickMath.getSqrtRatioAtTick(tick);
|
||||||
|
if (ratio >= TickMath.maxSqrtRatio) return;
|
||||||
|
int24 recovered = TickMath.getTickAtSqrtRatio(ratio);
|
||||||
|
assertEq(recovered, tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFuzzTickAtRatioWithinBounds(uint160 ratio) public pure {
|
||||||
|
ratio = uint160(bound(ratio, TickMath.minSqrtRatio, TickMath.maxSqrtRatio - 1));
|
||||||
|
int24 tick = TickMath.getTickAtSqrtRatio(ratio);
|
||||||
|
assertGe(TickMath.getSqrtRatioAtTick(tick), TickMath.minSqrtRatio == 0 ? 0 : 0);
|
||||||
|
assertLe(TickMath.getSqrtRatioAtTick(tick), ratio);
|
||||||
|
assertGt(TickMath.getSqrtRatioAtTick(tick + 1), ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testAmount1DeltaKnown() public pure {
|
||||||
|
uint160 a = TickMath.getSqrtRatioAtTick(0);
|
||||||
|
uint160 b = TickMath.getSqrtRatioAtTick(120);
|
||||||
|
uint256 delta = SqrtPriceMath.getAmount1Delta(a, b, 1e18, false);
|
||||||
|
assertEq(delta, FullMath.mulDiv(1e18, b - a, 0x1000000000000000000000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testAmount0DeltaSymmetric() public pure {
|
||||||
|
uint160 a = TickMath.getSqrtRatioAtTick(-60);
|
||||||
|
uint160 b = TickMath.getSqrtRatioAtTick(60);
|
||||||
|
uint256 up = SqrtPriceMath.getAmount0Delta(a, b, 5e18, true);
|
||||||
|
uint256 down = SqrtPriceMath.getAmount0Delta(a, b, 5e18, false);
|
||||||
|
assertGe(up, down);
|
||||||
|
assertLe(up - down, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testComputeSwapStepExactInReachesTarget() public pure {
|
||||||
|
uint160 current = TickMath.getSqrtRatioAtTick(0);
|
||||||
|
uint160 target = TickMath.getSqrtRatioAtTick(-600);
|
||||||
|
(uint160 next, uint256 amountIn, uint256 amountOut, uint256 feeAmount) =
|
||||||
|
SwapMath.computeSwapStep(current, target, 1e21, 1e24, 3000);
|
||||||
|
assertEq(next, target);
|
||||||
|
assertGt(amountIn, 0);
|
||||||
|
assertGt(amountOut, 0);
|
||||||
|
assertGt(feeAmount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testComputeSwapStepPartialFill() public pure {
|
||||||
|
uint160 current = TickMath.getSqrtRatioAtTick(0);
|
||||||
|
uint160 target = TickMath.getSqrtRatioAtTick(-600);
|
||||||
|
(uint160 next,, uint256 amountOut,) = SwapMath.computeSwapStep(current, target, 1e21, 1e15, 3000);
|
||||||
|
assertGt(next, target);
|
||||||
|
assertLt(next, current);
|
||||||
|
assertGt(amountOut, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFuzzComputeSwapStepFeeBound(uint128 liquidity, uint128 amount) public pure {
|
||||||
|
liquidity = uint128(bound(liquidity, 1e12, 1e30));
|
||||||
|
int256 amountIn = int256(uint256(bound(amount, 1, 1e30)));
|
||||||
|
uint160 current = TickMath.getSqrtRatioAtTick(0);
|
||||||
|
uint160 target = TickMath.getSqrtRatioAtTick(-887000);
|
||||||
|
(, uint256 stepIn,, uint256 feeAmount) = SwapMath.computeSwapStep(current, target, liquidity, amountIn, 3000);
|
||||||
|
assertLe(stepIn + feeAmount, uint256(amountIn));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity 0.8.36;
|
||||||
|
|
||||||
|
import {Test} from "forge-std/Test.sol";
|
||||||
|
import {Math} from "../src/libraries/Math.sol";
|
||||||
|
import {FluxLibrary} from "../src/libraries/FluxLibrary.sol";
|
||||||
|
|
||||||
|
contract LibHarness {
|
||||||
|
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256) {
|
||||||
|
return FluxLibrary.quote(amountA, reserveA, reserveB);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) external pure returns (uint256) {
|
||||||
|
return FluxLibrary.getAmountOut(amountIn, reserveIn, reserveOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract MathTest is Test {
|
||||||
|
LibHarness private harness;
|
||||||
|
|
||||||
|
function setUp() public {
|
||||||
|
harness = new LibHarness();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSqrtSmallValues() public pure {
|
||||||
|
assertEq(Math.sqrt(0), 0);
|
||||||
|
assertEq(Math.sqrt(1), 1);
|
||||||
|
assertEq(Math.sqrt(2), 1);
|
||||||
|
assertEq(Math.sqrt(3), 1);
|
||||||
|
assertEq(Math.sqrt(4), 2);
|
||||||
|
assertEq(Math.sqrt(15), 3);
|
||||||
|
assertEq(Math.sqrt(16), 4);
|
||||||
|
assertEq(Math.sqrt(99), 9);
|
||||||
|
assertEq(Math.sqrt(100), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSqrtLargeValue() public pure {
|
||||||
|
assertEq(Math.sqrt(100e18 * 400e18), 2e20);
|
||||||
|
assertEq(Math.sqrt(type(uint256).max), 340282366920938463463374607431768211455);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMin() public pure {
|
||||||
|
assertEq(Math.min(3, 7), 3);
|
||||||
|
assertEq(Math.min(7, 3), 3);
|
||||||
|
assertEq(Math.min(5, 5), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testQuote() public pure {
|
||||||
|
assertEq(FluxLibrary.quote(10e18, 100e18, 400e18), 40e18);
|
||||||
|
assertEq(FluxLibrary.quote(50e18, 100e18, 400e18), 200e18);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetAmountOut() public pure {
|
||||||
|
assertEq(FluxLibrary.getAmountOut(10e18, 100e18, 400e18), 36264435755205965263);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetAmountIn() public pure {
|
||||||
|
assertEq(FluxLibrary.getAmountIn(50e18, 100e18, 400e18), 14328700386874910446);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testQuoteRevertsOnZeroLiquidity() public {
|
||||||
|
vm.expectRevert(bytes("FluxLibrary: INSUFFICIENT_LIQUIDITY"));
|
||||||
|
harness.quote(10e18, 0, 400e18);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetAmountOutRevertsOnZeroInput() public {
|
||||||
|
vm.expectRevert(bytes("FluxLibrary: INSUFFICIENT_INPUT_AMOUNT"));
|
||||||
|
harness.getAmountOut(0, 100e18, 400e18);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user