58022 sc medium accounting mismatch and fund stuck due to dust eth on stargateethpoolstrategy
Submitted on Oct 30th 2025 at 02:50:32 UTC by @Jugger63 for Audit Comp | Alchemix V3
Report ID: #58022
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 24 hour
Permanent freezing of funds
Description
Finding description
In StargateEthPoolStrategy the _allocation() function:
uint256 amountToDeposit = (amount / 1e12) * 1e12; // rounded down
uint256 dust = amount - amountToDeposit; // remaining dust
pool.deposit{value: amountToDeposit}(address(this), amountToDeposit);
return amount; // ← Refund full amount!The contract unwraps WETH to ETH, then only the amountToDeposit (a multiple of 1e12) is actually sent to the pool, leaving the dust ETH (≤ 1e12-1 wei) in the contract. The function still returns amount, so the Morpho Vault (caller) records an allocation of amount, not amountToDeposit. The realAssets() function simply returns pool.redeemable(address(this)), so the dust ETH is never accounted for in the strategy's real asset reporting. This results in an accounting discrepancy between the allocation held by the vault and the real value of the assets redeemable by the strategy.
Impact
Allocation > realAssets() causes the vault to believe the strategy holds more assets than it actually does. When the vault wants to withdraw (deallocate) the allocation amount, the strategy must redeem LP equal to amountToDeposit and make up the difference by wrapping dust ETH into WET. If the dust is insufficient, the following check is performed:
will fail and the transaction-deallocation revert and vault funds may get stuck until the admin performs manual intervention.
Recommendation
Return amountToDeposit (the real value deposited) from _allocate and immediately rewrap dust to WETH or at least include dust in the realAssets() calculation so that accounting is always consistent.
Reference
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/strategies/optimism/StargateEthPoolStrategy.sol#L46-L47
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/strategies/optimism/StargateEthPoolStrategy.sol#L51-L52
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/strategies/optimism/StargateEthPoolStrategy.sol#L79
Proof of Concept
Scenario Considerations
User/vault allocates
1.000000001234567 ETHin WETH._allocate:
amountToDeposit = 1.000000001000000 ETH(rounded)dust = 0.000000000234567 ETHis deposited in the contract.The function returns
1.000000001234567 ETH. The vault increases the allocation by this amount.
realAssets()reports only1.000000001000000 ETH. The difference of234,567 weiis not recorded.In the future, the vault calls
deallocate(1.000000001234567 ETH).The strategy can only redeem
1.000000001000000 ETHfrom the pool and attempts to cover234567 weiwith dust.If the dust is insufficient → require fails → revert → vault cannot withdraw funds → funds stuck.
POC
Add to StargateEthPoolStrategy.t.sol.
Was this helpful?