Platform: Code4rena
Start Date: 27/10/2022
Pot Size: $33,500 USDC
Total HM: 8
Participants: 96
Period: 3 days
Judge: kirk-baird
Total Solo HM: 1
Id: 176
League: ETH
Rank: 92/96
Findings: 1
Award: $11.52
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: c3phas
Also found by: 0x1f8b, 0xNazgul, 0xRoxas, 0xSmartContract, 0xbepresent, Amithuddar, Awesome, B2, Bnke0x0, Dravee, KoKo, Mathieu, Picodes, RaymondFam, RedOneN, ReyAdmirado, RockingMiles, Ruhum, SadBase, SooYa, Waze, __141345__, adriro, ajtra, ballx, carlitox477, ch0bu, cylzxje, djxploit, durianSausage, emrekocak, erictee, gogo, halden, horsefacts, imare, indijanc, karanctf, leosathya, lukris02, neko_nyaa, oyc_109, peiw, sakman, shark, skyle, tnevler
11.5153 USDC - $11.52
The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 1 instances of this issue:
File: contracts/WardenPledge.sol /// @audit Cache `delegationBoost`. Used 5 times in `_pledge` 240: delegationBoost.checkpoint_user(user); 241: if(delegationBoost.allowance(user, address(this)) < amount) revert Errors.InsufficientAllowance(); 242: if(delegationBoost.delegable_balance(user) < amount) revert Errors.CannotDelegate(); 245: if(delegationBoost.adjusted_balance_of(pledgeParams.receiver) + amount > pledgeParams.targetVotes) revert Errors.TargetVotesOverflow(); 248: delegationBoost.boost(
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
payable
Marking a function as payable
reduces gas cost since the compiler does not have to check whether a payment was provided or not. This change will save around 21 gas per function call.
There are 10 instances of this issue:
File: contracts/WardenPledge.sol 541: function addMultipleRewardToken(address[] calldata tokens, uint256[] calldata minRewardsPerSecond) external onlyOwner { 560: function addRewardToken(address token, uint256 minRewardPerSecond) external onlyOwner { 570: function updateRewardToken(address token, uint256 minRewardPerSecond) external onlyOwner { 585: function removeRewardToken(address token) external onlyOwner { 599: function updateChest(address chest) external onlyOwner { 612: function updateMinTargetVotes(uint256 newMinTargetVotes) external onlyOwner { 625: function updatePlatformFee(uint256 newFee) external onlyOwner { 636: function pause() external onlyOwner { 643: function unpause() external onlyOwner { 653: function recoverERC20(address token) external onlyOwner returns(bool) {
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
++i
/i++
should be unchecked{++I}
/unchecked{I++}
in for
-loopsWhen an increment or any arithmetic operation is not possible to overflow it should be placed in unchecked{}
block. \This is because of the default compiler overflow and underflow safety checks since Solidity version 0.8.0. \In for-loops it saves around 30-40 gas per loop
There are 1 instances of this issue:
File: contracts/WardenPledge.sol 550: unchecked{ ++i; }
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 4 instances of this issue:
File: contracts/WardenPledge.sol 268: pledgeAvailableRewardAmounts[pledgeId] -= rewardAmount; 340: pledgeAvailableRewardAmounts[vars.newPledgeID] += vars.totalRewardAmount; 401: pledgeAvailableRewardAmounts[pledgeId] += totalRewardAmount; 445: pledgeAvailableRewardAmounts[pledgeId] += totalRewardAmount;
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
uint
s/int
s smaller than 32 bytes (256 bits) incurs overhead'When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.' \ https://docs.soliditylang.org/en/v0.8.15/internals/layout_in_storage.html \ Use a larger size then downcast where needed
There are 1 instances of this issue:
File: contracts/WardenPledge.sol 41: uint64 endTimestamp;
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM, there is no opcode for >=
or <=
. When using greater than or equal, two operations are performed: >
and =
. Using strict comparison operators hence saves gas
There are 10 instances of this issue:
File: contracts/WardenPledge.sol 223: if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); 229: if(pledgeParams.endTimestamp <= block.timestamp) revert Errors.ExpiredPledge(); 374: if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); 380: if(pledgeParams.endTimestamp <= block.timestamp) revert Errors.ExpiredPledge(); 420: if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); 426: if(pledgeParams.endTimestamp <= block.timestamp) revert Errors.ExpiredPledge(); 429: if(newRewardPerVote <= oldRewardPerVote) revert Errors.RewardsPerVotesTooLow(); 457: if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); 489: if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); 496: if(pledgeParams.endTimestamp <= block.timestamp) revert Errors.ExpiredPledge();
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
immutable
& constant
for state variables that do not change their valueThere are 2 instances of this issue:
File: contracts/WardenPledge.sol 60: IVotingEscrow public votingEscrow; 62: IBoostV2 public delegationBoost;
https://github.com/code-423n4/2022-10-paladin/tree/main/contracts/WardenPledge.sol
#0 - c4-judge
2022-11-12T00:54:39Z
kirk-baird marked the issue as grade-b