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: 95/120
Findings: 1
Award: $21.18
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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.1761 USDC - $21.18
Array length can be cached and used in the loop condition instead of reading it in every iteration and save gas
for (uint256 i = 0; i < _addresses.length; i++)
for (uint256 i = 0; i < _addresses.length; i++) {
for (uint256 i = 0; i < _addresses.length; i++) {
for (uint256 i = 0; i < _lenders.length; i++)
for (uint256 i = 0; i < _borrowers.length; i++)
for (uint256 i = 0; i < _approvedLenders.length; ++i)
for (uint256 i = 0; i < _approvedBorrowers.length; ++i)
for (uint256 i = 0; i < _addresses.length; i++)
for (uint256 i = 0; i < _addresses.length; i++)
for (uint256 i = 0; i < _addresses.length; i++)
String is a dynamic data structure and therefore consumes more gas, it can be replaced with bytes32
string public version = "1.0.0";
Variables that are known at compile time and not updated later can be converted to constant to avoid storage reads and save gas
uint256 public DEFAULT_MAX_LTV = 75000; // 75% with 1e5 precision uint256 public GLOBAL_MAX_LTV = 1e8; // 1000x (100,000%) with 1e5 precision, protects from rounding errors in LTV calc uint256 public DEFAULT_LIQ_FEE = 10000; // 10% with 1e5 precision
Variables that are initialized in constructor and not updated later can be converted to immutable to save gas on storage read
// Admin contracts address public CIRCUIT_BREAKER_ADDRESS; address public COMPTROLLER_ADDRESS; address public TIME_LOCK_ADDRESS;
Pre-increment saves a small amount of gas than postfix increment because it doesnt have to store the previous value. This can be more significant in loops where this operation is done multiple times.
for (uint256 i = 0; i < _addresses.length; i++)
for (uint256 i = 0; i < _addresses.length; i++) {
for (uint256 i = 0; i < _addresses.length; i++) {
i++;
i++;
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met. Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.
require(deployedPairsBySalt[salt] == address(0), "FraxlendPairDeployer: Pair already deployed");
require(_pairAddress != address(0), "FraxlendPairDeployer: create2 failed");
require(deployedPairsByName[_name] == address(0), "FraxlendPairDeployer: Pair name must be unique");
require(_maxLTV <= GLOBAL_MAX_LTV, "FraxlendPairDeployer: _maxLTV is too large");
require( IFraxlendWhitelist(FRAXLEND_WHITELIST_ADDRESS).fraxlendDeployerWhitelist(msg.sender), "FraxlendPairDeployer: Only whitelisted addresses" );
require( _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT, "LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT" ); require( _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT, "LinearInterestRate: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT" ); require( _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0, "LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0" );
Custom errors from solidity 0.8.4 are more efficient than revert strings with cheaper deployment and runtime time costs when revert condition is met
Refer: https://blog.soliditylang.org/2021/04/21/custom-errors/](https://blog.soliditylang.org/2021/04/21/custom-errors/
Deployed pair address name check can be performed in deploy()
function instead of _deploySecond()
to save gas on revert
require(deployedPairsByName[_name] == address(0), "FraxlendPairDeployer: Pair name must be unique");
string memory _name = string( abi.encodePacked( "FraxlendV1 - ", IERC20(_collateral).safeName(), "/", IERC20(_asset).safeName(), " - ", IRateCalculator(_rateContract).name(), " - ", (deployedPairsArray.length + 1).toString() ) );