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: 45/96
Findings: 2
Award: $31.16
š Selected for report: 0
š Solo Findings: 0
š Selected for report: robee
Also found by: 0x007, 0x1f8b, 0x52, 0xDjango, 0xNazgul, 0xSmartContract, 8olidity, Awesome, B2, Bnke0x0, Chom, Diana, Dravee, JTJabba, Jeiwan, Josiah, Lambda, Mathieu, Picodes, RaoulSchaffranek, RaymondFam, RedOneN, ReyAdmirado, Rolezn, Ruhum, Sm4rty, Tricko, Trust, Waze, __141345__, a12jmx, adriro, ajtra, brgltd, c3phas, carlitox477, cccz, ch0bu, chaduke, chrisdior4, corerouter, cryptonue, csanuragjain, ctf_sec, cylzxje, delfin454000, dic0de, djxploit, horsefacts, imare, jayphbee, jwood, ktg, ladboy233, leosathya, lukris02, minhtrng, neko_nyaa, oyc_109, pashov, peritoflores, rbserver, rvierdiiev, shark, tnevler, yixxas
19.6449 USDC - $19.64
There are 2 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L137-L140 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L
There should be require() that validate a perticular address is zero address or not
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L142
There should be upperbound or lowerbound check for minTargetVotes inside constructor
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L182
Multiple should occur before Divide like, (timestamp / WEEK) * WEEK; To (timestamp * WEEK) / WEEK;
This following code repeatedly used in multiple functions like in extendPledge(), increasePledgeRewardPerVote(), retrievePledgeRewards(), closePledge()
if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); address creator = pledgeOwner[pledgeId]; if(msg.sender != creator) revert Errors.NotPledgeCreator(); if(receiver == address(0)) revert Errors.ZeroAddress();
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L374-L378 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L420-L424 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L456-L462 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L488-L493
So i recommend there should be a private fuction that handle this verification of pledge part and return "Pledge storage pledgeParams" on success, and that private function call inside other external functions.
#0 - kirk-baird
2022-11-08T22:09:25Z
L-03: is invalid as it's a deliberate rounding technique. Remaining issues are valid but I consider them grade-b.
#1 - c4-judge
2022-11-08T22:09:28Z
kirk-baird marked the issue as grade-b
š 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
!= 0 costs less gas compared to > 0 for unsigned integers in require statements with the optimizer enabled (6 gas)
Proof: While it may seem that > 0 is cheaper than !=, this is only true without the optimizer enabled and outside a require statement. If you enable the optimizer at 10k AND youāre in a require statement, this will save gas. You can see this tweet for more proofs: https://twitter.com/gzeon/status/1485428085885640706
There are 2 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L471 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L504
I suggest changing > 0 with != 0 here:
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L79
<x> / 2 is the same as <x> >> 1. The DIV opcode costs 5 gas, whereas SHR only costs 3 gas
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L263
If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost
There are 9 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L560 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L570 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L585 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L599 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L612 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L625 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L636 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L643 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L653
If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for addressā¦). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
As an example: for (uint256 i = 0; i < numIterations; ++i) { should be replaced with for (uint256 i; i < numIterations; ++i) {
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L547
Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers. When an overflow or an underflow isnāt possible (as an example, when a comparison is made before the arithmetic operation), some gas can be saved by using an unchecked block: https://docs.soliditylang.org/en/v0.8.10/control-structures.html#checked-or-unchecked-arithmetic
Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L43 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L469 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L499
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from āfalseā to ātrueā, after having been ātrueā in the past
Due to how constant variables are implemented (replacements at compile-time), an expression assigned to a constant variable is recomputed each time that the variable is used, which wastes some gas.
If the variable was immutable instead: the calculation would only be done once at deploy time (in the constructor), and then the result would be saved and read directly at runtime rather than being recalculated.
Consequences: each usage of a āconstantā costs ~100gas more on each access (it is still a little better than storing the result in storage, but not much..). since these are not real constants, they canāt be referenced from a real constant environment (e.g. from assembly, or from another library )
There are 1 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L24
Change these expressions from constant to immutable and implement the calculation in the constructor or hardcode these values in the constants and add a comment to say how the value was calculated.
This following code repeatedly used in multiple functions like in extendPledge(), increasePledgeRewardPerVote(), retrievePledgeRewards(), closePledge()
if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID(); address creator = pledgeOwner[pledgeId]; if(msg.sender != creator) revert Errors.NotPledgeCreator(); if(receiver == address(0)) revert Errors.ZeroAddress();
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L374-L378 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L420-L424 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L456-L462 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L488-L493
So i recommend there should be a private fuction that handle this verification of pledge part and return "Pledge storage pledgeParams" on success, and that private function call inside other external functions.
There are 4 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L268 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L340 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L401 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L445
The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas
There are 13 instances of this issue:
** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L234 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L241 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L242 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L245 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L267 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L311 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L313 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L320 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L329 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L330 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L386 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L389 ** File : ** => https://github.com/code-423n4/2022-10-paladin/blob/main/contracts/WardenPledge.sol#L390
So its recommended to use >= whenever possible instead of >
#0 - kirk-baird
2022-11-08T22:15:20Z
The following issues are in the public C4 report G-01 G-03 G-05 G-07
#1 - c4-judge
2022-11-08T22:15:24Z
kirk-baird marked the issue as grade-b