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: 40/96
Findings: 2
Award: $45.91
🌟 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.2782 USDC - $28.28
/// @notice The days until which a buyout bid is valid, if the bid isn't rejected in buyout duration time, its automatically considered boughtOut
Change until
to during
The same typo (when
) occurs in all four lines referenced below:
contracts/NibblVault.sol: L137 contracts/NibblVault.sol: L144 contracts/NibblVault.sol: L368 contracts/NibblVault.sol: L448
Example:
/// @dev Check for the case when buyoutTime has not passed or buyout has been rejected
Change when
to where
The same typo (fee is
) occurs in the three lines referenced below:
contracts/NibblVault.sol: L234
contracts/NibblVault.sol: L284
contracts/NibblVault.sol: L344
Example:
/// @dev only admin and curator fee is charged in secondary curve
Change fee is
to fees are
in each case
The same typo (continous
) occurs in all four lines referenced below:
contracts/NibblVault.sol: L250 contracts/NibblVault.sol: L270 contracts/NibblVault.sol: L282 contracts/NibblVault.sol: L359
Example:
/// @dev The max continous tokens on SecondaryCurve is equal to initialTokenSupply
Change continous
to continuous
in each case
contracts/NibblVault.sol: L258
/// @dev fictitiousPrimaryReserveBalance doesn't denote any actual reserve balance its just for calculation purpose
Change purpose
to purposes
contracts/NibblVault.sol: L263
/// @dev Valuation = If current supply is on seconday curve we use secondaryReserveBalance and secondaryReserveRatio to calculate valuation else we use primary reserve ratio and balance
Change seconday
to seconday
contracts/NibblVault.sol: L361
/// @param _to Address to recieve the reserve token to
Change recieve
to receive
and remove the final to
contracts/NibblVault.sol: L462
/// @dev The redeemed reserve token are in proportion to the token supply someone owns
Change token
to tokens
The same typo (internall
) occurs in both lines referenced below:
contracts/Proxy/ProxyVault.sol: L26 contracts/Proxy/ProxyBasket.sol: L26
* This function does not return to its internall call site, it will return directly to the external caller.
Change internall
to internal
in both cases
For the sake of readability, comments over 79 characters should wrap using multi-line comment syntax. Note that in cases where the information can be communicated with fewer words, it might be possible (and preferable) to shorten the comments to fit on one line
/// @notice The days until which a buyout bid is valid, if the bid isn't rejected in buyout duration time, its automatically considered boughtOut
Suggestion:
/// @notice The days until which a buyout bid is valid, if the bid isn't rejected /// in buyout duration time, it's automatically considered boughtOut
Similarly for the comment lines referenced below:
contracts/NibblVault.sol: L16 contracts/NibblVault.sol: L17 contracts/NibblVault.sol: L19 contracts/NibblVault.sol: L27 contracts/NibblVault.sol: L33 contracts/NibblVault.sol: L36 contracts/NibblVault.sol: L39 contracts/NibblVault.sol: L45 contracts/NibblVault.sol: L77 contracts/NibblVault.sol: L78 contracts/NibblVault.sol: L79 contracts/NibblVault.sol: L86 contracts/NibblVault.sol: L98 contracts/NibblVault.sol: L169 contracts/NibblVault.sol: L208 contracts/NibblVault.sol: L209 contracts/NibblVault.sol: L210 contracts/NibblVault.sol: L211 contracts/NibblVault.sol: L249 contracts/NibblVault.sol: L251 contracts/NibblVault.sol: L258 contracts/NibblVault.sol: L259 contracts/NibblVault.sol: L260 contracts/NibblVault.sol: L261 contracts/NibblVault.sol: L262 contracts/NibblVault.sol: L263 contracts/NibblVault.sol: L295 contracts/NibblVault.sol: L296 contracts/NibblVault.sol: L297 contracts/NibblVault.sol: L298 contracts/NibblVault.sol: L356 contracts/NibblVault.sol: L357 contracts/NibblVault.sol: L358 contracts/NibblVault.sol: L395 contracts/NibblVault.sol: L396 contracts/NibblVault.sol: L397 contracts/NibblVault.sol: L405 contracts/NibblVault.sol: L461 contracts/NibblVault.sol: L463 contracts/NibblVault.sol: L512 contracts/NibblVault.sol: L530 contracts/NibblVault.sol: L531
require
revert stringRequire
message should be included to enable users to understand reason for failure
contracts/NibblVaultFactory.sol: L114
require(_success);
Add a brief message to explain require
failure
#0 - HardlyDifficult
2022-07-04T15:51:02Z
Valid NC improvements
🌟 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
17.626 USDC - $17.63
Require
message is too longThe revert strings below can be shortened to 32 characters or fewer (as shown) to save gas
contracts/NibblVaultFactory.sol: L48
require(msg.value >= MIN_INITIAL_RESERVE_BALANCE, "NibblVaultFactory: Initial reserve balance too low");
Change message to NibblVaultFactory: Low res bal
contracts/NibblVaultFactory.sol: L49
require(IERC721(_assetAddress).ownerOf(_assetTokenID) == msg.sender, "NibblVaultFactory: Invalid sender");
Change message to NibblVaultFactory: Inval sender
Identical long require
revert strings occur in all four lines referenced below. It's not clear how to shorten the message without abbreviating 'NibblVaultFactory'
contracts/NibblVaultFactory.sol: L107 contracts/NibblVaultFactory.sol: L131 contracts/NibblVaultFactory.sol: L149 contracts/NibblVaultFactory.sol: L166
Example:
require(basketUpdateTime != 0 && block.timestamp >= basketUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
require
functionSplitting such require()
statements into separate requires
instead of using '&&' saves gas
contracts/NibblVaultFactory.sol: L107
require(basketUpdateTime != 0 && block.timestamp >= basketUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
Recommendation:
require(basketUpdateTime != 0, "NibblVaultFactory: UPDATE_TIME has not passed"); require(block.timestamp >= basketUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
Similarly for the three additional instances of '&&' within require
functions referenced below:
contracts/NibblVaultFactory.sol: L131 contracts/NibblVaultFactory.sol: L149 contracts/NibblVaultFactory.sol: L166
For example, initializing uint
variables to their default value of 0
is unnecessary and costs gas
The for
loop counter i
is initialized unnecessarily to zero in the six loops referenced below:
contracts/NibblVault.sol: L506-508 contracts/NibblVault.sol: L525-527 contracts/NibblVault.sol: L547-550 contracts/Basket.sol: L43-46 contracts/Basket.sol: L70-74 contracts/Basket.sol: L93-96
Example:
for (uint256 i = 0; i < _assetAddresses.length; i++) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); }
Change uint256 i = 0;
to uint256 i;
in all cases
for
loopSince calculating the array length costs gas, it's best to read the length of the array from memory before executing the loop
contracts/NibblVault.sol: L506-508
for (uint256 i = 0; i < _assetAddresses.length; i++) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); }
Recommendation:
uint256 totalAssetAddresses = _assetAddresses.length; for (uint256 i = 0; i < totalAssetAddresses; ++i) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); }
Similarly for the five for
loops referenced below:
contracts/NibblVault.sol: L525-527 contracts/NibblVault.sol: L547-550 contracts/Basket.sol: L43-46 contracts/Basket.sol: L70-74 contracts/Basket.sol: L93-96
i++
to increase count in a for
loopSince use of i++ costs more gas, it would be better to use ++i in the six for
loops referenced below:
contracts/NibblVault.sol: L506-508 contracts/NibblVault.sol: L525-527 contracts/NibblVault.sol: L547-550 contracts/Basket.sol: L43-46 contracts/Basket.sol: L70-74 contracts/Basket.sol: L93-96
for
loopUnder/overflow checks are made every time i++
or (++i
) is called. Such checks are unnecessary since i
is already limited. Therefore, use unchecked{++i}
/unchecked{i++}
instead
contracts/NibblVault.sol: L506-508
for (uint256 i = 0; i < _assetAddresses.length; i++) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); }
Recommendation:
for (uint256 i = 0; i < _assetAddresses.length;) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); unchecked{ i++; } }
Similarly for the five additional for
loops that could save gas by using unchecked
:
contracts/NibblVault.sol: L525-527 contracts/NibblVault.sol: L547-550 contracts/Basket.sol: L43-46 contracts/Basket.sol: L70-74 contracts/Basket.sol: L93-96
For
loop gas optimization exampleWhile, for presentation purposes, I have separated the for
loop-related gas savings methods, they should be combined. Below I show how all four of the gas saving methods outlined in this submission can be implemented together.
i
) to zero++i
rather than i++
unchecked
++i
contracts/NibblVault.sol: L506-508
for (uint256 i = 0; i < _assetAddresses.length; i++) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); }
Recommendation:
uint256 totalAssetAddresses = _assetAddresses.length; for (uint256 i; i < totalAssetAddresses;) { IERC721(_assetAddresses[i]).safeTransferFrom(address(this), _to, _assetIDs[i]); unchecked{ ++i; } }
Storage of uints or ints smaller than 32 bytes incurs overhead. Instead, use size of at least 32, then downcast where needed
Recommendation: Use a larger size than uint8
in the four lines referenced below:
contracts/NibblVault.sol: L557 contracts/Twav/Twav.sol: L11 contracts/Twav/Twav.sol: L12 contracts/Twav/Twav.sol: L37