DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: low
Invalid

Can't ensure swapping at a premium due to the missing checks of value

Summary

The _swapUnderlyingToAsset function uses a simple numeric comparison, requiring minOut > _amount, to “ensure” a premium when swapping WETH for ALETH. However, this check only guarantees that the contract receives a higher number of ALETH tokens than the amount of WETH spent—it does not account for the market value of those tokens. If ALETH trades below 1:1 relative to WETH, the strategy can receive more ALETH in terms of token count yet end up with a lower total value, resulting in a net loss.

Vulnerability Details

Location:

https://github.com/Cyfrin/2024-12-alchemix/blob/82798f4891e41959eef866bd1d4cb44fc1e26439/src/StrategyArb.sol#L81

https://github.com/Cyfrin/2024-12-alchemix/blob/82798f4891e41959eef866bd1d4cb44fc1e26439/src/StrategyOp.sol#L95

The requirement require(minOut > _amount, "minOut too low"); attempts to enforce a premium by ensuring minOut (expected ALETH) is strictly greater than the _amount of WETH.

function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IRamsesRouter.route[] calldata _path) internal {
// TODO : we swap WETH to ALETH -> need to check that price is better than 1:1
// uint256 oraclePrice = 1e18 * 101 / 100;
@> require(minOut > _amount, "minOut too low");
uint256 underlyingBalance = underlying.balanceOf(address(this));
require(underlyingBalance >= _amount, "not enough underlying balance");
IRamsesRouter(router).swapExactTokensForTokens(_amount, minOut, _path, address(this), block.timestamp);
}

And the function then calls:

interface IRamsesRouter {
struct route {
address from;
address to;
bool stable;
}
@> function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
route[] calldata routes,
address to,
uint256 deadline
) external;
}

The contract only checks that the number of ALETH tokens exceeds the number of WETH tokens, it ignores the possibility that ALETH might be worth significantly less than WETH on the open market.

For instance, swapping 10000 WETH to 10010 ALETH appears to be a premium, but the ALETH/WETH price is 0.9852 in the Coinbase market now, the value of 10010 ALETH is equal to 9861.852 WETH, which means swapping 10000 WETH to 9851.852 WETH, is actually a net loss.

This approach to verifying a “premium swap” is thus incomplete. It overlooks the ratio or price feed that would confirm whether the received ALETH is indeed worth more than the WETH sent out.

Impact

The strategy can end up with a reduced total valuation despite receiving a larger token amount. This misalignment between token quantity and token market price directly harms any user whose assets are managed by the strategy.

Tools Used

Manual Review

Recommendations

1.Implement price feed: Use an oracle or reliable price feed to confirm that the market value of the ALETH to be received exceeds the value of the WETH spent.

function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IRamsesRouter.route[] calldata _path) internal {
// TODO : we swap WETH to ALETH -> need to check that price is better than 1:1
// uint256 oraclePrice = 1e18 * 101 100;
+ require(
+ minOut * oraclePriceALETH >= _amount * oraclePriceWETH,
+ "Not a real premium in value"
+ );
uint256 underlyingBalance = underlying.balanceOf(address(this));
require(underlyingBalance >= _amount, "not enough underlying balance");
IRamsesRouter(router).swapExactTokensForTokens(_amount, minOut, _path, address(this), block.timestamp);
}

2.Dynamic minOut Calculation: Instead of letting keepers supply any minOut, have the strategy compute a safe threshold based on recent on-chain or oracle-based WETH/ALETH prices, ensuring that a net profitable ratio is enforced.

Updates

Lead Judging Commences

inallhonesty Lead Judge
11 months ago

Appeal created

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

[INVALID]Lack of mechanism to ensure premium swaps

Support

FAQs

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