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: 39/96
Findings: 2
Award: $46.04
🌟 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.314 USDC - $28.31
Basket#withdrawERC20, Basket#Basket.withdrawMultipleERC20, NibblVault#withdrawERC20, NibblVault#Basket.withdrawMultipleERC20 all call IERC20 transfer method without checking for its return value (bool success). This is a problem because some ERC20 tokens do not revert on error but return “false” instead.
This can lead to some confusion on the ERC20 withdrawer side and to some wasted gas due to need to call withdraw methods again.
Always use SafeERC20.safeTransfer instead of ERC20.transfer so you handle ERC20 tokens that do not revert on error
Basket.sol line 80 sends ETH by using the low-level transfer call which is discouraged. Transfer can take up to a maximum of 2300 gas, which can lead to inability to withdraw the ether if the recipient is a smart contract with a receive function that uses more than 200 gas
This might lead to stuck ether for a user of the protocol. This might be a Medium risk finding.
Change “_to**.transfer**(address(this).balance);” to “_to**.call{value:** address(this).balance**}**("");”
(not putting Github links because they are ~10 here)
Externally provided function arguments for address parameters can mistakenly be set to the zero address
function parameters of type address that do not have a non-zero address check:
NibblVault#initialize - _assetAddress, _curator
NibblVault#updateCurator - _newCurator
NibblVaultFactory#constructor - _vaultImplementation, _feeTo, _basketImplementation
NibblVaultFactory#proposeNewBasketImplementation - _newBasketImplementation
NibblVaultFactory#proposeNewAdminFeeAddress - _newFeeAddress
NibblVaultFactory#proposeNewVaultImplementation - _newVaultImplementation
ProxyBasket#constructor - _implementation
ProxyVault#constructor - _factory
Mistakenly setting an address type field to the zero address can result in a need to send a new correct transaction (wasted gas) in the context of setter functions, and in a need for contract redeployment in the context of constructors or initialiser functions.
Add a require(_functionParam ! = address(0)) check for all places mentioned.
#0 - HardlyDifficult
2022-07-04T18:45:26Z
A few good 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.7282 USDC - $17.73
Using Solidity custom errors is gas efficient and can be helpful for external integrations’ error handling. Having a require statement with an error string is costly both for deployment cost for contract deployer and failed transaction cost for the user
This can save users a good amount of gas on failed transactions.
Replace all require statements in the code with a revert CustomError statements
All contract functions in NibblVaultFactory.sol that are declared as public can be declared as external.
Functions that are declared as external have their arguments in calldata instead of memory which saves gas for users
Change all public methods in NibblVaultFactory.sol to external
Basket.sol and NibblVault.sol contain for loops that are implemented inefficiently in terms of gas for the EVM. For example omitting assigning a default-zero type variable to zero, caching array's length, using ++i
instead of i++
can save a good chunk of gas, especially if the loop is long running.
Gas savings for protocol users
++i
instead of i++
in for loops (small gas saving)++i
in an unchecked block since you have a for loop end check expression anywayExample for loop implemented using the recommendations:
for (uint256 i = 0; i < _assets.length; i++) { uint256 balance = IERC1155(_assets[i]).balanceOf(address(this), _assetIDs[i]); IERC1155(_assets[i]).safeTransferFrom(address(this), _to, _assetIDs[i], balance, "0"); }
With recommended gas optimisations:
uint256 assetsLength = _assets.length; for (uint256 i; i < assetsLength;) { uint256 balance = IERC1155(_assets[i]).balanceOf(address(this), _assetIDs[i]); IERC1155(_assets[i]).safeTransferFrom(address(this), _to, _assetIDs[i], balance, "0"); unchecked { ++i; } }