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: 53/62
Findings: 1
Award: $87.39
🌟 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
87.3915 USDC - $87.39
April 12, 2022
@securerodd
The check performed in the beginning to see if the positionOwner is not yet set is semi-redundant as it is reperformed later in the code to determine if a position should be opened. This can be refactored to increase gas efficiency.
Current code:
accrue(); require( msg.sender == positionOwner[_nftIndex] || address(0) == positionOwner[_nftIndex], "unauthorized" ); require(_amount > 0, "invalid_amount"); require( totalDebtAmount + _amount <= settings.borrowAmountCap, "debt_cap" ); if (positionOwner[_nftIndex] == address(0)) { _openPosition(msg.sender, _nftIndex); }
Gas:
___________________________________________________________________________________________ | Contract · Method · Min · Max · Avg · | ___________________________________________________________________________________________ | NFTVault · borrow · 142891 · 428260 · 402204 · │ ___________________________________________________________________________________________
Recommended code:
accrue(); require(_amount != 0, "invalid_amount"); require( totalDebtAmount + _amount <= settings.borrowAmountCap, "debt_cap" ); if (positionOwner[_nftIndex] == address(0)) { _openPosition(msg.sender, _nftIndex); } else { require( msg.sender == positionOwner[_nftIndex], "unauthorized" ); }
Gas:
___________________________________________________________________________________________ | Contract · Method · Min · Max · Avg · | ___________________________________________________________________________________________ | NFTVault · borrow · 142868 · 427851 · 401821 · │ ___________________________________________________________________________________________
The for loops used throughout the codebase can benefit from one or more of the following gas saving techniques:
Current Code in harvest()
function of StrategyPUSDConvex.sol
:
for (uint256 i = 0; i < rewardTokens.length; i++) { uint256 balance = rewardTokens[i].balanceOf(address(this)); ... }
Gas:
___________________________________________________________________________________________ | Contract · Method · Min · Max · Avg · | ___________________________________________________________________________________________ | StrategyPUSDConvex· harvest · 635854 · 747869 · 691862 · │ ___________________________________________________________________________________________
Recommended logic:
uint rewardTokenLen = rewardTokens.length; for (uint256 i = 0; i < rewardTokenLen; ++i) { uint256 balance = rewardTokens[i].balanceOf(address(this)); ... }
Gas:
___________________________________________________________________________________________ | Contract · Method · Min · Max · Avg · | ___________________________________________________________________________________________ | StrategyPUSDConvex· harvest · 635762 · 747777 · 691770 · │ ___________________________________________________________________________________________
Example nested for loops in the initializer of NFTVault.sol
:
for (uint256 i = 0; i < _typeInitializers.length; i++) { NFTCategoryInitializer memory initializer = _typeInitializers[i]; nftTypeValueETH[initializer.hash] = initializer.valueETH; for (uint256 j = 0; j < initializer.nfts.length; j++) { nftTypes[initializer.nfts[j]] = initializer.hash; } }
Recommended logic:
uint256 typeInits = _typeInitializers.length; for (uint256 i = 0; i < typeInits; ++i) { NFTCategoryInitializer memory initializer = _typeInitializers[i]; nftTypeValueETH[initializer.hash] = initializer.valueETH; uint256 nftsLength = initializer.nfts.length; for (uint256 j = 0; j < nftsLength; ++j) { nftTypes[initializer.nfts[j]] = initializer.hash; } }
Other locations that could benefit from some or all of these suggestions:
balanceOfJPEG()
in StrategyPUSDConvex.sol
StrategyPUSDConvex.sol
_massUpdatePools()
in LPFarming.sol
_claimAll()
in LPFarming.sol
within require statements, != comparisons are slightly more gas efficient than > and when a uint is being compared to 0, != is effectively the same as > 0.
Locations: