code-423n4 / 2024-07-reserve-validation

0 stars 0 forks source link

Inaccurate BasketsNeeded Update in _scaleDown() Function Compromises RToken Collateralization and Stability #86

Closed c4-bot-4 closed 1 month ago

c4-bot-4 commented 2 months ago

Lines of code

https://github.com/code-423n4/2024-07-reserve/blob/3f133997e186465f4904553b0f8e86ecb7bbacbf/contracts/p1/RToken.sol#L508-L516 https://github.com/code-423n4/2024-07-reserve/blob/3f133997e186465f4904553b0f8e86ecb7bbacbf/contracts/p1/RToken.sol#L160-L190

Vulnerability details

The Redeem() and redeemTo() functions in the RToken contract allow users to redeem their RTokens for the underlying basket of collateral tokens. During the redemption process, the basketsNeeded variable is updated to reflect the reduced number of baskets required for collateralization.

However, the calculation of amtBaskets in the _scaleDown() function, is called by both redeem() and redeemTo(). This leads to incorrect accounting of the basketsNeeded value, affecting the overall stability and collateralization of the RToken system.

Arises in the _scaleDown() function in RToken.sol:508-516

function _scaleDown(address account, uint256 amtRToken) private returns (uint192 amtBaskets) {
    // D18{BU} = D18{BU} * {qRTok} / {qRTok}
    amtBaskets = basketsNeeded.muluDivu(amtRToken, totalSupply()); // FLOOR
    emit BasketsNeededChanged(basketsNeeded, basketsNeeded - amtBaskets);
    basketsNeeded -= amtBaskets;

    // Burn RToken from account; reverts if not enough balance
    _burn(account, amtRToken);
}

The calculation of amtBaskets uses basketsNeeded.muluDivu(amtRToken, totalSupply()), which may not accurately reflect the number of baskets to be deducted based on the redeemed RToken amount.

Impact

Proof of Concept

Let's say:

Tools Used

Manual review

Recommended Mitigation Steps

Update the calculation to reflect the number of baskets to be deducted based on the redeemed RToken amount. By calculating amtBaskets as amtRToken.muluDivu(basketsNeeded, totalSupply()), the function will accurately determine the number of baskets to be deducted based on the redeemed RToken amount.

function _scaleDown(address account, uint256 amtRToken) private returns (uint192 amtBaskets) {
-    amtBaskets = basketsNeeded.muluDivu(amtRToken, totalSupply()); // FLOOR
+    amtBaskets = amtRToken.muluDivu(basketsNeeded, totalSupply()); // FLOOR
    emit BasketsNeededChanged(basketsNeeded, basketsNeeded - amtBaskets);
    basketsNeeded -= amtBaskets;

    _burn(account, amtRToken);
}

Assessed type

Math