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

The availableWithdrawLimit function does not account for liquidity constraints, which could lead the contract to assume that all assets are immediately available for withdrawal.

Summary

The availableWithdrawLimit function currently does not account for liquidity restrictions, which may lead the contract to assume that all assets are immediately available for withdrawal, while in reality, some assets may not be liquid or may be locked. This oversight could cause issues where users believe they can withdraw their full balance, but due to liquidity constraints, they cannot.

Vulnerability Details

https://github.com/Cyfrin/2024-12-alchemix/blob/82798f4891e41959eef866bd1d4cb44fc1e26439/src/StrategyMainnet.sol#L217
The current implementation directly returns the sum of the contract's asset balance and the unexchanged balance without considering liquidity limitations. This means that the function does not take into account the possibility that some assets may not be available for immediate withdrawal due to liquidity constraints, freezing, or other restrictions, especially for unexchanged funds.

function availableWithdrawLimit(
address /*_owner*/
) public view override returns (uint256) {
return asset.balanceOf(address(this)) + transmuter.getUnexchangedBalance(address(this));
}

Impact

The current availableWithdrawLimit implementation ignores liquidity constraints, unexchanged funds, and possibly locked assets within the contract. As a result, the contract might assume all assets are available for immediate withdrawal, but some assets might actually be illiquid, frozen, or not yet converted to available funds. This could lead to users facing discrepancies between the amount they believe they can withdraw and the actual amount they can access.

Tools Used

Manual review

Recommendations

Check if unexchanged funds are immediately redeemable

function availableWithdrawLimit(address _owner) public view override returns (uint256) {
uint256 availableBalance = asset.balanceOf(address(this));
// Get the unexchanged funds
uint256 unexchangedBalance = transmuter.getUnexchangedBalance(address(this));
// Get the maximum redeemable balance from the transmuter
uint256 maxRedeemable = getMaxRedeemableFromTransmuter();
// If the contract has enough liquidity and unexchanged funds are redeemable, return the total available amount
uint256 totalAvailable = availableBalance + min(unexchangedBalance, maxRedeemable);
return totalAvailable;
}
Updates

Appeal created

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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