DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: low
Invalid

_harvestAndReport should deposit idled alETH tokens into the transmuter

Summary

As stated in yearn's documentation and BaseStrategy:_harvestAndReport code comments, the function _harvestAndReport should redeposit available alETH, but this isn't implemented in all 3 chains' functions.

Vulnerability Details

_harvestAndReport is called during every report. While it takes into account, as it should, the amount of loose asset in the strategy for the returned value, the function doesn't redeploy these assets to the transmuter, loosing on some potential conversion to WETH, that could come in handy if a strong profitable swapping opportunity presents itself.

This issue is mitigated by the fact that, when a user deposits in the strategy, the whole balance of assets will be deposited into the strategy.

The thing is, in case the vault ends in an shutdown state, the mitigation stated above will not be available anymore, while the main functions of the strategy will still be available (report for profit, swapping WETH alETH at premium, users withdrawing their deposit with potential yield). In this case, if the asset is not deposited in the _harvestAndReport function, this asset will never reach the transmuter for conversion to WETH.

This behavior should be implemented as stated in the documentation's purpose, best practice, and code example.

Impact

Reduced amount of alETH converted to WETH, limiting profits when valuable swap opportunities appears.

Not implementing the function as asked for in Yearn's documentation may trick/confuse users about what is the function doing.

Tools Used

Manual review, yearn's documentation

Recommendations

Because I don't see any edge case where the asset should not be deposited in the transmuter after an emergency shutdown of the vault, I suggest to deposit all assets every time the function _harvestAndReport is called, in all 3 chains :

function _harvestAndReport()
internal
override
returns (uint256 _totalAssets)
{
+ transmuter.deposit(asset.balanceOf(address(this)), address(this));
uint256 claimable = transmuter.getClaimableBalance(address(this));
uint256 unexchanged = transmuter.getUnexchangedBalance(address(this));
// NOTE : possible some dormant WETH that isn't swapped yet
uint256 underlyingBalance = underlying.balanceOf(address(this));
_totalAssets = unexchanged + asset.balanceOf(address(this)) + underlyingBalance;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
11 months ago

Appeal created

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
strapontin Submitter
10 months ago
inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.