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: 55/120
Findings: 2
Award: $67.05
🌟 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
45.8377 USDC - $45.84
Floating pragmas make sense for libraries but in other contracts their are necessary and it is recommended to use specific pragma version. Floating pragmas may be a security risk for application implementations.
There are 13 instances of this issue:
File: ./src/contracts/FraxlendPair.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/FraxlendPairConstants.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/FraxlendPairCore.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/FraxlendPairDeployer.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/FraxlendPairHelper.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/FraxlendWhitelist.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/LinearInterestRate.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/VariableInterestRate.sol 2: pragma solidity ^0.8.15;
File: ./src/contracts/interfaces/IERC4626.sol 2: pragma solidity >=0.8.15;
File: ./src/contracts/interfaces/IFraxlendPair.sol 2: pragma solidity >=0.8.15;
File: ./src/contracts/interfaces/IFraxlendWhitelist.sol 2: pragma solidity >=0.8.15;
File: ./src/contracts/interfaces/IRateCalculator.sol 2: pragma solidity >=0.8.15;
File: ./src/contracts/interfaces/ISwapper.sol 2: pragma solidity >=0.8.15;
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0xA5DF, 0xDjango, 0xNazgul, 0xSmartContract, 0xackermann, 0xbepresent, 0xc0ffEE, 0xkatana, 2997ms, Amithuddar, Aymen0909, Bnke0x0, Chinmay, Chom, CodingNameKiki, Deivitto, Diraco, Dravee, ElKu, EthLedger, Fitraldys, Funen, IgnacioB, JC, Junnon, Lambda, LeoS, Metatron, MiloTruck, Noah3o6, NoamYakov, PaludoX0, Randyyy, ReyAdmirado, Rohan16, Rolezn, Ruhum, SaharAP, Sm4rty, SooYa, TomJ, Tomio, Waze, Yiko, _Adam, __141345__, a12jmx, ajtra, ak1, asutorufos, ballx, brgltd, c3phas, cRat1st0s, carlitox477, chrisdior4, d3e4, delfin454000, dharma09, djxploit, durianSausage, erictee, fatherOfBlocks, find_a_bug, flyx, francoHacker, gerdusx, gogo, gzeon, hakerbaya, ignacio, jag, kyteg, ladboy233, ltyu, m_Rassska, medikko, mics, mrpathfindr, newfork01, nxrblsrpr, oyc_109, pfapostol, rbserver, reassor, ret2basic, robee, sach1r0, saian, simon135, sryysryy, zeesaw
21.2057 USDC - $21.21
Overriting varibles with defualt values with their default value will waste only gas and not necessary.
There are 9 instances of this issue:
File: ./src/contracts/FraxlendPair.sol:: 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
File: ./src/contracts/FraxlendPairCore.sol 265: for (uint256 i = 0; i < _approvedBorrowers.length; ++i) { 270: for (uint256 i = 0; i < _approvedLenders.length; ++i) {
File: ./src/contracts/FraxlendPairDeployer.sol 402: for (uint256 i = 0; i < _lengthOfArray; ) {
File: ./src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
File: ./src/contracts/libraries/SafeERC20.sol 22: uint8 i = 0;
unchecked{++i}
/unchecked{i++}
rather than this ++i
/i++
in for
-loopsUsing a unchecked{++i}
/unchecked{i++}
is recommended in for loops if underflow and overflow is not possible. This will save some gas because the compiler woudn't make a safety check. This safety checks is came from version 0.8.0 and that applies also to above versions.
There are 8 instances of this issue:
File: ./src/contracts/FraxlendPair.sol:: 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
File: ./src/contracts/FraxlendPairCore.sol 265: for (uint256 i = 0; i < _approvedBorrowers.length; ++i) { 270: for (uint256 i = 0; i < _approvedLenders.length; ++i) {
File: ./src/contracts/libraries/SafeERC20.sol 27: for (i = 0; i < 32 && data[i] != 0; i++) {
File: ./src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
++i
/--i
are more cheap operations than i++
/i--
Using a ++i
/--i
operations can save about 6 gas for loop/instance because compiler will make less operations
There are 6 instances of this issue:
File: ./src/contracts/FraxlendPair.sol:: 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
File: ./src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
File: ./src/contracts/libraries/SafeERC20.sol 27: for (i = 0; i < 32 && data[i] != 0; i++) {
For loop written like thisfor (uint256 i; i < array.length; ++i) {
will cost more gas than for (uint256 i; i < _lengthOfArray; ++i) {
because for every iteration we use mload and memory_offset
that will cost about 6 gas
There are 7 instances of this issue:
File: ./src/contracts/FraxlendPair.sol 289: for (uint256 i = 0; i < _lenders.length; i++) { 308: for (uint256 i = 0; i < _borrowers.length; i++) {
File: ./src/contracts/FraxlendPairCore.sol: 265: for (uint256 i = 0; i < _approvedBorrowers.length; ++i) { 270: for (uint256 i = 0; i < _approvedLenders.length; ++i) {
File: ./src/contracts/FraxlendWhitelist.sol 51: for (uint256 i = 0; i < _addresses.length; i++) { 66: for (uint256 i = 0; i < _addresses.length; i++) { 81: for (uint256 i = 0; i < _addresses.length; i++) {
> 0
will save about 3 gas per loop/instance when used on unsigned integers
There are 3 instances of this issue:
File: ./src/contracts/FraxlendPairCore.sol: 257: if (bytes(nameOfContract).length != 0) {
File: ./src/contracts/libraries/SafeERC20.sol 23: while (i < 32 && data[i] != 0) { 27: for (i = 0; i < 32 && data[i] != 0; i++) {
There are 13 instances of this issue:
File: ./src/contracts/VariableInterestRate.sol 47: return "Variable Time-Weighted Interest Rate";
File: ./src/contracts/FraxlendPair.sol 81: return string(abi.encodePacked("FraxlendV1 - ", collateralContract.safeSymbol(), "/", 85: return 18; 90: return totalAsset.shares; 97: return address(assetContract); 101: return totalAsset.amount; 121: return totalAsset.toShares(_amount, false); 125: return totalAsset.toAmount(_shares, true); 129: return totalAsset.toShares(_amount, true); 133: return totalAsset.toAmount(_shares, false); 145: return totalAsset.toAmount(balanceOf(owner), false); 184: return totalBorrow.toShares(_amount, _roundUp); 191: return totalBorrow.toAmount(_shares, _roundUp);
File: ./src/contracts/FraxlendPairCore.sol 300: return _totalAsset.amount - _totalBorrow.amount; 321: return maturityDate != 0 && block.timestamp > maturityDate;
String in require()
and revert()
that are bigger than 32 bytes (256 bits) will cost 3 gas for each memory work.
There are 5 instances of this issue:
File: ./src/contracts/FraxlendPairDeployer.sol 205: require(deployedPairsBySalt[salt] == address(0), "FraxlendPairDeployer: Pair already deployed"); 228: require(_pairAddress != address(0), "FraxlendPairDeployer: create2 failed");
File: ./src/contracts/LinearInterestRate.sol 57: require( 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 59: "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest 60: >= MIN_INT" 60; ); 61: require( 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT,"LinearInterestRate: 63: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT" 64: ); 65 require( 66 _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, 67 "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0" 68 );
revert()
/require()
strings to save gasCustom errors are available from solidity 0.8.4 and above. The code below match that and using them will save gas each time they're hit by avoiding having to allocate and store the revert string.
There are 5 instances of this issue:
File: ./src/contracts/FraxlendPairDeployer.sol 205: require(deployedPairsBySalt[salt] == address(0), "FraxlendPairDeployer: Pair already deployed"); 228: require(_pairAddress != address(0), "FraxlendPairDeployer: create2 failed");
File: ./src/contracts/LinearInterestRate.sol 57: require( 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 59: "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest 60: >= MIN_INT" 60; ); 61: require( 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT,"LinearInterestRate: 63: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT" 64: ); 65 require( 66 _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, 67 "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0" 68 );
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM machine command for <=
/>=
doesn't exist rather than two operations are performed >
/<
and =
that will cost more gas than using one comparison operator.
There are 14 instances of this issue:
File: ./src/contracts/FraxlendPairCore.sol 315: return _ltv <= maxLTV; 472: _interestEarned + _totalBorrow.amount <= type(uint128).max && 473: _interestEarned + _totalAsset.amount <= type(uint128).max 525: if (_answer <= 0) { 533: if (_answer <= 0) { 988: _collateralForLiquidator = _leftoverCollateral <= 0 1000: if (_leftoverCollateral <= 0) {
File: ./src/contracts/FraxlendPairDeployer.sol 365: require(_maxLTV <= GLOBAL_MAX_LTV, "FraxlendPairDeployer: _maxLTV is too large");
File: ./src/contracts/FraxlendPairHelper.sol 134: if (_answer <= 0) { 142: if (_answer <= 0) { 284: _collateralForLiquidator = _leftoverCollateral <= 0 292: if (_leftoverCollateral <= 0 && (_borrowerShares - _sharesToLiquidate) > 0) {
File: ./src/contracts/LinearInterestRate.sol 58: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, 62: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT,
<x> += <y>
is more expensive than <x> = <x> + <y>
for state variablesThere are 11 instances of this issue:
File: ./src/contracts/FraxlendPairCore.sol 475: _totalBorrow.amount += uint128(_interestEarned); 476: _totalAsset.amount += uint128(_interestEarned); 484: _totalAsset.shares += uint128(_feesShare); 566: _totalAsset.amount += _amount; 567: _totalAsset.shares += _shares; 718: _totalBorrow.amount += _borrowAmount; 719: _totalBorrow.shares += uint128(_sharesAdded); 724: userBorrowShares[msg.sender] += _sharesAdded; 772: userCollateralBalance[_borrower] += _collateralAmount; 773: totalCollateral += _collateralAmount;
File ./src/test/e2e/BasePairTest.sol 539: _sumOfInt += _interestEarned;