56859 sc medium lp underlying mismatch in stargateethpoolstrategy deallocate causes withdrawal dos
Submitted on Oct 21st 2025 at 10:16:27 UTC by @yesofcourse for Audit Comp | Alchemix V3
Report ID: #56859
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/strategies/optimism/StargateEthPoolStrategy.sol
Impacts:
Temporary freezing of funds for at least 1 hour
Description
Brief/Intro
The Optimism StargateEthPoolStrategy treats a caller-supplied underlying amount (WETH) as if it were LP shares during deallocation and also over-reports what it allocates after rounding down deposits.
In practice this causes under-redemption and a hard require revert when exiting, freezing vault withdrawals/rebalances that depend on this strategy. When the LP rate is favorable, excess ETH/WETH becomes stranded on the strategy, creating accounting drift (reduced realized returns).
Vulnerability Details
A) Unit mismatch on deallocation (LP != underlying). The strategy sizes the LP redemption as lpNeeded = amount, implicitly assuming 1:1 LP→underlying, but later enforces a WETH balance check against that same amount:
// inside _deallocate(uint256 amount)
uint256 lpNeeded = amount; // !! treats underlying as LP shares
pool.redeem(lpNeeded, address(this)); // returns ETH based on current exchange rate
// ...wrap some ETH to WETH...
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;If 1 LP < 1 ETH, redeeming lpNeeded = amount returns less than amount ETH; wrapping only the newly redeemed ETH leaves WETH < amount and the require reverts (withdrawal DoS). If 1 LP > 1 ETH, the function still approves/returns only amount, stranding surplus WETH on the strategy.
B) Over-reporting on allocation + unwrapped dust. On deposit, the adapter unwraps WETH to ETH and rounds down to a 1e12 multiple, but returns the original amount to the vault and leaves ETH dust on the contract:
During exit, _deallocate wraps only the new ETH redeemed, ignoring any historical ETH dust that would otherwise bridge the shortfall. The subsequent WETH ≥ amount check then fails.
The strategy API semantically treats
amountas underlying (WETH): it checks WETH balance, approves WETH, and returnsamount. Sizing the LP redemption aslpNeeded = amountis therefore inconsistent and unsafe for share-based LP tokens.Returning the unrounded amount in
_allocatemisleads the vault about what was actually put to work and increases the likelihood that_deallocate(amount)will fail later.
Scenario PoC - coded test in next section
Allocate an amount not divisible by 1e12 (e.g.,
1e18 - 1), which forces rounding down and creates ETH dust._allocatereturns the unrounded amount => vault thinks the full amount was deployed.With LP rate = 1.0 (to isolate the effect), call
_deallocatefor the sameamount. The adapter wraps only the newly redeemed ETH (ignoring the dust), then reverts onrequire(WETH >= amount).Changing the rate > 1.0 shows the complementary issue: the call succeeds but leaves surplus WETH stranded on the strategy (accounting drift).
Impact Details
Temporary freezing of funds for at least 1 hour.**
Any vault withdrawal/rebalance that requires deallocation from this strategy can revert, temporarily freezing the portion of user funds routed through this adapter until conditions change or the contract is patched.
This is deterministic when the recorded allocation exceeds what can be redeemed or when rounding dust is left unwrapped.
Secondary operational impacts
Contract fails to deliver promised returns, but doesn’t lose value: when the exchange rate > 1, over-redemption strands surplus WETH on the strategy, reducing realized yield for depositors and skewing accounting.
Cumulative dust growth: repeated allocations build up raw ETH dust, increasing the chance of future deallocation reverts.
This is not theft; it is a correctness issue that leads to service disruption and value marooned on the adapter. An adversary (or just organic conditions) can push the system into repeated failures by timing exits under unfavorable LP rates or after many rounded allocations.
References
Affected file:
src/strategies/optimism/StargateEthPoolStrategy.sol_allocate(uint256 amount)— rounds down deposit but returns the unroundedamount(over-reporting). https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/strategies/optimism/StargateEthPoolStrategy.sol#L52_deallocate(uint256 amount)— sizes redemption aslpNeeded = amount(unit mismatch), wraps only newly redeemed ETH, then requires WETH ≥amount. https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/strategies/optimism/StargateEthPoolStrategy.sol#L60
Proof of Concept
Proof of Concept
Insrc/test/strategies/StargateEthPoolStrategy.t.sol:
Add these imports right below the existing two imports at the top:
Append the following three blocks at the very end of the file:
Harness that exposes the internal functions:
Tiny local mocks:
The PoC test:
Run with:
Was this helpful?