Platform: Code4rena
Start Date: 23/05/2022
Pot Size: $75,000 USDC
Total HM: 23
Participants: 75
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 13
Id: 130
League: ETH
Rank: 63/75
Findings: 1
Award: $52.50
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0xNazgul, 0xf15ers, 0xkatana, Chom, ControlCplusControlV, DavidGialdi, Deivitto, Dravee, ElKu, Fitraldys, Funen, GimelSec, MadWookie, MaratCerby, MiloTruck, Picodes, Randyyy, TerrierLover, TomJ, Tomio, UnusualTurtle, WatchPug, Waze, _Adam, asutorufos, c3phas, catchup, csanuragjain, delfin454000, djxploit, fatherOfBlocks, gzeon, hake, hansfriese, horsefacts, orion, oyc_109, pauliax, reassor, rfa, rotcivegaf, sach1r0, saian, sashik_eth, simon135, supernova, teddav, z3s
52.5042 USDC - $52.50
All calculations for gas saved came from
forge test --gas-report
isForPair = _isForPair; if (isForPair) { (address _token0, address _token1) = IPair(stake).tokens(); IBribe(bribe).addRewardToken(_token0); isReward[_token0] = true; rewards.push(_token0); IBribe(bribe).addRewardToken(_token1); isReward[_token1] = true; rewards.push(_token1); }
Only set isForpair in the if statement. The default value for bools are false so if _isForPair is false gas is being wasted.
I suggest changing it to the code below, which saves 2,245 gas on deployment.
if (_isForPair) { (address _token0, address _token1) = IPair(stake).tokens(); IBribe(bribe).addRewardToken(_token0); isReward[_token0] = true; rewards.push(_token0); IBribe(bribe).addRewardToken(_token1); isReward[_token1] = true; rewards.push(_token1); isForPair = _isForPair; }
function notifyRewardAmount(address token, uint amount) external lock { require(amount > 0); if (!isReward[token]) { require(rewards.length < MAX_REWARD_TOKENS, "too many rewards tokens"); } // bribes kick in at the start of next bribe period uint adjustedTstamp = getEpochStart(block.timestamp); uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp]; _safeTransferFrom(token, msg.sender, address(this), amount); tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; if (!isReward[token]) { isReward[token] = true; rewards.push(token); IGauge(gauge).addBribeRewardToken(token); } emit NotifyReward(msg.sender, token, adjustedTstamp, amount); }
isReward[token] is used twice and can be cached in memory to save gas. The below implementation saves 149 gas per function call and 2,607 on deployment.
function notifyRewardAmount(address token, uint amount) external lock { require(amount > 0); bool _isReward = isReward[token]; if (!_isReward) { require(rewards.length < MAX_REWARD_TOKENS, "too many rewards tokens"); } // bribes kick in at the start of next bribe period uint adjustedTstamp = getEpochStart(block.timestamp); uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp]; _safeTransferFrom(token, msg.sender, address(this), amount); tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; if (!_isReward) { isReward[token] = true; rewards.push(token); IGauge(gauge).addBribeRewardToken(token); } emit NotifyReward(msg.sender, token, adjustedTstamp, amount); }
totalWeight -= uint256(_totalWeight);
totalWeight should never underflow here. Changing to the code below saves 74 gas.
unchecked { totalWeight -= uint256(_totalWeight); }
For loops can be made cheaper by using unchecked arithmetic when increasing the incrementor. In my opinion since this code base has a great deal of for-loops it would be a large benefit even if readability is reduced a little. At the very minimum i++ should be changed to ++i.
An example from Gauge.sol File: Gauge.sol#179-185
for (uint i = 0; i < numRewards; i++) { address token = sb.rewards(i); uint epochRewards = sb.deliverReward(token, bribeStart); if (epochRewards > 0) { _notifyBribeAmount(token, epochRewards, bribeStart); } }
Can be changed to
for (uint i = 0; i < numRewards;) { address token = sb.rewards(i); uint epochRewards = sb.deliverReward(token, bribeStart); if (epochRewards > 0) { _notifyBribeAmount(token, epochRewards, bribeStart); } unchecked{ ++i; //++i is cheaper than i++ } }
Instances where this can be implented
#0 - GalloDaSballo
2022-06-30T00:51:20Z
Will give 100 gas for not using a SLOAD
149, amazing report and work!
79 per the math shown (80 is avg for unchecked, seems about right)
25 per instance * 22 = 550
Great little report with actual gas estimates, good job!
Would highly recommend hunting for more immutable
and SLOAD
related savings which will help you score tons of savings with minimal report length
Total Gas Saved 878