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

Incomplete fund withdrawal logic in `_freeFunds` Function

Summary

The _freeFunds function in the StrategyMainnet contract does not account for all possible sources of funds when attempting to free assets for withdrawal. This could lead to underreporting of available funds and potential failure to meet withdrawal requests even when sufficient assets are available across different sources.

Vulnerability Details

https://github.com/Cyfrin/2024-12-alchemix/blob/5c19ee37df3aa7605bf782c9c40a482fd82adc67/src/StrategyMainnet.sol#L136-L143

function _freeFunds(uint256 _amount) internal override {
uint256 totalAvailabe = transmuter.getUnexchangedBalance(address(this));
if (_amount > totalAvailabe) {
transmuter.withdraw(totalAvailabe, address(this));
} else {
transmuter.withdraw(_amount, address(this));
}
}

This function only considers the unexpchanged balance in the transmuter, ignoring loose assets already in the contract and claimable WETH in the transmuter.

Impact

The incomplete withdrawal logic can lead to several issues:

  1. Underreporting of available funds, potentially causing unnecessary withdrawal failures.

  2. Inefficient use of available assets, as some sources of funds are not utilized.

  3. Possible user frustration due to failed withdrawals when sufficient funds are actually available.

  4. In extreme cases, this could lead to a loss of trust in the strategy if it consistently fails to meet withdrawal requests despite having sufficient assets.

Tools Used

manual code review.

Recommendations

Consider implementing a more comprehensive _freeFunds function that accounts for all potential sources of funds:

Check the balance of loose assets (alETH) already in the contract.
If more funds are needed, withdraw from the transmuter's unexpchanged balance.
If there's still a shortfall, claim WETH from the transmuter and swap it to alETH.

Something like this:

function _freeFunds(uint256 _amount) internal override {
uint256 looseAssets = asset.balanceOf(address(this));
if (looseAssets >= _amount) {
return; // We already have enough loose assets
}
uint256 stillNeeded = _amount - looseAssets;
uint256 unexpchangedBalance = transmuter.getUnexchangedBalance(address(this));
if (unexpchangedBalance > 0) {
uint256 toWithdraw = Math.min(stillNeeded, unexpchangedBalance);
transmuter.withdraw(toWithdraw, address(this));
stillNeeded -= toWithdraw;
}
if (stillNeeded > 0) {
uint256 claimable = transmuter.getClaimableBalance(address(this));
if (claimable > 0) {
// Implement logic to claim WETH and swap to alETH
// Ensure the swap covers the remaining stillNeeded amount
}
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
10 months ago

Appeal created

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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