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: 30/96
Findings: 2
Award: $143.48
🌟 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
It allows to set votingEscrow
, delegationBoost
and chestAddress
to address zero.
Impact:
votingEscrow
to address zero will leave pledgePercent and createPledge unusable.delegationBoost
to address zero will leave _pledge unusable. This will provoke functions pledge and pledgePercent to become unusable too.This function just returns pledges.length
. This is simple to do inside the contract, calling this function inside the contract is more expensive than just calling pledges.length
.
Mitigation steps: replace every occurency of pledgesIndex()
for pledges.length
; and change pledgesIndex()
visibility to external
If minAmountRewardToken[token] == minRewardPerSecond
then the minAmountRewardToken[token]
would not really be updated, leading to a wrong UpdateRewardToken
event emission.
Mitigation steps: Check that minAmountRewardToken[token] != minRewardPerSecond
If chestAddress == chest
then the chestAddress
would not really be updated, leading to a wrong ChestUpdated
event emission
Mitigation steps: Check that chestAddress != chest
If minTargetVotes == newMinTargetVotes
then the minTargetVotes
would not really be updated, leading to a wrong MinTargetUpdated
event emission
Mitigation steps: Check that minTargetVotes != newMinTargetVotes
If protocalFeeRatio == newFee
then the protocalFeeRatio
would not really be updated, leading to a wrong PlatformFeeUpdated
event emission
Mitigation steps: Check that protocalFeeRatio != newFee
#0 - c4-judge
2022-11-12T00:26:52Z
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
123.8403 USDC - $123.84
It is not modifed anywhere
The amount check do just one comparison and no function call, so amount == 0
is cheaper than pledgeId >= pledgesIndex()
. Replace these line for:
if(amount == 0) revert Errors.NullValue(); if(pledgeId >= pledgesIndex()) revert Errors.InvalidPledgeID();
Calling pledgesIndex()
is more expensive than just calling pledges.length
. Replace this line for
if(pledgeId >= pledges.length) revert Errors.InvalidPledgeID();
This state variable is used multiple times, it can be cached in order to save gas.
_pledgeAvailableRewardAmounts = pledgeAvailableRewardAmounts[pledgeId] if(rewardAmount > _pledgeAvailableRewardAmounts) revert Errors.RewardsBalanceTooLow(); pledgeAvailableRewardAmounts[pledgeId] = _pledgeAvailableRewardAmounts - rewardAmount;
This state variable is used multiple times, it can be cached in order to save gas.
// vars.newPledgeID = pledgesIndex(); //before vars.newPledgeID = plendge.length();
This state variable is accessed two times, it can be cached in order to save gas.
if(receiver == address(0) || rewardToken == address(0)) revert Errors.ZeroAddress(); if(targetVotes < minTargetVotes) revert Errors.TargetVoteUnderMin(); uint256 _minAmountRewardToken = minAmountRewardToken[rewardToken]; if(_minAmountRewardToken == 0) revert Errors.TokenNotWhitelisted(); if(rewardPerVote < _minAmountRewardToken) revert Errors.RewardPerVoteTooLow();
Calling pledgesIndex()
is more expensive than just calling pledges.length
. Replace this line for
if(pledgeId >= pledges.length) revert Errors.InvalidPledgeID();
Replace these lines for:
address _rewardToken = pledgeParams.rewardToken // Pull all the rewards in this contract IERC20(_rewardToken).safeTransferFrom(creator, address(this), totalRewardAmount); // And transfer the fees from the Pledge creator to the Chest contract IERC20(_rewardToken).safeTransferFrom(creator, chestAddress, feeAmount);
Calling pledgesIndex()
is more expensive than just calling pledges.length
. Replace this line for
if(pledgeId >= pledges.length) revert Errors.InvalidPledgeID();
Replace these lines for:
address _rewardToken = pledgeParams.rewardToken // Pull all the rewards in this contract IERC20(_rewardToken).safeTransferFrom(creator, address(this), totalRewardAmount); // And transfer the fees from the Pledge creator to the Chest contract IERC20(_rewardToken).safeTransferFrom(creator, chestAddress, feeAmount);
Calling pledgesIndex()
is more expensive than just calling pledges.length
. Replace this line for
if(pledgeId >= pledges.length) revert Errors.InvalidPledgeID();
Calling pledgesIndex()
is more expensive than just calling pledges.length
. Replace this line for
if(pledgeId >= pledges.length) revert Errors.InvalidPledgeID();
Given that newRewardPerVote <= oldRewardPerVote
was previously check, it is impossible for newRewardPerVote - oldRewardPerVote
to underflow. Replace this line for
unchecked{ uint256 rewardPerVoteDiff = newRewardPerVote - oldRewardPerVote; }
Given that pledgeParams.endTimestamp <= block.timestamp
was previously check, it is impossible for pledgeParams.endTimestamp - block.timestamp
to underflow. Replace this line for
unchecked{ uint256 remainingDuration = pledgeParams.endTimestamp - block.timestamp; }
Given that this amount was previously transfered, if this transfer was successful we can assure that it won't be an overflow, replace this line for:
unchecked{ pledgeAvailableRewardAmounts[pledgeId] += totalRewardAmount; }
Possible underflow was previously checked. Replace this line for
unchecked{ uint256 addedDuration = newEndTimestamp - oldEndTimestamp; }
Given that this amount was previously transfered, if this transfer was successful we can assure that it won't be an overflow, replace this line for:
unchecked{ pledgeAvailableRewardAmounts[pledgeId] += totalRewardAmount; }
Given that this amount was previously transfered, if this transfer was succesful we can assure that it won't be an overflow, replace this line for:
unchecked{ pledgeAvailableRewardAmounts[vars.newPledgeID] += vars.totalRewardAmount; }
Given that this amount was previously checked, we can assure that it won't be an underflow, replace this line for:
unchecked{ pledgeAvailableRewardAmounts[pledgeId] -= rewardAmount; }
#0 - c4-judge
2022-11-12T00:26:37Z
kirk-baird marked the issue as grade-b
#1 - c4-judge
2022-11-12T01:20:15Z
kirk-baird marked the issue as grade-a