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

No buffer when swapping tokens can lead to unprofitable trades due to gas costs and fees

Summary

Contracts in scope use the claimAndSwap function to claim wETH from the Transmuter contract and use these tokens to swap for alETH at a premium. However, this function only makes sure that the received alETH amount is greater than the wETH to make sure a swap is profitable, but this function does not consider gas costs or fees that will make these swaps overall unprofitable. This is not a problem for Optimism and Arbitrum chains but in Ethereum Mainnet, gas costs are noticeably higher which will lead to unfavourable swaps.

Vulnerability Details

The claimAndSwap function swaps the wETH received from Transmuter contract for alETH at a premium. For simplicity, focus on the mainnet version.

function claimAndSwap(
uint256 _amountClaim,
uint256 _minOut,
uint256 _routeNumber
) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this));
require(_minOut > _amountClaim, "minOut too low");
router.exchange(
routes[_routeNumber],
swapParams[_routeNumber],
_amountClaim,
_minOut,
pools[_routeNumber],
address(this)
);
uint256 balAfter = asset.balanceOf(address(this));
require((balAfter - balBefore) >= _minOut, "Slippage too high");
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}

As observed in this function, it only makes sure that the minimum amount of alETH received from this swap is greater than wETH. But this check alone does not make sure that a swap is profitable as it does not consider gas costs. When the price of alETH/wETH gets close to 1 (for example, 1 alETH = 0.998 wETH), added fees for the swap and gas costs on mainnet can make this swap unprofitable even though received alETH amount is greater than the swapped wETH amount.

In an example scenario when the function is used to swap 0.2 wETH for alETH, at the current pool state 0.202 alETH will be received. Considering that a direct swap in this stable pool will cost about 0.004 ETH

  • We have spent 0.2 wETH + 0.004 ETH for the swap = 0.204 ETH

  • Received 0.202 alETH

  • Overall a loss of 0.002 ETH occurs.

The possiblity of manipulation in this low liquidity pool leading to even more unfavourable profits and gas costs fluctuating, the loss can be even more severe.

Impact

Lack of a buffer will lead to unprofitable swaps that the system sees as profitable.

Tools Used

Manual review

Recommendations

Implement a buffer to take gas costs into account. An example is shown below.

uint256 gasCostBuffer = 0.004; // added buffer
function claimAndSwap(
uint256 _amountClaim,
uint256 _minOut,
uint256 _routeNumber
) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this));
require(_minOut > _amountClaim, "minOut too low");
router.exchange(
routes[_routeNumber],
swapParams[_routeNumber],
_amountClaim,
_minOut,
pools[_routeNumber],
address(this)
);
uint256 balAfter = asset.balanceOf(address(this));
require((balAfter - balBefore) >= _minOut + gasCostBuffer, "Slippage too high"); //changed line
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}
Updates

Appeal created

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
ljj Submitter
10 months ago
inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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