From 07b8930b948f4fda3e7c2abe59611cc368b5d4b3 Mon Sep 17 00:00:00 2001 From: dglowinski Date: Fri, 5 Jul 2024 17:51:28 +0200 Subject: [PATCH] fix div zero in liquidation when liability value is zero --- src/EVault/modules/Liquidation.sol | 4 +- .../evault/modules/Liquidation/full.t.sol | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/EVault/modules/Liquidation.sol b/src/EVault/modules/Liquidation.sol index 07d4ca0e..fd33bc2e 100644 --- a/src/EVault/modules/Liquidation.sol +++ b/src/EVault/modules/Liquidation.sol @@ -122,7 +122,9 @@ abstract contract LiquidationModule is ILiquidation, BalanceUtils, LiquidityUtil calculateLiquidity(vaultCache, liqCache.violator, liqCache.collaterals, true); // no violation - if (collateralAdjustedValue > liabilityValue) return liqCache; + if (collateralAdjustedValue > liabilityValue || liabilityValue == 0) { + return liqCache; + } // Compute discount diff --git a/test/unit/evault/modules/Liquidation/full.t.sol b/test/unit/evault/modules/Liquidation/full.t.sol index 3ec6e028..9fd9fff5 100644 --- a/test/unit/evault/modules/Liquidation/full.t.sol +++ b/test/unit/evault/modules/Liquidation/full.t.sol @@ -820,6 +820,57 @@ contract VaultLiquidation_Test is EVaultTestBase { assertEq(eTST.totalBorrows(), 0); } + function test_zeroLiabilityWorth() public { + // set up liquidator to support the debt + startHoax(lender); + evc.enableController(lender, address(eTST)); + evc.enableCollateral(lender, address(eTST3)); + evc.enableCollateral(lender, address(eTST2)); + + startHoax(borrower); + evc.enableCollateral(borrower, address(eTST3)); + evc.enableController(borrower, address(eTST)); + eTST.borrow(5e18, borrower); + + startHoax(address(this)); + eTST.setLTV(address(eTST3), 0.95e4, 0.95e4, 0); + + // liability is worthless now (could be a result of rounding down in real scenario) + oracle.setPrice(address(assetTST), unitOfAccount, 0); + + (uint256 collateralValue, uint256 liabilityValue) = eTST.accountLiquidity(borrower, false); + assertEq(liabilityValue, 0); + assertGt(collateralValue, 0); + + (uint256 maxRepay, uint256 maxYield) = eTST.checkLiquidation(lender, borrower, address(eTST2)); + assertEq(maxRepay, 0); + assertEq(maxYield, 0); + + // now collateral is worthless + oracle.setPrice(address(assetTST2), unitOfAccount, 0); + + (collateralValue, liabilityValue) = eTST.accountLiquidity(borrower, false); + // both values zero now + assertEq(liabilityValue, 0); + assertEq(collateralValue, 0); + + (maxRepay, maxYield) = eTST.checkLiquidation(lender, borrower, address(eTST2)); + assertEq(maxRepay, 0); + assertEq(maxYield, 0); + + uint256 debtBefore = eTST.debtOf(borrower); + uint256 balanceBefore = eTST2.balanceOf(borrower); + + // liquidation is a no-op + startHoax(lender); + vm.expectEmit(); + emit Events.Liquidate(lender, borrower, address(eTST2), 0, 0); + eTST.liquidate(borrower, address(eTST2), type(uint256).max, 0); + + assertEq(eTST.debtOf(borrower), debtBefore); + assertEq(eTST2.balanceOf(borrower), balanceBefore); + } + function test_zeroLTVCollateral() public { // set up liquidator to support the debt startHoax(lender);