Platform: Code4rena
Start Date: 16/10/2023
Pot Size: $60,500 USDC
Total HM: 16
Participants: 131
Period: 10 days
Judge: 0xTheC0der
Total Solo HM: 3
Id: 296
League: ETH
Rank: 78/131
Findings: 1
Award: $16.66
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 3docSec
Also found by: 0xCiphky, 0xbepresent, 0xbrett8571, Eigenvectors, MiloTruck, Toshii, Tricko, TrungOre, ZdravkoHr, b0g0, caventa, cu5t0mpeo, deth, ggg_ttt_hhh, gizzy, joaovwfreire, josephdara, serial-coder, smiling_heretic, stackachu
16.6643 USDC - $16.66
https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L468-L488 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketConfig.sol#L149-L159
When a market is initially deployed by the WildcatMarketController
through the deployMarket
method an internal method is called (enforceParameterConstraints
) to check if the provided values for annualInterestBips
, reserveRatioBips
and other key parameters are between the MIN/MAX
constraints set by the WildcatMarketControllerFactory
.
After a market has been deployed, its state variable for annualInterestBips
can be changed through the setAnnualInterestBips
method of the WildcatMarketController
contract. In this method no check is made if the provided value for the new annualInterestBips
violates the MIN/MAX
constraints. Also no check is made in the underlying function being called(with the same name - setAnnualInterestBips
) of the WildcatMarketConfig
contract which updates the actual state variable.
This way the boundaries set by the MinimumAnnualInterestBips
& MaximumAnnualInterestBips
state variables (set in the controller by the factory contract) can be violated, which leads to the following discrepancy for a market: annualInterestBips
> MaximumAnnualInterestBips
OR annualInterestBips
< MinimumAnnualInterestBips
/// 1. External function called by the borrower inside `WildcatMarketController` function setAnnualInterestBips( address market, uint16 annualInterestBips ) external virtual onlyBorrower onlyControlledMarket(market) { ... //No check for MIN/MAX violations of annualInterestBips is made WildcatMarket(market).setAnnualInterestBips(annualInterestBips); } /// 2. External function inside `WildcatMarketConfig` called by the above controller function setAnnualInterestBips( uint16 _annualInterestBips ) public onlyController nonReentrant { MarketState memory state = _getUpdatedState(); // This only checks for maximum possible value of BIPS 10000 -> 100% if (_annualInterestBips > BIP) { revert InterestRateTooHigh(); } //No check for MIN/MAX violations of annualInterestBips is made state.annualInterestBips = _annualInterestBips; _writeState(state); emit AnnualInterestBipsUpdated(_annualInterestBips); }
At the beginning of the setAnnualInterestBips
method in WildcatMarketController
the following check could be added:
assertValueInRange( annualInterestBips, MinimumAnnualInterestBips, MaximumAnnualInterestBips, AnnualInterestBipsOutOfBounds.selector );
This is the same method used for validation during market deployment
Invalid Validation
#0 - c4-pre-sort
2023-10-27T14:12:50Z
minhquanym marked the issue as duplicate of #443
#1 - c4-judge
2023-11-07T12:25:27Z
MarioPoneder marked the issue as satisfactory