Closed c4-bot-2 closed 1 month ago
@thereksfour I think this issue is wrongly grouped. The primary issue 74 and others in group 48 talks about slippage loss in rToken issuance. The issue was known and judged accordingly here
But this issue talks about slippage loss during rToken REDEMPTION. Please re-judge as primary issue and not a dup of #74.
The group label is not accurate, this is automated and we do not rely on it. redeem is only allowed when fully collateralized, when there is sufficient collateral and no slippage loss.
redeem is only allowed when fully collateralized, when there is sufficient collateral and no slippage loss.
Okay if users wants redeem only when collateralized. But redeem is still not protected during the processing of rToken revenue. Redemption with get affected by slippage loss during settle auction trade (either re-collateralization or processing RToken revenue).
Quoting from first 3 lines from Vulnerability details
rToken::redeemCustom has slippage protection due to portions and pro rata accounting which can be volatile during under-collateralized times. But during proper collateralized times, the exchange rate between total supply of rToken and backing needed can be volatile
The tokens of the revenue part will not be taken out when redeeming. When fully collateralized, the tokens of the revenue part will only be distributed in forwardRevenue.
function quote(
uint192 amount,
bool applyIssuancePremium,
RoundingMode rounding
) public view returns (address[] memory erc20s, uint256[] memory quantities) {
IAssetRegistry assetRegistry = main.assetRegistry();
erc20s = new address[](basket.erc20s.length);
quantities = new uint256[](basket.erc20s.length);
for (uint256 i = 0; i < basket.erc20s.length; ++i) {
erc20s[i] = address(basket.erc20s[i]);
ICollateral coll = assetRegistry.toColl(IERC20(erc20s[i]));
// {tok} = {tok/BU} * {BU}
uint192 q = _quantity(basket.erc20s[i], coll, rounding).safeMul(amount, rounding);
// Prevent toxic issuance by charging more when collateral is under peg
if (applyIssuancePremium) {
uint192 premium = issuancePremium(coll); // {1} always CEIL
// {tok} = {tok} * {1}
if (premium > FIX_ONE) q = q.safeMul(premium, rounding);
}
// {qTok} = {tok} * {qTok/tok}
quantities[i] = q.shiftl_toUint(
int8(IERC20Metadata(address(basket.erc20s[i])).decimals()),
rounding
);
}
}
Lines of code
https://github.com/code-423n4/2024-07-reserve/blob/3f133997e186465f4904553b0f8e86ecb7bbacbf/contracts/p1/RToken.sol#L183-L225 https://github.com/code-423n4/2024-07-reserve/blob/3f133997e186465f4904553b0f8e86ecb7bbacbf/contracts/p1/RToken.sol#L342 https://github.com/code-423n4/2024-07-reserve/blob/3f133997e186465f4904553b0f8e86ecb7bbacbf/contracts/p1/RToken.sol#L409-L413
Vulnerability details
Impact
rToken::redeemCustom has slippage protection due to portions and pro rata accounting which can be volatile during under-collateralized times. But during proper collateralized times, the exchange rate between total supply of rToken and backing needed can be volatile and user might incur slippage loss when redeeming the rTokens and there's no validation to check the minimum erc20 token amounts transferred after redemption.
Rebalancing can happen if the rToken is not frozen during trade settlement or when
tradeEnd < block.timestamp
, and redemption can be done by users if rToken isn't frozen. So, there are flows where exchange rate between total supply of rToken and backing needed, it can be allowed to move betweenlow >= MIN_EXCHANGE_RATE && high <= MAX_EXCHANGE_RATE
, 1e9 < rate < 1e27And if this sudden slippage change is over > 0.5%, it is a concern to the user who is trying to mint at the current exchange rate. And to protect his slippage, there should be a minimum rToken minted validation during these rebalancing times.
rToken.setBasketsNeeded
Proof of Concept
A user wants to redeem
x
rTokens. But the amount of erc20 tokens transferred depends on exchange rate betweenbasketsNeeded
andtotalSupply
ThebasketsNeeded
is volatile irrespective or independent oftotalSupply
in the following flow of rebalancing the backing manager. BackingManagerP1::settleTrade >> BackingManagerP1::rebalance >> BackingManagerP1::compromiseBasketsNeeded >> rToken.setBasketsNeededAnd if any redemption is submitted by a user, and suddenly the rToken is rebalanced to move the exchange rate between total supply of rToken and backing needed for > 2%, then slippage loss to the user The slippage loss can be allowed to move between
low >= MIN_EXCHANGE_RATE && high <= MAX_EXCHANGE_RATE
, 1e9 < rate < 1e27. So the loss of funds is a severe issue. Adding minTokensOut is a good slippage protection.rToken::redeemTo and rToken::_scaleDown
Tools Used
Vs code
Recommended Mitigation Steps
Modify rToken::redeemTo just like rToken::redeemCustom
Assessed type
MEV