Platform: Code4rena
Start Date: 07/04/2022
Pot Size: $100,000 USDC
Total HM: 20
Participants: 62
Period: 7 days
Judge: LSDan
Total Solo HM: 11
Id: 107
League: ETH
Rank: 57/62
Findings: 1
Award: $80.91
π Selected for report: 0
π Solo Findings: 0
π Selected for report: Dravee
Also found by: 0v3rf10w, 0x1f8b, 0xDjango, 0xNazgul, 0xkatana, Cityscape, Cr4ckM3, FSchmoede, Foundation, Funen, Hawkeye, IllIllI, JMukesh, Meta0xNull, PPrieditis, Picodes, TerrierLover, Tomio, WatchPug, berndartmueller, catchup, delfin454000, dirk_y, ellahi, hickuphh3, ilan, kebabsec, kenta, nahnah, rayn, rfa, robee, rokinot, saian, securerodd, slywaters, sorrynotsorry
80.9074 USDC - $80.91
Using both named returns and a return statement isnβt necessary
Removing unused named returns variables can reduce gas usage (MSTOREs/MLOADs) and improve code clarity. To save gas and improve code quality: consider using only one of those.
This can be found in the following;
NFTEscrow.sol
, LPFarming.sol
, yVaultLPFarming.sol
, CryptoPunksHelper.sol
, EtherRocksHelper.sol
, StrategyPUSDConvex.sol
, Controller.sol
, YVault.sol
, FungibleAssetVaultForDAO.sol
, NFTVault.sol
Strings are broken into 32 byte chunks for operations. Error strings in reverts more than 32 bytes consume more gas. Therefore, error messages less than 32 bytes shold be selected. If possible, custom error messages consume much more less and supported by Solidity ^0.8.0. E.g.
function mint(address to, uint256 amount) external { require( hasRole(MINTER_ROLE, _msgSender()), "JPEG: must have minter role to mint" ); _mint(to, amount); }
Also the variable names more than 32 bytes is recommended to reduce to save more gas. Below is the list
At Controller.sol : inCaseStrategyTokensGetStuck()
At NFTVault.sol : setInsuranceLiquidationPenaltyRate()
, _validateCreditLimitAndLiquidationRate()
,
By minimising the number of SLOADs which are expensive (100 gas) compared to MLOADs/MSTOREs (3 gas), SLOADs calls can be cached to memory variables to turn the proces into MLOADs. And prior to writing to storage again, those can also be cached back. Following contract sections are having this optimization;
LPFarming.sol
, pendingReward
method, cache the pool
and the user
to memory variables after initiliazing to save 6 SLOADsLPFarming.sol
, deposit
method, cache the pool
and the user
to memory variables after initiliazing to save 3 SLOADsLPFarming.sol
, withdraw
method, cache the pool
and the user
to memory variables after initiliazing to save 3 SLOADsLPFarming.sol
, _updatePool
method, cache the pool
to a memory variable after initiliazing to save 8 SLOADsNFTVault.sol
, borrow
method, cache the position
to a memory variable after initiliazing to save 9 SLOADsReading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration. The optimization can be applied to following contract sections:
LPFarming.sol
, claimAll
method, caching poolInfo.length
StrategyPUSDConvex.sol
, harvest
method, caching rewardTokens.length