diff --git a/test/invariants/BaseInvariants.sol b/test/invariants/BaseInvariants.sol index 0f8478e..0e9ccc7 100644 --- a/test/invariants/BaseInvariants.sol +++ b/test/invariants/BaseInvariants.sol @@ -52,7 +52,6 @@ abstract contract Invariant_Base_Test_ is Invariant_Shared_Test_ { * Invariant C: previewRedeem(∑shares) == totalAssets * Invariant D: previewRedeem(shares) == (, uint256 assets) = previewRedeem(shares) Not really invariant, but tested on handler * Invariant E: previewDeposit(amount) == uint256 shares = previewDeposit(amount) Not really invariant, but tested on handler - * Invariant L: ∀ user, weth balances + previewRedeem(user shares) >= initialWETHBalance. // i.e. shares are up only. * Withdraw Queue: * Invariant F: nextWithdrawalIndex == requestRedeem call count @@ -70,6 +69,11 @@ abstract contract Invariant_Base_Test_ is Invariant_Shared_Test_ { * Invariant B: address(arm).balance == 0 * Invariant C: All slot allow for gap are empty + * After invariants: + * All user can withdraw their funds + * Log stats + + */ ////////////////////////////////////////////////////// @@ -161,21 +165,6 @@ abstract contract Invariant_Base_Test_ is Invariant_Shared_Test_ { assertEq(weth.balanceOf(feeCollector), ownerHandler.sum_of_fees(), "lpHandler.invariant_M"); } - function assert_lp_invariant_L(uint256 initialUserWETHBalance) public { - // 1. Finalize all claims on Lido - llmHandler.finalizeAllClaims(); - // 2. Swap all stETH to WETH - _sweepAllStETH(); - // 3. Finalize all claim redeem on ARM. - lpHandler.finalizeAllClaims(); - // 4. Check that all shares values are up only -> WETH balance + previewRedeem(shares) >= MAX_WETH_PER_USERS - for (uint256 i; i < lps.length; i++) { - address user = lps[i]; - uint256 previewRedeem = lidoARM.previewRedeem(lidoARM.balanceOf(user)); - assertGe(weth.balanceOf(user) + previewRedeem + 1, initialUserWETHBalance, "lpHandler.invariant_L"); - } - } - ////////////////////////////////////////////////////// /// --- LIDO LIQUIDITY MANAGER ASSERTIONS ////////////////////////////////////////////////////// @@ -228,6 +217,23 @@ abstract contract Invariant_Base_Test_ is Invariant_Shared_Test_ { assertApproxEqAbs(steth.balanceOf(address(lidoARM)), 0, 1, "SwepAllStETH"); } + /// @notice Empties the ARM + /// @dev Finalize all claims on lido, swap all stETH to WETH, finalize all + /// claim redeem on ARM and withdraw all user funds. + function emptiesARM() internal { + // 1. Finalize all claims on Lido + llmHandler.finalizeAllClaims(); + + // 2. Swap all stETH to WETH + _sweepAllStETH(); + + // 3. Finalize all claim redeem on ARM. + lpHandler.finalizeAllClaims(); + + // 4. Withdraw all user funds + lpHandler.withdrawAllUserFunds(); + } + /// @notice Absolute difference between two numbers function absDiff(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a - b : b - a; @@ -237,11 +243,6 @@ abstract contract Invariant_Base_Test_ is Invariant_Shared_Test_ { value = uint256(vm.load(address(lidoARM), bytes32(slotNumber))); } - modifier logStat(bool display) { - _; - if (display) logStats(); - } - function logStats() public view { // Don't trace this function as it's only for logging data. vm.pauseTracing(); diff --git a/test/invariants/BasicInvariants.sol b/test/invariants/BasicInvariants.sol index 2e1a725..82e5a8b 100644 --- a/test/invariants/BasicInvariants.sol +++ b/test/invariants/BasicInvariants.sol @@ -23,7 +23,6 @@ contract Invariant_Basic_Test_ is Invariant_Base_Test_ { uint256 private constant MAX_SELL_T1 = 1.02 * 1e36; // We could have use type(uint256).max, but this is non-sense uint256 private constant MAX_WETH_PER_USERS = 10_000 ether; // 10M uint256 private constant MAX_STETH_PER_USERS = 10_000 ether; // 10M, actual total supply - bool private constant LOG_STATS = true; // Reduce speed but increase readability when debugging invariants. ////////////////////////////////////////////////////// /// --- SETUP @@ -110,7 +109,7 @@ contract Invariant_Basic_Test_ is Invariant_Base_Test_ { ////////////////////////////////////////////////////// /// --- INVARIANTS ////////////////////////////////////////////////////// - function invariant_lp() external logStat(LOG_STATS) { + function invariant_lp() external view { assert_lp_invariant_A(); assert_lp_invariant_B(); assert_lp_invariant_C(); @@ -122,18 +121,22 @@ contract Invariant_Basic_Test_ is Invariant_Base_Test_ { assert_lp_invariant_I(); assert_lp_invariant_J(); assert_lp_invariant_K(); - assert_lp_invariant_L(MAX_WETH_PER_USERS); assert_lp_invariant_M(); } - function invariant_swap() external view logStat(LOG_STATS) { + function invariant_swap() external view { assert_swap_invariant_A(); assert_swap_invariant_B(); } - function invariant_llm() external view logStat(LOG_STATS) { + function invariant_llm() external view { assert_llm_invariant_A(); assert_llm_invariant_B(); assert_llm_invariant_C(); } + + function afterInvariant() external { + logStats(); + emptiesARM(); + } } diff --git a/test/invariants/handlers/LpHandler.sol b/test/invariants/handlers/LpHandler.sol index d98cb5b..095cfb4 100644 --- a/test/invariants/handlers/LpHandler.sol +++ b/test/invariants/handlers/LpHandler.sol @@ -232,6 +232,29 @@ contract LpHandler is BaseHandler { rewind(arm.claimDelay()); } + /// @notice Withdraw all user funds + /// @dev This function assumes that all pending request on lido have been finalized, + /// all stETH have been swapped to WETH and all claim redeem requests have been finalized. + function withdrawAllUserFunds() external { + for (uint256 i; i < lps.length; i++) { + address user = lps[i]; + vm.startPrank(user); + + // Request Claim + (uint256 requestId,) = arm.requestRedeem(arm.balanceOf(user)); + + // Timejump to request deadline + skip(arm.claimDelay()); + + // Claim request + arm.claimRedeem(requestId); + + // Jump back to current time, to avoid issues with other tests + rewind(arm.claimDelay()); + vm.stopPrank(); + } + } + /// @notice Get all requests for a user function getRequests(address user) external view returns (uint256[] memory) { return requests[user];