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: 76/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
uints are 0
by default.removeing this will reduce contract size and save a bit of gas.WardenPledge.sol:547: for(uint256 i = 0; i < length;){
.length
in loopsReading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration.
WardenPledge.sol:154: return pledges.length; WardenPledge.sol:542: uint256 length = tokens.length; WardenPledge.sol:545: if(length != minRewardsPerSecond.length) revert Errors.InequalArraySizes();
!= 0
instead of > 0
WardenPledge.sol:471: if(remainingAmount > 0) { WardenPledge.sol:504: if(remainingAmount > 0) {
<x> += <y>
costs more gas than <x> = <x> + <y>
WardenPledge.sol:268: pledgeAvailableRewardAmounts[pledgeId] -= rewardAmount; WardenPledge.sol:340: pledgeAvailableRewardAmounts[vars.newPledgeID] += vars.totalRewardAmount; WardenPledge.sol:401: pledgeAvailableRewardAmounts[pledgeId] += totalRewardAmount; WardenPledge.sol:445: pledgeAvailableRewardAmounts[pledgeId] += totalRewardAmount;
WardenPledge.sol:227: Pledge memory pledgeParams = pledges[pledgeId]; WardenPledge.sol:318: CreatePledgeVars memory vars;
public
functions not called by the contract should be declared external
insteadWardenPledge.sol:153: function pledgesIndex() public view returns(uint256){
variable == false|0
-> !variable
or variable == true
-> variable
WardenPledge.sol:224: if(amount == 0) revert Errors.NullValue(); WardenPledge.sol:233: if(endTimestamp == 0) endTimestamp = pledgeParams.endTimestamp; WardenPledge.sol:312: if(minAmountRewardToken[rewardToken] == 0) revert Errors.TokenNotWhitelisted(); WardenPledge.sol:315: if(endTimestamp == 0) revert Errors.NullEndTimestamp(); WardenPledge.sol:381: if(newEndTimestamp == 0) revert Errors.NullEndTimestamp(); WardenPledge.sol:528: if(minRewardPerSecond == 0) revert Errors.NullValue(); WardenPledge.sol:544: if(length == 0) revert Errors.EmptyArray(); WardenPledge.sol:572: if(minAmountRewardToken[token] == 0) revert Errors.NotAllowedToken(); WardenPledge.sol:573: if(minRewardPerSecond == 0) revert Errors.InvalidValue(); WardenPledge.sol:587: if(minAmountRewardToken[token] == 0) revert Errors.NotAllowedToken(); WardenPledge.sol:613: if(newMinTargetVotes == 0) revert Errors.InvalidValue(); WardenPledge.sol:657: if(amount == 0) revert Errors.NullValue();
>=
COSTS LESS GAS THAN >
The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas https://gist.github.com/IllIllI000/3dc79d25acccfa16dee4e83ffdc6ffde
WardenPledge.sol:207: if(percent > MAX_PCT) revert Errors.PercentOverMax(); WardenPledge.sol:234: if(endTimestamp > pledgeParams.endTimestamp || endTimestamp != _getRoundedTimestamp(endTimestamp)) revert Errors.InvalidEndTimestamp(); WardenPledge.sol:245: if(delegationBoost.adjusted_balance_of(pledgeParams.receiver) + amount > pledgeParams.targetVotes) revert Errors.TargetVotesOverflow(); WardenPledge.sol:267: if(rewardAmount > pledgeAvailableRewardAmounts[pledgeId]) revert Errors.RewardsBalanceTooLow(); WardenPledge.sol:329: if(vars.totalRewardAmount > maxTotalRewardAmount) revert Errors.IncorrectMaxTotalRewardAmount(); WardenPledge.sol:330: if(vars.feeAmount > maxFeeAmount) revert Errors.IncorrectMaxFeeAmount(); WardenPledge.sol:389: if(totalRewardAmount > maxTotalRewardAmount) revert Errors.IncorrectMaxTotalRewardAmount(); WardenPledge.sol:390: if(feeAmount > maxFeeAmount) revert Errors.IncorrectMaxFeeAmount(); WardenPledge.sol:434: if(totalRewardAmount > maxTotalRewardAmount) revert Errors.IncorrectMaxTotalRewardAmount(); WardenPledge.sol:435: if(feeAmount > maxFeeAmount) revert Errors.IncorrectMaxFeeAmount(); WardenPledge.sol:463: if(pledgeParams.endTimestamp > block.timestamp) revert Errors.PledgeNotExpired(); WardenPledge.sol:471: if(remainingAmount > 0) { WardenPledge.sol:504: if(remainingAmount > 0) { WardenPledge.sol:626: if(newFee > 500) revert Errors.InvalidValue(); WardenPledge.sol:666: if(n > type(uint64).max) revert Errors.NumberExceed64Bits();
private
for constants
WardenPledge.sol:22: uint256 public constant UNIT = 1e18; WardenPledge.sol:23: uint256 public constant MAX_PCT = 10000; WardenPledge.sol:24: uint256 public constant WEEK = 7 * 86400;
address
to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.
WardenPledge.sol:52: mapping(address => uint256[]) public ownerPledges; WardenPledge.sol:67: mapping(address => uint256) public minAmountRewardToken;
#0 - c4-judge
2022-11-12T00:21:25Z
kirk-baird marked the issue as grade-b