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: 85/96
Findings: 1
Award: $28.28
🌟 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.2795 USDC - $28.28
_totalSupply
shadowedThere are multiple usages of _totalSupply
that shadow the inherited ERC20Upgradeable variable _totalSupply
Change the length variable to a local variable and increment the index on the end of the for loop statement inside an unchecked block.
For example:
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 withdrawMultipleERC20(address[] memory _tokens) external override { require(_isApprovedOrOwner(msg.sender, 0), "withdraw:not allowed"); uint256 tokensLength = _tokens.length for (uint256 i = 0; i < tokensLength ; ) { IERC20(_tokens[i]).transfer(msg.sender, IERC20(_tokens[i]).balanceOf(address(this))); emit WithdrawERC20(_tokens[i], msg.sender); unchecked { ++i; } } }
The multiple usages of uint32(block.timestamp % 2**32)
doesn't seem needed , because solidity already deals with the overflow case, this has been described on this uniswapV2-core issue by moodysalem, https://github.com/Uniswap/v2-core/issues/96.
A more in depth explanation :
4294967296
when hex representation is 0xffffffff + 1
which is 84 years from now.On the NibblVaultFactoryData
on line 6 uint256 public UPDATE_TIME = 2 days;
is missing the constant keyword.
Some variables in NibblVault
and NibblVaultFactoryData
can be converted to smaller integer values (e.g.: uint32
instead of uint256
) with no risk of overflow.
This in turn opens the possibility of more tighly packing them together for more gas-efficient storage (e.g.: by packing and address
with 3 uint32
, we can use a single 256-bit slot instead of 4).
Relevant examples:
NibbVaultData.feeAdmin
can likely be a uint32
since it represents a percentageNibbVaultData.pendingFeeAdmin
can likely be a uint32
since it represents a percentageNibblVaultData.feeAdminUpdateTime
can be a uint32
as it represents a timestampNibblVaultData.basketUpdateTime
can be a uint32
as it represents a timestampNibblVaultData.vaultUpdateTime
can be a uint32
as it represents a timestampNibblVault.buyoutEndTime
can be a uint32
as it represents a timestampNibblVault.minBuyoutTime
can be a uint32
as it represents a timestampNibblVault.minBuyoutTime
can be a uint32
as it represents a timestamp
timestampNibblVault.unlocked
can be a uint8
as it represents a non-zero boolean#0 - HardlyDifficult
2022-07-03T23:46:43Z
#1 - HardlyDifficult
2022-07-03T23:50:46Z
#2 - HardlyDifficult
2022-07-04T18:18:23Z
Mostly a gas report which should have been submitted separately.
Merged reports incl good suggestions.