Lucene search

K
code423n4Code4renaCODE423N4:2023-06-ANGLE-FINDINGS-ISSUES-20
HistoryJul 07, 2023 - 12:00 a.m.

LACK OF deadline CHECK COULD PROMPT DELAYED EXECUTION OF swap OPERATION

2023-07-0700:00:00
Code4rena
github.com
10
vulnerability
delayed execution
disadvantageous prices
deadline check
collateral tokens
loss of funds
sandbox attack
one_inch_router
malicious mev bot
mitigation steps

Lines of code

Vulnerability details

Impact

The RewardHandler.sellRewards() function is used by governance and trusted sellers to sell reward tokens for collateral tokens. This function ensures that none of the collateral should be decreased after the swap by checking their respective balances before and after the swap transaction via ONE_INCH_ROUTER.

The issue here is there is no deadline check for this swap transaction inside the RewardHandler.sellRewards() function. Even if the deadline is passed in as an input parameter in the payload of the sellRewards() function, this deadline may not be used by the particular AMM used by the ONE_INCH_ROUTER. This is because ONE_INCH_ROUTER uses multiple DEXes for liquidity, to execute the swap trade.

Hence if this transaction is originated with less gas, it can be delayed by the miners. As a result this transaction can be executed at a later point in time at a disadvantageous price point for the protocol.

Hence the protocol will receive less collateral tokens for their reward tokens swapped which is loss of funds for the protocol.

And add to that the minAmountOut can also get outdated if the exchange rate changes in favour of the collateral and same reward amount can receive large collateral. A malicious MEV bot can use this transaction to perform a sandwich attack since the minAmountOut is not now updated to the new value.

Proof of Concept

    function sellRewards(uint256 minAmountOut, bytes memory payload) external returns (uint256 amountOut) {
        TransmuterStorage storage ts = s.transmuterStorage();
        if (!LibDiamond.isGovernorOrGuardian(msg.sender) && ts.isSellerTrusted[msg.sender] == 0) revert NotTrusted();
        address[] memory list = ts.collateralList;
        uint256 listLength = list.length;
        uint256[] memory balances = new uint256[](listLength);
        // Getting the balances of all collateral assets of the protocol to see if those do not decrease during
        // the swap: this is the only way to check that collateral assets have not been sold
        // Not checking the subCollaterals here as swaps should try to increase the balance of one collateral
        for (uint256 i; i < listLength; ++i) {
            balances[i] = IERC20(list[i]).balanceOf(address(this));
        }
        //solhint-disable-next-line
        (bool success, bytes memory result) = ONE_INCH_ROUTER.call(payload);
        if (!success) _revertBytes(result);
        amountOut = abi.decode(result, (uint256));
        if (amountOut < minAmountOut) revert TooSmallAmountOut();
        bool hasIncreased;
        for (uint256 i; i < listLength; ++i) {
            uint256 newBalance = IERC20(list[i]).balanceOf(address(this));
            if (newBalance < balances[i]) revert InvalidSwap();
            else if (newBalance > balances[i]) {
                hasIncreased = true;
                emit RewardsSoldFor(list[i], newBalance - balances[i]);
            }
        }
        if (!hasIncreased) revert InvalidSwap();
    }

<https://github.com/AngleProtocol/angle-transmuter/blob/9707ee4ed3d221e02dcfcd2ebaa4b4d38d280936/contracts/transmuter/facets/RewardHandler.sol#L29-L56&gt;

Tools Used

Manual Review and VSCode

Recommended Mitigation Steps

Hence it is recommended to perform a deadline check for this transaction by providing a deadline timestamp as input parameter to the RewardHandler.sellRewards() and later checking it against the block.timestamp as shown below, to ensure the transaction has executed before the deadline.

require(block.timestamp &lt; deadline, "Expired Trade");

Assessed type

Other


The text was updated successfully, but these errors were encountered:

All reactions