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: 27/120
Findings: 1
Award: $136.19
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
136.1861 USDC - $136.19
deployedPairsArray
Severity: Low
Context: FraxlendPairDeployer.sol#L96
deployedPairsArray
is a string[] that contains the names of each deployed pair. However, there is no maximium length enforced on this array. Additionally, there is no maximium length enforced on the length of the name. Furthermore, there is no means to remove items from this list.
Impact:
In getAllPairAddresses()
this array is copied to memory then iterated over to create another in-memory array of the same length. The longer the array, and the longer the string elements of the array are, the more gas will be consumed by an external contract that calls this method within a transaction. Furthermore, even when calling this method off-chain, a large amount of data could make the returnvalue of this function difficult or impossible to deal with.
[PASS] testGetAllPairAddressesMulti() Logs: gas used with 1 pair with 32 byte name: 3702 gas used with 100 pairs with 100 byte name: 383162 gas used with 1000 pairs with 100 byte name: 3818626 gas used with 10000 pairs with 100 byte name: 38156200
Recommendation:
index f8d959e..8f5077a 100644 --- a/src/contracts/FraxlendPairDeployer.sol +++ b/src/contracts/FraxlendPairDeployer.sol @@ -111,6 +111,22 @@ contract FraxlendPairDeployer is Ownable { // Functions: View Functions // ============================================================================================ + function removeDeployedPair(string calldata name) public ownerOnly { + string[] memory _deployedPairsArray = deployedPairsArray; + uint256 _lengthOfArray = _deployedPairsArray.length; + for (uint i; i < _lengthOfArray; ) { + if (keccak256(bytes(_deployedPairsArray[i])) == keccak256(bytes(name))) { + deployedPairsArray[i] = deployedPairsArray[_lengthOfArray - 1]; + deployedPairsArray.pop(); + return; + } + unchecked { + i++; + } + } + } + +
previewDeposit
and previewMint
don't revert when they shouldSeverity: Low
The Fraxlend previewDeposit and previewMint functions are ERC-4626 complatibility functions. The ERC-4626 spec intends these functions to effectively "simulate" a deposit or mint, and to revert if the corresponding deposit or mint would revert.
In its current implementation, previewDeposit and previewMint do not revert when the vault is paused or past maturity; however, the deposit and mint functions do revert when the vault is paused or past maturity.
Impact The vault/pair will not be fully ERC-4626 compliant. Strict ERC-4626 clients may not be able to interact with the protocol.
Recommendation:
This can be rememdiated by adding the isNotPastMaturity
and whenNotPaused
modifiers to the following functions:
maxDeposit
and maxMint
return incorrect resultsSeverity: Low
The Fraxlend maxDeposit and maxMint functions are ERC-4626 complatibility functions. The ERC-4626 spec intends these functions to be used to indicate global & user-specific deposit limitations.
In its current implementation, maxDeposit and maxMint always return type(uint128).max
, regardless of whether the vault is paused or if the address corresponds to an approved lender.
Impact The vault/pair will not be fully ERC-4626 compliant. Strict ERC-4626 clients may not be able to interact with the protocol.
Recommendation: To remediate this, the maxDeposit and maxMint functions must:
type(uint128).max
previewRateInterest()
does not handle edge caseSeverity: Low
Context: FraxlendPairHelper.sol#L155
Not in scope, but just wanted to point out that previewRateInterest
does not handle the edge case when the rate had been updated in the same block. So the result will be different than if the new rate generated by _addInterest
. Specific logic missing:
CurrentRateInfo memory _currentRateInfo = currentRateInfo; if (_currentRateInfo.lastTimestamp == block.timestamp) { _newRate = _currentRateInfo.ratePerSec; return (_interestEarned, _feesAmount, _feesShare, _newRate); }
Impact:
May cause some problems with those trying to integrate with the protocol and expecting an accurate preview.
Recommendation:
Add missing edge case logic shown above.
addInterest()
missing eventSeverity: Low
Context: FraxlendPairCore.sol#L432
Impact:
May cause some problems with those trying to integrate with the protocol or with the front end.
Recommendation:
Emit event UpdateRate
event.
liquidate()
functionSeverity: Low
Context: FraxlendPairCore.sol#L931
The liquidate()
function applies the clean liquidation fee with no checks for whether the liquidation was clean or dirty. It appears that liquidate()
should use the dirtyLiquidationFee
and that liquidators should only get the cleanLiquidationFee
if they call liquidateClean()
and satify the requirements of a clean liquidation.
Impact:
Liquidators will use the liquidate function to get clean liquidation fees even if doing a dirty liquidation.
Recommendation:
Change cleanLiquidationFee
to dirtyLiquidationFee
at line 931 or revert for non-clean liquidations.
Severity: Informational
Context: FraxlendPairCore.sol#L153
_immutables
param does not have a natspec
_addInterest()
incorrect commentSeverity: Informational
Context: FraxlendPairCore.sol#L429
Comment says:
// If there are no borrows or contract is paused, no interest accrues and we reset interest rate
but actually the rate only resets if the shares == 0 but its not paused.
updateExchangeRate()
unnecessary assignmentSeverity: Informational / Gas
Context: FraxlendPairCore.sol#L519
It's unneccesary to assign a value to the named return var if you're returning it.
function _updateExchangeRate() internal returns (uint256 _exchangeRate) { ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo; if (_exchangeRateInfo.lastTimestamp == block.timestamp) { return _exchangeRate = _exchangeRateInfo.exchangeRate;
Just return it return _exchangeRateInfo.exchangeRate;
Severity: Informational
Context: FraxlendPairDeployer.sol#L31
Solmate
is now located in Transmissions11's repo.