Platform: Code4rena
Start Date: 29/03/2024
Pot Size: $36,500 USDC
Total HM: 5
Participants: 72
Period: 5 days
Judge: 3docSec
Total Solo HM: 1
Id: 357
League: ETH
Rank: 46/72
Findings: 1
Award: $8.28
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: immeas
Also found by: 0xAkira, 0xCiphky, 0xGreyWolf, 0xJaeger, 0xMosh, 0xabhay, 0xlemon, 0xmystery, 0xweb3boy, Aamir, Abdessamed, Aymen0909, Breeje, DanielArmstrong, DarkTower, Dots, EaglesSecurity, FastChecker, HChang26, Honour, IceBear, JC, K42, Krace, MaslarovK, Omik, OxTenma, SAQ, Shubham, Stormreckson, Tigerfrake, Tychai0s, VAD37, ZanyBonzy, albahaca, arnie, ast3ros, asui, b0g0, bareli, baz1ka, btk, caglankaan, carrotsmuggler, cheatc0d3, dd0x7e8, grearlake, igbinosuneric, jaydhales, kaden, kartik_giri_47538, m4ttm, ni8mare, niser93, nonn_ac, oualidpro, pfapostol, pkqs90, popeye, radev_sw, samuraii77, slvDev, zabihullahazadzoi
8.2807 USDC - $8.28
Functions ousgInstantManager.mint()
, ousgInstantManager.mintRebasingOUSG()
, ousgInstantManager.redeem()
and ousgInstantManager.redeemRebasingOUSG()
fully rely on output of ousgInstantManager.getOUSGPrice()
. This function returns price of OUSG in USDC from oracle.
function getOUSGPrice() public view returns (uint256 price) { (price, ) = oracle.getPriceData(); require( price > MINIMUM_OUSG_PRICE, "OUSGInstantManager::getOUSGPrice: Price unexpectedly low" ); }
As written in natspec.
@dev Sanity check: this function will revert if the price is unexpectedly low
For that, there is require
statement that checks whether price from oracle satisfies minimum OUSG price in USDC which is 105e18
. But there is no guarantee that price won't go lower than MINIMUM_OUSG_PRICE
, so If price naturally goes lower (oracle aggregates price from exchangers where price is lower, owners of OUSG make more sales in OUSG/USDC pool, etc.) then all of mint and redeem functions won't work as transaction would revert. As contract ousgInstantManager
is not upgradable and price of OUSG constantly lower than MINIMUM_OUSG_PRICE
users won't be able to retrieve their USDC for owned OUSG and rOUSG and they would lose all of deposited USDC.
Deposited by users USDC are stuck if price naturally or not goes lower than MINIMUM_OUSG_PRICE
.
To mitigate that, protocol should make this variable dynamic and add ability to change it by configurer (or admin). In that case, if configurer lowers minimum OUSG price then user can redeem their USDC even if price is low, so they can get back at least part of initial deposit.
@@ -59,9 +59,6 @@ contract OUSGInstantManager is // Role to pause minting and redemptions bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); - // Safety circuit breaker in case of Oracle malfunction - uint256 public constant MINIMUM_OUSG_PRICE = 105e18; - // Helper constant that allows us to precisely specify fees in basis points uint256 public constant FEE_GRANULARITY = 10_000; @@ -89,6 +86,9 @@ contract OUSGInstantManager is // The address that receives USDC for subscriptions address public immutable usdcReceiver; + // Safety circuit breaker in case of Oracle malfunction + uint256 public minimumOUSGPrice = 105e18; + // Address of the oracle that provides the `ousgPrice` IRWAOracle public oracle; @@ -479,7 +479,7 @@ contract OUSGInstantManager is function getOUSGPrice() public view returns (uint256 price) { (price, ) = oracle.getPriceData(); require( - price > MINIMUM_OUSG_PRICE, + price > minimumOUSGPrice, "OUSGInstantManager::getOUSGPrice: Price unexpectedly low" ); } @@ -788,6 +788,16 @@ contract OUSGInstantManager is emit RedeemUnpaused(); } + /// @notice Change minimum OUSG price + function changeMinimumOUSGPrice( + uint256 _newMinimumOUSGPrice + ) external onlyRole(CONFIGURER_ROLE) { + uint256 oldMinimumOUSGPrice = minimumOUSGPrice; + minimumOUSGPrice = _newMinimumOUSGPrice; + + emit MinimumOUSGPriceSet(oldMinimumOUSGPrice, _newMinimumOUSGPrice); + }
@@ -322,4 +322,15 @@ interface IOUSGInstantManager { address oldInvestorBasedRateLimiter, address newInvestorBasedRateLimiter ); + + /** + * @notice Event emitted when minimum OUSG price is set + * + * @param oldMinimumOUSGPrice Old minimum OUSG price + * @param newMinimumOUSGPrice New minimum OUSG price + */ + event MinimumOUSGPriceSet( + uint256 oldMinimumOUSGPrice, + uint256 newMinimumOUSGPrice + ); }
Oracle
#0 - c4-pre-sort
2024-04-04T04:33:23Z
0xRobocop marked the issue as duplicate of #245
#1 - c4-judge
2024-04-09T13:01:21Z
3docSec changed the severity to QA (Quality Assurance)
#2 - c4-judge
2024-04-09T13:01:56Z
3docSec marked the issue as grade-b