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: 34/96
Findings: 3
Award: $41.07
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ladboy233
Also found by: 0x52, 0xDecorativePineapple, 0xhunter, Aymen0909, Bnke0x0, Dravee, JTJabba, Jeiwan, Lambda, Nyx, Picodes, Trust, cccz, cryptonue, csanuragjain, dic0de, hansfriese, horsefacts, imare, minhtrng, pashov, peritoflores, rbserver, rvierdiiev, wagmi, yixxas
9.9073 USDC - $9.91
https://github.com/code-423n4/2022-10-paladin/blob/d6d0c0e57ad80f15e9691086c9c7270d4ccfe0e6/contracts/WardenPledge.sol#L585 https://github.com/code-423n4/2022-10-paladin/blob/d6d0c0e57ad80f15e9691086c9c7270d4ccfe0e6/contracts/WardenPledge.sol#L654
The owner
of a WardenPledge
contract instance can recover stuck ERC20 token using recoverERC20
. recoverERC20
will revert in case a token is used as a reward token.
But if the owner prior of calling recoverERC20
calls removeRewardToken
he/she can take any ERC20 token out of the contract.
This is not good for investors. To give more trust to users these functions should be put behind a timelock.
Manual review
Add a timelock with an on-chain governance controlling the smart contract at least for recoverERC20
function.
#0 - trust1995
2022-10-30T21:05:26Z
Good find. Dup of #236 .
#1 - Kogaroshi
2022-10-31T00:27:34Z
Duplicate of #17
#2 - c4-judge
2022-11-10T07:10:25Z
kirk-baird marked the issue as not a duplicate
#3 - c4-judge
2022-11-10T07:10:31Z
kirk-baird marked the issue as duplicate
#4 - c4-judge
2022-11-10T21:20:19Z
kirk-baird marked the issue as satisfactory
#5 - c4-judge
2022-11-10T21:20:25Z
kirk-baird marked the issue as not a duplicate
#6 - c4-judge
2022-11-10T21:20:31Z
kirk-baird marked the issue as duplicate of #17
#7 - c4-judge
2022-12-06T17:32:42Z
Simon-Busch marked the issue as duplicate of #68
🌟 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
This function returns array of all Pledge
structures which is a fairly big structure.
I think this is a good case for using pagination. Something like this:
function getAllPledges(uint256 cursor, uint256 howMany) external view returns(Pledge[] memory values, uint256 newCursor) { uint256 length = howMany; if (length > pledges.length - cursor) { length = pledges.length - cursor; } values = new Pledge[](length); for (uint256 i; i < length; ) { values[i] = pledges[cursor + i]; unchecked{ ++i; } } return (values, cursor + length); }
WEEK
constant state variableSolidity provides some native units for dealing with time. The WEEK constant its only used in one place when calculating the rounded down timestamp.
Instead of using this :
uint256 public constant WEEK = 7 * 86400; function _getRoundedTimestamp(uint256 timestamp) view public returns(uint256) { return (timestamp / WEEK) * WEEK; }
You can use something like this:
function _getRoundedTimestamp(uint256 timestamp) view public returns(uint256) { return (timestamp / 1 weeks) * 1 weeks; }
The comment for this functions says that the function will : Retrieves all non distributed rewards from a closed Pledge
But the function
The only difference with closePledge
function is that the closePledge
will check if a Pledge is closed and revert in the case it is closed.
I don't think you need both functions because a user cannot pledge a closed Pledge so there is no point to having both. And also in closing the pledge with closePledge
you are also retrieving the rewards as in (as the name would suggest) retrievePledgeRewards
.
#0 - c4-judge
2022-11-12T00:39:45Z
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
If a 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 10 instances of this issue:
function addMultipleRewardToken(address[] calldata tokens, uint256[] calldata minRewardsPerSecond) external onlyOwner {
function addRewardToken(address token, uint256 minRewardPerSecond) external onlyOwner {
function updateRewardToken(address token, uint256 minRewardPerSecond) external onlyOwner {
function removeRewardToken(address token) external onlyOwner {
function updateChest(address chest) external onlyOwner {
function updateMinTargetVotes(uint256 newMinTargetVotes) external onlyOwner {
function updatePlatformFee(uint256 newFee) external onlyOwner {
function pause() external onlyOwner {
function unpause() external onlyOwner {
function recoverERC20(address token) external onlyOwner returns(bool) {
#0 - c4-judge
2022-11-12T00:39:25Z
kirk-baird marked the issue as grade-b