test(libraries): add math library unit tests

This commit is contained in:
dualfroz committed 2026-08-27 11:44:00 +02:00
1 parent b2ec603567
commit da99c14cdd
2 files changed
+160

No files matched your search

+90
View File
@@ -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));
}
}
+70
View File
@@ -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);
}
}