Platform: Code4rena
Start Date: 23/06/2023
Pot Size: $60,500 USDC
Total HM: 31
Participants: 132
Period: 10 days
Judge: 0xean
Total Solo HM: 10
Id: 254
League: ETH
Rank: 3/132
Findings: 2
Award: $2,247.11
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: turvy_fuzz
Also found by: SpicyMeatball
2166.6817 USDC - $2,166.68
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L127 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L161
doesn't calculate the current borrowing amount for the provider, including the provider's borrowed shares and accumulated fees.
Borrowers collateralRatio in the liquidation() function is calculated by:
uint256 onBehalfOfCollateralRatio = (depositedAsset[onBehalfOf] * assetPrice * 100) / getBorrowedOf(onBehalfOf);
notice it calls the getBorrowedOf() function, which calculate the current borrowing amount for the borrower, including the borrowed shares and accumulated fees and not just the borrowed amount https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L253
function getBorrowedOf(address user) public view returns (uint256) { return borrowed[user] + feeStored[user] + _newFee(user); }
However, the providers collateralRatio in the rigidRedemption() function is calculated by: https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L161
uint256 providerCollateralRatio = (depositedAsset[provider] * assetPrice * 100) / borrowed[provider];
here the deposit asset is divided by just the borrowed amount, missing out the borrowed shares and accumulated fees
Visual Studio Code
Be consistent with collateralRatio calculation
Other
#0 - c4-pre-sort
2023-07-11T19:13:55Z
JeffCX marked the issue as primary issue
#1 - c4-sponsor
2023-07-14T09:09:36Z
LybraFinance marked the issue as sponsor confirmed
#2 - c4-judge
2023-07-25T23:13:42Z
0xean marked the issue as satisfactory
#3 - c4-judge
2023-07-28T20:41:24Z
0xean marked the issue as selected for report
🌟 Selected for report: JCN
Also found by: 0xAnah, DavidGiladi, MohammedRizwan, Rageur, Raihan, ReyAdmirado, Rolezn, SAAJ, SAQ, SM3_SS, Sathish9098, ayo_dev, dharma09, fatherOfBlocks, hunter_w3b, mgf15, mrudenko, naman1778, shamsulhaq123, souilos, turvy_fuzz
80.434 USDC - $80.43
3 instance of this: https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L92 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L156 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/ProtocolRewardsPool.sol#L162
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L204 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L205
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/LybraStETHVault.sol#L75 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/LybraStETHVault.sol#L78
uint256 payAmount = (((realAmount * getAssetPrice()) / 1e18) * getDutchAuctionDiscountPrice()) / 10000;
emit LSDValueCaptured(realAmount, payAmount, getDutchAuctionDiscountPrice(), block.timestamp);
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/LybraStETHVault.sol#L66 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/LybraStETHVault.sol#L94
In the modifier updateReward() , rewardPerToken() is called twice first here:
rewardPerTokenStored = rewardPerToken();
and still called in the earned() function
modifier updateReward(address _account) { rewardPerTokenStored = rewardPerToken(); updatedAt = lastTimeRewardApplicable(); if (_account != address(0)) { rewards[_account] = earned(_account); userRewardPerTokenPaid[_account] = rewardPerTokenStored; userUpdatedAt[_account] = block.timestamp; } _; }
function earned(address _account) public view returns (uint256) { return ((balanceOf[_account] * getBoost(_account) * (rewardPerToken() - userRewardPerTokenPaid[_account])) / 1e38) + rewards[_account]; }
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/token/LBR.sol#L15 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/token/esLBR.sol#L20
This block of code will never get executed
else { feeStored[_onBehalfOf] = totalFee - amount; PeUSD.transferFrom(_provider, address(configurator), amount); }
rather, only the if block will ever get executed because amount will never be less than totalFee due to the fact that it was already checked before assigning, here:
uint256 amount = borrowed[_onBehalfOf] + totalFee >= _amount ? _amount : borrowed[_onBehalfOf] + totalFee;
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L196 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L201
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L156 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L159
https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L190 https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/pools/base/LybraEUSDVaultBase.sol#L192
#0 - c4-pre-sort
2023-07-27T22:32:01Z
JeffCX marked the issue as high quality report
#1 - c4-judge
2023-07-27T23:42:16Z
0xean marked the issue as grade-a
#2 - c4-sponsor
2023-07-29T10:20:31Z
LybraFinance marked the issue as sponsor acknowledged