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

Value loss when swapping WETH to alETH.

Summary

The current implementation allows swapping WETH to alETH at ratio better than 1:1 but without verifying whether the actual market price of alETH aligns with this ratio.
If the price of alETH is significantly lower than WETH in market terms, this can result in substantial value loss during the swap, causing financial harm to the protocol or its users.

Vulnerability Details

Price Mismatch Risk:

  • The swap ratio for WETH:alETH forces the keeper to only swap if the ratio is WETH 1:1.1 alETH but it doesn't take into account the difference between WETH/alETH market Price.

  • If the real market price of alETH is lower than WETH Price, the protocol effectively overpays in WETH for alETH, leading to value loss.

So there is an issue when swapping WETH for alETH because 1:1 ratio doesn't means same market Price so keeper can swap WETH: 3450$ for alETH: 3400$ there is loss in value when swapping WETH for alETH.
Dexes determine ratio if both Tokens has same amount but not same price.

function claimAndSwap(uint256 _amountClaim, uint256 _minOut, IRamsesRouter.route[] calldata _path) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this));
_swapUnderlyingToAsset(_amountClaim, _minOut, _path);
uint256 balAfter = asset.balanceOf(address(this));
require((balAfter - balBefore) >= _minOut, "Slippage too high");
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}
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);
}

How Ramses Pairs get getAmountOut:

function _getAmountOut(
uint256 amountIn,
address tokenIn,
uint256 _reserve0,
uint256 _reserve1
) internal view returns (uint256) {
if (stable) {
uint256 xy = _k(_reserve0, _reserve1);
_reserve0 = (_reserve0 * 1e18) / decimals0;
_reserve1 = (_reserve1 * 1e18) / decimals1;
(uint256 reserveA, uint256 reserveB) = tokenIn == token0
? (_reserve0, _reserve1)
: (_reserve1, _reserve0);
amountIn = tokenIn == token0
? (amountIn * 1e18) / decimals0
: (amountIn * 1e18) / decimals1;
uint256 y = reserveB - _get_y(amountIn + reserveA, xy, reserveB);
return (y * (tokenIn == token0 ? decimals1 : decimals0)) / 1e18;
} else {
(uint256 reserveA, uint256 reserveB) = tokenIn == token0
? (_reserve0, _reserve1)
: (_reserve1, _reserve0);
return (amountIn * reserveB) / (reserveA + amountIn);
}
}

Impact

Financial Loss: The protocol may incur significant losses by swapping WETH for alETH.

Tools Used

Recommendations

  1. Implement Price Validation:
    Integrate an oracle-based price check to validate the actual market price of alETH against WETH before executing the swap:
    Example:

uint256 marketPrice = priceOracle.getPrice(alETH, WETH);
require(marketPrice >= 1.1 ether, "Swap rate below threshold");
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.