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

Selling of the protocol profits has no slippage parameter, and can be stolen by sandwich attacks

Summary

Swap of the fees for WETH will accept an amount out of 0 tokens, and can be sandwiched to steal a portion of the profits.

Vulnerability Details

Fees.sol contract will receive the fees of the Lender contract, convert them to WETH by way of the Uniswap V3 router, and finally will send the WETH to the staking contract, funding the rewards of the stakers.

Fees.sol sellProfits() accepts an amountOutMinimum of 0 WETH. The protocol can have a catastrophic loss of funds via MEV bot sandwich attacks. Also the function can be called by anyone, making it even easier to sandwich with a MEV bundle of the 3 transactions whenever there is profit to be had for the MEV bot.

Impact

Selling of profits can return lower than expected amounts of WETH to the protocol and be stolen by MEV bots.

Tools Used

Manual review.

Recommendations

The function should be restricted to only be callable by the owner of the contract and a parameter for amountOutMinimum should be added to the function.

diff --git a/src/Fees.sol b/src/Fees.sol

@@ -3,12 +3,13 @@ pragma solidity ^0.8.19;

import "./utils/Errors.sol";
import "./utils/Structs.sol";
+import {Ownable} from "./utils/Ownable.sol";

-contract Fees {
+contract Fees is Ownable {
    address public immutable WETH;
    address public immutable staking;

    @@ -23,7 +24,10 @@ contract Fees {

    /// @notice swap loan tokens for collateral tokens from liquidations
    /// @param _profits the token to swap for WETH
+    // @audit-issue no slippage parameter. Can be attacked by MEV bot sandwich. 
+    // @audit-issue Anyone can call for the swap to occour makes this even easier to steal by the use of MEV bundles 
+    // @audit-issue recommendation is to pass as a parameter amountOutMinimum and have this function only callable by the owner
-    function sellProfits(address _profits) public {
+    function sellProfits(address _profits, uint256 _amountOutMinimum) public onlyOwner {
        require(_profits != WETH, "not allowed");
        uint256 amount = IERC20(_profits).balanceOf(address(this));

@@ -35,7 +39,7 @@ contract Fees {
                recipient: address(this),
                deadline: block.timestamp,
                amountIn: amount,
-                amountOutMinimum: 0,
+                amountOutMinimum: _amountOutMinimum, // @audit-issue can be sandwiched 
                sqrtPriceLimitX96: 0
            });

Support

FAQs

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

Give us feedback!