Open code423n4 opened 1 year ago
thereksfour marked the issue as primary issue
External requirement with oracle errors
thereksfour changed the severity to 2 (Med Risk)
pmckelvy1 marked the issue as sponsor confirmed
thereksfour marked the issue as satisfactory
thereksfour marked the issue as selected for report
Lines of code
https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol#L46-L54 https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/curve/CurveStableCollateral.sol#L119-L121 https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/curve/CurveStableMetapoolCollateral.sol#L122-L138
Vulnerability details
The CurveStableMetapoolCollateral is intended for 2-fiattoken stable metapools that involve RTokens, such as eUSD-fraxBP. The metapoolToken coin0 is pairedToken, which is also a RToken, and the coin1 is lpToken, e.g. 3CRV. And the
CurveStableRTokenMetapoolCollateral.tryPairedPrice
usesRTokenAsset.price()
as the oracle to get the pairedToken price:Impact
Users can't redeem from RToken when any underlying collateral of paired RToken's price oracle is offline(timeout). It can lead to a serious run/depeg on the RToken.
Proof of Concept
First I submitted another issue named "RTokenAsset price oracle can return a huge but valid high price when any underlying collateral's price oracle timeout". It's the premise for this issue. Because this issue is located in different collateral codes, I split them into two issues.
The conclusion from the pre issue:
Back to the
CurveStableRTokenMetapoolCollateral
. There are two cases that will revert in the super classCurveStableCollateral.refresh()
.The
CurveStableRTokenMetapoolCollateral.tryPairedPrice
function gets low/high price frompaired RTokenAsset.price()
. So when any underlying collateral's price oracle of paired RTokenAsset reverts, the max high price will be FIX_MAX and the low price is non-zero.If the high price is FIX_MAX, the assert for low price will revert:
And if high price is There is a little smaller than FIX_MAX, the
_anyDepeggedOutsidePool
check in the refresh function will revert.And the
CurveStableMetapoolCollateral
overrides it:So the
uint192 mid = (low + high) / 2;
will revert because of uint192 overflow. TheCurveStableRTokenMetapoolCollateral.refresh()
will revert without any catch.Becuase RToken.redeemTo and redeemCustom need to call
assetRegistry.refresh();
at the beginning, it will revert directly.Tools Used
Manual review
Recommended Mitigation Steps
The Fix.plus can't handle the uint192 overflow error. Try to override
_anyDepeggedOutsidePool
forCurveStableRTokenMetapoolCollateral
as:The assert
assert(low <= high)
in the RTokenAsset.tryPrice has already protected everything.Assessed type
DoS