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

Keepers are not able to handle existing WETH balance in `claimAndSwap()`

## Summary

The claimAndSwap() is designed to allow keepers to claim WETH from the transmuter and swap it to alETH. However, the implementation in @src/StrategyMainnet.sol, @src/StrategyArb.sol and @src/StrategyOp.sol only swaps the newly claimed WETH amount from transmuter and ignores any existing WETH balance in the strategy. This creates a situation where WETH that accumulates in the strategy from previous operations cannot be swapped to alETH, effectively trapping these funds.

The issue stems from the router.exchange() call using _amountClaim as the amount to swap, rather than the strategy's total WETH balance. The _amountClaim parameter only represents the amount being claimed from the Transmuter in the current transaction, excluding any pre-existing WETH balance in the strategy.

e.g from the @src/StrategyMainnet.sol

https://github.com/Cyfrin/2024-12-alchemix/blob/82798f4891e41959eef866bd1d4cb44fc1e26439/src/StrategyMainnet.sol#L93-L109

function claimAndSwap(
uint256 _amountClaim,
uint256 _minOut,
uint256 _routeNumber
) external onlyKeepers {
// @audit-issue we don't include the current underlying balance in the `_amountClaim`, this leads to no way possible for keepers to swap and use
// the weth contained in the strategy => Mitigation: on router.exchange calls with underlying.balanceOf(address(this)) instead of _amountClaim
// NOTE minOUt must be more than amount to claim
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this));
// NOTE: we swap to get alEth to do the farming strategy:
require(_minOut > _amountClaim, "minOut too low");
router.exchange(
routes[_routeNumber],
swapParams[_routeNumber],
@>> _amountClaim,

## Recommended mitigation steps

Modify the `claimAndSwap()` function to use the total WETH balance for the swap operation instead of just the claimed amount.

This is how the fix could look like in `@src/StrategyMainnet.sol` :

function claimAndSwap(
uint256 _amountClaim,
uint256 _minOut,
uint256 _routeNumber
) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this));
uint256 totalWethToSwap = underlying.balanceOf(address(this));
router.exchange(
routes[_routeNumber],
swapParams[_routeNumber],
totalWethToSwap, // Use total WETH balance instead of _amountClaim
_minOut,
pools[_routeNumber],
address(this)
);
require(_minOut > totalWethToSwap, "minOut too low");
Updates

Appeal created

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

Dormant WETH in the contract will never be swapped back to alETH

alix402 Submitter
6 months ago
0xkann Auditor
6 months ago
inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Dormant WETH is not properly treated

Support

FAQs

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