58067 sc high asymmetric deallocation in tokeautoethstrategy leads to permanent weth funds stuck in strategy
Submitted on Oct 30th 2025 at 12:15:42 UTC by @dobrevaleri for Audit Comp | Alchemix V3
Report ID: #58067
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/strategies/mainnet/TokeAutoEth.sol
Impacts:
Permanent freezing of funds
Description
Brief/Intro
When the TokeAutoEthStrategy::_deallocate() function determines that remaining shares after withdrawal would be small (≤ 1e18), it withdraws all shares to avoid rounding issues. However, this creates an asymmetry where more assets are withdrawn than the requested amount, but only the requested amount is approved for transfer back to the vault. The excess WETH remains permanently stuck in the strategy contract.
Vulnerability Details
The vulnerability exists in the TokeAutoEthStrategy::_deallocate() function at lines 72-80. When the difference between held shares and needed shares (shareDiff) is less than or equal to 1e18, the strategy withdraws ALL shares instead of just the required amount:
function _deallocate(uint256 amount) internal override returns (uint256) {
uint256 sharesNeeded = autoEth.convertToShares(amount);
uint256 actualSharesHeld = rewarder.balanceOf(address(this));
uint256 shareDiff = actualSharesHeld - sharesNeeded;
if (shareDiff <= 1e18) {
// account for vault rounding up
@> sharesNeeded = actualSharesHeld;
}
// withdraw shares, claim any rewards
@> rewarder.withdraw(address(this), sharesNeeded, true);
uint256 wethBalanceBefore = TokenUtils.safeBalanceOf(address(weth), address(this));
autoEth.redeem(sharesNeeded, address(this), address(this));
uint256 wethBalanceAfter = TokenUtils.safeBalanceOf(address(weth), address(this));
uint256 wethRedeemed = wethBalanceAfter - wethBalanceBefore;
if (wethRedeemed < amount) {
emit StrategyDeallocationLoss("Strategy deallocation loss.", amount, wethRedeemed);
}
require(TokenUtils.safeBalanceOf(address(weth), address(this)) >= amount, "Strategy balance is less than the amount needed");
TokenUtils.safeApprove(address(weth), msg.sender, amount);
@> return amount;
}The issue manifests in the following sequence:
The strategy withdraws
actualSharesHeldshares (all shares) from the rewarderThe
autoEth.redeem()call returns all underlying WETH assets corresponding to ALL sharesHowever, the function only approves and returns the originally requested
amountThe excess WETH (representing the
shareDiff) remains in the strategy contract
Only the requested amount is approved for transfer, leaving the excess permanently inaccessible.
Impact Details
Excess WETH tokens become permanently stuck in the strategy contract with no mechanism for recovery.
References
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/strategies/mainnet/TokeAutoEth.sol#L67-L87
Proof of Concept
Proof of Concept
Was this helpful?