Platform: Code4rena
Start Date: 04/03/2024
Pot Size: $88,500 USDC
Total HM: 31
Participants: 105
Period: 11 days
Judge: ronnyx2017
Total Solo HM: 7
Id: 342
League: ETH
Rank: 24/105
Findings: 3
Award: $594.73
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: JohnSmith
Also found by: Arz, Aymen0909, BowTiedOriole, DanielArmstrong, FastChecker, KupiaSec, deepplus, kennedy1030, kfx, shaka
38.4591 USDC - $38.46
https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L1251 https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L1263
Since daily increase limit is set much larger than the intention, it is possible to cause a catastrophic exploit to the protocol.
V3Vault.sol#_resetDailyLendIncreaseLimit
function is the following.
function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal { // daily lend limit reset handling uint256 time = block.timestamp / 1 days; if (force || time > dailyLendIncreaseLimitLastReset) { 1250: uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up) * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32; dailyLendIncreaseLimitLeft = dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit; dailyLendIncreaseLimitLastReset = time; } }
L1250
calculates the maximum increase of lending amount during a day to 110% of the present total shares.
This is 11 times greater than the intended maximum increase of 10%.
Thus, there is a possibility of causing a catastrophic exploit to the protocol by malicious attacker's attacks.
V3Vault.sol#_resetDailyDebtIncreaseLimit
function also has the same issue.
Manual Review
Modify V3Vault.sol#_resetDailyLendIncreaseLimit
function as follows.
function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal { // daily lend limit reset handling uint256 time = block.timestamp / 1 days; if (force || time > dailyLendIncreaseLimitLastReset) { uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up) -- * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32; ++ * MAX_DAILY_LEND_INCREASE_X32 / Q32; dailyLendIncreaseLimitLeft = dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit; dailyLendIncreaseLimitLastReset = time; } }
In the same way, modify V3Vault.sol#_resetDailyDebtIncreaseLimit
function as follows.
function _resetDailyDebtIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal { // daily debt limit reset handling uint256 time = block.timestamp / 1 days; if (force || time > dailyDebtIncreaseLimitLastReset) { uint256 debtIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up) -- * (Q32 + MAX_DAILY_DEBT_INCREASE_X32) / Q32; ++ * MAX_DAILY_DEBT_INCREASE_X32 / Q32; dailyDebtIncreaseLimitLeft = dailyDebtIncreaseLimitMin > debtIncreaseLimit ? dailyDebtIncreaseLimitMin : debtIncreaseLimit; dailyDebtIncreaseLimitLastReset = time; } }
Math
#0 - c4-pre-sort
2024-03-21T14:22:27Z
0xEVom marked the issue as duplicate of #415
#1 - c4-pre-sort
2024-03-21T14:22:33Z
0xEVom marked the issue as sufficient quality report
#2 - c4-judge
2024-04-01T06:46:19Z
jhsagd76 marked the issue as satisfactory
#3 - c4-judge
2024-04-01T15:43:13Z
jhsagd76 changed the severity to 2 (Med Risk)
🌟 Selected for report: FastChecker
Also found by: DanielArmstrong
545.9832 USDC - $545.98
https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L949
First withdraw or repay cannot increase daily available deposit or borrow amount. This results in decreasing the system's incentives.
When a user withdraw or repay funds just after new date started, it increases dailyLendIncreaseLimitLeft
or dailyDebtIncreaseLimitLeft
but it has no effect.
That's why it resets them when deposit or borrow. So daily available deposit or borrow amount cannot be increased.
V3Vault.sol#_withdraw
function is as follows.
function _withdraw(address receiver, address owner, uint256 amount, bool isShare) internal returns (uint256 assets, uint256 shares) { (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96) = _updateGlobalInterest(); ... // when amounts are withdrawn - they may be deposited again 949 dailyLendIncreaseLimitLeft += assets; emit Withdraw(msg.sender, receiver, owner, assets, shares); }
As you can see above, on L949 it increases dailyLendIncreaseLimitLeft
without considering current date.
And V3Vault.sol#_deposit
function is as follows.
function _deposit(address receiver, uint256 amount, bool isShare, bytes memory permitData) internal returns (uint256 assets, uint256 shares) { (, uint256 newLendExchangeRateX96) = _updateGlobalInterest(); 883 _resetDailyLendIncreaseLimit(newLendExchangeRateX96, false); ... if (assets > dailyLendIncreaseLimitLeft) { revert DailyLendIncreaseLimit(); } else { dailyLendIncreaseLimitLeft -= assets; } emit Deposit(msg.sender, receiver, assets, shares); }
On L883, it resets dailyLendIncreaseLimitLeft
if available through _resetDailyLendIncreaseLimit
function.
function _resetDailyLendIncreaseLimit(uint256 newLendExchangeRateX96, bool force) internal { // daily lend limit reset handling uint256 time = block.timestamp / 1 days; if (force || time > dailyLendIncreaseLimitLastReset) { uint256 lendIncreaseLimit = _convertToAssets(totalSupply(), newLendExchangeRateX96, Math.Rounding.Up) * (Q32 + MAX_DAILY_LEND_INCREASE_X32) / Q32; dailyLendIncreaseLimitLeft = dailyLendIncreaseLimitMin > lendIncreaseLimit ? dailyLendIncreaseLimitMin : lendIncreaseLimit; dailyLendIncreaseLimitLastReset = time; } }
As we can see, if new date starts, it resets dailyLendIncreaseLimitLeft
.
So first withdraw cannot increase daily available deposit amount.
This problem occurs in repay and borrow as same way.
Manual Review
We have to modify V3Vault.sol#_withdraw, _repay
functions as follows.
function _withdraw(address receiver, address owner, uint256 amount, bool isShare) internal returns (uint256 assets, uint256 shares) { (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96) = _updateGlobalInterest(); + _resetDailyLendIncreaseLimit(newLendExchangeRateX96, false); ... // when amounts are withdrawn - they may be deposited again dailyLendIncreaseLimitLeft += assets; emit Withdraw(msg.sender, receiver, owner, assets, shares); } ... function _repay(uint256 tokenId, uint256 amount, bool isShare, bytes memory permitData) internal { (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96) = _updateGlobalInterest(); + _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, false); ... // when amounts are repayed - they maybe borrowed again dailyDebtIncreaseLimitLeft += assets; ... emit Repay(tokenId, msg.sender, owner, assets, shares); }
Error
#0 - c4-pre-sort
2024-03-21T14:59:34Z
0xEVom marked the issue as duplicate of #400
#1 - c4-pre-sort
2024-03-21T14:59:42Z
0xEVom marked the issue as sufficient quality report
#2 - c4-sponsor
2024-03-26T17:28:51Z
kalinbas (sponsor) confirmed
#3 - c4-judge
2024-04-01T10:43:03Z
jhsagd76 marked the issue as satisfactory
🌟 Selected for report: Bauchibred
Also found by: 0x11singh99, 0x175, 0xAlix2, 0xDemon, 0xGreyWolf, 0xPhantom, 0xspryon, 14si2o_Flint, Arabadzhiev, Aymen0909, Bigsam, BowTiedOriole, CRYP70, DanielArmstrong, FastChecker, JecikPo, KupiaSec, MohammedRizwan, Norah, Timenov, Topmark, VAD37, adeolu, btk, crypticdefense, cryptphi, givn, grearlake, jnforja, kennedy1030, kfx, ktg, lanrebayode77, n1punp, santiellena, stonejiajia, t4sk, thank_you, tpiliposian, wangxx2026, y0ng0p3, zaevlad
10.2896 USDC - $10.29
https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L827 https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L828
When resetting limit values, it resets dailyLendIncreaseLimit
and dailyDebyIncreaseLimit
forcefully. So daily amounts of lend and debt can exceed limits at that day.
V3Vault.sol#setLimits
function which resets limits is as follows.
function setLimits( uint256 _minLoanSize, uint256 _globalLendLimit, uint256 _globalDebtLimit, uint256 _dailyLendIncreaseLimitMin, uint256 _dailyDebtIncreaseLimitMin ) external { if (msg.sender != emergencyAdmin && msg.sender != owner()) { revert Unauthorized(); } minLoanSize = _minLoanSize; globalLendLimit = _globalLendLimit; globalDebtLimit = _globalDebtLimit; dailyLendIncreaseLimitMin = _dailyLendIncreaseLimitMin; dailyDebtIncreaseLimitMin = _dailyDebtIncreaseLimitMin; (, uint256 newLendExchangeRateX96) = _updateGlobalInterest(); // force reset daily limits with new values 827 _resetDailyLendIncreaseLimit(newLendExchangeRateX96, true); 828 _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, true); emit SetLimits( _minLoanSize, _globalLendLimit, _globalDebtLimit, _dailyLendIncreaseLimitMin, _dailyDebtIncreaseLimitMin ); }
As we can see, on L827, 828 it resets dailyLendIncreaseLimit
and dailyDebtIncreaseLimit
forcefully.
Manual Review
We have modify V3Vault.sol#setLimits
as follows.
function setLimits( uint256 _minLoanSize, uint256 _globalLendLimit, uint256 _globalDebtLimit, uint256 _dailyLendIncreaseLimitMin, uint256 _dailyDebtIncreaseLimitMin ) external { ... (, uint256 newLendExchangeRateX96) = _updateGlobalInterest(); - // force reset daily limits with new values - _resetDailyLendIncreaseLimit(newLendExchangeRateX96, true); - _resetDailyDebtIncreaseLimit(newLendExchangeRateX96, true); emit SetLimits( _minLoanSize, _globalLendLimit, _globalDebtLimit, _dailyLendIncreaseLimitMin, _dailyDebtIncreaseLimitMin ); }
Error
#0 - c4-pre-sort
2024-03-21T14:26:06Z
0xEVom marked the issue as duplicate of #367
#1 - c4-pre-sort
2024-03-21T14:26:10Z
0xEVom marked the issue as sufficient quality report
#2 - c4-pre-sort
2024-03-23T20:02:45Z
0xEVom marked the issue as insufficient quality report
#3 - c4-judge
2024-03-31T09:02:11Z
jhsagd76 changed the severity to QA (Quality Assurance)
#4 - c4-judge
2024-04-01T06:45:10Z
jhsagd76 marked the issue as grade-b