Lucene search

K
code423n4Code4renaCODE423N4:2023-08-DOPEX-FINDINGS-ISSUES-2092
HistorySep 06, 2023 - 12:00 a.m.

Attacker can DOS the sync function of RdpxV2Core which will brick critical functionality

2023-09-0600:00:00
Code4rena
github.com
6
rdpxv2core
dos
sync function
vulnerability
totalwethdelegated
manipulation
underflow
revert
uniswap
mitigation

6.8 Medium

AI Score

Confidence

High

Lines of code
<https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L975-L990&gt;
<https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1001-L1003&gt;

Vulnerability details

Impact

The sync function of the RdpxV2Core contract is critical for ensuring that the cached balances of the tokens in the contract are up to date. For example, all of the AMO logic involves sending tokens directly to the RdpxV2Core contract, meaning there’s no function which is used to both transfer the tokens and update the token balances accordingly. This sync function is therefore used to ensure that the token balances are up to date following the token transfers, allowing the RdpxV2Core contract to function smoothly.

The issue is that an attacker can trivially DOS this sync function by making it effectively always revert, which will in turn brick the entire system. Among other issues, it means that any of the Uniswap V2 AMO actions will not be able to update the RdpxV2Core contract state - and the Uniswap V3 AMO actions will always revert, as they call this sync function directly.

Proof of Concept

Consider how the sync function is implemented:

function sync() external {
  for (uint256 i = 1; i &lt; reserveAsset.length; i++) {
    uint256 balance = IERC20WithBurn(reserveAsset[i].tokenAddress).balanceOf(
      address(this)
    );

    if (weth == reserveAsset[i].tokenAddress) {
      balance = balance - totalWethDelegated;
    }
    reserveAsset[i].tokenBalance = balance;
  }

  emit LogSync();
}

Importantly notice that when the reserve asset being updated is WETH, the balance is calculated as balance = balance - totalWethDelegated;. The issue with the current implementation is that it’s trivial to force totalWethDelegated to be greater than balance, causing this subtraction to underflow and the function to revert. This attack can be done in the following way:

  1. In one tx, flashloan borrow WETH (from wherever there’s no fees) and first call addToDelegate on the RdpxV2Core contract with this amount of WETH. This will update the totalWethDelegated in the following way: totalWethDelegated += _amount;.
  2. At the end of the tx, call withdraw with delegateId equal to the position you created with the earlier call to addToDelegate. This will send you the entire amount of WETH back, which you will repay the flashloan with. Notably, this function will not decrement totalWethDelegated, meaning you have just increased it by a significant amount, without changing the balance of the WETH in the contract post this tx.

Following this attack, totalWethDelegated will be significantly larger than the balance of WETH in the RdpxV2Core contract, and so the subtraction in the sync function will always revert.

Tools Used

Manual review

Recommended Mitigation Steps

Update the withdraw function of the RdpxV2Core contract so that it properly decrements totalWethDelegated.

Assessed type

DoS


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

All reactions

6.8 Medium

AI Score

Confidence

High