From 6aa15065bf9c82027ca0de64d70ec01129c4a716 Mon Sep 17 00:00:00 2001 From: Steffel <2143646+steffenix@users.noreply.github.com> Date: Sun, 16 May 2021 19:55:26 +0200 Subject: [PATCH] fix: inconsistent Liquidations in BaseStrategy Emergency Exit Mode (#311) * fix: inconsistent Liquidations in BaseStrategy Emergency Exit Mode * refactor: move code back into harvest --- contracts/BaseStrategy.sol | 23 ++++++++++++++--------- contracts/test/TestStrategy.sol | 5 +++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/contracts/BaseStrategy.sol b/contracts/BaseStrategy.sol index 1676220b..7b8261a7 100644 --- a/contracts/BaseStrategy.sol +++ b/contracts/BaseStrategy.sol @@ -584,13 +584,19 @@ abstract contract BaseStrategy { * liquidation. If there is a difference between them, `_loss` indicates whether the * difference is due to a realized loss, or if there is some other sitution at play * (e.g. locked funds) where the amount made available is less than what is needed. - * This function is used during emergency exit instead of `prepareReturn()` to - * liquidate all of the Strategy's positions back to the Vault. * * NOTE: The invariant `_liquidatedAmount + _loss <= _amountNeeded` should always be maintained */ function liquidatePosition(uint256 _amountNeeded) internal virtual returns (uint256 _liquidatedAmount, uint256 _loss); + /** + * Liquidate everything and returns the amount that got freed. + * This function is used during emergency exit instead of `prepareReturn()` to + * liquidate all of the Strategy's positions back to the Vault. + */ + + function liquidateAllPositions() internal virtual returns (uint256 _amountFreed); + /** * @notice * Provide a signal to the keeper that `tend()` should be called. The @@ -720,14 +726,13 @@ abstract contract BaseStrategy { uint256 debtPayment = 0; if (emergencyExit) { // Free up as much capital as possible - uint256 totalAssets = estimatedTotalAssets(); - // NOTE: use the larger of total assets or debt outstanding to book losses properly - (debtPayment, loss) = liquidatePosition(totalAssets > debtOutstanding ? totalAssets : debtOutstanding); - // NOTE: take up any remainder here as profit - if (debtPayment > debtOutstanding) { - profit = debtPayment.sub(debtOutstanding); - debtPayment = debtOutstanding; + uint256 amountFreed = liquidateAllPositions(); + if (amountFreed < debtOutstanding) { + loss = debtOutstanding.sub(amountFreed); + } else if (amountFreed > debtOutstanding) { + profit = amountFreed.sub(debtOutstanding); } + debtPayment = debtOutstanding.sub(loss); } else { // Free up returns for Vault to pull (profit, loss, debtPayment) = prepareReturn(debtOutstanding); diff --git a/contracts/test/TestStrategy.sol b/contracts/test/TestStrategy.sol index ac6dfa65..e7cb6d84 100644 --- a/contracts/test/TestStrategy.sol +++ b/contracts/test/TestStrategy.sol @@ -125,4 +125,9 @@ contract TestStrategy is BaseStrategyInitializable { protected[0] = protectedToken; return protected; } + + function liquidateAllPositions() internal override returns (uint256 amountFreed) { + uint256 totalAssets = want.balanceOf(address(this)); + amountFreed = totalAssets; + } }