Platform: Code4rena
Start Date: 26/05/2022
Pot Size: $75,000 USDT
Total HM: 31
Participants: 71
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 18
Id: 126
League: ETH
Rank: 17/71
Findings: 3
Award: $1,142.75
๐ Selected for report: 0
๐ Solo Findings: 0
937.187 USDT - $937.19
Judge has assessed an item in Issue #268 as Medium risk. The relevant finding follows:
The protocol does not support fee on transfer and other weird tokens, e.g.:
IERC20(_rewardToken).safeTransferFrom(msg.sender, address(this), _amount); rewardTokenInfo[_rewardToken].queuedRewards += _amount;
#0 - JeeberC4
2022-07-28T20:05:29Z
Duplicate of #190
๐ Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xf15ers, BouSalman, Chom, Deivitto, Dravee, ElKu, FSchmoede, Funen, GimelSec, Hawkeye, MiloTruck, Picodes, SecureZeroX, SmartSek, TerrierLover, WatchPug, _Adam, asutorufos, berndartmueller, c3phas, catchup, cccz, cogitoergosumsw, cryptphi, csanuragjain, delfin454000, dipp, ellahi, gzeon, hansfriese, horsefacts, hyh, kirk-baird, minhquanym, oyc_109, pauliax, reassor, robee, sashik_eth, shenwilly, simon135, sorrynotsorry, sseefried, unforgiven, xiaoming90, z3s
153.4868 USDT - $153.49
pragma solidity 0.8.7; using SafeMath for uint256;
Now it basically performs safe math operations twice, thus wasting gas.
function createLock(uint256, uint256) external; function createLock(uint256 _value, uint256 _unlockTime) external returns (bool)
The interface does not declare the return value, while the implementation returns a boolean indicating success. Better always explicitly implement an interface to force compile-time enforcements.
setOwner could be a 2-step (propose-accept) process to avoid accidental errors.
In VoterProxy when an operator deposits a new token, it is added to the list of protectedTokens. This token is never set back to false again. Consider setting protectedTokens to false in operator withdrawal functions (withdraw, withdrawAll) when the balance after becomes 0. Then tokens might be reclaimed if the operator has withdrawn all of them, and later someone accidentally sends them directly to the contract or something like that.
You can make event parameters 'indexed' to allow for filtering, e.g. hash in VoteSet:
event VoteSet(bytes32 hash, bool valid);
function voteGaugeWeight could validate that the lengths of _tokenVote
and _weight
are equal.
You can use built-in time keywords, e.g. here:
uint256 private constant WEEK = 7 * 86400; uint256 private constant WEEK = 7 weeks;
safeApprove is deprecated, see: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol#L39-L44
The protocol does not support fee on transfer and other weird tokens, e.g.:
IERC20(_rewardToken).safeTransferFrom(msg.sender, address(this), _amount); rewardTokenInfo[_rewardToken].queuedRewards += _amount;
or
//add supply _totalSupply = _totalSupply.add(_amount); //add to _for's balance sheet _balances[_for] = _balances[_for].add(_amount); //take tokens from sender stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
Make sure that your users are informed about that, or consider validating the balance before/after to know the real amount transferred.
//calc the amount of veAssetEarned uint256 _veAssetEarned = _amount.mul(veTokenMinter.veAssetWeights(address(this))).div( veTokenMinter.totalWeight() );
veToken.safeTransfer(_to, _amount); totalSupply += _amount;
There are many more functions that do the external interactions and are not protected. Consider adding ReentrancyGuard to all the main user interacting functions.
#0 - GalloDaSballo
2022-07-08T00:37:16Z
Valid Refactor
Valid Refactor
##ย setOwner could be a 2-step (propose-accept) process to avoid accidental errors. NC
I must disagree in lack of further details over this refactoring, removing protectedTokens
is a rug vector
For this event, valid NC
Valid R (reverts on failure)
Valid R
Valid NC for this codebase
Valid Low (may bump based on other findings)
Valid Low
Valid Low (may bump based on other findings)
Good report, short and sweet, would benefit by having better formatted headlines (the dotted list looks odd as you can see above)
#1 - GalloDaSballo
2022-07-08T00:38:06Z
3L 4R 3NC
#2 - GalloDaSballo
2022-07-28T17:32:05Z
TODO - Raise:
The protocol does not support fee on transfer and other weird tokens, e.g.: - > M-25
New Score: 2L 4R 3NC
๐ Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, Cityscape, Dravee, ElKu, FSchmoede, Funen, GalloDaSballo, Hawkeye, Kaiziron, MiloTruck, Randyyy, RoiEvenHaim, Ruhum, SecureZeroX, SmartSek, TerrierLover, TomJ, Tomio, WatchPug, Waze, _Adam, asutorufos, c3phas, catchup, cogitoergosumsw, delfin454000, ellahi, fatherOfBlocks, gzeon, hansfriese, horsefacts, jonatascm, minhquanym, oyc_109, pauliax, reassor, robee, sach1r0, saian, sashik_eth, simon135, z3s
52.0655 USDT - $52.07
function setFees(uint256 _lockIncentive) ... if (_lockIncentive >= 0 && _lockIncentive <= 30)
if (_balance < _amount) { _amount = _withdrawSome(_gauge, _amount.sub(_balance));
function withdraw(IERC20 _asset) external returns (uint256 balance) { ... return balance;
uint256 public periodFinish = 0; uint256 public rewardRate = 0; uint256 public queuedRewards = 0; uint256 public currentRewards = 0; uint256 public historicalRewards = 0;
uint256 veAssetBalance = IERC20(veAsset).balanceOf(address(this)); if (veAssetBalance > 0) { IERC20(veAsset).safeTransfer(staker, veAssetBalance); } //increase ammount uint256 veAssetBalanceStaker = IERC20(veAsset).balanceOf(staker);
#0 - GalloDaSballo
2022-07-18T23:23:18Z
##ย No need for safe math where overflow/underflow is impossible, e.g.: Saves 20 gas
Saves 97 + 94 gas
Saves less than 500 gas