DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: medium
Valid

Incomplete Harvest Implementation in _harvestAndReport() Results in Inaccurate Asset Reporting

Summary

The _harvestAndReport() function in the StrategyMainnet contract does not currently perform the necessary actions to realize claimable underlying tokens. Although it identifies a claimable amount, the operation to actually claim and then swap these tokens back into the asset (alETH) is commented out, causing the strategy to underreport its total assets and fail to realize profits accurately.

Vulnerability Details

By not claiming the transmutable (claimable) underlying tokens and not converting them back into the asset, the strategy’s profit calculation and totalAssets reporting become unreliable. The function should harvest rewards, perform conversions, and redeploy funds to maintain accurate accounting. Currently, it only calculates claimable amounts but never finalizes that claim process nor reinvests, missing out on actual yield realization.

Impact

  • Inaccurate Profit/Loss Accounting: The strategy will inaccurately report its assets, potentially causing misrepresented gains or losses.

  • Reduced Yield for Users: Unclaimed and unconverted tokens mean that users do not benefit from the full yield that the underlying source generates.

  • Potential Fee Misallocation: Performance and management fees may be incorrectly calculated if the actual profits are not realized and reported, impacting both strategists and users.

Tools Used

  • Manual code review of the StrategyMainnet contract.

  • Conceptual analysis of the expected behavior of _harvestAndReport() and the standard Yearn strategy lifecycle.

Recommendations

  1. Implement Claim Logic: Uncomment and properly implement the code that calls transmuter.claim() and retrieves the underlying tokens.

  2. Swap Underlying to Asset: Ensure that any claimed underlying tokens are swapped back into the asset using the configured Curve router parameters.

  3. Redeploy Idle Assets: After conversion, call _deployFunds() with the updated asset balance to ensure idle funds are reintroduced into the yield source.

  4. Accurate Minimum Outputs: Implement a strategy to determine _minOut during swaps to protect against unfavorable slippage.

  5. Testing and Validation: Thoroughly test the modified _harvestAndReport() function to confirm it correctly realizes, reports, and redeploys yield under various conditions.

Corrected Implementation Example:

function _harvestAndReport()
internal
override
returns (uint256 _totalAssets)
{
// Only perform harvest logic if the strategy is not shutdown
if(!TokenizedStrategy.isShutdown()) {
// 1. Claim any available underlying tokens from the transmuter
uint256 claimable = transmuter.getClaimableBalance(address(this));
if (claimable > 0) {
transmuter.claim(claimable, address(this));
}
// 2. If we have underlying tokens, swap them into 'asset' (alETH)
uint256 underlyingBal = underlying.balanceOf(address(this));
if (underlyingBal > 0 && nRoutes > 0) {
uint256 minOut = underlyingBal; // Adjust this based on slippage requirements
router.exchange(
routes[0],
swapParams[0],
underlyingBal,
minOut,
pools[0],
address(this)
);
}
// 3. After swapping, if we have idle 'asset', redeploy it
uint256 assetBal = asset.balanceOf(address(this));
if (assetBal > 0) {
_deployFunds(assetBal);
}
}
// 4. Return a trusted accounting of all assets
uint256 unexchanged = transmuter.getUnexchangedBalance(address(this));
uint256 underlyingBalance = underlying.balanceOf(address(this));
uint256 assetBalance = asset.balanceOf(address(this));
_totalAssets = unexchanged + assetBalance + underlyingBalance;
}

By following these recommendations, the strategy can accurately harvest, realize, and report yield, ensuring that users and stakeholders receive a fair and accurate representation of the strategy’s performance.

Updates

Appeal created

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect accounting in `_harvestAndReport` claimable should be included

Support

FAQs

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