Platform: Code4rena
Start Date: 14/09/2022
Pot Size: $50,000 USDC
Total HM: 25
Participants: 110
Period: 5 days
Judge: hickuphh3
Total Solo HM: 9
Id: 162
League: ETH
Rank: 94/110
Findings: 1
Award: $16.18
π Selected for report: 0
π Solo Findings: 0
π Selected for report: pfapostol
Also found by: 0x040, 0x1f8b, 0x4non, 0xNazgul, 0xSmartContract, 0xc0ffEE, 0xkatana, Aymen0909, Bnke0x0, Deivitto, Diana, JAGADESH, KIntern_NA, Lambda, MiloTruck, R2, RaymondFam, Respx, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, Ruhum, Saintcode_, Samatak, Sm4rty, SnowMan, Tomio, Tomo, WilliamAmbrozic, _Adam, __141345__, ajtra, ak1, async, c3phas, ch0bu, cryptostellar5, d3e4, delfin454000, dharma09, djxploit, durianSausage, eierina, erictee, fatherOfBlocks, gianganhnguyen, gogo, ignacio, imare, jag, jonatascm, leosathya, lukris02, malinariy, oyc_109, pashov, pauliax, peanuts, peiw, prasantgupta52, robee, rokinot, rotcivegaf, rvierdiiev, seyni, simon135, slowmoses, sryysryy, tnevler, zishansami
16.1756 USDC - $16.18
Require
revert string is too longThe revert strings below can be shortened to 32 characters or fewer (as shown) to save gas (or else consider using custom error codes, which could save even more gas)
require(_oracle1 != address(0), "oracle1 cannot be the zero address");
Change message to oracle1 cannot be the 0 address
require(_oracle2 != address(0), "oracle2 cannot be the zero address");
Change message to oracle2 cannot be the 0 address
require( tokenAddress != address(stakingToken), "Cannot withdraw the staking token" );
Change message to Cannot withdraw staking token
The revert strings below are also longer than 32 characters but it's not clear how to shorten them:
SemiFungibleVault.sol: L116-119
require( msg.sender == owner || isApprovedForAll(owner, receiver), "Only owner can withdraw, or owner has approved receiver for all" );
require( block.timestamp > periodFinish, "Previous rewards period must be complete before changing the duration for the new period" );
!= 0
instead of > 0
in a require
statement if variable is an unsigned integer (uint
)!= 0
should be used where possible since > 0
costs more gas
require(msg.value > 0, "ZeroValue");
Change to require(msg.value != 0, "ZeroValue");
require(amount > 0, "Cannot withdraw 0");
Change to require(amount != 0, "Cannot withdraw 0");
Initializing uint
variables to their default value of 0
is unnecessary and costs gas
uint256 public periodFinish = 0;
Change to uint256 public periodFinish;
++i
instead of i++
to increase count in a for
loopSince use of i++
(or equivalent counter) costs more gas, it is better to use ++i
for (uint256 i = 0; i < epochsLength(); i++) { if (epochs[i] == _epoch) { if (i == epochsLength() - 1) { return 0; } return epochs[i + 1]; } }
Suggestion:
for (uint256 i = 0; i < epochsLength(); ++i) { if (epochs[i] == _epoch) { if (i == epochsLength() - 1) { return 0; } return epochs[i + 1]; } }
for
loopUnderflow/overflow checks are made every time ++i
(or equivalent counter) is called. Such checks are unnecessary since i
is already limited. Therefore, use unchecked {++i}
instead
for (uint256 i = 0; i < epochsLength(); i++) { if (epochs[i] == _epoch) { if (i == epochsLength() - 1) { return 0; } return epochs[i + 1]; } }
Suggestion:
for (uint256 i = 0; i < epochsLength();) { if (epochs[i] == _epoch) { if (i == epochsLength() - 1) { return 0; } return epochs[i + 1]; unchecked { ++i; } } }
It costs less gas to inline the code of functions that are only called once. Doing so saves the cost of allocating the function selector, and the cost of the jump when the function is called.
modifier epochHasNotStarted(uint256 id) { if(block.timestamp > idEpochBegin[id] - timewindow) revert EpochAlreadyStarted(); _; }
Since epochHasNotStarted()
is used only once in this contract (in function deposit()
) as shown below, it should be inlined to save gas
function deposit( uint256 id, uint256 assets, address receiver ) public override marketExists(id) epochHasNotStarted(id) nonReentrant returns (uint256 shares)
modifier epochHasEnded(uint256 id) { if((block.timestamp < id) && idDepegged[id] == false) revert EpochNotFinished(); _; }
Since epochHasEnded()
is used only once in this contract (in function withdraw()
) as shown below, it should be inlined to save gas
function withdraw( uint256 id, uint256 assets, address receiver, address owner ) external override epochHasEnded(id) marketExists(id) returns (uint256 shares)