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: 80/132
Findings: 2
Award: $76.32
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: alexweb3
Also found by: D_Auditor, DedOhWale, DelerRH, LuchoLeonel1, Musaka, Neon2835, Silvermist, Timenov, TorpedoPistolIXC41, adeolu, cartlex_, hals, josephdara, koo, lanrebayode77, mahyar, mladenov, mrudenko, pep7siup, zaevlad, zaggle
18.4208 USDC - $18.42
In LybraConfigurator.sol, there are two modifiers, checkOnlyRole and checkRole from GovernanceTimelock, designed to verify whether the msg.sender is authorized. However, these modifiers lack "require" statements to enforce the condition that the returned boolean must be true. As a result, anyone can call functions that are intended to be restricted.
Due to the absence of "require" statements, restricted functions can be executed without proper verification of the boolean return values. Consequently, unauthorized users gain access to admin functions and can modify configurations, potentially causing severe disruptions to the protocol.
modifier onlyRole(bytes32 role) { GovernanceTimelock.checkOnlyRole(role, msg.sender); _; } modifier checkRole(bytes32 role) { GovernanceTimelock.checkRole(role, msg.sender); _; }
Manual Review
modifier onlyRole(bytes32 role) { require(GovernanceTimelock.checkOnlyRole(role, msg.sender),"Unauthorized"); _; }
modifier checkRole(bytes32 role) { require(GovernanceTimelock.checkRole(role, msg.sender), "Unauthorized" ); _; }
Access Control
#0 - c4-pre-sort
2023-07-09T12:47:12Z
JeffCX marked the issue as duplicate of #704
#1 - c4-judge
2023-07-28T15:23:59Z
0xean marked the issue as satisfactory
🌟 Selected for report: 0xnev
Also found by: 0xRobocop, 0xbrett8571, 0xkazim, 0xnacho, 3agle, 8olidity, ABAIKUNANBAEV, Bauchibred, Co0nan, CrypticShepherd, D_Auditor, DelerRH, HE1M, Iurii3, Kaysoft, MrPotatoMagic, RedOneN, RedTiger, Rolezn, SanketKogekar, Sathish9098, Timenov, Toshii, Vagner, bart1e, bytes032, codetilda, devival, halden, hals, kutugu, m_Rassska, naman1778, nonseodion, seth_lawson, solsaver, squeaky_cactus, totomanov, y51r, yudan, zaevlad
57.9031 USDC - $57.90
This protocol's main purpose of liquidation is to raise the borrower's collateral ratio above the bad collateral ratio and reach at least the safe collateral ratio. However, currently, there is no check after liquidation to confirm if the borrower's account has achieved this goal.
Recommendation: To ensure the intended liquidation objective is fully met, it is recommended to implement a verification step using the _checkHealth() function from the base vault contract. This will provide a straightforward measure to confirm that the borrower's collateral ratio is indeed above the bad collateral ratio. By incorporating this simple yet important verification process, the liquidation mechanism can be strengthened, reducing any potential vulnerabilities and ensuring the desired outcome.
function initToken(address _eusd, address _peusd) external onlyRole(DAO) { if (address(EUSD) == address(0)) EUSD = IEUSD(_eusd); if (address(peUSD) == address(0)) peUSD = IEUSD(_peusd); }
The comments accompanying the initToken()
function indicate that it should only be called once. However, there is no modifier in place to enforce this restriction. Although the impact of this omission is relatively minor, as only the DAO can call the function to reset the token address, it is important to ensure clarity and consistency in the codebase.
Recommendation: To align with the intention expressed in the comments, consider either removing the comment if the function is meant to be called multiple times or adding a modifier to restrict the number of calls to only one. By implementing this change, the code will accurately reflect the expected behavior and avoid any potential confusion for future developers working with the contract.
In the event of a liquidation that is initiated by someone other than the provider, the individual who utilized the provider's account to trigger the liquidation process is eligible to receive a reward2keeper. This reward is capped at a maximum of 5%.
function setKeeperRatio(address pool,uint256 newRatio) external checkRole(TIMELOCK) { require(newRatio <= 5, "Max Keeper reward is 5%"); vaultKeeperRatio[pool] = newRatio; emit KeeperRatioChanged(pool, newRatio); }
The calculation for the reward2keeper in the code divides the keeper ratio by 110 instead of 100. As a result, the intended 5% reward2keeper is approximately 4.5%. However, due to a precision error caused by the decimal, the keeper may end up losing a maximum of 1% in rewards.
reward2keeper = (reducedAsset * configurator.vaultKeeperRatio(address(this))) / 110; collateralAsset.transfer(provider, reducedAsset - reward2keeper); collateralAsset.transfer(msg.sender, reward2keeper);
Since the safe collateral ratio is a derivative of the bad collateral ratio, once the bad collateral ratio changes, the safe collateral ratio should also be set to at least 10% more than the safe collateral ratio. Failure to do this translates to the usage of a stale and incongruent safe collateral ratio when the bad collateral ratio changes.
Recommendation:
function setBadCollateralRatio(address pool, uint256 newRatio, uint256 safeRatio) external onlyRole(DAO) { require(newRatio >= 130 * 1e18 && newRatio <= 150 * 1e18 && newRatio <= vaultSafeCollateralRatio[pool] + 1e19, "LNA"); vaultBadCollateralRatio[pool] = newRatio; setSafeCollateralRatio(safeRatio); //change visibility from external to public emit SafeCollateralRatioChanged(pool, newRatio); }
Just like in LybraConfigurator::getBadCollateralRatio(), instead of outrightly returning 160%, calculate the safe collateral ratio as a derivative of the bad collateral ratio.
Recommendation:
function getSafeCollateralRatio( address pool ) external view returns (uint256) { if (vaultSafeCollateralRatio[pool] == 0) return vaultBadCollateralRatio[pool] + 1e19; return vaultSafeCollateralRatio[pool]; }
#0 - c4-pre-sort
2023-07-27T16:08:18Z
JeffCX marked the issue as high quality report
#1 - c4-judge
2023-07-27T23:51:06Z
0xean marked the issue as grade-a
#2 - c4-sponsor
2023-07-29T08:58:01Z
LybraFinance marked the issue as sponsor acknowledged