cleaned up tests

This commit is contained in:
giteadmin 2025-07-06 10:29:34 +02:00
parent 79c26e3c31
commit 3a239b6cbf

View file

@ -1,6 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;
/**
* @title LiquidityManager Test Suite
* @notice Comprehensive tests for the LiquidityManager contract including:
* - Extreme price condition handling
* - Protocol death scenarios
* - Liquidity recentering operations
* - Edge case classification and recovery
* @dev Uses setUp() pattern for consistent test initialization
*/
import "forge-std/Test.sol";
import "@aperture/uni-v3-lib/TickMath.sol";
import {LiquidityAmounts} from "@aperture/uni-v3-lib/LiquidityAmounts.sol";
@ -20,11 +30,12 @@ import {UniswapTestBase} from "./helpers/UniswapTestBase.sol";
import "../src/Optimizer.sol";
import "../test/mocks/MockOptimizer.sol";
// Test constants
address constant TAX_POOL = address(2);
// default fee of 1%
uint24 constant FEE = uint24(10_000);
uint24 constant FEE = uint24(10_000); // 1% fee
int24 constant TICK_SPACING = 200;
int24 constant ANCHOR_SPACING = 5 * TICK_SPACING;
int24 constant EXTREME_PRICE_MARGIN = 12000; // Safety margin from tick boundaries
// Dummy.sol
contract Dummy {
@ -32,6 +43,13 @@ contract Dummy {
}
contract LiquidityManagerTest is UniswapTestBase, CSVManager {
// Setup configuration
bool constant DEFAULT_TOKEN0_IS_WETH = false;
uint256 constant DEFAULT_ACCOUNT_BALANCE = 300 ether;
// Flag to skip automatic setUp for tests that need custom setup
bool private _skipAutoSetup;
using UniswapHelpers for IUniswapV3Pool;
using CSVHelper for *;
@ -110,13 +128,13 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
(, int24 currentTick, , , , , ) = pool.slot0();
// Handle extreme expensive HARB (near MAX_TICK) - perform swap first
if (currentTick >= TickMath.MAX_TICK - 12000) {
if (currentTick >= TickMath.MAX_TICK - EXTREME_PRICE_MARGIN) {
console.log("Detected extremely expensive HARB, performing normalizing swap...");
_performNormalizingSwap(currentTick, true); // true = expensive HARB
}
// Handle extreme cheap HARB (near MIN_TICK) - perform swap first
if (currentTick <= TickMath.MIN_TICK + 12000) {
if (currentTick <= TickMath.MIN_TICK + EXTREME_PRICE_MARGIN) {
console.log("Detected extremely cheap HARB, performing normalizing swap...");
_performNormalizingSwap(currentTick, false); // false = cheap HARB
}
@ -297,14 +315,10 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
writeCSVToFile("./out/positions.csv"); // Write CSV to file
}
/// @notice Tests overflow handling in cumulative calculations
/// @dev Simulates extreme values that could cause arithmetic overflow
function testHandleCumulativeOverflow() public {
setUpCustomToken0(false);
vm.deal(account, 201 ether);
vm.prank(account);
weth.deposit{value: 201 ether}();
// Setup initial liquidity
recenter(false);
_setupCustom(false, 201 ether);
vm.store(
address(lm),
@ -339,18 +353,51 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
assertTrue(calculatedPrice > 0 && calculatedPrice < 10**40, "Calculated price after wrap-around is not within a reasonable range");
}
function testExtremeExpensiveHarbHandling() public {
setUpCustomToken0(false);
vm.deal(account, 300 ether);
function setUp() public {
if (!_skipAutoSetup) {
_commonSetup(DEFAULT_TOKEN0_IS_WETH, DEFAULT_ACCOUNT_BALANCE);
}
}
/// @notice Call this in tests that need custom setup to skip automatic setUp
function _skipSetup() internal {
_skipAutoSetup = true;
}
/// @notice Grant recenter access for testing (commonly needed)
function _grantRecenterAccess() internal {
vm.prank(feeDestination);
lm.setRecenterAccess(address(this));
}
/// @notice Setup with custom parameters but standard flow
function _setupCustom(bool token0IsWeth, uint256 accountBalance) internal {
_skipSetup();
_commonSetup(token0IsWeth, accountBalance);
}
/// @notice Common setup for most tests
/// @param token0IsWeth Whether token0 should be WETH
/// @param accountBalance How much ETH to give to account
function _commonSetup(bool token0IsWeth, uint256 accountBalance) internal {
setUpCustomToken0(token0IsWeth);
// Fund account and convert to WETH
vm.deal(account, accountBalance);
vm.prank(account);
weth.deposit{value: 300 ether}();
weth.deposit{value: accountBalance}();
// Grant recenter access to bypass oracle checks
vm.prank(feeDestination);
lm.setRecenterAccess(address(this));
// Setup initial liquidity
recenter(false);
}
/// @notice Tests handling of extremely expensive HARB prices near MAX_TICK
/// @dev Validates client-side price detection and normalization swaps
function testExtremeExpensiveHarbHandling() public {
// Record initial state
(, int24 initialTick, , , , , ) = pool.slot0();
@ -366,7 +413,7 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
// Test client-side detection and normalization
console.log("\n=== PHASE 2: Test client-side normalization ===");
if (postBuyTick >= TickMath.MAX_TICK - 12000) {
if (postBuyTick >= TickMath.MAX_TICK - EXTREME_PRICE_MARGIN) {
console.log("[SUCCESS] Successfully pushed to extreme expensive range");
console.log("[SUCCESS] Client-side detection should trigger normalization swap");
} else {
@ -401,7 +448,7 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
console.log("[SUCCESS] Client-side normalization: PASSED");
console.log("[SUCCESS] No arithmetic overflow: PASSED");
assertTrue(true, "Extreme expensive HARB handling test completed successfully");
// Test passes if we reach here without reverting
}
// Custom error types for better test diagnostics
@ -417,8 +464,7 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
if (reason.length >= 4) {
bytes4 selector = bytes4(reason);
// Log the selector for debugging
console.log("Error selector:", vm.toString(uint256(uint32(selector))));
// Note: Error selector logged for debugging when needed
if (selector == 0xae47f702) { // FullMulDivFailed()
return (FailureType.ARITHMETIC_OVERFLOW, "FullMulDivFailed - arithmetic overflow in liquidity calculations");
@ -468,18 +514,15 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
return (FailureType.OTHER_ERROR, "Unclassified error");
}
/// @notice Helper to decode string errors from revert data
function decodeStringError(bytes memory data) external pure returns (string memory) {
return abi.decode(data, (string));
}
/// @notice Tests systematic classification of different failure modes
/// @dev Performs multiple trading cycles to trigger various edge cases
function testEdgeCaseClassification() public {
setUpCustomToken0(false);
vm.deal(account, 20 ether);
vm.prank(account);
weth.deposit{value: 20 ether}();
// Setup initial liquidity
recenter(false);
_setupCustom(DEFAULT_TOKEN0_IS_WETH, 20 ether);
uint256 successCount = 0;
uint256 arithmeticOverflowCount = 0;
@ -549,21 +592,12 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
console.log("Other errors:", vm.toString(otherErrorCount));
// Test should complete
assertTrue(true, "Edge case classification test completed");
// Test passes if we reach here without reverting
}
/// @notice Tests distinction between protocol death and recoverable edge cases
/// @dev Analyzes ETH reserves vs outstanding HARB to diagnose scenario type
function testProtocolDeathVsEdgeCase() public {
setUpCustomToken0(false);
vm.deal(account, 300 ether);
vm.prank(account);
weth.deposit{value: 300 ether}();
// Grant recenter access to bypass oracle checks
vm.prank(feeDestination);
lm.setRecenterAccess(address(this));
// Setup initial liquidity
recenter(false);
// Record initial state
uint256 initialEthBalance = address(lm).balance + weth.balanceOf(address(lm));
@ -596,9 +630,9 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
// Diagnose the scenario type
console.log("\n=== SCENARIO DIAGNOSIS ===");
if (postBuyTick >= TickMath.MAX_TICK - 12000) {
if (postBuyTick >= TickMath.MAX_TICK - EXTREME_PRICE_MARGIN) {
console.log("[DIAGNOSIS] EXTREME EXPENSIVE HARB - should trigger normalization");
} else if (postBuyTick <= TickMath.MIN_TICK + 12000) {
} else if (postBuyTick <= TickMath.MIN_TICK + EXTREME_PRICE_MARGIN) {
console.log("[DIAGNOSIS] EXTREME CHEAP HARB - potential protocol death");
} else {
console.log("[DIAGNOSIS] NORMAL RANGE - may still have arithmetic issues");
@ -620,74 +654,22 @@ contract LiquidityManagerTest is UniswapTestBase, CSVManager {
console.log("Final tick:", vm.toString(finalTick));
console.log("[SUCCESS] Test completed successfully");
assertTrue(true, "Protocol death vs edge case test completed");
// Test passes if we reach here without reverting
}
// function testScenarioB() public {
// setUpCustomToken0(false);
// vm.deal(account, 501 ether);
// vm.prank(account);
// weth.deposit{value: 501 ether}();
// uint256 traderBalanceBefore = weth.balanceOf(account);
// // Setup initial liquidity
// recenter(false);
// buy(25 ether);
// recenter(false);
// buy(45 ether);
// recenter(false);
// buy(80 ether);
// recenter(false);
// buy(120 ether);
// recenter(false);
// sell(harberg.balanceOf(account) / 4);
// recenter(true);
// sell(harberg.balanceOf(account) / 4);
// recenter(true);
// sell(harberg.balanceOf(account) / 4);
// recenter(true);
// sell(harberg.balanceOf(account));
// recenter(true);
// writeCsv();
// uint256 traderBalanceAfter = weth.balanceOf(account);
// console.log(traderBalanceBefore);
// console.log(traderBalanceAfter);
// assertGt(traderBalanceBefore, traderBalanceAfter, "trader should not have made profit");
// revert();
// }
/// @notice Fuzz test with random trading sequences to discover edge cases
/// @dev Tests protocol robustness under unpredictable trading patterns
/// @param numActions Number of buy/sell operations to perform
/// @param frequency Frequency parameter (for future use)
/// @param amounts Array of trade amounts to use
function testScenarioFuzz(uint8 numActions, uint8 frequency, uint8[] calldata amounts) public {
vm.assume(numActions > 5);
vm.assume(frequency > 0);
vm.assume(frequency < 20);
vm.assume(frequency < 20); // Bound frequency parameter
vm.assume(amounts.length >= numActions);
setUpCustomToken0(numActions % 2 == 0 ? true : false);
vm.deal(account, 20 ether);
vm.prank(account);
weth.deposit{value: 20 ether}();
// Setup initial liquidity
recenter(false);
_setupCustom(numActions % 2 == 0 ? true : false, 20 ether);
uint256 traderBalanceBefore = weth.balanceOf(account);
uint8 f = 0;