Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
MorphoYearnOGWETH will always emit the StrategyDeallocationLoss event as the calculations done will always lead to 0.
Vulnerability Details
Currently in _deallocate, the contract checks a wethBalanceBefore and wethBalanceAfter, the problem with this is that the contract does this sequentially rather than before calling vault.withdraw.
What this effectively does is that it will have the same value resulting in wethRedeemed always been 0.
When this occurs, this triggers the event StrategyDeallocationLoss. Further down, there is then also a duplication of the check which would effectively be the same calculated values.
Impact Details
No user funds are lost, and the function executes correctly. However, it emits misleading StrategyDeallocationLoss events, which may confuse monitoring systems or off-chain analytics.
...
require(wethRedeemed + wethBalanceBefore >= amount, "Strategy balance is less than the amount needed");
require(TokenUtils.safeBalanceOf(address(weth), address(this)) >= amount, "Strategy balance is less than the amount needed");
...
### Summary
- The contract calls `vault.withdraw` first, then measures `wethBalanceBefore` and `wethBalanceAfter`.
- Since both balances are measured after the withdrawal, `wethRedeemed` is always 0.
- This triggers the `StrategyDeallocationLoss` event erroneously.
...
+import "forge-std/console.sol";
...
function _deallocate(uint256 amount) internal override returns (uint256) {
vault.withdraw(amount, address(this), address(this));
uint256 wethBalanceBefore = TokenUtils.safeBalanceOf(address(weth), address(this));
uint256 wethBalanceAfter = TokenUtils.safeBalanceOf(address(weth), address(this));
+ console.log("Balance before : ", wethBalanceBefore);
+ console.log("Balance after : ", wethBalanceAfter);
uint256 wethRedeemed = wethBalanceAfter - wethBalanceBefore;
if (wethRedeemed < amount) {
+ console.log("Emit for 'Strategy deallocation loss.' : ", amount, wethRedeemed);
emit StrategyDeallocationLoss("Strategy deallocation loss.", amount, wethRedeemed);
}
require(wethRedeemed + wethBalanceBefore >= amount, "Strategy balance is less than the amount needed");
require(TokenUtils.safeBalanceOf(address(weth), address(this)) >= amount, "Strategy balance is less than the amount needed");
+ console.log("(wethRedeemed + wethBalanceBefore >= amount) values : ", wethRedeemed, wethBalanceBefore, amount);
+ console.log("(TokenUtils.safeBalanceOf(address(weth), address(this)) >= amount) values : ", TokenUtils.safeBalanceOf(address(weth), address(this)), amount);
TokenUtils.safeApprove(address(weth), msg.sender, amount);
return amount;
}