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: 30/96
Findings: 2
Award: $49.74
π 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
32.4789 USDC - $32.48
The return value of an external transfer
/transferFrom
call is not checked
/// @notice withdraw ERC20 in the case a held NFT earned ERC20 function withdrawERC20(address _token) external override { require(_isApprovedOrOwner(msg.sender, 0), "withdraw:not allowed"); IERC20(_token).transfer(msg.sender, IERC20(_token).balanceOf(address(this))); emit WithdrawERC20(_token, msg.sender); } function withdrawMultipleERC20(address[] memory _tokens) external override { require(_isApprovedOrOwner(msg.sender, 0), "withdraw:not allowed"); for (uint256 i = 0; i < _tokens.length; i++) { IERC20(_tokens[i]).transfer(msg.sender, IERC20(_tokens[i]).balanceOf(address(this))); emit WithdrawERC20(_tokens[i], msg.sender); } }
function withdrawERC20(address _asset, address _to) external override boughtOut { require(msg.sender == bidder, "NibblVault: Only winner"); IERC20(_asset).transfer(_to, IERC20(_asset).balanceOf(address(this))); } /// @notice withdraw multiple ERC20s /// @param _assets the addresses of assets to be unlocked /// @param _to the address where unlocked NFTs will be sent function withdrawMultipleERC20(address[] memory _assets, address _to) external override boughtOut { require(msg.sender == bidder, "NibblVault: Only winner"); for (uint256 i = 0; i < _assets.length; i++) { IERC20(_assets[i]).transfer(_to, IERC20(_assets[i]).balanceOf(address(this))); } }
Use SafeERC20
, or ensure that the transfer
/transferFrom
return value is checked.
manual, slither
#0 - mundhrakeshav
2022-06-26T17:21:30Z
#16
#1 - HardlyDifficult
2022-07-03T22:29:04Z
#2 - HardlyDifficult
2022-07-03T22:34:00Z
#3 - HardlyDifficult
2022-07-03T22:44:04Z
#4 - HardlyDifficult
2022-07-03T22:45:43Z
#5 - HardlyDifficult
2022-07-04T15:56:09Z
Good low risk improvements suggested
π 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.2596 USDC - $17.26
Reading 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.
Basket.sol::43 => for (uint256 i = 0; i < _tokens.length; i++) { Basket.sol::70 => for (uint256 i = 0; i < _tokens.length; i++) { Basket.sol::93 => for (uint256 i = 0; i < _tokens.length; i++) { NibblVault.sol::506 => for (uint256 i = 0; i < _assetAddresses.length; i++) { NibblVault.sol::525 => for (uint256 i = 0; i < _assets.length; i++) { NibblVault.sol::547 => for (uint256 i = 0; i < _assets.length; i++) {
Store the arrayβs length in a variable before the for-loop.
++i
costs less gas compared to i++
or i += 1
++i
costs less gas compared to i++
or i += 1
for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.
Basket.sol::43 => for (uint256 i = 0; i < _tokens.length; i++) { Basket.sol::70 => for (uint256 i = 0; i < _tokens.length; i++) { Basket.sol::93 => for (uint256 i = 0; i < _tokens.length; i++) { NibblVault.sol::506 => for (uint256 i = 0; i < _assetAddresses.length; i++) { NibblVault.sol::525 => for (uint256 i = 0; i < _assets.length; i++) { NibblVault.sol::547 => for (uint256 i = 0; i < _assets.length; i++) {
Use ++i
instead of i++
to increment the value of an uint variable.
Same thing for --i
and 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.
NibblVaultFactory.sol::48 => require(msg.value >= MIN_INITIAL_RESERVE_BALANCE, "NibblVaultFactory: Initial reserve balance too low"); NibblVaultFactory.sol::49 => require(IERC721(_assetAddress).ownerOf(_assetTokenID) == msg.sender, "NibblVaultFactory: Invalid sender"); NibblVaultFactory.sol::107 => require(basketUpdateTime != 0 && block.timestamp >= basketUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed"); NibblVaultFactory.sol::131 => require(feeToUpdateTime != 0 && block.timestamp >= feeToUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed"); NibblVaultFactory.sol::141 => require(_newFee <= MAX_ADMIN_FEE, "NibblVaultFactory: Fee value greater than MAX_ADMIN_FEE"); NibblVaultFactory.sol::149 => require(feeAdminUpdateTime != 0 && block.timestamp >= feeAdminUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed"); NibblVaultFactory.sol::166 => require(vaultUpdateTime != 0 && block.timestamp >= vaultUpdateTime, "NibblVaultFactory: UPDATE_TIME has not passed");
Shorten the revert strings to fit in 32 bytes, or use custom errors if >0.8.4.
Custom errors from Solidity 0.8.4 are cheaper than revert strings (cheaper deployment cost and runtime cost when the revert condition is met)
Use custom errors instead of revert strings.
c4udit, manual, slither
#0 - mundhrakeshav
2022-06-26T17:09:51Z
#2, #3, #6, #7, #8, #9, #15