Platform: Code4rena
Start Date: 21/06/2022
Pot Size: $30,000 USDC
Total HM: 12
Participants: 96
Period: 3 days
Judge: HardlyDifficult
Total Solo HM: 5
Id: 140
League: ETH
Rank: 21/96
Findings: 2
Award: $79.46
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0x52, 0xNazgul, 0xNineDec, 0xc0ffEE, 0xf15ers, 0xkatana, BowTiedWardens, Chom, ElKu, Funen, GalloDaSballo, JC, JMukesh, JohnSmith, Lambda, Limbooo, MadWookie, MiloTruck, Nethermind, Noah3o6, Nyamcil, Picodes, PwnedNoMore, Randyyy, RoiEvenHaim, SmartSek, StErMi, Tadashi, TerrierLover, TomJ, Tomio, Treasure-Seeker, UnusualTurtle, Varun_Verma, Wayne, Waze, _Adam, apostle0x01, asutorufos, berndartmueller, c3phas, catchup, cccz, cloudjunky, codexploder, cryptphi, defsec, delfin454000, dipp, ellahi, exd0tpy, fatherOfBlocks, hansfriese, hyh, joestakey, kebabsec, kenta, masterchief, minhquanym, naps62, oyc_109, pashov, peritoflores, reassor, rfa, robee, sach1r0, saian, sashik_eth, shenwilly, simon135, slywaters, sorrynotsorry, sseefried, unforgiven, xiaoming90, ych18, zuhaibmohd, zzzitron
28.2781 USDC - $28.28
Recommend not using a floating pragma and changing to 0.8.10 to be consistent with other contracts. AccessControlMechanism.sol#L4
The Same require check is repeated 8 times, recommend creating a modifier and using that instead. Basket.sol#L36 Basket.sol#L42 Basket.sol#L53 Basket.sol#L62 Basket.sol#L69 Basket.sol#L79 Basket.sol#L86 Basket.sol#L92
NibblVaultFactory.sol#L37 - missing @return NibblVaultFactory.sol#L63 - missing @return NibblVault.sol#L271 - missing @param _ totalSupply NibblVault.sol#L283 - missing @param _ totalSupply NibblVault.sol#L299 - missing @return NibblVault.sol#L334 - missing @param _ totalSupply NibblVault.sol#L346 - missing @param _ totalSupply NibblVault.sol#L361 - missing @return NibblVault.sol#L397 - missing @return NibblVault.sol#L463 - missing @param _ to NibblVault.sol#L473 - missing @return Basket.sol#L34 - missing @param _ to Basket.sol#L51 - missing @param _ to Basket.sol#L60 - missing @param _ to
#0 - HardlyDifficult
2022-07-04T14:34:04Z
NC code style & comments. Good format & concise feedback.
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 8olidity, ACai, BowTiedWardens, Chandr, Chom, ElKu, Fitraldys, Funen, IgnacioB, JC, Lambda, Limbooo, MiloTruck, Noah3o6, Nyamcil, Picodes, Randyyy, SmartSek, StErMi, TerrierLover, TomJ, Tomio, UnusualTurtle, Waze, _Adam, ajtra, c3phas, cRat1st0s, catchup, codexploder, cryptphi, defsec, delfin454000, ellahi, exd0tpy, fatherOfBlocks, hansfriese, joestakey, kebabsec, kenta, m_Rassska, minhquanym, oyc_109, pashov, reassor, rfa, robee, sach1r0, saian, sashik_eth, simon135, slywaters, ych18, ynnad, zuhaibmohd
51.1766 USDC - $51.18
The following functions are never called in their contracts and can be switched to external to save gas: NibblVaultFactory.sol#L64-L69 NibblVaultFactory.sol#L76 NibblVaultFactory.sol#L80 NibblVaultFactory.sol#L88 Twav.sol#L44
When incrementing i in for loops there is no chance of overflow so unchecked can be used to save gas. I ran a simple test in remix and found deployment savings of 31,653 gas and on each function call saved ~141 gas per iteration.
contract Test { function loopTest() external { for (uint256 i; i < 1; ++i) { Deployment Cost: 125,637, Cost on function call: 24,601 vs for (uint256 i; i < 1; ) { // for loop body unchecked { ++i } Deployment Cost: 93,984, Cost on function call: 24,460 } } }
For loops that can use unchecked increments: NibblVault.sol#L506 NibblVault.sol#L525 NibblVault.sol#L547 Basket.sol#L43 Basket.sol#L70 Basket.sol#L93
In for loops pre increments can also be used to save a small amount of gas per iteration. I ran a test in remix using a for loop and found the deployment savings of 497 gas and ~5 gas per iteration.
contract Test { function loopTest() external { for (uint256 i; i < 1; i++) { (Deployment cost: 118,408, Cost on function call: 24,532) vs for (uint256 i; i < 1; ++i) { (Deployment cost: 117,911, Cost on function call: 24,527) } } }
For loops that can use pre increments: NibblVault.sol#L506 NibblVault.sol#L525 NibblVault.sol#L547 Basket.sol#L43 Basket.sol#L70 Basket.sol#L93
As your using a solidity version > 0.8.4 for most of the contracts you can replace revert strings with custom errors. This will save in deployment costs and runtime costs. I ran a test in remix comparing a revert string vs custom errors and found that replacing a single revert string with a custom error saved 12,404 gas in deployment cost and 86 gas on each function call.
contract Test { uint256 a; function check() external { require(a != 0, "check failed"); } } (Deployment cost: 114,703, Cost on Function call: 23,392) vs contract Test { uint256 a; error checkFailed(); function check() external { if (a != 0) revert checkFailed(); } } (Deployment cost: 102,299, Cost on Function call: 23,306)
There are 41 revert strings throughout your contracts that can be replaced with custom errors.
If you opt not to use custom errors keeping revert strings <= 32 bytes in length will save gas. I ran a test in remix and found the savings for a single short revert string vs long string to be 9,377 gas in deployment cost and 18 gas on function call.
contract Test { uint256 a; function check() external { require(a != 0, "short error message"); (Deployment cost: 114,799, Cost on function call: 23,392) vs require(a != 0, "A longer Error Message over 32 bytes in length"); (Deployment cost: 124,176, Cost on function call: 23,410) } }
I recommend shortenning the following revert strings to < 32 bytes in length: NibblVaultFactory.sol#L48-L49 NibblVaultFactory.sol#L107 NibblVaultFactory.sol#L131 NibblVaultFactory.sol#L141 NibblVaultFactory.sol#L149 NibblVaultFactory.sol#L166
If optimising for runtime costs over deployment costs you can seperate && in require functions into 2 parts. I ran a basic test in remix and it cost an extra 234 gas to deploy but will save ~9 gas everytime the require function is called.
contract Test { uint256 a = 0; uint256 b = 1; function test() external { require(a == 0 && b > a) (Deployment cost: 123,291, Cost on function call: 29,371) vs require(a == 0); require(b > a); (Deployment cost: 123,525, Cost on function call: 29,362) } }
Require statements that can be split up: NibblVaultFactory.sol#L107 NibblVaultFactory.sol#L131 NibblVaultFactory.sol#L149 NibblVaultFactory.sol#L166
Moving the uint32 variable primaryReserveRatio down to line 52 will it allow it to be stored with secondaryReserveRatio and use 1 less storage slot (save 20,000 gas). NibblVault.sol#L28
When using function arguments that you only need to reference and not make any modifications to it is cheaper to use calldata than memory. Instances where calldata can be used instead of memory: NibblVaultFactory.sol#L41-L42 NibblVaultFactory.sol#L80 NibblVaultFactory.sol#L88 NibblVault.sol#L174-L175 NibblVault.sol#L504 NibblVault.sol#L523 NibblVault.sol#L545 Basket.sol#L41 Basket.sol#L68 Basket.sol#L91 EIP712Base.sol#L15
Whenever referencing a storage variable more than once in a function without modifying it, it is cheaper to cache locally and use that instead. (normally 100 gas each use vs 103 gas to SLOAD/MSTORE for the first use and then only 3 gas for any others)
NibblVaultFactory.sol#L107 can cache basketUpdateTime (save ~97 gas) NibblVaultFactory.sol#L131 can cache feeToUpdateTime (save ~97 gas) NibblVaultFactory.sol#L149 can cache feeAdminUpdateTime (save ~97 gas) NibblVaultFactory.sol#L166 can cache vaultUpdateTime (save ~97 gas) For the previous 4 make sure to only use cached variables when referencing not when deleting. NibblVault.sol#L139 can cache buyoutEndTime (save ~97 gas) Twav.sol#L27-L29 can cache twavObservationsIndex (save ~194 gas) On line 29 ensure the cached value is only used on the right side of the assignment.
As explained in Solidity Docs using elements smaller than 32 bytes can cost more gas. Recommend replacing the follpwing with uint256: Twav.sol#L22 Twav.sol#L37
#0 - mundhrakeshav
2022-06-26T06:58:57Z
[G07] Packing Variables Moving the uint32 variable primaryReserveRatio down to line 52 will it allow it to be stored with secondaryReserveRatio and use 1 less storage slot (save 20,000 gas). NibblVault.sol#L28