20,000 USDC
View results
Submission Details
Severity: high
Valid

Sandwich attack for `exactInputSingle` in contract `Fees`

Summary

Without a specified minimum amount for the output token (WETH), an attacker could front-run the transaction and manipulate the price, causing the contract to receive less WETH than expected.

Vulnerability Details

The amountOutMinimum parameter in the ExactInputSingleParams structure is used to ensure that the swap will only succeed if the amount of the output token (in this case, WETH) is greater than or equal to a specified minimum value. This can help protect against unfavorable price changes between the time you create the transaction and the time it is included in a block.

ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: _profits,
tokenOut: WETH,
fee: 3000,
recipient: address(this),
deadline: block.timestamp,
amountIn: amount,
amountOutMinimum: 0, // <-----------------
sqrtPriceLimitX96: 0
});
amount = swapRouter.exactInputSingle(params);

The attacker monitors the pending transactions pool (mempool) for any calls to the sellProfits function within the Fees contract. They look for transactions where a significant amount of tokens is being swapped and amountOutMinimum is set to 0. Once the attacker identifies a suitable victim's transaction that meets their criteria, they prepare to place two transactions of their own: one before and one after the victim's transaction.

Impact

By setting the amountOutMinimum to 0, it opens the door for an attacker to perform a "sandwich attack", manipulating the token's price and causing the victim to buy or sell at an unfavorable price.

Tools Used

Manual review

Recommendations

Instead of setting the amountOutMinimum parameter to 0, use a meaningful value that represents the minimum acceptable output amount for the swap. To implement amountOutMinimum, you need to calculate the minimum amount of WETH that you are willing to accept for the swap. This can be based on the current price of the token and a tolerable slippage percentage.

// Query the current price from Uniswap (this will depend on your specific setup)
uint256 currentPrice = getPrice(_profits, WETH);
// Determine the minimum acceptable amount of WETH, allowing for some slippage
uint256 slippage = 1; // 1% slippage
uint256 amountOutMinimum = (currentPrice * amountIn * (100 - slippage)) / 100;
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: _profits,
tokenOut: WETH,
fee: 3000,
recipient: address(this),
deadline: block.timestamp,
amountIn: amount,
amountOutMinimum: amountOutMinimum, // <-----------------
sqrtPriceLimitX96: 0
});
amount = swapRouter.exactInputSingle(params);

The getPrice() function should be implemented based on the specific way you are interfacing with Uniswap or any other exchange.

Support

FAQs

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