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: 46/71
Findings: 2
Award: $152.57
π Selected for report: 0
π Solo Findings: 0
π 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
100.4975 USDT - $100.50
address(0)
when assigning values to address state variables.Setters of address type parameters should include a zero-address check otherwise contract functionality may become inaccessible or tokens burnt forever.
constructor( address _staker, address _minter, address _veAsset, address _escrow, uint256 _maxTime ) { staker = _staker; minter = _minter; veAsset = _veAsset; escrow = _escrow; feeManager = msg.sender; maxTime = _maxTime; }
function setFeeManager(address _feeManager) external { require(msg.sender == feeManager, "!auth"); feeManager = _feeManager; emit FeeManagerUpdated(_feeManager); }
constructor( address _staker, address _minter, address _veAsset, address _feeDistro ) { isShutdown = false; staker = _staker; owner = msg.sender; voteDelegate = msg.sender; feeManager = msg.sender; poolManager = msg.sender; minter = _minter; veAsset = _veAsset; feeDistro = _feeDistro; }
function setOwner(address _owner) external { require(msg.sender == owner, "!auth"); owner = _owner; emit OwnerUpdated(_owner); } function setFeeManager(address _feeM) external { require(msg.sender == feeManager, "!auth"); feeManager = _feeM; emit FeeManagerUpdated(_feeM); } function setPoolManager(address _poolM) external { require(msg.sender == poolManager, "!auth"); poolManager = _poolM; emit PoolManagerUpdated(_poolM); }
function setVoteDelegate(address _voteDelegate) external { require(msg.sender == voteDelegate, "!auth"); voteDelegate = _voteDelegate; emit VoteDelegateUpdated(_voteDelegate); }
function withdrawTo( uint256 _pid, uint256 _amount, address _to ) external returns (bool) { address rewardContract = poolInfo[_pid].veAssetRewards; require(msg.sender == rewardContract, "!auth"); // @audit require(_to != address(0)); _withdraw(_pid, _amount, msg.sender, _to); return true; }
constructor( uint256 pid_, address stakingToken_, address rewardToken_, address operator_, address rewardManager_ ) { pid = pid_; stakingToken = IERC20(stakingToken_); rewardToken = IERC20(rewardToken_); operator = operator_; rewardManager = rewardManager_; }
constructor(address stakingToken_, address rewardManager_) { stakingToken = IERC20(stakingToken_); rewardManager = rewardManager_; }
function addReward( address _rewardToken, address _veAssetDeposits, address _ve3TokenRewards, address _ve3Token ) external onlyOwner { rewardTokenInfo[_rewardToken].veAssetDeposits = _veAssetDeposits; rewardTokenInfo[_rewardToken].ve3TokenRewards = _ve3TokenRewards; rewardTokenInfo[_rewardToken].ve3Token = _ve3Token; rewardTokens.add(_rewardToken); } function addOperator(address _newOperator) public onlyOwner { operators.add(_newOperator); }
Add address(0)
checks.
Contracts implementing access control's, e.g. owner
, should consider implementing a Two-Step Transfer pattern.
Otherwise it's possible that the role mistakenly transfers ownership to the wrong address, resulting in a loss of the role
function setFeeManager(address _feeManager) external { require(msg.sender == feeManager, "!auth"); feeManager = _feeManager; emit FeeManagerUpdated(_feeManager); }
function setOwner(address _owner) external { require(msg.sender == owner, "!auth"); owner = _owner; emit OwnerUpdated(_owner); } function setFeeManager(address _feeM) external { require(msg.sender == feeManager, "!auth"); feeManager = _feeM; emit FeeManagerUpdated(_feeM); } function setPoolManager(address _poolM) external { require(msg.sender == poolManager, "!auth"); poolManager = _poolM; emit PoolManagerUpdated(_poolM); }
function setVoteDelegate(address _voteDelegate) external { require(msg.sender == voteDelegate, "!auth"); voteDelegate = _voteDelegate; emit VoteDelegateUpdated(_voteDelegate); }
Consider following the example below where the new role will have to accept.
Example
address owner; address pendingOwner; // ... function setPendingOwner(address newPendingOwner) external { require(msg.sender == owner, "!owner"); emit NewPendingOwner(newPendingOwner); pendingOwner = newPendingOwner; } function acceptOwnership() external { require(msg.sender == pendingOwner, "!pendingOwner"); emit NewOwner(pendingOwner); owner = pendingOwner; pendingOwner = address(0); }
function setOwner(address _owner) external { require(msg.sender == owner, "!auth"); owner = _owner; }
Require owner to set priviledged addresses.
function setFeeManager(address _feeM) external { - require(msg.sender == feeManager, "!auth"); + require(msg.sender == owner, "!auth") feeManager = _feeM; emit FeeManagerUpdated(_feeM); } function setPoolManager(address _poolM) external { - require(msg.sender == poolManager, "!auth"); + require(msg.sender == owner, "!auth") poolManager = _poolM; emit PoolManagerUpdated(_poolM); }
function setVoteDelegate(address _voteDelegate) external { - require(msg.sender == voteDelegate, "!auth"); + require(msg.sender == owner, "!auth") voteDelegate = _voteDelegate; emit VoteDelegateUpdated(_voteDelegate); }
Use require (msg.sender == owner, "!auth")
for all the functions that need authorization when assigning a new address to a role.
The usage of deprecated library functions should be discouraged.
Booster.sol::374 => IERC20(token).safeApprove(rewardContract, _amount); VE3DRewardPool.sol::287 => IERC20(_rewardToken).safeApprove(rewardTokenInfo[_rewardToken].veAssetDeposits, 0); VE3DRewardPool.sol::288 => IERC20(_rewardToken).safeApprove( VE3DRewardPool.sol::301 => IERC20(rewardTokenInfo[_rewardToken].ve3Token).safeApprove( VE3DRewardPool.sol::305 => IERC20(rewardTokenInfo[_rewardToken].ve3Token).safeApprove( VeAssetDepositor.sol::162 => IERC20(minter).safeApprove(_stakeAddress, _amount); VoterProxy.sol::101 => IERC20(_token).safeApprove(_gauge, 0); VoterProxy.sol::102 => IERC20(_token).safeApprove(_gauge, balance); VoterProxy.sol::152 => IERC20(veAsset).safeApprove(escrow, 0); VoterProxy.sol::153 => IERC20(veAsset).safeApprove(escrow, _value); VoterProxy.sol::160 => IERC20(veAsset).safeApprove(escrow, 0); VoterProxy.sol::161 => IERC20(veAsset).safeApprove(escrow, _value);
Use safeIncreaseAllowance
/ safeDecreaseAllowance
instead of safeApprove
.
- //increase ammount + //increase amount
manual, slither
#0 - GalloDaSballo
2022-07-07T22:41:19Z
Valid Low
Valid NC
##Β [L-03] Require owner Disagree with the finding, the sponsor chose to have multiple admin accounts with different roles
##Β [L-04] Do not use Deprecated Library Functions Valid NC as the function is used as intended
Valid NC
Neat Report
1L, 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
If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
uint256 public periodFinish = 0; uint256 public rewardRate = 0; uint256 public queuedRewards = 0; uint256 public currentRewards = 0; uint256 public historicalRewards = 0;
BaseRewardPool.sol::176 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::199 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::218 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::245 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::282 => for (uint256 i = 0; i < extraRewards.length; i++) { Booster.sol::110 => isShutdown = false; Booster.sol::329 => for (uint256 i = 0; i < poolInfo.length; i++) { VE3DRewardPool.sol::148 => for (uint256 i = 0; i < rewardTokens.length(); i++) { VE3DRewardPool.sol::214 => for (uint256 i = 0; i < length; i++) { VE3DRewardPool.sol::238 => for (uint256 i = 0; i < length; i++) { VE3DRewardPool.sol::257 => for (uint256 i = 0; i < length; i++) { VE3DRewardPool.sol::281 => for (uint256 i = 0; i < rewardTokens.length(); i++) { VE3DRewardPool.sol::326 => for (uint256 i = 0; i < length; i++) { VoterProxy.sol::217 => for (uint256 i = 0; i < _tokenVote.length; i++) { VoterProxy.sol::227 => uint256 _balance = 0;
Remove explicit default initializations.
!= 0
instead of > 0
for Unsigned Integer Comparison in require statements.!= 0
is cheapear than > 0
when comparing unsigned integers in require statements.
BaseRewardPool.sol::173 => require(_amount > 0, "RewardPool : Cannot stake 0"); BaseRewardPool.sol::196 => require(_amount > 0, "RewardPool : Cannot stake 0"); BaseRewardPool.sol::215 => require(amount > 0, "RewardPool : Cannot withdraw 0"); VE3DRewardPool.sol::210 => require(_amount > 0, "RewardPool : Cannot stake 0"); VE3DRewardPool.sol::234 => require(_amount > 0, "RewardPool : Cannot stake 0"); VE3DRewardPool.sol::253 => require(_amount > 0, "RewardPool : Cannot withdraw 0"); VeAssetDepositor.sol::132 => require(_amount > 0, "!>0");
Use != 0
instead of > 0
.
Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration.
BaseRewardPool.sol::176 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::199 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::218 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::245 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::282 => for (uint256 i = 0; i < extraRewards.length; i++) { Booster.sol::329 => for (uint256 i = 0; i < poolInfo.length; i++) { VE3DRewardPool.sol::148 => for (uint256 i = 0; i < rewardTokens.length(); i++) { VE3DRewardPool.sol::281 => for (uint256 i = 0; i < rewardTokens.length(); i++) { VoterProxy.sol::217 => for (uint256 i = 0; i < _tokenVote.length; i++) {
Store the arrayβs length in a variable before the for-loop.
++i
costs less gas compared to i++
or i += 1
++i
costs less gas compared to i++
or i += 1
for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.
BaseRewardPool.sol::176 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::199 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::218 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::245 => for (uint256 i = 0; i < extraRewards.length; i++) { BaseRewardPool.sol::282 => for (uint256 i = 0; i < extraRewards.length; i++) { Booster.sol::329 => for (uint256 i = 0; i < poolInfo.length; i++) { VE3DRewardPool.sol::148 => for (uint256 i = 0; i < rewardTokens.length(); i++) { VE3DRewardPool.sol::214 => for (uint256 i = 0; i < length; i++) { VE3DRewardPool.sol::238 => for (uint256 i = 0; i < length; i++) { VE3DRewardPool.sol::257 => for (uint256 i = 0; i < length; i++) { VE3DRewardPool.sol::281 => for (uint256 i = 0; i < rewardTokens.length(); i++) { VE3DRewardPool.sol::326 => for (uint256 i = 0; i < length; i++) { VoterProxy.sol::217 => for (uint256 i = 0; i < _tokenVote.length; i++) {
Use ++i
instead of i++
to increment the value of an uint variable.
Same thing for --i
and i--
.
SafeMath
is unnecessary in solidity versions >0.8.0.Arithmetic operations revert on underflow and overflow in solidity versions >0.8.0. Using SafeMath
is redundant and a waste of gas.
pragma solidity 0.8.7; import "@openzeppelin/contracts/utils/math/SafeMath.sol";
pragma solidity 0.8.7; import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
pragma solidity 0.8.7; import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
Get rid of SafeMath.sol
.
c4udit, manual, slither
#0 - GalloDaSballo
2022-07-14T01:59:36Z
Less than 500 gas