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: 25/96
Findings: 2
Award: $190.55
🌟 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/main/contracts/WardenPledge.sol#L653-L654
Potential Rug Vector via recoverERC20
There is a function called recoverERC20()
which initially created to "Recover ERC20 tokens sent by mistake to the contract". To make it trustable, the function need to check if minAmountRewardToken[token] != 0
so that any active
or whitelisted
tokens will not affected with this function.
But, if this recoverERC20()
function is called after removeRewardToken()
being called for the same token, then the rug vector is clearly visible.
Manual analysis
If the intention of recoverERC20()
function is to recover token sent by mistake, then we need to check if the token is already have a pledge active or not. If it's really a mistake
then normally there is no pledge for that token. If there's a pledge active for that token, surely we need to make sure the creator (other user) need to withdraw their token first.
#0 - Kogaroshi
2022-10-30T23:43:31Z
Duplicate of #17
#1 - c4-judge
2022-11-10T07:12:35Z
kirk-baird marked the issue as not a duplicate
#2 - c4-judge
2022-11-10T07:12:42Z
kirk-baird marked the issue as duplicate
#3 - c4-judge
2022-11-10T21:22:36Z
kirk-baird marked the issue as satisfactory
#4 - c4-judge
2022-11-10T21:22:40Z
kirk-baird marked the issue as not a duplicate
#5 - c4-judge
2022-11-10T21:22:47Z
kirk-baird marked the issue as duplicate of #17
#6 - 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
180.6401 USDC - $180.64
in _pledge()
internal function, the amount
value is only check if it's not 0, but not being checked to at least to make the slope > 0 (in L:256), in other word if the amount is less than boostDuration
value, it will make the slope 0, when this slope is 0, the bias
, totalDelegatedAmount
, and rewardAmount
will also 0, thus waste of gas for transferring 0 token reward.
File: WardenPledge.sol 234: if(endTimestamp > pledgeParams.endTimestamp || endTimestamp != _getRoundedTimestamp(endTimestamp)) revert Errors.InvalidEndTimestamp(); 237: uint256 boostDuration = endTimestamp - block.timestamp; 256: uint256 slope = amount / boostDuration; 257: uint256 bias = slope * boostDuration; 263: uint256 totalDelegatedAmount = ((bias * boostDuration) + bias) / 2; 264: // Then we can calculate the total amount of rewards for this Boost 265: uint256 rewardAmount = (totalDelegatedAmount * pledgeParams.rewardPerVote) / UNIT; 266: 267: if(rewardAmount > pledgeAvailableRewardAmounts[pledgeId]) revert Errors.RewardsBalanceTooLow(); 268: pledgeAvailableRewardAmounts[pledgeId] -= rewardAmount; 269: 270: // Send the rewards to the user 271: IERC20(pledgeParams.rewardToken).safeTransfer(user, rewardAmount);
Protocol vs Protocal
File: WardenPledge.sol 70: /** @notice ratio of fees to pay the protocol (in BPS) */ 71: uint256 public protocalFeeRatio = 250; //bps 328: vars.feeAmount = (vars.totalRewardAmount * protocalFeeRatio) / MAX_PCT ; 388: uint256 feeAmount = (totalRewardAmount * protocalFeeRatio) / MAX_PCT ; 433: uint256 feeAmount = (totalRewardAmount * protocalFeeRatio) / MAX_PCT ; 627: uint256 oldfee = protocalFeeRatio; 628: protocalFeeRatio = newFee;
Events descriptions is not finished it will make the contract less prepared
/** @notice Event emitted when xx */
There are units for seconds, minutes, hours, days, and weeks
File: WardenPledge.sol 24: uint256 public constant WEEK = 7 * 86400;
Keep line width to max 120 characters for better readability.
#0 - c4-judge
2022-11-12T00:15:26Z
kirk-baird marked the issue as grade-a