The discrepency in `issuancePremium` accounting, during the `issuance of RTokens` and the `available basket units` calculation in the `BackingManager`, could lead to an `incorrect assessment` of the `collateralization status` #211
There is a discrepancy between the calculation of the required collateral tokens during issuance of RToken (which includes the issuancePremium) and the calculation of the available basket units held by the BackingManager (which does not account for the issuancePremium).
During a depeg scenario, when the RToken.issueTo function is executed, the BasketHandler.quote function is called with applyIssuancePremium set to true. This ensures that the required collateral token quantities are adjusted to account for the issuance premium, effectively requiring more collateral tokens to be transferred to the BackingManager contract. The following code snippet from BasketHandler.quote depicts this scenario:
if (applyIssuancePremium) {
uint192 premium = issuancePremium(coll); // {1} always CEIL by definition
// {tok} = {tok} * {1}
if (premium > FIX_ONE) q = q.safeMul(premium, rounding);
}
However, when the BackingManager.rebalance function is executed, the BasketHandler.basketsHeldBy function is called to determine the number of basket units held by the BackingManager. This function directly uses the calculated token quantity per basket unit and does not apply the issuancePremium to calculate the available basket units as shown below:
uint192 q = _quantity(basket.erc20s[i], coll, CEIL); //@audit-info - token quantity per basket unit is rounded up
if (q == FIX_MAX) return BasketRange(FIX_ZERO, FIX_MAX); //@audit-info - (bottom, top)
// {BU} = {tok} / {tok/BU}
uint192 inBUs = coll.bal(account).div(q); //@audit-info - basket unit amount is rounded down
baskets.bottom = fixMin(baskets.bottom, inBUs);
baskets.top = fixMax(baskets.top, inBUs);
This discrepancy can lead to a situation where the basketsHeld.bottom value (the number of whole basket units held by the BackingManager) is overestimated because it does not account for the additional collateral tokens required due to the issuance premium.
Consequently, the following condition in the BackingManager.rebalance function may incorrectly evaluate to true, even though the BackingManager does not hold enough collateral tokens to fulfill the basketsNeeded value after considering the issuance premium:
if (basketsHeld.bottom >= rToken.basketsNeeded()) return;
This potential bug could lead to an incorrect assessment of the collateralization status as true and potentially allow the protocol to continue operating in an undercollateralized state assuming it is collateralized, which could put both RToken holders and RSR stakers at risk. It's important to note that this bug may have implications for the overall collateralization management and the safety of the Reserve Protocol.
To mitigate this issue, it is recommended to modify the BasketHandler.basketsHeldBy function to incorporate the issuancePremium calculation when determining the available basket units. This would ensure that the basketsHeld.bottom value accurately reflects the number of basket units that can be fulfilled with the available collateral tokens, taking into account the issuance premium during depeg scenarios.
Lines of code
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/RToken.sol#L139-L143 https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BasketHandler.sol#L499-L504 https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BackingManager.sol#L124 https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BasketHandler.sol#L620-L626 https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BackingManager.sol#L132
Vulnerability details
Impact
There is a discrepancy between the calculation of the
required collateral tokens
duringissuance of RToken
(which includes the issuancePremium) and the calculation of theavailable basket units
held by theBackingManager
(which does not account for the issuancePremium).During a depeg scenario, when the
RToken.issueTo
function is executed, theBasketHandler.quote
function is called withapplyIssuancePremium
set to true. This ensures that therequired collateral token quantities
areadjusted
to account for theissuance premium
, effectively requiring more collateral tokens to be transferred to theBackingManager
contract. The following code snippet fromBasketHandler.quote
depicts this scenario:However, when the
BackingManager.rebalance
function is executed, theBasketHandler.basketsHeldBy
function is called to determine thenumber of basket units
held by theBackingManager
. This function directly uses the calculated token quantity per basket unit anddoes not apply the issuancePremium
to calculate theavailable basket units
as shown below:This discrepancy can lead to a situation where the
basketsHeld.bottom
value (the number of whole basket units held by the BackingManager) isoverestimated
becauseit does not account
for theadditional collateral tokens required due to the issuance premium
.Consequently, the following condition in the
BackingManager.rebalance
function may incorrectly evaluate to true, even though theBackingManager does not hold enough collateral tokens
to fulfill thebasketsNeeded
value after considering the issuance premium:This potential bug could lead to an
incorrect assessment
of thecollateralization status as true
and potentially allow the protocol tocontinue operating in an undercollateralized state
assuming it is collateralized, which could put bothRToken holders and RSR stakers at risk
. It's important to note that this bug may have implications for theoverall collateralization management
and thesafety of the Reserve Protocol
.Proof of Concept
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/RToken.sol#L139-L143
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BasketHandler.sol#L499-L504
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BackingManager.sol#L124
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BasketHandler.sol#L620-L626
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/BackingManager.sol#L132
Tools Used
Manual Review and VSCode
Recommended Mitigation Steps
To mitigate this issue, it is recommended to modify the
BasketHandler.basketsHeldBy
function toincorporate
theissuancePremium calculation
when determining theavailable basket units
. This would ensure that thebasketsHeld.bottom
valueaccurately reflects the number of basket units
that can befulfilled with the available collateral tokens
, taking into account theissuance premium during depeg scenarios
.Assessed type
Other