Platform: Code4rena
Start Date: 12/08/2022
Pot Size: $50,000 USDC
Total HM: 15
Participants: 120
Period: 5 days
Judge: Justin Goro
Total Solo HM: 6
Id: 153
League: ETH
Rank: 11/120
Findings: 3
Award: $1,192.60
π Selected for report: 1
π Solo Findings: 0
Borrower charged penalty rate for time before maturity
if (_isPastMaturity()) { _newRate = uint64(penaltyRate); } else { _currentRateInfo.ratePerSec = _newRate; _currentRateInfo.lastTimestamp = uint64(block.timestamp); _currentRateInfo.lastBlock = uint64(block.number); // Calculate interest accrued _interestEarned = (_deltaTime * _totalBorrow.amount * _currentRateInfo.ratePerSec) / 1e18;
When _addInterest is called after maturity, the interest rate is set to the penalty rate. This rate is then applied for all the time between the last _addInterest call. This means that the first time that _addInterest is called after maturity, it will back charge the borrowers penalty interest for time before maturity up until when it was last updated. This is unfair to borrower who should only be charged penalty interest for time after maturity.
For the first call after maturity, the interest rate should be calculated as normal and applied up to maturity. Then the penaltyRate should be used from maturity until current time.
#0 - 0xA5DF
2022-08-17T20:51:43Z
Duplicate of #111
π Selected for report: 0x52
Also found by: Lambda, berndartmueller, cryptphi
462.1238 USDC - $462.12
https://github.com/code-423n4/2022-08-frax/blob/c4189a3a98b38c8c962c5ea72f1a322fbc2ae45f/src/contracts/FraxlendPair.sol#L136-L138 https://github.com/code-423n4/2022-08-frax/blob/c4189a3a98b38c8c962c5ea72f1a322fbc2ae45f/src/contracts/FraxlendPair.sol#L140-L142
FraxlendPair.sol is not EIP-4626 compliant, variation from the standard could break composability and potentially lead to loss of funds
According to EIP-4626 method specifications (https://eips.ethereum.org/EIPS/eip-4626)
For maxDeposit:
MUST factor in both global and user-specific limits, like if deposits are entirely disabled (even temporarily) it MUST return 0.
For maxMint:
MUST factor in both global and user-specific limits, like if mints are entirely disabled (even temporarily) it MUST return 0.
When FraxlendPair.sol is paused, deposit and mint are both disabled. This means that maxMint and maxDeposit should return 0 when the contract is paused.
The current implementations of maxMint and maxDeposit do not follow this specification:
function maxDeposit(address) external pure returns (uint256) { return type(uint128).max; } function maxMint(address) external pure returns (uint256) { return type(uint128).max; }
No matter the state of the contract they always return uint128.max, but they should return 0 when the contract is paused.
maxDeposit and maxMint should be updated to return 0 when contract is paused. Use of the whenNotPaused modifier is not appropriate because that would cause a revert and maxDeposit and maxMint should never revert according to EIP-4626
#0 - DrakeEvans
2022-09-06T12:40:52Z
Valid. Disagree with severity, no user funds at risk, no incorrect operations can occur. Only result is reverts.
#1 - gititGoro
2022-10-02T03:57:18Z
The use of an EIP such as this one is to facilitate downstream integration without risk. If downstream protocols behave incorrectly because this contract reverts unexpectedly then it can lead to downstream loss of user funds. In the immediate context, no user funds are locked but protocol behaves in an unpredictable way. The medium severity is worded "Assets not at direct risk, but function/availability of the protocol could be impacted or leak value " which fits here.
π Selected for report: 0x1f8b
Also found by: 0x52, 0xA5DF, 0xDjango, 0xNazgul, 0xNineDec, 0xSmartContract, 0xmatt, 0xsolstars, Aymen0909, Bnke0x0, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, EthLedger, Funen, IllIllI, JC, Junnon, Lambda, LeoS, MiloTruck, Noah3o6, PaludoX0, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, SaharAP, Sm4rty, SooYa, The_GUILD, TomJ, Waze, Yiko, _Adam, __141345__, a12jmx, ak1, asutorufos, auditor0517, ayeslick, ballx, beelzebufo, berndartmueller, bin2chen, brgltd, c3phas, cRat1st0s, cccz, cryptonue, cryptphi, d3e4, delfin454000, dipp, djxploit, durianSausage, dy, erictee, fatherOfBlocks, gogo, gzeon, hyh, ignacio, kyteg, ladboy233, medikko, mics, minhquanym, oyc_109, pfapostol, rbserver, reassor, ret2basic, robee, sach1r0, simon135, sryysryy, tabish, yac, yash90, zzzitron
45.8482 USDC - $45.85
https://github.com/code-423n4/2022-08-frax/blob/c4189a3a98b38c8c962c5ea72f1a322fbc2ae45f/src/contracts/FraxlendPairCore.sol#L911-L942 https://github.com/code-423n4/2022-08-frax/blob/c4189a3a98b38c8c962c5ea72f1a322fbc2ae45f/src/contracts/FraxlendPairCore.sol#L950-L1032
Lender blocks liquidations
FraxlendPair.sol#setApprovedLenders can be called by any whitelisted lender to both revoke and add approved lenders to the whitelist. A malicious lender could remove every other whitelisted lender from the pair then refuse to liquidate the position themselves, making it impossible to liquidate.
Exploiting this is straight forward. If the lending market is only whitelisted for lenders, the malicious lender could withdraw their lending position, deposit collateral and borrow everything else in the pool then remove all other lenders from the pool. Something like this could be used to open a high leverage zero risk position.
If the market has whitelist borrowers, the lender could easily collude with a borrower to pull off the attack.
I don't see why FraxlendPairCore.sol#liquidate and liquidateClean can only be called by whitelist lenders. It is in the best interest of both parties if anyone can liquidate a position even in a whitelisted market. If it truly is desirable that only whitelist lenders are able to liquidate, then FraxlendPair.sol#setApprovedLenders should be modified to only allow lenders to add new lenders rather than remove current lenders.
#0 - amirnader-ghazvini
2022-08-29T18:53:30Z
Duplicate of #157