Platform: Code4rena
Start Date: 11/05/2022
Pot Size: $150,000 USDC
Total HM: 23
Participants: 93
Period: 14 days
Judge: LSDan
Total Solo HM: 18
Id: 123
League: ETH
Rank: 3/93
Findings: 5
Award: $10,751.19
🌟 Selected for report: 5
🚀 Solo Findings: 1
🌟 Selected for report: IllIllI
5188.7624 USDC - $5,188.76
Users can grief reward distributions by spending dust
If a reward is targeted for an epoch in the past, a user can front-run the txn in the mempool and call addRewardToEpoch()
with a dust amount at an epoch after the one in question. This will cause the transaction in the mempool to revert
File: contracts/ExtraRewardsDistributor.sol #1 74 require(len == 0 || rewardEpochs[_token][len - 1] < _epoch, "Cannot backdate to this epoch");
Code inspection
Allow the backdating of rewards, which will cost more gas
#0 - 0xMaharishi
2022-05-27T14:12:14Z
Fair finding, however since this is a peripheral contract and only affects user reward claiming. In the Aura system, rewards are only added to the current epoch so should be fine
🌟 Selected for report: IllIllI
Also found by: Aits, BowTiedWardens, MaratCerby
945.652 USDC - $945.65
If rewards are given in fee-on-transfer tokens, users may get no rewards, breaking functionality
Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or :::leak value with a hypothetical attack path with stated assumptions:::, but external requirements.
(emphasis mine)
The underlying BAL protocol support fee-on-transfer tokens, so so should Aura
File: contracts/ExtraRewardsDistributor.sol #1 87 function _addReward( 88 address _token, 89 uint256 _amount, 90 uint256 _epoch 91 ) internal nonReentrant { 92 // Pull before reward accrual 93 IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); 94 95 //convert to reward per token 96 uint256 supply = auraLocker.totalSupplyAtEpoch(_epoch); 97 uint256 rPerT = (_amount * 1e20) / supply; 98 rewardData[_token][_epoch] += rPerT;
If a fee is charged the total amount available to be transferred later will be less than the _amount
passed in.
Consider the following scenario: User A holds 98% of the total supply of vlBAL (the system is being bootstrapped) User B holds 1% User C holds 1%
_token
is given out as a reward. It is a fee-on-transfer token with a fee of 2%File: contracts/ExtraRewardsDistributor.sol #2 87 function _addReward( 88 address _token, 89 uint256 _amount, 90 uint256 _epoch 91 ) internal nonReentrant { 92 // Pull before reward accrual 93 IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); 94 95 //convert to reward per token 96 uint256 supply = auraLocker.totalSupplyAtEpoch(_epoch); 97 uint256 rPerT = (_amount * 1e20) / supply; 98 rewardData[_token][_epoch] += rPerT;
Code inspection
Measure the contract balance before and after the transfer, and use the difference as the amount, rather than the stated amount
#0 - 0xMaharishi
2022-05-26T15:44:32Z
This contract is optional to use - it is not supposed to support fee bearing tokens
#1 - dmvt
2022-07-08T17:51:10Z
See comment on #18
🌟 Selected for report: IllIllI
Also found by: csanuragjain
2334.9431 USDC - $2,334.94
Users are charged the penalty due to admin actions, and they have no way to avoid it
When claiming their rewards, users are charged a penalty if they take the reward directly, rather than by passing it into the auraLocker
. Those are the only two options:
File: contracts/AuraBalRewardPool.sol #1 176 function getReward(bool _lock) public updateReward(msg.sender) returns (bool) { 177 uint256 reward = rewards[msg.sender]; 178 if (reward > 0) { 179 rewards[msg.sender] = 0; 180 if (_lock) { 181 auraLocker.lock(msg.sender, reward); 182 } else { 183 uint256 penalty = (reward * 2) / 10; 184 pendingPenalty += penalty; 185 rewardToken.safeTransfer(msg.sender, reward - penalty); 186 }
If the pool has been shut down, the auraLocker.lock()
call will always revert, which means the user must take the penalty path:
File: contracts/AuraLocker.sol #2 258 function _lock(address _account, uint256 _amount) internal { 259 require(_amount > 0, "Cannot stake 0"); 260 require(!isShutdown, "shutdown");
Code inspection
Don't charge the penalty if the locker has been shut down
#0 - 0xMaharishi
2022-05-26T15:25:11Z
The auraBAL reward pool only runs for 2 weeks at the beginning of the protocol. Its highly unlikely the AuraLocker will be shut down.
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x4non, 0xNazgul, 0xNineDec, 0xf15ers, 0xkatana, 242, AlleyCat, BouSalman, BowTiedWardens, CertoraInc, Chom, Cityscape, FSchmoede, Funen, GimelSec, Hawkeye, JC, JDeryl, Kaiziron, Kthere, Kumpa, MaratCerby, MiloTruck, Nethermind, NoamYakov, PPrieditis, QuantumBrief, Rolezn, Ruhum, SmartSek, SooYa, Tadashi, TerrierLover, WatchPug, Waze, _Adam, asutorufos, berndartmueller, bobirichman, c3phas, catchup, cccz, ch13fd357r0y3r, cryptphi, csanuragjain, cthulhu_cult, defsec, delfin454000, ellahi, fatherOfBlocks, hansfriese, hubble, hyh, jayjonah8, joestakey, kenta, kenzo, kirk-baird, mics, oyc_109, p_crypt0, reassor, robee, sach1r0, samruna, sashik_eth, sikorico, simon135, sorrynotsorry, sseefried, tintin, unforgiven, z3s, zmj
1466.9507 USDC - $1,466.95
Issue | Instances | |
---|---|---|
1 | Wrong amounts sent if arrays don't match | 1 |
2 | Incorrect/misleading NatSpec | 1 |
3 | Function reverts if called a second time | 1 |
4 | pragma experimental ABIEncoderV2 is deprecated | 1 |
5 | safeApprove() is deprecated | 36 |
6 | Missing checks for address(0x0) when assigning values to address state variables | 103 |
Total: 143 instances over 6 issues
Issue | Instances | |
---|---|---|
1 | Unused file | 1 |
2 | Call For /From variants instead of copying an pasting code | 1 |
3 | Remove tautological code | 1 |
4 | Adding a return statement when the function defines a named return variable, is redundant | 3 |
5 | override function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings | 1 |
6 | public functions not called by the contract should be declared external instead | 18 |
7 | type(uint<n>).max should be used instead of uint<n>(-1) | 8 |
8 | constant s should be defined rather than using magic numbers | 47 |
9 | Redundant cast | 2 |
10 | Numeric values having to do with time should use time units for readability | 4 |
11 | Missing event for critical parameter change | 24 |
12 | Use a more recent version of solidity | 1 |
13 | Use a more recent version of solidity | 26 |
14 | Use a more recent version of solidity | 1 |
15 | Constant redefined elsewhere | 38 |
16 | Inconsistent spacing in comments | 80 |
17 | Non-library/interface files should use fixed compiler versions, not floating ones | 12 |
18 | Typos | 29 |
19 | File is missing NatSpec | 6 |
20 | NatSpec is incomplete | 21 |
21 | Event is missing indexed fields | 66 |
Total: 390 instances over 21 issues
The caller may make a copy-paste error where they provide all amounts, but miss one of the recipients in the middle of the list they're copying. This will cause all recipients after that mistake to get the wrong amounts, and the function will not revert
There is 1 instance of this issue:
File: contracts/AuraVestedEscrow.sol #1 96: function fund(address[] calldata _recipient, uint256[] calldata _amount) external nonReentrant {
The function retrieves the number of votes at the end of an epoch, not at the end of a block. Furthermore, blockNumber
is not an actual variable name
There is 1 instance of this issue:
File: contracts/AuraLocker.sol #1 595: * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
safeApprove()
reverts if called a second time without fist calling safeApprove(0)
There is 1 instance of this issue:
File: contracts/CrvDepositorWrapper.sol #1 /// @audit `setApprovals()` is an external function that calls this function. If it's called more than once, the secondary calls will revert 51 function _setApprovals() internal { 52 IERC20(WETH).safeApprove(address(BALANCER_VAULT), type(uint256).max); 53 IERC20(BAL).safeApprove(address(BALANCER_VAULT), type(uint256).max); 54: }
pragma experimental ABIEncoderV2
is deprecatedUse pragma abicoder v2
instead
There is 1 instance of this issue:
File: contracts/AuraLocker.sol #1 3: pragma experimental ABIEncoderV2;
safeApprove()
is deprecatedDeprecated in favor of safeIncreaseAllowance()
and safeDecreaseAllowance()
. If only setting the initial allowance to the value that means infinite, safeIncreaseAllowance()
can be used instead
There are 36 instances of this issue:
File: contracts/AuraClaimZap.sol 98: IERC20(crv).safeApprove(crvDepositWrapper, 0); 99: IERC20(crv).safeApprove(crvDepositWrapper, type(uint256).max); 101: IERC20(cvxCrv).safeApprove(cvxCrvRewards, 0); 102: IERC20(cvxCrv).safeApprove(cvxCrvRewards, type(uint256).max); 104: IERC20(cvx).safeApprove(locker, 0); 105: IERC20(cvx).safeApprove(locker, type(uint256).max);
File: contracts/AuraMerkleDrop.sol 131: aura.safeApprove(address(auraLocker), 0); 132: aura.safeApprove(address(auraLocker), _amount);
File: contracts/AuraPenaltyForwarder.sol 41: token.safeApprove(address(distributor), type(uint256).max);
File: contracts/AuraBalRewardPool.sol 75: rewardToken.safeApprove(_auraLocker, type(uint256).max);
File: contracts/AuraLocker.sol 240: IERC20(cvxCrv).safeApprove(cvxcrvStaking, 0); 241: IERC20(cvxCrv).safeApprove(cvxcrvStaking, type(uint256).max);
File: contracts/CrvDepositorWrapper.sol 52: IERC20(WETH).safeApprove(address(BALANCER_VAULT), type(uint256).max); 53: IERC20(BAL).safeApprove(address(BALANCER_VAULT), type(uint256).max);
File: contracts/AuraStakingProxy.sol 147: IERC20(crv).safeApprove(crvDepositorWrapper, 0); 148: IERC20(crv).safeApprove(crvDepositorWrapper, type(uint256).max); 150: IERC20(cvxCrv).safeApprove(rewards, 0); 151: IERC20(cvxCrv).safeApprove(rewards, type(uint256).max); 215: _token.safeApprove(rewards, 0); 216: _token.safeApprove(rewards, type(uint256).max);
File: contracts/AuraVestedEscrow.sol 186: rewardToken.safeApprove(address(auraLocker), claimable);
File: contracts/BalLiquidityProvider.sol 59: tkn.safeApprove(address(bVault), 0); 60: tkn.safeApprove(address(bVault), bal);
File: convex-platform/contracts/contracts/CrvDepositor.sol 199: IERC20(minter).safeApprove(_stakeAddress,0); 200: IERC20(minter).safeApprove(_stakeAddress,_amount);
File: convex-platform/contracts/contracts/VoterProxy.sol 176: IERC20(_token).safeApprove(_gauge, 0); 177: IERC20(_token).safeApprove(_gauge, balance); 193: _asset.safeApprove(rewardDeposit, 0); 194: _asset.safeApprove(rewardDeposit, balance); 244: IERC20(crvBpt).safeApprove(escrow, 0); 245: IERC20(crvBpt).safeApprove(escrow, _value); 255: IERC20(crvBpt).safeApprove(escrow, 0); 256: IERC20(crvBpt).safeApprove(escrow, _value);
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol 40: IERC20(asset).safeApprove(operator_, type(uint256).max);
File: convex-platform/contracts/contracts/Booster.sol 422: IERC20(token).safeApprove(rewardContract,0); 423: IERC20(token).safeApprove(rewardContract,_amount);
address(0x0)
when assigning values to address
state variablesThere are 103 instances of this issue:
File: contracts/AuraClaimZap.sol 76: crv = _crv; 77: cvx = _cvx; 78: cvxCrv = _cvxCrv; 79: crvDepositWrapper = _crvDepositWrapper; 80: cvxCrvRewards = _cvxCrvRewards; 81: locker = _locker;
File: contracts/AuraMerkleDrop.sol 62: dao = _dao; 66: penaltyForwarder = _penaltyForwarder; 79: dao = _newDao;
File: contracts/AuraBalRewardPool.sol 72: rewardManager = _rewardManager; 74: penaltyForwarder = _penaltyForwarder;
File: contracts/AuraLocker.sol 159: cvxCrv = _cvxCrv; 160: cvxcrvStaking = _cvxCrvStaking;
File: contracts/ClaimFeesHelper.sol 36: voterProxy = _voterProxy;
File: contracts/CrvDepositorWrapper.sol 114: crvDeposit = _crvDeposit;
File: contracts/Aura.sol 51: vecrvProxy = _proxy; 85: operator = newOperator;
File: contracts/AuraStakingProxy.sol 74: rewards = _rewards; 76: crv = _crv; 77: cvx = _cvx; 78: cvxCrv = _cvxCrv; 79: crvDepositorWrapper = _crvDepositorWrapper; 92: crvDepositorWrapper = _crvDepositorWrapper; 101: keeper = _keeper; 109: pendingOwner = _po; 139: rewards = _rewards;
File: contracts/AuraVestedEscrow.sol 60: admin = admin_; 79: admin = _admin;
File: contracts/BalLiquidityProvider.sol 38: dao = _dao;
File: convex-platform/contracts/contracts/RewardHook.sol 33: stash = _stash; 34: rewardToken = _reward;
File: convex-platform/contracts/contracts/PoolManagerProxy.sol 27: pools = _pools; 28: owner = _owner; 44: owner = _owner; 49: operator = _operator;
File: convex-platform/contracts/contracts/DepositToken.sol 44: operator = _operator;
File: convex-platform/contracts/contracts/cCrv.sol 40: operator = _operator;
File: convex-platform/contracts/contracts/StashFactoryV2.sol 40: operator = _operator; 41: rewardFactory = _rewardFactory; 42: proxyFactory = _proxyFactory; 48: v1Implementation = _v1; 49: v2Implementation = _v2; 50: v3Implementation = _v3;
File: convex-platform/contracts/contracts/PoolManagerV3.sol 34: pools = _pools; 35: gaugeController = _gaugeController; 36: operator = _operator; 42: operator = _operator;
File: convex-platform/contracts/contracts/ArbitartorVault.sol 34: depositor = _depositor; 39: operator = _op;
File: convex-platform/contracts/contracts/CrvDepositor.sol 54: staker = _staker; 55: minter = _minter; 56: crvBpt = _crvBpt; 57: escrow = _escrow; 59: daoOperator = _daoOperator; 64: feeManager = _feeManager; 69: daoOperator = _daoOperator;
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 40: gaugeController = _gaugeController; 41: pools = _pools; 42: booster = _booster; 43: owner = _owner; 59: owner = _owner; 64: operator = _operator;
File: convex-platform/contracts/contracts/TokenFactory.sol 36: operator = _operator;
File: convex-platform/contracts/contracts/VoterProxy.sol 58: mintr = _mintr; 59: crv = _crv; 60: crvBpt = _crvBpt; 61: escrow = _escrow; 62: gaugeController = _gaugeController; 75: owner = _owner; 85: withdrawer = _withdrawer; 86: rewardDeposit = _rewardDeposit; 96: gaugeController = _gaugeController; 97: mintr = _mintr; 109: operator = _operator; 119: depositor = _depositor;
File: convex-platform/contracts/contracts/BoosterOwner.sol 77: owner = _owner; 78: poolManager = _poolManager; 79: booster = _booster; 80: stashFactory = _stashFactory; 81: rescueStash = _rescueStash; 91: pendingowner = _owner;
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 59: crv = _crv; 72: operator = _operator; 73: staker = _staker; 74: gauge = _gauge; 75: rewardFactory = _rFactory; 148: rewardHook = _hook;
File: convex-platform/contracts/contracts/BaseRewardPool.sol 109: operator = operator_; 110: rewardManager = rewardManager_;
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 116: operator = op_;
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol 39: asset = lptoken_;
File: convex-platform/contracts/contracts/Booster.sol 103: staker = _staker; 104: minter = _minter; 105: crv = _crv; 106: voteOwnership = _voteOwnership; 107: voteParameter = _voteParameter; 130: owner = _owner; 140: feeManager = _feeM; 150: poolManager = _poolM; 183: rewardArbitrator = _arb; 193: voteDelegate = _voteDelegate; 296: treasury = _treasury;
File: convex-platform/contracts/contracts/RewardFactory.sol 42: crv = _crv;
The file is never imported by any other file
There is 1 instance of this issue:
File: convex-platform/contracts/contracts/interfaces/BoringMath.sol #1 0: // SPDX-License-Identifier: MIT
For
/From
variants instead of copying an pasting codeDuplicating code can lead to errors when a change is made to only one of the locations
There is 1 instance of this issue:
File: contracts/AuraBalRewardPool.sol #1 /// @audit This function should call `stakeFor(msg.sender, _amount)` instead 120 function stake(uint256 _amount) public updateReward(msg.sender) returns (bool) { 121 require(_amount > 0, "RewardPool : Cannot stake 0"); 122 123 _totalSupply = _totalSupply.add(_amount); 124 _balances[msg.sender] = _balances[msg.sender].add(_amount); 125 126 stakingToken.safeTransferFrom(msg.sender, address(this), _amount); 127 emit Staked(msg.sender, _amount); 128 129 return true; 130: }
There is 1 instance of this issue:
File: convex-platform/contracts/contracts/CrvDepositor.sol #1 /// @audit `_lockIncentive` is always greater than or equal to zero, so the condition should be removed 75: if(_lockIncentive >= 0 && _lockIncentive <= 30){
return
statement when the function defines a named return variable, is redundantThere are 3 instances of this issue:
File: contracts/AuraLocker.sol #1 678: return amount;
File: contracts/AuraLocker.sol #2 778: return userRewards;
File: convex-platform/contracts/contracts/VoterProxy.sol #3 196: return balance;
override
function arguments that are unused should have the variable name removed or commented out to avoid compiler warningsThere is 1 instance of this issue:
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol #1 134: function maxDeposit(address owner) public view virtual override returns (uint256) {
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents' functions and change the visibility from external
to public
.
There are 18 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol 117: function getReward(address _account, address _token) public { 127 function getReward( 128 address _account, 129 address _token, 130: uint256 _startIndex
File: contracts/AuraMerkleDrop.sol 114 function claim( 115 bytes32[] calldata _proof, 116 uint256 _amount, 117 bool _lock 118: ) public returns (bool) { 149 function forwardPenalty() public { 150: uint256 toForward = pendingPenalty;
File: contracts/AuraPenaltyForwarder.sol 47 function forward() public { 48: require(block.timestamp > lastDistribution + distributionDelay, "!elapsed");
File: contracts/AuraBalRewardPool.sol 138: function stakeFor(address _for, uint256 _amount) public updateReward(_for) returns (bool) { 152 function withdraw( 153 uint256 amount, 154 bool claim, 155 bool lock 156: ) public updateReward(msg.sender) returns (bool) { 195 function forwardPenalty() public { 196: uint256 toForward = pendingPenalty;
File: contracts/BalLiquidityProvider.sol 46: function provideLiquidity(bytes32 _poolId, IVault.JoinPoolRequest memory _request) public {
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 96 function add( 97 uint256 _allocPoint, 98 IERC20 _lpToken, 99 IRewarder _rewarder, 100 bool _withUpdate 101: ) public onlyOwner { 121 function set( 122 uint256 _pid, 123 uint256 _allocPoint, 124 IRewarder _rewarder, 125 bool _withUpdate, 126 bool _updateRewarder 127: ) public onlyOwner { 209: function deposit(uint256 _pid, uint256 _amount) public { 239: function withdraw(uint256 _pid, uint256 _amount) public { 283: function emergencyWithdraw(uint256 _pid) public {
File: convex-platform/contracts/contracts/VoterProxy.sol 151: function isValidSignature(bytes32 _hash, bytes memory) public view returns (bytes4) {
File: convex-platform/contracts/contracts/BaseRewardPool.sol 191 function stakeFor(address _for, uint256 _amount) 192 public 193: returns(bool)
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 178 function withdraw(address _account, uint256 amount) 179 public 180: updateReward(_account)
File: convex-platform/contracts/contracts/Booster.sol 493: function withdrawAll(uint256 _pid) public returns(bool){
type(uint<n>).max
should be used instead of uint<n>(-1)
There are 8 instances of this issue:
File: convex-platform/contracts/contracts/interfaces/BoringMath.sol 25: require(a <= uint128(-1), "BoringMath: uint128 Overflow"); 30: require(a <= uint64(-1), "BoringMath: uint64 Overflow"); 35: require(a <= uint32(-1), "BoringMath: uint32 Overflow"); 40: require(a <= uint40(-1), "BoringMath: uint40 Overflow"); 45: require(a <= uint112(-1), "BoringMath: uint112 Overflow"); 50: require(a <= uint224(-1), "BoringMath: uint224 Overflow"); 55: require(a <= uint208(-1), "BoringMath: uint208 Overflow"); 60: require(a <= uint216(-1), "BoringMath: uint216 Overflow");
constant
s should be defined rather than using magic numbersThere are 47 instances of this issue:
File: contracts/AuraMinter.sol /// @audit 156 23: inflationProtectionTime = block.timestamp + 156 weeks;
File: contracts/ExtraRewardsDistributor.sol /// @audit 1e20 97: uint256 rPerT = (_amount * 1e20) / supply; /// @audit 1e20 257: return (balance * rewardData[_token][_epoch]) / 1e20;
File: contracts/AuraBalRewardPool.sol /// @audit 1e18 109: lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(totalSupply()) /// @audit 1e18 115: balanceOf(account).mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(
File: contracts/AuraLocker.sol /// @audit 18 156: _decimals = 18; /// @audit 500 216: require(_rate <= 500, "over max rate"); //max 5% per epoch /// @audit 1e18 795: return _balance.mul(_rewardPerToken(_rewardsToken).sub(data.rewardPerTokenPaid)).div(1e18).add(data.rewards); /// @audit 1e18 811: .mul(1e18) /// @audit 1000 839: uint256 queuedRatio = currentAtNow.mul(1000).div(_rewards);
File: contracts/CrvDepositorWrapper.sol /// @audit 3600 60: queries[0].secs = 3600; // last hour /// @audit 1e18 73: uint256 minOut = (((amount * 1e18) / bptOraclePrice) * minOutBps) / 10000; /// @audit 10000 73: uint256 minOut = (((amount * 1e18) / bptOraclePrice) * minOutBps) / 10000;
File: contracts/Aura.sol /// @audit 5 111: uint256 reduction = totalCliffs.sub(cliff).mul(5).div(2).add(700); /// @audit 700 111: uint256 reduction = totalCliffs.sub(cliff).mul(5).div(2).add(700);
File: contracts/AuraStakingProxy.sol /// @audit 9000 90: require(_outputBps > 9000 && _outputBps < 10000, "Invalid output bps"); /// @audit 10000 90: require(_outputBps > 9000 && _outputBps < 10000, "Invalid output bps"); /// @audit 100 129: require(_incentive <= 100, "too high");
File: contracts/AuraVestedEscrow.sol /// @audit 16 66: require(totalTime >= 16 weeks, "!short");
File: convex-platform/contracts/contracts/ConvexMasterChef.sol /// @audit 1e12 171: cvxReward.mul(1e12).div(lpSupply) /// @audit 1e12 174: return user.amount.mul(accCvxPerShare).div(1e12).sub(user.rewardDebt); /// @audit 1e12 203: cvxReward.mul(1e12).div(lpSupply) /// @audit 1e12 217: .div(1e12) /// @audit 1e12 227: user.rewardDebt = user.amount.mul(pool.accCvxPerShare).div(1e12); /// @audit 1e12 244: uint256 pending = user.amount.mul(pool.accCvxPerShare).div(1e12).sub( /// @audit 1e12 249: user.rewardDebt = user.amount.mul(pool.accCvxPerShare).div(1e12); /// @audit 1e12 267: uint256 pending = user.amount.mul(pool.accCvxPerShare).div(1e12).sub( /// @audit 1e12 271: user.rewardDebt = user.amount.mul(pool.accCvxPerShare).div(1e12);
File: convex-platform/contracts/contracts/StashFactoryV2.sol /// @audit 3 58: if(_stashVersion == uint256(3) && IsV3(_gauge)){
File: convex-platform/contracts/contracts/PoolManagerV3.sol /// @audit 3 57: _addPool(_gauge,3);
File: convex-platform/contracts/contracts/CrvDepositor.sol /// @audit 30 75: if(_lockIncentive >= 0 && _lockIncentive <= 30){
File: convex-platform/contracts/contracts/VoterProxy.sol /// @audit 0xffffffff 155: return 0xffffffff;
File: convex-platform/contracts/contracts/BaseRewardPool.sol /// @audit 1e18 160: .mul(1e18) /// @audit 1e18 169: .div(1e18) /// @audit 1000 339: uint256 queuedRatio = currentAtNow.mul(1000).div(_rewards);
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol /// @audit 1e18 146: .mul(1e18) /// @audit 1e18 155: .div(1e18) /// @audit 1000 227: uint256 queuedRatio = currentAtNow.mul(1000).div(_rewards);
File: convex-platform/contracts/contracts/Booster.sol /// @audit 825 26: uint256 public lockIncentive = 825; //incentive to crv stakers /// @audit 825 27: uint256 public stakerIncentive = 825; //incentive to native token stakers /// @audit 50 28: uint256 public earmarkIncentive = 50; //incentive to users who spend gas to make calls /// @audit 300 278: require(_lockFees >= 300 && _lockFees <= 1500, "!lockFees"); /// @audit 1500 278: require(_lockFees >= 300 && _lockFees <= 1500, "!lockFees"); /// @audit 300 279: require(_stakerFees >= 300 && _stakerFees <= 1500, "!stakerFees"); /// @audit 1500 279: require(_stakerFees >= 300 && _stakerFees <= 1500, "!stakerFees"); /// @audit 100 280: require(_callerFees >= 10 && _callerFees <= 100, "!callerFees"); /// @audit 200 281: require(_platform <= 200, "!platform");
The type of the variable is the same as the type to which the variable is being cast
There are 2 instances of this issue:
File: contracts/AuraLocker.sol #1 /// @audit uint256(_epoch) 654: uint256 epochStart = uint256(epochs[0].date).add(uint256(_epoch).mul(rewardsDuration));
File: contracts/AuraLocker.sol #2 /// @audit uint256(_epoch) 718: uint256 epochStart = uint256(epochs[0].date).add(uint256(_epoch).mul(rewardsDuration));
There are units for seconds, minutes, hours, days, and weeks
There are 4 instances of this issue:
File: contracts/AuraLocker.sol #1 /// @audit 86400 81: uint256 public constant rewardsDuration = 86400 * 7;
File: contracts/CrvDepositorWrapper.sol #2 /// @audit 3600 60: queries[0].secs = 3600; // last hour
File: convex-platform/contracts/contracts/CrvDepositor.sol #3 /// @audit 86400 26: uint256 private constant MAXTIME = 1 * 364 * 86400;
File: convex-platform/contracts/contracts/CrvDepositor.sol #4 /// @audit 86400 27: uint256 private constant WEEK = 7 * 86400;
There are 24 instances of this issue:
File: contracts/AuraStakingProxy.sol 88 function setCrvDepositorWrapper(address _crvDepositorWrapper, uint256 _outputBps) external { 89 require(msg.sender == owner, "!auth"); 90 require(_outputBps > 9000 && _outputBps < 10000, "Invalid output bps"); 91 92 crvDepositorWrapper = _crvDepositorWrapper; 93 outputBps = _outputBps; 94: } 99 function setKeeper(address _keeper) external { 100 require(msg.sender == owner, "!auth"); 101 keeper = _keeper; 102: } 107 function setPendingOwner(address _po) external { 108 require(msg.sender == owner, "!auth"); 109 pendingOwner = _po; 110: } 137 function setRewards(address _rewards) external { 138 require(msg.sender == owner, "!auth"); 139 rewards = _rewards; 140: }
File: contracts/AuraVestedEscrow.sol 77 function setAdmin(address _admin) external { 78 require(msg.sender == admin, "!auth"); 79 admin = _admin; 80: }
File: convex-platform/contracts/contracts/PoolManagerProxy.sol 43 function setOwner(address _owner) external onlyOwner{ 44 owner = _owner; 45: } 48 function setOperator(address _operator) external onlyOwner{ 49 operator = _operator; 50: }
File: convex-platform/contracts/contracts/cCrv.sol 38 function setOperator(address _operator) external { 39 require(msg.sender == operator, "!auth"); 40 operator = _operator; 41: }
File: convex-platform/contracts/contracts/StashFactoryV2.sol 45 function setImplementation(address _v1, address _v2, address _v3) external{ 46 require(msg.sender == IDeposit(operator).owner(),"!auth"); 47 48 v1Implementation = _v1; 49 v2Implementation = _v2; 50 v3Implementation = _v3; 51: }
File: convex-platform/contracts/contracts/PoolManagerV3.sol 40 function setOperator(address _operator) external { 41 require(msg.sender == operator, "!auth"); 42 operator = _operator; 43: } 48 function setProtectPool(bool _protectAddPool) external { 49 require(msg.sender == operator, "!auth"); 50 protectAddPool = _protectAddPool; 51: }
File: convex-platform/contracts/contracts/ArbitartorVault.sol 37 function setOperator(address _op) external { 38 require(msg.sender == operator, "!auth"); 39 operator = _op; 40: }
File: convex-platform/contracts/contracts/CrvDepositor.sol 62 function setFeeManager(address _feeManager) external { 63 require(msg.sender == feeManager, "!auth"); 64 feeManager = _feeManager; 65: } 67 function setDaoOperator(address _daoOperator) external { 68 require(msg.sender == daoOperator, "!auth"); 69 daoOperator = _daoOperator; 70: } 72 function setFees(uint256 _lockIncentive) external{ 73 require(msg.sender==feeManager, "!auth"); 74 75 if(_lockIncentive >= 0 && _lockIncentive <= 30){ 76 lockIncentive = _lockIncentive; 77 } 78: } 80 function setCooldown(bool _cooldown) external { 81 require(msg.sender == daoOperator, "!auth"); 82 cooldown = _cooldown; 83: }
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 58 function setOwner(address _owner) external onlyOwner{ 59 owner = _owner; 60: } 63 function setOperator(address _operator) external onlyOwner{ 64 operator = _operator; 65: }
File: convex-platform/contracts/contracts/VoterProxy.sol 73 function setOwner(address _owner) external { 74 require(msg.sender == owner, "!auth"); 75 owner = _owner; 76: } 83 function setRewardDeposit(address _withdrawer, address _rewardDeposit) external { 84 require(msg.sender == owner, "!auth"); 85 withdrawer = _withdrawer; 86 rewardDeposit = _rewardDeposit; 87: } 94 function setSystemConfig(address _gaugeController, address _mintr) external returns (bool) { 95 require(msg.sender == owner, "!auth"); 96 gaugeController = _gaugeController; 97 mintr = _mintr; 98 return true; 99: } 105 function setOperator(address _operator) external { 106 require(msg.sender == owner, "!auth"); 107 require(operator == address(0) || IDeposit(operator).isShutdown() == true, "needs shutdown"); 108 109 operator = _operator; 110: } 116 function setDepositor(address _depositor) external { 117 require(msg.sender == owner, "!auth"); 118 119 depositor = _depositor; 120: }
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 145 function setRewardHook(address _hook) external{ 146 //owner of booster can set reward hook 147 require(IDeposit(operator).owner() == msg.sender, "!owner"); 148 rewardHook = _hook; 149: }
Use a solidity version of at least 0.8.12 to get string.concat()
to be used instead of abi.encodePacked(<str>,<str>)
There is 1 instance of this issue:
File: contracts/AuraMerkleDrop.sol #1 2: pragma solidity ^0.8.11;
Use a solidity version of at least 0.8.13 to get the ability to use using for
with a list of free functions
There are 26 instances of this issue:
File: contracts/AuraClaimZap.sol 2: pragma solidity ^0.8.11;
File: contracts/ExtraRewardsDistributor.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraPenaltyForwarder.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraBalRewardPool.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraLocker.sol 2: pragma solidity ^0.8.11;
File: contracts/CrvDepositorWrapper.sol 2: pragma solidity 0.8.11;
File: contracts/Aura.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraStakingProxy.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraVestedEscrow.sol 2: pragma solidity ^0.8.11;
File: contracts/BalLiquidityProvider.sol 2: pragma solidity ^0.8.11;
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 3: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/RewardHook.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/cCrv.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/StashFactoryV2.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/ArbitartorVault.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/CrvDepositor.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/TokenFactory.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/VoterProxy.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/IRewarder.sol 3: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/BaseRewardPool.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/Booster.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/RewardFactory.sol 2: pragma solidity 0.6.12;
Use a solidity version of at least 0.8.4 to get bytes.concat()
instead of abi.encodePacked(<bytes>,<bytes>)
Use a solidity version of at least 0.8.12 to get string.concat()
instead of abi.encodePacked(<str>,<str>)
There is 1 instance of this issue:
File: convex-platform/contracts/contracts/DepositToken.sol #1 2: pragma solidity 0.6.12;
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant
in a library
. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.
There are 38 instances of this issue:
File: contracts/AuraMerkleDrop.sol /// @audit seen in /var/tmp/hh/contracts/AuraMinter.sol 25: IERC20 public immutable aura;
File: contracts/AuraBalRewardPool.sol /// @audit seen in /var/tmp/hh/contracts/ExtraRewardsDistributor.sol 33: IAuraLocker public immutable auraLocker; /// @audit seen in /var/tmp/hh/contracts/AuraMerkleDrop.sol 34: address public immutable penaltyForwarder;
File: contracts/AuraLocker.sol /// @audit seen in /var/tmp/hh/contracts/AuraBalRewardPool.sol 104: IERC20 public immutable stakingToken; /// @audit seen in /var/tmp/hh/contracts/AuraClaimZap.sol 105: address public immutable cvxCrv;
File: contracts/AuraStakingProxy.sol /// @audit seen in /var/tmp/hh/contracts/AuraClaimZap.sol 38: address public immutable crv; /// @audit seen in /var/tmp/hh/contracts/AuraClaimZap.sol 39: address public immutable cvx; /// @audit seen in /var/tmp/hh/contracts/AuraLocker.sol 40: address public immutable cvxCrv; /// @audit seen in /var/tmp/hh/contracts/AuraLocker.sol 45: uint256 public constant denominator = 10000;
File: contracts/AuraVestedEscrow.sol /// @audit seen in /var/tmp/hh/contracts/AuraBalRewardPool.sol 24: IERC20 public immutable rewardToken; /// @audit seen in /var/tmp/hh/contracts/AuraBalRewardPool.sol 29: uint256 public immutable startTime;
File: convex-platform/contracts/contracts/ConvexMasterChef.sol /// @audit seen in /var/tmp/hh/contracts/AuraStakingProxy.sol 52: IERC20 public immutable cvx;
File: convex-platform/contracts/contracts/RewardHook.sol /// @audit seen in /var/tmp/hh/contracts/AuraVestedEscrow.sol 25: address public immutable rewardToken;
File: convex-platform/contracts/contracts/PoolManagerV3.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/PoolManagerProxy.sol 18: address public immutable pools;
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/PoolManagerV3.sol 19: address public immutable gaugeController; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/PoolManagerV3.sol 20: address public immutable pools; /// @audit seen in /var/tmp/hh/contracts/ClaimFeesHelper.sol 21: address public immutable booster;
File: convex-platform/contracts/contracts/TokenFactory.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/StashFactoryV2.sol 20: address public immutable operator;
File: convex-platform/contracts/contracts/VoterProxy.sol /// @audit seen in /var/tmp/hh/contracts/AuraStakingProxy.sol 23: address public immutable crv; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/CrvDepositor.sol 24: address public immutable crvBpt; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/CrvDepositor.sol 26: address public immutable escrow;
File: convex-platform/contracts/contracts/BoosterOwner.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 44: address public immutable booster;
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/VoterProxy.sol 30: address public immutable crv;
File: convex-platform/contracts/contracts/BaseRewardPool.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/RewardHook.sol 63: IERC20 public immutable rewardToken; /// @audit seen in /var/tmp/hh/contracts/AuraLocker.sol 64: IERC20 public immutable stakingToken; /// @audit seen in /var/tmp/hh/contracts/AuraBalRewardPool.sol 65: uint256 public constant duration = 7 days; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/TokenFactory.sol 67: address public immutable operator; /// @audit seen in /var/tmp/hh/contracts/AuraBalRewardPool.sol 68: address public immutable rewardManager; /// @audit seen in /var/tmp/hh/contracts/AuraLocker.sol 78: uint256 public constant newRewardRatio = 830;
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/BaseRewardPool.sol 84: IERC20 public immutable rewardToken; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/BaseRewardPool.sol 85: uint256 public constant duration = 7 days; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/BaseRewardPool.sol 87: address public immutable operator; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/BaseRewardPool.sol 96: uint256 public constant newRewardRatio = 830;
File: convex-platform/contracts/contracts/Booster.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/ExtraRewardStashV3.sol 22: address public immutable crv; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/CrvDepositor.sol 31: uint256 public constant FEE_DENOMINATOR = 10000; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/CrvDepositor.sol 36: address public immutable staker; /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/CrvDepositor.sol 37: address public immutable minter;
File: convex-platform/contracts/contracts/RewardFactory.sol /// @audit seen in /var/tmp/hh/convex-platform/contracts/contracts/Booster.sol 25: address public immutable crv;
Some lines use // x
and some use //x
. The instances below point out the usages that don't follow the majority, within each file
There are 80 instances of this issue:
File: contracts/AuraClaimZap.sol 155: // claim others/deposit/lock/stake 170: // prettier-ignore 171: function _claimExtras( // solhint-disable-line
File: contracts/ExtraRewardsDistributor.sol 19: // token -> epoch -> amount 21: // token -> epochList 23: // token -> account -> last claimed epoch index 92: // Pull before reward accrual 219: // e.g. tokenEpochs = 31, 21 222: // e.g. epochIndex = 0 224: // e.g. epochIndex = 27 > 0 ? 27 : 0 = 27
File: contracts/AuraLocker.sol 61: uint32 date; //epoch start date 214: //set kick incentive 216: require(_rate <= 500, "over max rate"); //max 5% per epoch 217: require(_delay >= 2, "min delay"); //minimum 2 epochs of grace 224: //shutdown the contract. unstake all tokens. release all locks 250: //pull tokens 253: //lock 257: //lock tokens 264: //must try check pointing epoch first 267: //add user balances 271: //add to total supplies 274: //add user lock records or add to current 291: //update epoch supply, epoch checkpointed above so safe to add to latest 325: //insert a new epoch if needed. fill in any gaps 330: //first epoch add in constructor, no need to check 0 length 331: //check to add 333: //fill any epoch gaps until the next epoch date. 347: //allow kick after grace period of 'kickRewardEpochDelay' 390: //if time is beyond last lock, can just bundle everything together 393: //dont delete, just set next index 396: //check for kick reward 397: //this wont have the exact reward rate that you would get if looped through 398: //but this section is supposed to be for quick and easy low gas processing of all locks 399: //we'll assume that if the reward was good enough someone would have processed at an earlier epoch 407: //use a processed index(nextUnlockIndex) to not loop as much 408: //deleting does not change array length 411: //unlock time must be less or equal to time 414: //add to cumulative amounts 417: //check for kick reward 418: //each epoch over due increases reward 425: //set next unlock index 428: //update next unlock index 433: //update user balances and total supplies 437: //checkpoint the delegatee 442: //send process incentive 444: //reduce return amount by the kick reward 447: //transfer reward 452: //relock or return to user 661: //need to add up since the range could be in the middle somewhere 662: //traverse inversely to make more current queries more gas efficient 666: //lock epoch must be less or equal to the epoch we're basing from. 667: //also not include the current epoch 672: //stop now as no futher checks matter 835: //et = now - (finish-duration) 837: //current at now: rewardRate * elapsedTime
File: contracts/AuraStakingProxy.sol 170: // If keeper enabled, require
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 51: //cvx 201: //cvx.mint(address(this), cvxReward); 229: //extra rewards 252: //extra rewards 273: //extra rewards 291: //extra rewards
File: convex-platform/contracts/contracts/PoolManagerProxy.sol 52: // sealed to be immutable 53: // function revertControl() external{ 54: // }
File: convex-platform/contracts/contracts/BoosterOwner.sol 193: // --- Helper functions for other systems, could also just use execute() ---
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 138: // (any new incentive that is not directly on curve gauges)
File: convex-platform/contracts/contracts/BaseRewardPool.sol 10: _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ /
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 10: _\ \ / // // _ \/ __// _ \/ -_)/ __// / \ \ / 170: // require(amount > 0, 'VirtualDepositRewardPool: Cannot stake 0');
File: convex-platform/contracts/contracts/Booster.sol 123: /// SETTER SECTION /// 228: // Distributed directly 301: /// END SETTER SECTION /// 340: // voteproxy so it can grab the incentive tokens off the contract after claiming rewards 341: // reward factory so that stashes can make new extra reward contracts if a new incentive is added to the gauge 463: // if shutdown tokens will be in this contract 594: // LockIncentive = cvxCrv stakers (currently 10%) 596: // StakerIncentive = cvx stakers (currently 5%) 598: // CallIncentive = caller of this contract (currently 1%) 601: // Treasury = vlCVX (currently 1%)
There are 12 instances of this issue:
File: contracts/AuraClaimZap.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraMinter.sol 2: pragma solidity ^0.8.11;
File: contracts/ExtraRewardsDistributor.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraMerkleDrop.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraPenaltyForwarder.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraBalRewardPool.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraLocker.sol 2: pragma solidity ^0.8.11;
File: contracts/ClaimFeesHelper.sol 2: pragma solidity ^0.8.11;
File: contracts/Aura.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraStakingProxy.sol 2: pragma solidity ^0.8.11;
File: contracts/AuraVestedEscrow.sol 2: pragma solidity ^0.8.11;
File: contracts/BalLiquidityProvider.sol 2: pragma solidity ^0.8.11;
There are 29 instances of this issue:
File: contracts/AuraClaimZap.sol /// @audit crvCvx 121: * @param depositCrvMaxAmount The max amount of CRV to deposit if converting to crvCvx /// @audit upto 195: //lock upto given amount of crv and stake
File: contracts/ExtraRewardsDistributor.sol /// @audit constructoor 33: * @dev Simple constructoor
File: contracts/AuraBalRewardPool.sol /// @audit constructoor 55: * @dev Simple constructoor
File: contracts/AuraLocker.sol /// @audit dont 393: //dont delete, just set next index /// @audit futher 672: //stop now as no futher checks matter
File: contracts/Aura.sol /// @audit dont 95: // dont error just return. if a shutdown happens, rewards on old system
File: contracts/AuraStakingProxy.sol /// @audit convers 24: * @notice Receives CRV from the Booster as overall reward, then convers to cvxCRV and distributes to vlCVX holders.
File: contracts/AuraVestedEscrow.sol /// @audit Arrary 94: * @param _amount Arrary of amount of rewardTokens to vest
File: convex-platform/contracts/contracts/ConvexMasterChef.sol /// @audit muliplier 55: // Bonus muliplier for early cvx makers. /// @audit vairables 177: // Update reward vairables for all pools. Be careful of gas spending!
File: convex-platform/contracts/contracts/CrvDepositor.sol /// @audit ammount 117: //increase ammount /// @audit isnt 163: * the cvx reward contract isnt costly to claim rewards.
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol /// @audit Executoor 32: * @param _owner Executoor
File: convex-platform/contracts/contracts/interfaces/IERC4626.sol /// @audit redeemption 114: /// the effects of their redeemption at the current block,
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol /// @audit Guage 19: * On the Curve Guage. This tells the Gauge where to send rewards. The Booster crafts the calldata for this /// @audit dont 48: //use mapping+array so that we dont have to loop check each time setToken is called /// @audit Guage 92: * Guage rewards are sent directly to this stash even though the Curve method claim_rewards /// @audit guages 93: * is being called by the VoterProxy. This is because Curves guages have the ability to redirect
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol /// @audit cxvCRV 78: * which tracks the virtual balance of cxvCRV stakers and distributes their share /// @audit diributes 163: * actually hold any staked tokens it just diributes reward tokens
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol /// @audit redeemption 193: * the effects of their redeemption at the current block,
File: convex-platform/contracts/contracts/Booster.sol /// @audit vcxCrv 215: * @dev This creates a secondary (VirtualRewardsPool) rewards contract for the vcxCrv staking contract /// @audit ot 372: * @notice Shuts down the WHOLE SYSTEM by withdrawing all the LP tokens ot here and then allowing /// @audit seperate 411: //some gauges claim rewards when depositing, stash them in a seperate contract until next claim /// @audit seperate 468: //some gauges claim rewards when withdrawing, stash them in a seperate contract until next claim /// @audit Repsonsible 569: * Repsonsible for collecting the crv from gauge, and then redistributing to the correct place. /// @audit Repsonsible 631: * Repsonsible for collecting the crv from gauge, and then redistributing to the correct place.
File: convex-platform/contracts/contracts/RewardFactory.sol /// @audit guages 18: * - BaseRewardPool handles CRV rewards for guages
There are 6 instances of this issue:
File: contracts/Interfaces.sol
File: convex-platform/contracts/contracts/Interfaces.sol
File: convex-platform/contracts/contracts/interfaces/IGaugeController.sol
File: convex-platform/contracts/contracts/interfaces/IProxyFactory.sol
File: convex-platform/contracts/contracts/interfaces/IRewardHook.sol
File: convex-platform/contracts/contracts/interfaces/IRewarder.sol
There are 21 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol /// @audit Missing: '@return' 185 * @param _token Reward token address 186 */ 187: function claimableRewards(address _account, address _token) external view returns (uint256) { /// @audit Missing: '@return' 196 * @param _epoch The epoch to check for rewards 197 */ 198 function claimableRewardsAtEpoch( 199 address _account, 200 address _token, 201 uint256 _epoch 202: ) external view returns (uint256) { /// @audit Missing: '@return' 211 * @param _startIndex Index of rewardEpochs[_token] to start checking for rewards from 212 */ 213 function _allClaimableRewards( 214 address _account, 215 address _token, 216 uint256 _startIndex 217: ) internal view returns (uint256, uint256) { /// @audit Missing: '@return' 248 * @param _epoch The epoch to check for rewards 249 */ 250 function _claimableRewards( 251 address _account, 252 address _token, 253 uint256 _epoch 254: ) internal view returns (uint256) {
File: contracts/AuraBalRewardPool.sol /// @audit Missing: '@param _startDelay' 54 /** 55 * @dev Simple constructoor 56 * @param _stakingToken Pool LP token 57 * @param _rewardToken $AURA 58 * @param _rewardManager Depositor 59 * @param _auraLocker $AURA lock contract 60 * @param _penaltyForwarder Address to which penalties are sent 61 */ 62 constructor( 63 address _stakingToken, 64 address _rewardToken, 65 address _rewardManager, 66 address _auraLocker, 67 address _penaltyForwarder, 68: uint256 _startDelay /// @audit Missing: '@return' 174 * @param _lock Lock the rewards? If false, takes a 20% haircut 175 */ 176: function getReward(bool _lock) public updateReward(msg.sender) returns (bool) {
File: contracts/AuraVestedEscrow.sol /// @audit Missing: '@return' 136 * @param _recipient Recipient to lookup 137 */ 138: function available(address _recipient) public view returns (uint256) { /// @audit Missing: '@return' 145 * @param _recipient Recipient to lookup 146 */ 147: function remaining(address _recipient) public view returns (uint256) { /// @audit Missing: '@return' 155 * @param _time Timestamp to check vesting amount for 156 */ 157: function _totalVestedOf(address _recipient, uint256 _time) internal view returns (uint256 total) {
File: convex-platform/contracts/contracts/CrvDepositor.sol /// @audit Missing: '@param _daoOperator' 41 /** 42 * @param _staker CVX VoterProxy (0x989AEb4d175e16225E39E87d0D97A3360524AD80) 43 * @param _minter cvxCRV token (0x62B9c7356A2Dc64a1969e19C23e4f579F9810Aa7) 44 * @param _crvBpt crvBPT for veCRV deposits 45 * @param _escrow CRV VotingEscrow (0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2) 46 */ 47 constructor( 48 address _staker, 49 address _minter, 50 address _crvBpt, 51 address _escrow, 52: address _daoOperator /// @audit Missing: '@param to' 159 /** 160 * @notice Deposit crvBpt for cvxCrv 161 * @dev Can locking immediately or defer locking to someone else by paying a fee. 162 * while users can choose to lock or defer, this is mostly in place so that 163 * the cvx reward contract isnt costly to claim rewards. 164 * @param _amount Units of CRV to deposit 165 * @param _lock Lock now? or pay ~1% to the locker 166 * @param _stakeAddress Stake in cvxCrv staking? 167 */ 168: function depositFor(address to, uint256 _amount, bool _lock, address _stakeAddress) public {
File: convex-platform/contracts/contracts/VoterProxy.sol /// @audit Missing: '@return' 92 * @param _mintr Token minter address for claiming rewards 93 */ 94: function setSystemConfig(address _gaugeController, address _mintr) external returns (bool) { /// @audit Missing: '@param bytes' 143 /** 144 * @notice Verifies that the hash is valid 145 * @dev Snapshot Hub will call this function when a vote is submitted using 146 * snapshot.js on behalf of this contract. Snapshot Hub will call this 147 * function with the hash and the signature of the vote that was cast. 148 * @param _hash Hash of the message that was sent to Snapshot Hub to cast a vote 149 * @return EIP1271 magic value if the signature is value 150 */ 151: function isValidSignature(bytes32 _hash, bytes memory) public view returns (bytes4) { /// @audit Missing: '@return' 164 * @param _gauge Gauge contract to deposit to 165 */ 166: function deposit(address _token, address _gauge) external returns(bool){ /// @audit Missing: '@return' 204 * @param _amount Amount of LP token to withdraw 205 */ 206: function withdraw(address _token, address _gauge, uint256 _amount) public returns(bool){ /// @audit Missing: '@return' 221 * @param _gauge Gauge for this LP token 222 */ 223: function withdrawAll(address _token, address _gauge) external returns(bool){ /// @audit Missing: '@return' 240 * @param _unlockTime Timestamp to unlock (max is 4 years) 241 */ 242: function createLock(uint256 _value, uint256 _unlockTime) external returns(bool){ /// @audit Missing: '@return' 263 * @param _value Timestamp to increase locking to 264 */ 265: function increaseTime(uint256 _value) external returns(bool){ /// @audit Missing: '@return' 331 * @param _token LP token to claim fees for 332 */ 333: function claimFees(address _distroContract, address _token) external returns (uint256){
File: convex-platform/contracts/contracts/BoosterOwner.sol /// @audit Missing: '@param _seal' 62 /** 63 * @param _owner Owner (e.g. CVX multisig) 64 * @param _poolManager PoolManager (e.g. PoolManagerSecondaryProxy or 0xD20904e5916113D11414F083229e9C8C6F91D1e1) 65 * @param _booster The booster (e.g. 0xF403C135812408BFbE8713b5A23a04b3D48AAE31) 66 * @param _stashFactory Creates stashes (e.g. 0x884da067B66677e72530df91eabb6e3CE69c2bE4) 67 * @param _rescueStash Rescues tokens for subsequent vlCVX redistribution (e.g. 0x01140351069af98416cC08b16424b9E765436531) 68 */ 69 constructor( 70 address _owner, 71 address _poolManager, 72 address _booster, 73 address _stashFactory, 74 address _rescueStash, 75: bool _seal
File: convex-platform/contracts/contracts/BaseRewardPool.sol /// @audit Missing: '@return' 283 * @param _claimExtras Get the child rewards too? 284 */ 285: function getReward(address _account, bool _claimExtras) public updateReward(_account) returns(bool){
indexed
fieldsEach event
should use three indexed
fields if there are three or more fields
There are 66 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol 28: event RewardAdded(address indexed token, uint256 indexed epoch, uint256 reward); 29: event RewardPaid(address indexed user, address indexed token, uint256 reward, uint256 index); 30: event RewardForfeited(address indexed user, address indexed token, uint256 index);
File: contracts/AuraMerkleDrop.sol 36: event DaoSet(address newDao); 37: event RootSet(bytes32 newRoot); 39: event ExpiredWithdrawn(uint256 amount); 40: event LockerSet(address newLocker); 41: event Claimed(address addr, uint256 amt, bool locked); 42: event PenaltyForwarded(uint256 amount);
File: contracts/AuraPenaltyForwarder.sol 22: event Forwarded(uint256 amount);
File: contracts/AuraBalRewardPool.sol 48: event RewardAdded(uint256 reward); 49: event Staked(address indexed user, uint256 amount); 50: event Withdrawn(address indexed user, uint256 amount); 51: event RewardPaid(address indexed user, uint256 reward, bool locked); 52: event PenaltyForwarded(uint256 amount);
File: contracts/AuraLocker.sol 126: event Recovered(address _token, uint256 _amount); 127: event RewardPaid(address indexed _user, address indexed _rewardsToken, uint256 _reward); 128: event Staked(address indexed _user, uint256 _paidAmount, uint256 _lockedAmount); 129: event Withdrawn(address indexed _user, uint256 _amount, bool _relocked); 130: event KickReward(address indexed _user, address indexed _kicked, uint256 _reward); 131: event RewardAdded(address indexed _token, uint256 _reward); 133: event KickIncentiveSet(uint256 rate, uint256 delay);
File: contracts/AuraStakingProxy.sol 53: event RewardsDistributed(address indexed token, uint256 amount); 54: event CallIncentiveChanged(uint256 incentive);
File: contracts/AuraVestedEscrow.sol 38: event Funded(address indexed recipient, uint256 reward); 40: event Claim(address indexed user, uint256 amount, bool locked);
File: contracts/BalLiquidityProvider.sol 24: event LiquidityProvided(uint256[] input, uint256 output); 25: event MinPairAmountChanged(uint256 oldMinPairAmount, uint256 newMinPairAmount);
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 69: event Deposit(address indexed user, uint256 indexed pid, uint256 amount); 70: event Withdraw(address indexed user, uint256 indexed pid, uint256 amount); 71: event RewardPaid(address indexed user, uint256 indexed pid, uint256 amount); 72 event EmergencyWithdraw( 73 address indexed user, 74 uint256 indexed pid, 75 uint256 amount 76: );
File: convex-platform/contracts/contracts/StashFactoryV2.sol 31: event StashCreated(address stash, uint256 stashVersion);
File: convex-platform/contracts/contracts/TokenFactory.sol 24: event DepositTokenCreated(address token, address lpToken);
File: convex-platform/contracts/contracts/VoterProxy.sol 41: event VoteSet(bytes32 hash, bool valid);
File: convex-platform/contracts/contracts/BoosterOwner.sol 56: event ShutdownStarted(uint256 executableTimestamp); 58: event TransferOwnership(address pendingOwner); 59: event AcceptedOwnership(address newOwner);
File: convex-platform/contracts/contracts/interfaces/IERC4626.sol 15 event Deposit( 16 address indexed sender, 17 address indexed receiver, 18 uint256 assets, 19 uint256 shares 20: ); 24 event Withdraw( 25 address indexed sender, 26 address indexed receiver, 27 uint256 assets, 28 uint256 shares 29: );
File: convex-platform/contracts/contracts/BaseRewardPool.sol 86: event RewardAdded(uint256 reward); 87: event Staked(address indexed user, uint256 amount); 88: event Withdrawn(address indexed user, uint256 amount); 89: event RewardPaid(address indexed user, uint256 reward);
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 100: event RewardAdded(uint256 reward); 101: event Staked(address indexed user, uint256 amount); 102: event Withdrawn(address indexed user, uint256 amount); 103: event RewardPaid(address indexed user, uint256 reward);
File: convex-platform/contracts/contracts/Booster.sol 69: event Deposited(address indexed user, uint256 indexed poolid, uint256 amount); 70: event Withdrawn(address indexed user, uint256 indexed poolid, uint256 amount); 72: event PoolAdded(address lpToken, address gauge, address token, address rewardPool, address stash, uint256 pid); 73: event PoolShutdown(uint256 poolId); 75: event OwnerUpdated(address newOwner); 76: event FeeManagerUpdated(address newFeeManager); 77: event PoolManagerUpdated(address newPoolManager); 78: event FactoriesUpdated(address rewardFactory, address stashFactory, address tokenFactory); 79: event ArbitratorUpdated(address newArbitrator); 80: event VoteDelegateUpdated(address newVoteDelegate); 81: event RewardContractsUpdated(address lockRewards, address stakerRewards); 82: event FeesUpdated(uint256 lockIncentive, uint256 stakerIncentive, uint256 earmarkIncentive, uint256 platformFee); 83: event TreasuryUpdated(address newTreasury); 84: event FeeInfoUpdated(address feeDistro, address lockFees, address feeToken); 85: event FeeInfoChanged(address feeDistro, bool active);
File: convex-platform/contracts/contracts/RewardFactory.sol 31: event RewardPoolCreated(address rewardPool, uint256 _pid, address depositToken); 32: event TokenRewardPoolCreated(address rewardPool, address token, address mainRewards, address operator); 34: event AccessChanged(address stash, bool hasAccess);
#0 - itsmetechjay
2022-05-23T20:40:58Z
Warden created this issue as a placeholder because their submission was too large for the contest form. They then emailed their md file to our team on 05/23/2022 at 4:17 AM central time. I've updated this issue with their md file content.
#1 - liveactionllama
2022-07-14T20:55:53Z
Per discussion with @dmvt (judge), they agree with the risk ratings listed by the warden in this submission.
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, BowTiedWardens, CertoraInc, DavidGialdi, FSchmoede, Fitraldys, Funen, GimelSec, Hawkeye, JC, Kaiziron, Kthere, MaratCerby, MiloTruck, NoamYakov, QuantumBrief, Randyyy, Ruhum, SmartSek, SooYa, Tadashi, TerrierLover, Tomio, UnusualTurtle, WatchPug, Waze, _Adam, antonttc, asutorufos, bobirichman, c3phas, catchup, csanuragjain, cthulhu_cult, defsec, delfin454000, ellahi, fatherOfBlocks, hansfriese, hyh, jayjonah8, joestakey, kenta, marcopaladin, mics, minhquanym, orion, oyc_109, reassor, rfa, robee, sach1r0, samruna, sashik_eth, sikorico, simon135, unforgiven, z3s, zmj
814.8921 USDC - $814.89
Issue | Instances | |
---|---|---|
1 | Remove or replace unused state variables | 1 |
2 | Multiple address mappings can be combined into a single mapping of an address to a struct , where appropriate | 8 |
3 | State variables only set in the constructor should be declared immutable | 6 |
4 | State variables can be packed into fewer storage slots | 3 |
5 | Using calldata instead of memory for read-only arguments in external functions saves gas | 6 |
6 | State variables should be cached in stack variables rather than re-reading them from storage | 60 |
7 | <x> += <y> costs more gas than <x> = <x> + <y> for state variables | 5 |
8 | internal functions only called once can be inlined to save gas | 4 |
9 | <array>.length should not be looked up in every loop of a for -loop | 13 |
10 | ++i /i++ should be unchecked{++i} /unchecked{i++} when it is not possible for them to overflow, as is the case when used in for - and while -loops | 13 |
11 | require() /revert() strings longer than 32 bytes cost extra gas | 1 |
12 | keccak256() should only need to be called on a specific string literal once | 1 |
13 | Not using the named return variables when a function returns, wastes deployment gas | 10 |
14 | Using bool s for storage incurs overhead | 18 |
15 | Use a more recent version of solidity | 28 |
16 | Using > 0 costs more gas than != 0 when used on a uint in a require() statement | 23 |
17 | It costs more gas to initialize variables to zero than to let the default of zero be applied | 26 |
18 | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) | 24 |
19 | Splitting require() statements that use && saves gas | 15 |
20 | Usage of uints /ints smaller than 32 bytes (256 bits) incurs overhead | 99 |
21 | abi.encode() is less efficient than abi.encodePacked() | 2 |
22 | Using private rather than public for constants, saves gas | 30 |
23 | Don't compare boolean expressions to boolean literals | 9 |
24 | Don't use SafeMath once the solidity version is 0.8.0 or greater | 2 |
25 | Duplicated require() /revert() checks should be refactored to a modifier or function | 32 |
26 | Multiplication/division by two should use bit shifting | 5 |
27 | Stack variable used as a cheaper cache for a state variable is only used once | 1 |
28 | require() or revert() statements that check input arguments should be at the top of the function | 11 |
29 | Empty blocks should be removed or emit something | 6 |
30 | Use custom errors rather than revert() /require() strings to save deployment gas | 101 |
31 | Functions guaranteed to revert when called by normal users can be marked payable | 37 |
32 | public functions not called by the contract should be declared external instead | 18 |
Total: 618 instances over 32 issues
Saves a storage slot. If the variable is assigned a non-zero value, saves Gsset (20000 gas). If it's assigned a zero value, saves Gsreset (2900 gas). If the variable remains unassigned, there is no gas savings unless the variable is public
, in which case the compiler-generated non-payable getter deployment cost is saved. If the state variable is overriding an interface's public function, mark the variable as constant
or immutable
so that it does not use a storage slot
There is 1 instance of this issue:
File: convex-platform/contracts/contracts/RewardFactory.sol #1 28: mapping(address => uint256[]) public rewardActiveList;
address
mappings can be combined into a single mapping
of an address
to a struct
, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot
There are 8 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol 20 mapping(address => mapping(uint256 => uint256)) public rewardData; 21 // token -> epochList 22 mapping(address => uint256[]) public rewardEpochs; 23 // token -> account -> last claimed epoch index 24: mapping(address => mapping(address => uint256)) public userClaims;
File: contracts/AuraBalRewardPool.sol 44 mapping(address => uint256) public userRewardPerTokenPaid; 45 mapping(address => uint256) public rewards; 46: mapping(address => uint256) private _balances;
File: contracts/AuraLocker.sol 91 mapping(address => Balances) public balances; 92 mapping(address => LockedBalance[]) public userLocks; 93 94 // Voting 95 // Stored delegations 96 mapping(address => address) private _delegates; 97 // Checkpointed votes 98 mapping(address => DelegateeCheckpoint[]) private _checkpointedVotes; 99 // Delegatee balances (user -> unlock timestamp -> amount) 100: mapping(address => mapping(uint256 => uint256)) public delegateeUnlocks;
File: contracts/AuraVestedEscrow.sol 35 mapping(address => uint256) public totalLocked; 36: mapping(address => uint256) public totalClaimed;
File: convex-platform/contracts/contracts/VoterProxy.sol 35 mapping (address => bool) private stashPool; 36: mapping (address => bool) private protectedTokens;
File: convex-platform/contracts/contracts/BaseRewardPool.sol 80 mapping(address => uint256) public userRewardPerTokenPaid; 81 mapping(address => uint256) public rewards; 82: mapping(address => uint256) private _balances;
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 97 mapping(address => uint256) public userRewardPerTokenPaid; 98: mapping(address => uint256) public rewards;
File: convex-platform/contracts/contracts/RewardFactory.sol 27 mapping (address => bool) private rewardAccess; 28: mapping(address => uint256[]) public rewardActiveList;
immutable
Avoids a Gsset (20000 gas) in the constructor, and replaces each Gwarmacces (100 gas) with a PUSH32
(3 gas).
There are 6 instances of this issue:
File: contracts/AuraLocker.sol 117: string private _name; 118: string private _symbol;
File: contracts/ClaimFeesHelper.sol 23: IFeeDistributor public feeDistro;
File: convex-platform/contracts/contracts/TokenFactory.sol 21: string public namePostfix; 22: string public symbolPrefix;
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol 26: address public override asset;
If variables occupying the same slot are both written the same function or by the constructor, avoids a separate Gsset (20000 gas). Reads of the variables can also be cheaper
There are 3 instances of this issue:
File: convex-platform/contracts/contracts/CrvDepositor.sol #1 /// @audit Variable ordering with 5 slots instead of the current 6: uint256(32):lockIncentive, uint256(32):incentiveCrv, uint256(32):unlockTime, address(20):feeManager, bool(1):cooldown, address(20):daoOperator 29: uint256 public lockIncentive = 10; //incentive to users who spend gas to lock crvBpt
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol #2 /// @audit Variable ordering with 9 slots instead of the current 10: uint256(32):pid, mapping(32):historicalRewards, mapping(32):tokenInfo, address[](32):tokenList, address(20):operator, bool(1):hasRedirected, bool(1):hasCurveRewards, address(20):staker, address(20):gauge, address(20):rewardFactory, address(20):rewardHook 33: uint256 public pid;
File: convex-platform/contracts/contracts/Booster.sol #3 /// @audit Variable ordering with 18 slots instead of the current 19: uint256(32):lockIncentive, uint256(32):stakerIncentive, uint256(32):earmarkIncentive, uint256(32):platformFee, mapping(32):feeTokens, user-defined[](32):poolInfo, mapping(32):gaugeMap, address(20):owner, bool(1):isShutdown, address(20):feeManager, address(20):poolManager, address(20):rewardFactory, address(20):stashFactory, address(20):tokenFactory, address(20):rewardArbitrator, address(20):voteDelegate, address(20):treasury, address(20):stakerRewards, address(20):lockRewards 26: uint256 public lockIncentive = 825; //incentive to crv stakers
calldata
instead of memory
for read-only arguments in external
functions saves gasWhen a function with a memory
array is called externally, the abi.decode()
step has to use a for-loop to copy each index of the calldata
to the memory
index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length
). Using calldata
directly, obliviates the need for such a loop in the contract code and runtime execution. Structs have the same overhead as an array of length one
There are 6 instances of this issue:
File: contracts/Interfaces.sol 17: function getTimeWeightedAverage(OracleAverageQuery[] memory queries) 79: JoinPoolRequest memory request 83: SingleSwap memory singleSwap, 84: FundManagement memory funds, 93: ExitPoolRequest memory request
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 68: function setUsedAddress(address[] memory usedList) external onlyOwner{
The instances below point to the second+ access of a state variable within a function. Caching will replace each Gwarmaccess (100 gas) with a much cheaper stack read. Less obvious fixes/optimizations include having local storage variables of mappings within state variable mappings or mappings within state variable structs, having local storage variables of structs within mappings, having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.
There are 60 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol /// @audit rewardEpochs 74: require(len == 0 || rewardEpochs[_token][len - 1] < _epoch, "Cannot backdate to this epoch"); /// @audit rewardEpochs 102: if (len == 0 || rewardEpochs[_token][len - 1] < _epoch) { /// @audit rewardEpochs 103: rewardEpochs[_token].push(_epoch); /// @audit rewardEpochs 235: if (rewardEpochs[_token][i] < latestEpoch) { /// @audit rewardEpochs 236: claimableTokens += _claimableRewards(_account, _token, rewardEpochs[_token][i]); /// @audit userClaims 175: userClaims[_token][msg.sender] = _index + 1;
File: contracts/AuraMerkleDrop.sol /// @audit dao 100: aura.safeTransfer(dao, amt); /// @audit merkleRoot 126: require(MerkleProof.verify(_proof, merkleRoot, leaf), "invalid proof"); /// @audit auraLocker 132: aura.safeApprove(address(auraLocker), _amount); /// @audit auraLocker 133: auraLocker.lock(msg.sender, _amount); /// @audit startTime 70: expiryTime = startTime + _expiresAfter;
File: contracts/AuraLocker.sol /// @audit rewardData 199: rewardData[_rewardsToken].lastUpdateTime = uint32(block.timestamp); /// @audit rewardData 200: rewardData[_rewardsToken].periodFinish = uint32(block.timestamp); /// @audit lockedSupply 812: .div(lockedSupply) /// @audit userLocks 278: if (idx == 0 || userLocks[_account][idx - 1].unlockTime < unlockTime) { /// @audit kickRewardPerEpoch 422: uint256 rRate = AuraMath.min(kickRewardPerEpoch.mul(epochsover + 1), denominator);
File: contracts/ClaimFeesHelper.sol /// @audit feeDistro 48: feeDistro.claimToken(voterProxy, _token); /// @audit feeDistro 52: feeDistro.claimToken(voterProxy, _token);
File: contracts/AuraStakingProxy.sol /// @audit keeper 172: require(msg.sender == keeper, "!auth"); /// @audit crvDepositorWrapper 148: IERC20(crv).safeApprove(crvDepositorWrapper, type(uint256).max); /// @audit crvDepositorWrapper 179: ICrvDepositor(crvDepositorWrapper).deposit(crvBal, minOut, true, address(0)); /// @audit rewards 151: IERC20(cvxCrv).safeApprove(rewards, type(uint256).max); /// @audit rewards 216: _token.safeApprove(rewards, type(uint256).max); /// @audit rewards 219: IAuraLocker(rewards).notifyRewardAmount(address(_token), bal); /// @audit pendingOwner 119: owner = pendingOwner;
File: contracts/AuraVestedEscrow.sol /// @audit admin 123: rewardToken.safeTransfer(admin, delta); /// @audit auraLocker 186: rewardToken.safeApprove(address(auraLocker), claimable); /// @audit auraLocker 187: auraLocker.lock(_recipient, claimable);
File: convex-platform/contracts/contracts/StashFactoryV2.sol /// @audit v1Implementation 68: address stash = IProxyFactory(proxyFactory).clone(v1Implementation); /// @audit v2Implementation 75: address stash = IProxyFactory(proxyFactory).clone(v2Implementation); /// @audit v3Implementation 61: address stash = IProxyFactory(proxyFactory).clone(v3Implementation);
File: convex-platform/contracts/contracts/CrvDepositor.sol /// @audit incentiveCrv 146: ITokenMinter(minter).mint(msg.sender,incentiveCrv); /// @audit incentiveCrv 177: _amount = _amount.add(incentiveCrv);
File: convex-platform/contracts/contracts/VoterProxy.sol /// @audit rewardDeposit 194: _asset.safeApprove(rewardDeposit, balance); /// @audit rewardDeposit 195: IRewardDeposit(rewardDeposit).addReward(address(_asset), balance); /// @audit operator 107: require(operator == address(0) || IDeposit(operator).isShutdown() == true, "needs shutdown"); /// @audit operator 311: IERC20(crv).safeTransfer(operator, _balance); /// @audit operator 337: IERC20(_token).safeTransfer(operator, _balance);
File: convex-platform/contracts/contracts/BoosterOwner.sol /// @audit owner 99: emit AcceptedOwnership(owner); /// @audit pendingowner 97: owner = pendingowner; /// @audit forceTimestamp 165: emit ShutdownStarted(forceTimestamp);
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol /// @audit pid 111: IDeposit(operator).claimRewards(pid,gauge); /// @audit operator 104: IDeposit(operator).setGaugeRedirect(pid); /// @audit operator 111: IDeposit(operator).claimRewards(pid,gauge); /// @audit operator 209: IERC20(token).safeTransfer(operator, amount); /// @audit rewardHook 116: try IRewardHook(rewardHook).onRewardClaim(){
File: convex-platform/contracts/contracts/BaseRewardPool.sol /// @audit periodFinish 336: uint256 elapsedTime = block.timestamp.sub(periodFinish.sub(duration)); /// @audit periodFinish 359: uint256 remaining = periodFinish.sub(block.timestamp);
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol /// @audit periodFinish 224: uint256 elapsedTime = block.timestamp.sub(periodFinish.sub(duration)); /// @audit periodFinish 244: uint256 remaining = periodFinish.sub(block.timestamp);
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol /// @audit asset 40: IERC20(asset).safeApprove(operator_, type(uint256).max);
File: convex-platform/contracts/contracts/Booster.sol /// @audit platformFee 604: uint256 _platform = crvBal.mul(platformFee).div(FEE_DENOMINATOR); /// @audit rewardFactory 238: address rewards = IRewardFactory(rewardFactory).CreateTokenRewards(_feeToken, lockRewards, address(this)); /// @audit rewardFactory 345: IRewardFactory(rewardFactory).setAccess(stash,true); /// @audit treasury 606: IERC20(crv).safeTransfer(treasury, _platform); /// @audit lockRewards 232: rewards: lockRewards, /// @audit lockRewards 235: emit FeeInfoUpdated(_feeDistro, lockRewards, crv); /// @audit lockRewards 238: address rewards = IRewardFactory(rewardFactory).CreateTokenRewards(_feeToken, lockRewards, address(this)); /// @audit lockRewards 622: IRewards(lockRewards).queueNewRewards(_lockIncentive); /// @audit poolInfo 328: poolInfo.push(
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 5 instances of this issue:
File: contracts/AuraMerkleDrop.sol 137: pendingPenalty += penalty;
File: contracts/AuraBalRewardPool.sol 184: pendingPenalty += penalty;
File: contracts/AuraLocker.sol 363: lockedSupply -= amt;
File: contracts/Aura.sol 130: minterMinted += _amount;
File: contracts/AuraVestedEscrow.sol 66: require(totalTime >= 16 weeks, "!short");
internal
functions only called once can be inlined to save gasNot inlining costs 20 to 40 gas because of two extra JUMP
instructions and additional stack operations needed for function calls.
There are 4 instances of this issue:
File: contracts/AuraClaimZap.sol #1 171 function _claimExtras( // solhint-disable-line 172 uint256 depositCrvMaxAmount, 173 uint256 minAmountOut, 174 uint256 depositCvxMaxAmount, 175 uint256 removeCrvBalance, 176 uint256 removeCvxBalance, 177: uint256 options
File: convex-platform/contracts/contracts/VoterProxy.sol #2 230: function _withdrawSome(address _gauge, uint256 _amount) internal returns (uint256) {
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol #3 124 function checkForNewRewardTokens() internal { 125: for(uint256 i = 0; i < maxRewards; i++){
File: convex-platform/contracts/contracts/Booster.sol #4 572: function _earmarkRewards(uint256 _pid) internal {
<array>.length
should not be looked up in every loop of a for
-loopThe overheads outlined below are PER LOOP, excluding the first loop
MLOAD
(3 gas)CALLDATALOAD
(3 gas)Caching the length changes each of these to a DUP<N>
(3 gas), and gets rid of the extra DUP<N>
needed to store the stack offset
There are 13 instances of this issue:
File: contracts/AuraClaimZap.sol 143: for (uint256 i = 0; i < rewardContracts.length; i++) { 147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { 151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
File: contracts/AuraLocker.sol 696: for (uint256 i = nextUnlockIndex; i < locks.length; i++) {
File: contracts/AuraVestedEscrow.sol 100: for (uint256 i = 0; i < _recipient.length; i++) {
File: convex-platform/contracts/contracts/ArbitartorVault.sol 49: for(uint256 i = 0; i < _toPids.length; i++){
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 69: for(uint i=0; i < usedList.length; i++){
File: convex-platform/contracts/contracts/BaseRewardPool.sol 214: for(uint i=0; i < extraRewards.length; i++){ 230: for(uint i=0; i < extraRewards.length; i++){ 262: for(uint i=0; i < extraRewards.length; i++){ 296: for(uint i=0; i < extraRewards.length; i++){
File: convex-platform/contracts/contracts/Booster.sol 379: for(uint i=0; i < poolInfo.length; i++){ 538: for(uint256 i = 0; i < _gauge.length; i++){
++i
/i++
should be unchecked{++i}
/unchecked{i++}
when it is not possible for them to overflow, as is the case when used in for
- and while
-loopsThe unchecked
keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP
There are 13 instances of this issue:
File: contracts/AuraClaimZap.sol 143: for (uint256 i = 0; i < rewardContracts.length; i++) { 147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { 151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
File: contracts/ExtraRewardsDistributor.sol 233: for (uint256 i = epochIndex; i < tokenEpochs; i++) {
File: contracts/AuraLocker.sol 174: for (uint256 i = 0; i < rewardTokensLength; i++) { 306: for (uint256 i; i < rewardTokensLength; i++) { 410: for (uint256 i = nextUnlockIndex; i < length; i++) { 664: for (uint256 i = locksLength; i > 0; i--) { 696: for (uint256 i = nextUnlockIndex; i < locks.length; i++) { 726: for (uint256 i = epochIndex + 1; i > 0; i--) { 773: for (uint256 i = 0; i < userRewardsLength; i++) {
File: contracts/AuraVestedEscrow.sol 100: for (uint256 i = 0; i < _recipient.length; i++) {
File: contracts/BalLiquidityProvider.sol 51: for (uint256 i = 0; i < 2; i++) {
require()
/revert()
strings longer than 32 bytes cost extra gasThere is 1 instance of this issue:
File: contracts/AuraLocker.sol #1 197: require(_rewardsToken != address(stakingToken), "Cannot add StakingToken as reward");
keccak256()
should only need to be called on a specific string literal onceIt should be saved to an immutable variable, and the variable used instead. If the hash is being used as a part of a function selector, the cast to bytes4
should also only be done once
There is 1 instance of this issue:
File: convex-platform/contracts/contracts/Booster.sol #1 562: bytes memory data = abi.encodeWithSelector(bytes4(keccak256("set_rewards_receiver(address)")), stash);
There are 10 instances of this issue:
File: contracts/AuraLocker.sol 603: return 0; 649: return balanceAtEpochOf(findEpochId(block.timestamp), _user); 708: return (userBalance.locked, unlockable, locked, lockData); 708: return (userBalance.locked, unlockable, locked, lockData); 708: return (userBalance.locked, unlockable, locked, lockData); 708: return (userBalance.locked, unlockable, locked, lockData); 713: return totalSupplyAtEpoch(findEpochId(block.timestamp)); 740: return _time.sub(epochs[0].date).div(rewardsDuration);
File: contracts/AuraVestedEscrow.sol 159: return 0;
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol 180: return convertToShares(assets);
bool
s for storage incurs overhead// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27
Use uint256(1)
and uint256(2)
for true/false
There are 18 instances of this issue:
File: contracts/AuraMerkleDrop.sol 34: mapping(address => bool) public hasClaimed;
File: contracts/AuraLocker.sol 77: mapping(address => mapping(address => bool)) public rewardDistributors; 114: bool public isShutdown = false;
File: contracts/AuraVestedEscrow.sol 33: bool public initialised = false;
File: convex-platform/contracts/contracts/PoolManagerV3.sol 22: bool public protectAddPool;
File: convex-platform/contracts/contracts/CrvDepositor.sol 39: bool public cooldown;
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 24: bool public isShutdown; 26: mapping(address => bool) public usedMap;
File: convex-platform/contracts/contracts/VoterProxy.sol 35: mapping (address => bool) private stashPool; 36: mapping (address => bool) private protectedTokens; 37: mapping (bytes32 => bool) private votes;
File: convex-platform/contracts/contracts/BoosterOwner.sol 49: bool public isSealed; 53: bool public isForceTimerStarted;
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 40: bool public hasRedirected; 41: bool public hasCurveRewards;
File: convex-platform/contracts/contracts/Booster.sol 54: bool public isShutdown; 67: mapping(address => bool) public gaugeMap;
File: convex-platform/contracts/contracts/RewardFactory.sol 27: mapping (address => bool) private rewardAccess;
Use a solidity version of at least 0.8.0 to get overflow protection without SafeMath
Use a solidity version of at least 0.8.2 to get compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require()
strings
Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
There are 28 instances of this issue:
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 3: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/RewardHook.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/Interfaces.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/PoolManagerProxy.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/DepositToken.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/cCrv.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/StashFactoryV2.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/PoolManagerV3.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/ArbitartorVault.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/CrvDepositor.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/TokenFactory.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/VoterProxy.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/BoosterOwner.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/IGaugeController.sol 3: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/MathUtil.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/IProxyFactory.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/IERC4626.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/IRewardHook.sol 3: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/BoringMath.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/interfaces/IRewarder.sol 3: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/ProxyFactory.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/BaseRewardPool.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/BaseRewardPool4626.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/Booster.sol 2: pragma solidity 0.6.12;
File: convex-platform/contracts/contracts/RewardFactory.sol 2: pragma solidity 0.6.12;
> 0
costs more gas than != 0
when used on a uint
in a require()
statementThis change saves 6 gas per instance
There are 23 instances of this issue:
File: contracts/AuraMerkleDrop.sol 122: require(_amount > 0, "!amount");
File: contracts/AuraPenaltyForwarder.sol 52: require(bal > 0, "!empty");
File: contracts/AuraBalRewardPool.sol 121: require(_amount > 0, "RewardPool : Cannot stake 0"); 139: require(_amount > 0, "RewardPool : Cannot stake 0"); 157: require(amount > 0, "RewardPool : Cannot withdraw 0"); 210: require(rewardsAvailable > 0, "!balance");
File: contracts/AuraLocker.sol 259: require(_amount > 0, "Cannot stake 0"); 359: require(amt > 0, "Nothing locked"); 385: require(length > 0, "no locks"); 431: require(locked > 0, "no exp locks"); 471: require(len > 0, "Nothing to delegate"); 822: require(_rewards > 0, "No reward"); 851: require(_reward > 0, "No reward");
File: contracts/Aura.sol 68: require(_amount > 0, "Must mint something");
File: contracts/BalLiquidityProvider.sol 70: require(balAfter > 0, "!mint");
File: convex-platform/contracts/contracts/CrvDepositor.sol 169: require(_amount > 0,"!>0");
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 104: require(weight > 0, "must have weight");
File: convex-platform/contracts/contracts/interfaces/BoringMath.sol 20: require(b > 0, "BoringMath: division by zero"); 102: require(b > 0, "BoringMath: division by zero"); 123: require(b > 0, "BoringMath: division by zero"); 143: require(b > 0, "BoringMath: division by zero");
File: convex-platform/contracts/contracts/BaseRewardPool.sol 211: require(_amount > 0, 'RewardPool : Cannot stake 0'); 227: require(amount > 0, 'RewardPool : Cannot withdraw 0');
There are 26 instances of this issue:
File: contracts/AuraClaimZap.sol 143: for (uint256 i = 0; i < rewardContracts.length; i++) { 147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { 151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
File: contracts/ExtraRewardsDistributor.sol 231: uint256 claimableTokens = 0;
File: contracts/AuraLocker.sol 174: for (uint256 i = 0; i < rewardTokensLength; i++) { 381: uint256 reward = 0; 485: uint256 futureUnlocksSum = 0; 540: uint256 unlocksSinceLatestCkpt = 0; 630: uint256 low = 0; 773: for (uint256 i = 0; i < userRewardsLength; i++) {
File: contracts/AuraVestedEscrow.sol 99: uint256 totalAmount = 0; 100: for (uint256 i = 0; i < _recipient.length; i++) {
File: contracts/BalLiquidityProvider.sol 51: for (uint256 i = 0; i < 2; i++) {
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 180: for (uint256 pid = 0; pid < length; ++pid) {
File: convex-platform/contracts/contracts/ArbitartorVault.sol 49: for(uint256 i = 0; i < _toPids.length; i++){
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 69: for(uint i=0; i < usedList.length; i++){
File: convex-platform/contracts/contracts/VoterProxy.sol 308: uint256 _balance = 0;
File: convex-platform/contracts/contracts/BoosterOwner.sol 144: for(uint256 i = 0; i < poolCount; i++){
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 125: for(uint256 i = 0; i < maxRewards; i++){ 199: for(uint i=0; i < tCount; i++){
File: convex-platform/contracts/contracts/BaseRewardPool.sol 214: for(uint i=0; i < extraRewards.length; i++){ 230: for(uint i=0; i < extraRewards.length; i++){ 262: for(uint i=0; i < extraRewards.length; i++){ 296: for(uint i=0; i < extraRewards.length; i++){
File: convex-platform/contracts/contracts/Booster.sol 379: for(uint i=0; i < poolInfo.length; i++){ 538: for(uint256 i = 0; i < _gauge.length; i++){
++i
costs less gas than i++
, especially when it's used in for
-loops (--i
/i--
too)Saves 6 gas PER LOOP
There are 24 instances of this issue:
File: contracts/AuraClaimZap.sol 143: for (uint256 i = 0; i < rewardContracts.length; i++) { 147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { 151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
File: contracts/ExtraRewardsDistributor.sol 233: for (uint256 i = epochIndex; i < tokenEpochs; i++) {
File: contracts/AuraLocker.sol 174: for (uint256 i = 0; i < rewardTokensLength; i++) { 306: for (uint256 i; i < rewardTokensLength; i++) { 410: for (uint256 i = nextUnlockIndex; i < length; i++) { 664: for (uint256 i = locksLength; i > 0; i--) { 696: for (uint256 i = nextUnlockIndex; i < locks.length; i++) { 726: for (uint256 i = epochIndex + 1; i > 0; i--) { 773: for (uint256 i = 0; i < userRewardsLength; i++) {
File: contracts/AuraVestedEscrow.sol 100: for (uint256 i = 0; i < _recipient.length; i++) {
File: contracts/BalLiquidityProvider.sol 51: for (uint256 i = 0; i < 2; i++) {
File: convex-platform/contracts/contracts/ArbitartorVault.sol 49: for(uint256 i = 0; i < _toPids.length; i++){
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 69: for(uint i=0; i < usedList.length; i++){
File: convex-platform/contracts/contracts/BoosterOwner.sol 144: for(uint256 i = 0; i < poolCount; i++){
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 125: for(uint256 i = 0; i < maxRewards; i++){ 199: for(uint i=0; i < tCount; i++){
File: convex-platform/contracts/contracts/BaseRewardPool.sol 214: for(uint i=0; i < extraRewards.length; i++){ 230: for(uint i=0; i < extraRewards.length; i++){ 262: for(uint i=0; i < extraRewards.length; i++){ 296: for(uint i=0; i < extraRewards.length; i++){
File: convex-platform/contracts/contracts/Booster.sol 379: for(uint i=0; i < poolInfo.length; i++){ 538: for(uint256 i = 0; i < _gauge.length; i++){
require()
statements that use &&
saves gasSee this issue which describes the fact that there is a larger deployment gas cost, but with enough runtime calls, the change ends up being cheaper
There are 15 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol 171: require(_index > 0 && _index < rewardEpochs[_token].length - 1, "!past");
File: contracts/AuraStakingProxy.sol 90: require(_outputBps > 9000 && _outputBps < 10000, "Invalid output bps"); 159: require(_token != crv && _token != cvx && _token != cvxCrv, "not allowed"); 203: require(address(_token) != crv && address(_token) != cvxCrv, "not allowed");
File: contracts/BalLiquidityProvider.sol 48: require(_request.assets.length == 2 && _request.maxAmountsIn.length == 2, "!valid"); 57: require(bal > 0 && bal == _request.maxAmountsIn[i], "!bal");
File: convex-platform/contracts/contracts/StashFactoryV2.sol 83: require(!isV1 && !isV2 && !isV3,"stash version mismatch");
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 111: require(!usedMap[_lptoken] && !usedMap[_gauge], "cant force used pool");
File: convex-platform/contracts/contracts/Booster.sol 220: require(lockRewards != address(0) && rewardFactory != address(0), "!initialised"); 222: require(_feeToken != address(0) && _feeDistro != address(0), "!addresses"); 278: require(_lockFees >= 300 && _lockFees <= 1500, "!lockFees"); 279: require(_stakerFees >= 300 && _stakerFees <= 1500, "!stakerFees"); 280: require(_callerFees >= 10 && _callerFees <= 100, "!callerFees"); 313: require(msg.sender==poolManager && !isShutdown, "!add"); 314: require(_gauge != address(0) && _lptoken != address(0),"!param");
uints
/ints
smaller than 32 bytes (256 bits) incurs overheadWhen using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.
https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
There are 99 instances of this issue:
File: contracts/AuraLocker.sol 35: uint32 periodFinish; 37: uint32 lastUpdateTime; 39: uint96 rewardRate; 41: uint96 rewardPerTokenStored; 44: uint128 rewardPerTokenPaid; 45: uint128 rewards; 52: uint112 locked; 53: uint32 nextUnlockIndex; 56: uint112 amount; 57: uint32 unlockTime; 60: uint224 supply; 61: uint32 date; //epoch start date 64: uint224 votes; 65: uint32 epochStart; 119: uint8 private immutable _decimals; 268: uint112 lockAmount = _amount.to112(); 379: uint112 locked; 409: uint32 nextUnlockIndex = userBalance.nextUnlockIndex; 583: function checkpoints(address account, uint32 pos) external view virtual returns (DelegateeCheckpoint memory) { 590: function numCheckpoints(address account) external view virtual returns (uint32) { 752: function decimals() external view returns (uint8) {
File: contracts/AuraMath.sol 39: function to224(uint256 a) internal pure returns (uint224 c) { 44: function to128(uint256 a) internal pure returns (uint128 c) { 49: function to112(uint256 a) internal pure returns (uint112 c) { 54: function to96(uint256 a) internal pure returns (uint96 c) { 59: function to32(uint256 a) internal pure returns (uint32 c) { 67: function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { 67: function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { 67: function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { 74: function add(uint112 a, uint112 b) internal pure returns (uint112 c) { 74: function add(uint112 a, uint112 b) internal pure returns (uint112 c) { 74: function add(uint112 a, uint112 b) internal pure returns (uint112 c) { 78: function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { 78: function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { 78: function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { 85: function add(uint224 a, uint224 b) internal pure returns (uint224 c) { 85: function add(uint224 a, uint224 b) internal pure returns (uint224 c) { 85: function add(uint224 a, uint224 b) internal pure returns (uint224 c) {
File: convex-platform/contracts/contracts/Interfaces.sol 34: function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory); 34: function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory); 34: function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory); 34: function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory);
File: convex-platform/contracts/contracts/interfaces/IGaugeController.sol 9: function add_gauge(address,int128,uint256) external;
File: convex-platform/contracts/contracts/interfaces/BoringMath.sol 24: function to128(uint256 a) internal pure returns (uint128 c) { 29: function to64(uint256 a) internal pure returns (uint64 c) { 34: function to32(uint256 a) internal pure returns (uint32 c) { 39: function to40(uint256 a) internal pure returns (uint40 c) { 44: function to112(uint256 a) internal pure returns (uint112 c) { 49: function to224(uint256 a) internal pure returns (uint224 c) { 54: function to208(uint256 a) internal pure returns (uint208 c) { 59: function to216(uint256 a) internal pure returns (uint216 c) { 67: function add(uint128 a, uint128 b) internal pure returns (uint128 c) { 67: function add(uint128 a, uint128 b) internal pure returns (uint128 c) { 67: function add(uint128 a, uint128 b) internal pure returns (uint128 c) { 71: function sub(uint128 a, uint128 b) internal pure returns (uint128 c) { 71: function sub(uint128 a, uint128 b) internal pure returns (uint128 c) { 71: function sub(uint128 a, uint128 b) internal pure returns (uint128 c) { 78: function add(uint64 a, uint64 b) internal pure returns (uint64 c) { 78: function add(uint64 a, uint64 b) internal pure returns (uint64 c) { 78: function add(uint64 a, uint64 b) internal pure returns (uint64 c) { 82: function sub(uint64 a, uint64 b) internal pure returns (uint64 c) { 82: function sub(uint64 a, uint64 b) internal pure returns (uint64 c) { 82: function sub(uint64 a, uint64 b) internal pure returns (uint64 c) { 89: function add(uint32 a, uint32 b) internal pure returns (uint32 c) { 89: function add(uint32 a, uint32 b) internal pure returns (uint32 c) { 89: function add(uint32 a, uint32 b) internal pure returns (uint32 c) { 93: function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { 93: function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { 93: function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { 97: function mul(uint32 a, uint32 b) internal pure returns (uint32 c) { 97: function mul(uint32 a, uint32 b) internal pure returns (uint32 c) { 97: function mul(uint32 a, uint32 b) internal pure returns (uint32 c) { 101: function div(uint32 a, uint32 b) internal pure returns (uint32) { 101: function div(uint32 a, uint32 b) internal pure returns (uint32) { 101: function div(uint32 a, uint32 b) internal pure returns (uint32) { 110: function add(uint112 a, uint112 b) internal pure returns (uint112 c) { 110: function add(uint112 a, uint112 b) internal pure returns (uint112 c) { 110: function add(uint112 a, uint112 b) internal pure returns (uint112 c) { 114: function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { 114: function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { 114: function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { 118: function mul(uint112 a, uint112 b) internal pure returns (uint112 c) { 118: function mul(uint112 a, uint112 b) internal pure returns (uint112 c) { 118: function mul(uint112 a, uint112 b) internal pure returns (uint112 c) { 122: function div(uint112 a, uint112 b) internal pure returns (uint112) { 122: function div(uint112 a, uint112 b) internal pure returns (uint112) { 122: function div(uint112 a, uint112 b) internal pure returns (uint112) { 130: function add(uint224 a, uint224 b) internal pure returns (uint224 c) { 130: function add(uint224 a, uint224 b) internal pure returns (uint224 c) { 130: function add(uint224 a, uint224 b) internal pure returns (uint224 c) { 134: function sub(uint224 a, uint224 b) internal pure returns (uint224 c) { 134: function sub(uint224 a, uint224 b) internal pure returns (uint224 c) { 134: function sub(uint224 a, uint224 b) internal pure returns (uint224 c) { 138: function mul(uint224 a, uint224 b) internal pure returns (uint224 c) { 138: function mul(uint224 a, uint224 b) internal pure returns (uint224 c) { 138: function mul(uint224 a, uint224 b) internal pure returns (uint224 c) { 142: function div(uint224 a, uint224 b) internal pure returns (uint224) { 142: function div(uint224 a, uint224 b) internal pure returns (uint224) { 142: function div(uint224 a, uint224 b) internal pure returns (uint224) {
abi.encode()
is less efficient than abi.encodePacked()
There are 2 instances of this issue:
File: contracts/CrvDepositorWrapper.sol #1 93: abi.encode(IVault.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, maxAmountsIn, minOut),
File: convex-platform/contracts/contracts/StashFactoryV2.sol #2 88: bytes memory data = abi.encode(rewarded_token);
private
rather than public
for constants, saves gasIf needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table
There are 30 instances of this issue:
File: contracts/AuraMinter.sol 18: uint256 public immutable inflationProtectionTime;
File: contracts/AuraMerkleDrop.sol 32: uint256 public immutable expiryTime;
File: contracts/AuraPenaltyForwarder.sol 19: uint256 public immutable distributionDelay;
File: contracts/AuraBalRewardPool.sol 29: uint256 public constant duration = 14 days; 36: uint256 public immutable startTime;
File: contracts/AuraLocker.sol 73: uint256 public constant newRewardRatio = 830; 81: uint256 public constant rewardsDuration = 86400 * 7; 83: uint256 public constant lockDuration = rewardsDuration * 17; 107: uint256 public constant denominator = 10000;
File: contracts/CrvDepositorWrapper.sol 30: bytes32 public immutable BAL_ETH_POOL_ID;
File: contracts/Aura.sol 28: uint256 public constant EMISSIONS_MAX_SUPPLY = 5e25; // 50m 29: uint256 public constant totalCliffs = 500; 30: uint256 public immutable reductionPerCliff;
File: contracts/AuraStakingProxy.sol 45: uint256 public constant denominator = 10000;
File: contracts/AuraVestedEscrow.sol 29: uint256 public immutable startTime; 30: uint256 public immutable endTime; 31: uint256 public immutable totalTime;
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 54: uint256 public immutable rewardPerBlock; 56: uint256 public constant BONUS_MULTIPLIER = 2; 65: uint256 public immutable startBlock; 66: uint256 public immutable endBlock;
File: convex-platform/contracts/contracts/CrvDepositor.sol 30: uint256 public constant FEE_DENOMINATOR = 10000;
File: convex-platform/contracts/contracts/BoosterOwner.sol 51: uint256 public constant FORCE_DELAY = 30 days;
File: convex-platform/contracts/contracts/BaseRewardPool.sol 65: uint256 public constant duration = 7 days; 70: uint256 public immutable pid; 78: uint256 public constant newRewardRatio = 830;
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 85: uint256 public constant duration = 7 days; 96: uint256 public constant newRewardRatio = 830;
File: convex-platform/contracts/contracts/Booster.sol 30: uint256 public constant MaxFees = 2500; 31: uint256 public constant FEE_DENOMINATOR = 10000;
if (<x> == true)
=> if (<x>)
, if (<x> == false)
=> if (!<x>)
There are 9 instances of this issue:
File: contracts/AuraMerkleDrop.sol 123: require(hasClaimed[msg.sender] == false, "already claimed");
File: convex-platform/contracts/contracts/ArbitartorVault.sol 54: require(shutdown==false,"pool closed");
File: convex-platform/contracts/contracts/VoterProxy.sol 107: require(operator == address(0) || IDeposit(operator).isShutdown() == true, "needs shutdown"); 168: if(protectedTokens[_token] == false){ 171: if(protectedTokens[_gauge] == false){ 190: require(protectedTokens[address(_asset)] == false, "protected");
File: convex-platform/contracts/contracts/Booster.sol 400: require(pool.shutdown == false, "pool is closed"); 574: require(pool.shutdown == false, "pool is closed");
File: convex-platform/contracts/contracts/RewardFactory.sol 72: require(msg.sender == operator || rewardAccess[msg.sender] == true, "!auth");
SafeMath
once the solidity version is 0.8.0 or greaterVersion 0.8.0 introduces internal overflow checks, so using SafeMath
is redundant and adds overhead
There are 2 instances of this issue:
File: contracts/AuraBalRewardPool.sol #1 5: import { SafeMath } from "@openzeppelin/contracts-0.8/utils/math/SafeMath.sol";
File: contracts/AuraStakingProxy.sol #2 7: import { SafeMath } from "@openzeppelin/contracts-0.8/utils/math/SafeMath.sol";
require()
/revert()
checks should be refactored to a modifier or functionSaves deployment costs
There are 32 instances of this issue:
File: contracts/AuraMerkleDrop.sol 84: require(msg.sender == dao, "!auth");
File: contracts/AuraBalRewardPool.sol 139: require(_amount > 0, "RewardPool : Cannot stake 0");
File: contracts/AuraLocker.sol 719: require(epochStart < block.timestamp, "Epoch is in the future");
File: contracts/AuraStakingProxy.sol 100: require(msg.sender == owner, "!auth");
File: contracts/AuraVestedEscrow.sol 87: require(msg.sender == admin, "!auth");
File: convex-platform/contracts/contracts/DepositToken.sol 54: require(msg.sender == operator, "!authorized");
File: convex-platform/contracts/contracts/cCrv.sol 56: require(msg.sender == operator, "!authorized");
File: convex-platform/contracts/contracts/PoolManagerV3.sol 49: require(msg.sender == operator, "!auth");
File: convex-platform/contracts/contracts/ArbitartorVault.sol 47: require(msg.sender == operator, "!auth");
File: convex-platform/contracts/contracts/CrvDepositor.sol 73: require(msg.sender==feeManager, "!auth"); 81: require(msg.sender == daoOperator, "!auth"); 141: require(!cooldown, "cooldown");
File: convex-platform/contracts/contracts/VoterProxy.sol 84: require(msg.sender == owner, "!auth"); 138: require(msg.sender == operator, "!auth"); 254: require(msg.sender == depositor, "!auth");
File: convex-platform/contracts/contracts/BoosterOwner.sol 159: require(IOwner(poolManager).isShutdown(),"!poolMgrShutdown");
File: convex-platform/contracts/contracts/interfaces/BoringMath.sol 68: require((c = a + b) >= b, "BoringMath: Add Overflow"); 72: require((c = a - b) <= a, "BoringMath: Underflow"); 98: require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow"); 102: require(b > 0, "BoringMath: division by zero");
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 196: require(msg.sender == operator, "!operator"); 147: require(IDeposit(operator).owner() == msg.sender, "!owner");
File: convex-platform/contracts/contracts/BaseRewardPool.sol 133: require(msg.sender == rewardManager, "!authorized");
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 182: require(msg.sender == address(deposits), "!authorized");
File: convex-platform/contracts/contracts/Booster.sol 159: require(msg.sender == owner, "!auth"); 273: require(msg.sender==feeManager, "!auth"); 357: require(msg.sender==poolManager, "!auth"); 515: require(msg.sender == voteDelegate, "!auth"); 398: require(!isShutdown,"shutdown"); 574: require(pool.shutdown == false, "pool is closed"); 560: require(msg.sender == stash,"!auth");
File: convex-platform/contracts/contracts/RewardFactory.sol 57: require(msg.sender == operator, "!auth");
<x> * 2
is equivalent to <x> << 1
and <x> / 2
is the same as <x> >> 1
. The MUL
and DIV
opcodes cost 5 gas, whereas SHL
and SHR
only cost 3 gas
There are 5 instances of this issue:
File: contracts/AuraMerkleDrop.sol 136: uint256 penalty = address(auraLocker) == address(0) ? 0 : (_amount * 2) / 10;
File: contracts/AuraBalRewardPool.sol 183: uint256 penalty = (reward * 2) / 10;
File: contracts/AuraMath.sol 36: return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); 36: return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); 36: return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
If the variable is only accessed once, it's cheaper to use the state variable directly that one time
There is 1 instance of this issue:
File: contracts/AuraLocker.sol #1 328: uint256 epochindex = epochs.length;
require()
or revert()
statements that check input arguments should be at the top of the functionChecks that involve constants should come before checks that involve state variables
There are 11 instances of this issue:
File: contracts/AuraMerkleDrop.sol 69: require(_expiresAfter > 2 weeks, "!expiry"); 122: require(_amount > 0, "!amount");
File: contracts/AuraBalRewardPool.sol 77: require(_startDelay < 2 weeks, "!delay");
File: contracts/AuraLocker.sol 472: require(newDelegatee != address(0), "Must delegate to someone"); 822: require(_rewards > 0, "No reward"); 851: require(_reward > 0, "No reward");
File: contracts/Aura.sol 68: require(_amount > 0, "Must mint something"); 69: require(_minter != address(0), "Invalid minter");
File: contracts/AuraStakingProxy.sol 129: require(_incentive <= 100, "too high");
File: convex-platform/contracts/contracts/BaseRewardPool.sol 127: require(_reward != address(0),"!reward setting");
File: convex-platform/contracts/contracts/Booster.sol 281: require(_platform <= 200, "!platform");
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...}
=> if(!x){if(y){...}else{...}}
)
There are 6 instances of this issue:
File: convex-platform/contracts/contracts/VoterProxy.sol 312: }catch{}
File: convex-platform/contracts/contracts/ExtraRewardStashV3.sol 116 try IRewardHook(rewardHook).onRewardClaim(){ 117: }catch{} 117: }catch{}
File: convex-platform/contracts/contracts/Booster.sol 361 try IStaker(staker).withdrawAll(pool.lptoken,pool.gauge){ 362: }catch{} 362: }catch{} 389: }catch{}
revert()
/require()
strings to save deployment gasCustom errors are available from solidity version 0.8.4. The instances below match or exceed that version
There are 101 instances of this issue:
File: contracts/AuraClaimZap.sol 96: require(msg.sender == owner, "!auth"); 137: require(tokenRewardContracts.length == tokenRewardTokens.length, "!parity");
File: contracts/AuraMinter.sol 32: require(block.timestamp > inflationProtectionTime, "Inflation protected for now");
File: contracts/ExtraRewardsDistributor.sol 68: require(_epoch <= latestEpoch, "Cannot assign to the future"); 74: require(len == 0 || rewardEpochs[_token][len - 1] < _epoch, "Cannot backdate to this epoch"); 171: require(_index > 0 && _index < rewardEpochs[_token].length - 1, "!past"); 172: require(_index >= userClaims[_token][msg.sender], "already claimed");
File: contracts/AuraMerkleDrop.sol 69: require(_expiresAfter > 2 weeks, "!expiry"); 78: require(msg.sender == dao, "!auth"); 84: require(msg.sender == dao, "!auth"); 85: require(merkleRoot == bytes32(0), "already set"); 91: require(msg.sender == dao, "!auth"); 97: require(msg.sender == dao, "!auth"); 98: require(block.timestamp > expiryTime, "!expired"); 105: require(msg.sender == dao, "!auth"); 119: require(merkleRoot != bytes32(0), "!root"); 120: require(block.timestamp > startTime, "!started"); 121: require(block.timestamp < expiryTime, "!active"); 122: require(_amount > 0, "!amount"); 123: require(hasClaimed[msg.sender] == false, "already claimed"); 126: require(MerkleProof.verify(_proof, merkleRoot, leaf), "invalid proof"); 152: require(penaltyForwarder != address(0), "!forwarder");
File: contracts/AuraPenaltyForwarder.sol 48: require(block.timestamp > lastDistribution + distributionDelay, "!elapsed"); 52: require(bal > 0, "!empty");
File: contracts/AuraBalRewardPool.sol 77: require(_startDelay < 2 weeks, "!delay"); 121: require(_amount > 0, "RewardPool : Cannot stake 0"); 139: require(_amount > 0, "RewardPool : Cannot stake 0"); 157: require(amount > 0, "RewardPool : Cannot withdraw 0"); 206: require(msg.sender == rewardManager || block.timestamp > startTime, "!authorized"); 207: require(rewardRate == 0, "!one time"); 210: require(rewardsAvailable > 0, "!balance");
File: contracts/AuraLocker.sol 196: require(rewardData[_rewardsToken].lastUpdateTime == 0, "Reward already exists"); 197: require(_rewardsToken != address(stakingToken), "Cannot add StakingToken as reward"); 210: require(rewardData[_rewardsToken].lastUpdateTime > 0, "Reward does not exist"); 216: require(_rate <= 500, "over max rate"); //max 5% per epoch 217: require(_delay >= 2, "min delay"); //minimum 2 epochs of grace 232: require(_tokenAddress != address(stakingToken), "Cannot withdraw staking token"); 233: require(rewardData[_tokenAddress].lastUpdateTime == 0, "Cannot withdraw reward token"); 259: require(_amount > 0, "Cannot stake 0"); 260: require(!isShutdown, "shutdown"); 353: require(isShutdown, "Must be shutdown"); 359: require(amt > 0, "Nothing locked"); 385: require(length > 0, "no locks"); 431: require(locked > 0, "no exp locks"); 471: require(len > 0, "Nothing to delegate"); 472: require(newDelegatee != address(0), "Must delegate to someone"); 476: require(newDelegatee != oldDelegatee, "Must choose new delegatee"); 598: require(timestamp <= block.timestamp, "ERC20Votes: block not yet mined"); 616: require(timestamp < block.timestamp, "ERC20Votes: block not yet mined"); 655: require(epochStart < block.timestamp, "Epoch is in the future"); 719: require(epochStart < block.timestamp, "Epoch is in the future"); 821: require(rewardDistributors[cvxCrv][msg.sender], "!authorized"); 822: require(_rewards > 0, "No reward"); 849: require(_rewardsToken != cvxCrv, "Use queueNewRewards"); 850: require(rewardDistributors[_rewardsToken][msg.sender], "Must be rewardsDistributor"); 851: require(_reward > 0, "No reward");
File: contracts/ClaimFeesHelper.sol 45: require(tokenTime > lastTokenTimes[address(_token)], "not time yet");
File: contracts/CrvDepositorWrapper.sol 42: require(poolAddress != address(0), "!poolAddress"); 119: require(IERC20(BALANCER_POOL_TOKEN).approve(crvDeposit, type(uint256).max), "!approval");
File: contracts/Aura.sol 66: require(msg.sender == operator, "Only operator"); 67: require(totalSupply() == 0, "Only once"); 68: require(_amount > 0, "Must mint something"); 69: require(_minter != address(0), "Invalid minter"); 92: require(totalSupply() != 0, "Not initialised"); 129: require(msg.sender == minter, "Only minter");
File: contracts/AuraStakingProxy.sol 89: require(msg.sender == owner, "!auth"); 90: require(_outputBps > 9000 && _outputBps < 10000, "Invalid output bps"); 100: require(msg.sender == owner, "!auth"); 108: require(msg.sender == owner, "!auth"); 116: require(msg.sender == owner, "!auth"); 117: require(pendingOwner != address(0), "invalid owner"); 128: require(msg.sender == owner, "!auth"); 129: require(_incentive <= 100, "too high"); 138: require(msg.sender == owner, "!auth"); 158: require(msg.sender == owner, "!auth"); 159: require(_token != crv && _token != cvx && _token != cvxCrv, "not allowed"); 172: require(msg.sender == keeper, "!auth"); 203: require(address(_token) != crv && address(_token) != cvxCrv, "not allowed");
File: contracts/AuraMath.sol 40: require(a <= type(uint224).max, "AuraMath: uint224 Overflow"); 45: require(a <= type(uint128).max, "AuraMath: uint128 Overflow"); 50: require(a <= type(uint112).max, "AuraMath: uint112 Overflow"); 55: require(a <= type(uint96).max, "AuraMath: uint96 Overflow"); 60: require(a <= type(uint32).max, "AuraMath: uint32 Overflow");
File: contracts/AuraVestedEscrow.sol 56: require(starttime_ >= block.timestamp, "start must be future"); 57: require(endtime_ > starttime_, "end must be greater"); 66: require(totalTime >= 16 weeks, "!short"); 78: require(msg.sender == admin, "!auth"); 87: require(msg.sender == admin, "!auth"); 97: require(!initialised, "initialised already"); 117: require(msg.sender == admin, "!auth"); 118: require(totalLocked[_recipient] > 0, "!funding"); 185: require(address(auraLocker) != address(0), "!auraLocker");
File: contracts/BalLiquidityProvider.sol 47: require(msg.sender == provider, "!auth"); 48: require(_request.assets.length == 2 && _request.maxAmountsIn.length == 2, "!valid"); 49: require(pairToken.balanceOf(address(this)) > minPairAmount, "!minLiq"); 53: require(asset == address(startToken) || asset == address(pairToken), "!asset"); 57: require(bal > 0 && bal == _request.maxAmountsIn[i], "!bal"); 65: require(supplyBefore == 0, "!init"); 70: require(balAfter > 0, "!mint"); 79: require(msg.sender == dao, "!auth"); 89: require(msg.sender == provider || msg.sender == dao, "!auth");
payable
If a function modifier such as onlyOwner
is used, the 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 37 instances of this issue:
File: contracts/AuraMinter.sol 31: function mint(address _to, uint256 _amount) external onlyOwner {
File: contracts/AuraLocker.sol 195: function addReward(address _rewardsToken, address _distributor) external onlyOwner { 205 function approveRewardDistributor( 206 address _rewardsToken, 207 address _distributor, 208 bool _approved 209: ) external onlyOwner { 215: function setKickIncentive(uint256 _rate, uint256 _delay) external onlyOwner { 225: function shutdown() external onlyOwner { 231: function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 96 function add( 97 uint256 _allocPoint, 98 IERC20 _lpToken, 99 IRewarder _rewarder, 100 bool _withUpdate 101: ) public onlyOwner { 121 function set( 122 uint256 _pid, 123 uint256 _allocPoint, 124 IRewarder _rewarder, 125 bool _withUpdate, 126 bool _updateRewarder 127: ) public onlyOwner {
File: convex-platform/contracts/contracts/PoolManagerProxy.sol 43: function setOwner(address _owner) external onlyOwner{ 48: function setOperator(address _operator) external onlyOwner{ 57: function shutdownPool(uint256 _pid) external onlyOperator returns(bool){ 66: function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external onlyOperator returns(bool){
File: convex-platform/contracts/contracts/PoolManagerSecondaryProxy.sol 58: function setOwner(address _owner) external onlyOwner{ 63: function setOperator(address _operator) external onlyOwner{ 68: function setUsedAddress(address[] memory usedList) external onlyOwner{ 75: function shutdownSystem() external onlyOwner{ 84: function shutdownPool(uint256 _pid) external onlyOperator returns(bool){ 101: function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external onlyOperator returns(bool){ 110: function forceAddPool(address _lptoken, address _gauge, uint256 _stashVersion) external onlyOperator returns(bool){
File: convex-platform/contracts/contracts/BoosterOwner.sol 90: function transferOwnership(address _owner) external onlyOwner{ 102: function sealOwnership() external onlyOwner{ 107: function setBoosterOwner() external onlyOwner{ 115: function setFactories(address _rfactory, address _sfactory, address _tfactory) external onlyOwner{ 119: function setArbitrator(address _arb) external onlyOwner{ 123: function setFeeInfo(address _feeToken, address _feeDistro) external onlyOwner{ 127: function updateFeeInfo(address _feeToken, bool _active) external onlyOwner{ 131: function setFeeManager(address _feeM) external onlyOwner{ 135: function setVoteDelegate(address _voteDelegate) external onlyOwner{ 139: function shutdownSystem() external onlyOwner{ 158: function queueForceShutdown() external onlyOwner{ 169: function forceShutdownSystem() external onlyOwner{ 180 function execute( 181 address _to, 182 uint256 _value, 183 bytes calldata _data 184: ) external onlyOwner returns (bool, bytes memory) { 196: function setRescueTokenDistribution(address _distributor, address _rewardDeposit, address _treasury) external onlyOwner{ 201: function setRescueTokenReward(address _token, uint256 _option) external onlyOwner{ 206: function setStashExtraReward(address _stash, address _token) external onlyOwner{ 211: function setStashRewardHook(address _stash, address _hook) external onlyOwner{ 216: function setStashFactoryImplementation(address _v1, address _v2, address _v3) external onlyOwner{
public
functions not called by the contract should be declared external
insteadContracts are allowed to override their parents' functions and change the visibility from external
to public
and can save gas by doing so.
There are 18 instances of this issue:
File: contracts/ExtraRewardsDistributor.sol 117: function getReward(address _account, address _token) public { 127 function getReward( 128 address _account, 129 address _token, 130: uint256 _startIndex
File: contracts/AuraMerkleDrop.sol 114 function claim( 115 bytes32[] calldata _proof, 116 uint256 _amount, 117 bool _lock 118: ) public returns (bool) { 149 function forwardPenalty() public { 150: uint256 toForward = pendingPenalty;
File: contracts/AuraPenaltyForwarder.sol 47 function forward() public { 48: require(block.timestamp > lastDistribution + distributionDelay, "!elapsed");
File: contracts/AuraBalRewardPool.sol 138: function stakeFor(address _for, uint256 _amount) public updateReward(_for) returns (bool) { 152 function withdraw( 153 uint256 amount, 154 bool claim, 155 bool lock 156: ) public updateReward(msg.sender) returns (bool) { 195 function forwardPenalty() public { 196: uint256 toForward = pendingPenalty;
File: contracts/BalLiquidityProvider.sol 46: function provideLiquidity(bytes32 _poolId, IVault.JoinPoolRequest memory _request) public {
File: convex-platform/contracts/contracts/ConvexMasterChef.sol 96 function add( 97 uint256 _allocPoint, 98 IERC20 _lpToken, 99 IRewarder _rewarder, 100 bool _withUpdate 101: ) public onlyOwner { 121 function set( 122 uint256 _pid, 123 uint256 _allocPoint, 124 IRewarder _rewarder, 125 bool _withUpdate, 126 bool _updateRewarder 127: ) public onlyOwner { 209: function deposit(uint256 _pid, uint256 _amount) public { 239: function withdraw(uint256 _pid, uint256 _amount) public { 283: function emergencyWithdraw(uint256 _pid) public {
File: convex-platform/contracts/contracts/VoterProxy.sol 151: function isValidSignature(bytes32 _hash, bytes memory) public view returns (bytes4) {
File: convex-platform/contracts/contracts/BaseRewardPool.sol 191 function stakeFor(address _for, uint256 _amount) 192 public 193: returns(bool)
File: convex-platform/contracts/contracts/VirtualBalanceRewardPool.sol 178 function withdraw(address _account, uint256 amount) 179 public 180: updateReward(_account)
File: convex-platform/contracts/contracts/Booster.sol 493: function withdrawAll(uint256 _pid) public returns(bool){
#0 - liveactionllama
2022-05-16T04:13:33Z
Warden created this issue as a placeholder, because their submission was too large for the contest form. They then emailed their md file to our team on 05/13/2022. I've updated this issue with their md file content.