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 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

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

alix402 Submitter
10 months ago
0xkann Auditor
10 months ago
inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 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.