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: 40/93
Findings: 2
Award: $234.74
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
150.0334 USDC - $150.03
Information : L003 - Unspecific Compiler Version Pragma Consensys Audit of 1inch Solidity docs
ClaimFeesHelper.sol:2:pragma solidity ^0.8.11; mocks/MockAuraMath.sol:2:pragma solidity ^0.8.11; AuraVestedEscrow.sol:2:pragma solidity ^0.8.11; BalLiquidityProvider.sol:2:pragma solidity ^0.8.11; AuraStakingProxy.sol:2:pragma solidity ^0.8.11; AuraLocker.sol:2:pragma solidity ^0.8.11; AuraMinter.sol:2:pragma solidity ^0.8.11; AuraMerkleDrop.sol:2:pragma solidity ^0.8.11; Aura.sol:2:pragma solidity ^0.8.11; ExtraRewardsDistributor.sol:2:pragma solidity ^0.8.11; AuraBalRewardPool.sol:2:pragma solidity ^0.8.11; AuraMath.sol:2:pragma solidity ^0.8.11; AuraPenaltyForwarder.sol:2:pragma solidity ^0.8.11; AuraClaimZap.sol:2:pragma solidity ^0.8.11;
It is recommended to use a concrete compiler version, for example :
ClaimFeesHelper.sol:2:pragma solidity 0.8.11;
Information : L005 - Do not use Deprecated Library Functions SafeERC20.sol - safeApprove
AuraVestedEscrow.sol:186: rewardToken.safeApprove(address(auraLocker), claimable); BalLiquidityProvider.sol:59: tkn.safeApprove(address(bVault), 0); BalLiquidityProvider.sol:60: tkn.safeApprove(address(bVault), bal); CrvDepositorWrapper.sol:52: IERC20(WETH).safeApprove(address(BALANCER_VAULT), type(uint256).max); CrvDepositorWrapper.sol:53: IERC20(BAL).safeApprove(address(BALANCER_VAULT), type(uint256).max); AuraStakingProxy.sol:147: IERC20(crv).safeApprove(crvDepositorWrapper, 0); AuraStakingProxy.sol:148: IERC20(crv).safeApprove(crvDepositorWrapper, type(uint256).max); AuraStakingProxy.sol:150: IERC20(cvxCrv).safeApprove(rewards, 0); AuraStakingProxy.sol:151: IERC20(cvxCrv).safeApprove(rewards, type(uint256).max); AuraStakingProxy.sol:215: _token.safeApprove(rewards, 0); AuraStakingProxy.sol:216: _token.safeApprove(rewards, type(uint256).max); AuraLocker.sol:240: IERC20(cvxCrv).safeApprove(cvxcrvStaking, 0); AuraLocker.sol:241: IERC20(cvxCrv).safeApprove(cvxcrvStaking, type(uint256).max); AuraMerkleDrop.sol:131: aura.safeApprove(address(auraLocker), 0); AuraMerkleDrop.sol:132: aura.safeApprove(address(auraLocker), _amount); AuraBalRewardPool.sol:75: rewardToken.safeApprove(_auraLocker, type(uint256).max); AuraPenaltyForwarder.sol:41: token.safeApprove(address(distributor), type(uint256).max); AuraClaimZap.sol:98: IERC20(crv).safeApprove(crvDepositWrapper, 0); AuraClaimZap.sol:99: IERC20(crv).safeApprove(crvDepositWrapper, type(uint256).max); AuraClaimZap.sol:101: IERC20(cvxCrv).safeApprove(cvxCrvRewards, 0); AuraClaimZap.sol:102: IERC20(cvxCrv).safeApprove(cvxCrvRewards, type(uint256).max); AuraClaimZap.sol:104: IERC20(cvx).safeApprove(locker, 0); AuraClaimZap.sol:105: IERC20(cvx).safeApprove(locker, type(uint256).max);
Usage of deprecated library functions, for instance safeApprove
from OpenZeppelin's SafeERC20
library is discouraged, it is recommended to use safeIncreaseAllowance
and safeDecreaseAllowance
instead, for example :
AuraVestedEscrow.sol:186: rewardToken.safeIncreaseAllowance(address(auraLocker), claimable);
Information : L001 - Unsafe ERC20 Operation(s)
mocks/balancer/MockBalancerVault.sol:67: IERC20(tokenB).transferFrom(funds.sender, address(this), singleSwap.amount); mocks/balancer/MockBalancerVault.sol:68: IERC20(tokenA).transfer(funds.recipient, singleSwap.amount); mocks/balancer/MockBalancerVault.sol:71: IERC20(tokenA).transferFrom(funds.sender, address(this), singleSwap.amount); mocks/balancer/MockBalancerVault.sol:72: IERC20(tokenB).transfer(funds.recipient, singleSwap.amount); mocks/curve/MockCurveVoteEscrow.sol:48: IERC20(token).transferFrom(msg.sender, address(this), amount); mocks/curve/MockCurveVoteEscrow.sol:58: IERC20(token).transferFrom(msg.sender, address(this), amount); mocks/curve/MockCurveVoteEscrow.sol:78: IERC20(token).transfer(msg.sender, amount); mocks/curve/MockCurveMinter.sol:21: crv.transfer(msg.sender, rate); mocks/curve/MockCurveGauge.sol:25: IERC20(lp_token).transferFrom(msg.sender, address(this), amount); mocks/curve/MockCurveGauge.sol:30: IERC20(lp_token).transfer(msg.sender, amount); mocks/curve/MockCurveGauge.sol:37: IERC20(reward_tokens[i]).transfer(msg.sender, amount);
It is recommended to always use OpenZeppelin's SafeERC20
library, for example :
import {SafeERC20} from "openzeppelin/token/utils/SafeERC20.sol"; ... IERC20(tokenB).safeTransferFrom(funds.sender, address(this), singleSwap.amount);
distirbuted
, constructoor
, transferrable
Aura.sol:18: * distirbuted along a supply curve (cliffs etc). Fork of ConvexToken. ExtraRewardsDistributor.sol:33: * @dev Simple constructoor AuraBalRewardPool.sol:55: * @dev Simple constructoor mocks/curve/MockCurveVoteEscrow.sol:28: revert("Not transferrable"); mocks/curve/MockCurveVoteEscrow.sol:36: revert("Not transferrable");
🌟 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
84.7121 USDC - $84.71
Uninitialized variables are assigned with the default value of their type, initializing a variable with its default value costs unnecessary gas.
mocks/balancer/MockFeeDistro.sol:19: for (uint256 i = 0; i < _tokens.length; i++) { mocks/balancer/MockFeeDistro.sol:38: for (uint256 i = 0; i < tokens.length; i++) { mocks/curve/MockCurveGauge.sol:36: for (uint256 i = 0; i < reward_tokens.length; i++) { AuraVestedEscrow.sol:99: uint256 totalAmount = 0; AuraVestedEscrow.sol:100: for (uint256 i = 0; i < _recipient.length; i++) { BalLiquidityProvider.sol:51: for (uint256 i = 0; i < 2; i++) { AuraLocker.sol:72: uint256 public queuedCvxCrvRewards = 0; AuraLocker.sol:174: for (uint256 i = 0; i < rewardTokensLength; i++) { AuraLocker.sol:381: uint256 reward = 0; AuraLocker.sol:485: uint256 futureUnlocksSum = 0; AuraLocker.sol:540: uint256 unlocksSinceLatestCkpt = 0; AuraLocker.sol:630: uint256 low = 0; AuraLocker.sol:773: for (uint256 i = 0; i < userRewardsLength; i++) { AuraMerkleDrop.sol:29: uint256 public pendingPenalty = 0; ExtraRewardsDistributor.sol:231: uint256 claimableTokens = 0; AuraBalRewardPool.sol:35: uint256 public pendingPenalty = 0; AuraBalRewardPool.sol:38: uint256 public periodFinish = 0; AuraBalRewardPool.sol:39: uint256 public rewardRate = 0; AuraClaimZap.sol:143: for (uint256 i = 0; i < rewardContracts.length; i++) { AuraClaimZap.sol:147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { AuraClaimZap.sol:151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) { AuraVestedEscrow.sol:33: bool public initialised = false; AuraLocker.sol:114: bool public isShutdown = false;
It is recommended to initialize variables without assigning them the default value, for example :
AuraVestedEscrow.sol:99: uint256 totalAmount; AuraVestedEscrow.sol:33: bool public initialised;
Caching the array length outside a loop saves reading it on each iteration, as long as the array's length is not changed during the loop.
mocks/balancer/MockFeeDistro.sol:19: for (uint256 i = 0; i < _tokens.length; i++) { mocks/balancer/MockFeeDistro.sol:38: for (uint256 i = 0; i < tokens.length; i++) { mocks/curve/MockCurveGauge.sol:36: for (uint256 i = 0; i < reward_tokens.length; i++) { AuraVestedEscrow.sol:100: for (uint256 i = 0; i < _recipient.length; i++) { AuraLocker.sol:696: for (uint256 i = nextUnlockIndex; i < locks.length; i++) { AuraClaimZap.sol:143: for (uint256 i = 0; i < rewardContracts.length; i++) { AuraClaimZap.sol:147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { AuraClaimZap.sol:151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
It is recommended to cache the array length on a variable before running the loop, then it doesn't need to read the length on every iteration, which cost gas, for example :
uint256 len = _tokens.length; for (uint256 i = 0; i < len; i++) {
!= 0 will do the same as > 0 for unsigned integers, but != 0 costs less gas compared to > 0 for unsigned integers in require statements with the optimizer enabled.
mocks/curve/MockCurveVoteEscrow.sol:43: require(amount > 0, "!amount"); mocks/curve/MockCurveVoteEscrow.sol:53: require(lockAmounts[msg.sender] > 0, "Must have a lock"); mocks/curve/MockCurveVoteEscrow.sol:55: require(amount > 0, "!amount"); mocks/curve/MockCurveVoteEscrow.sol:63: require(lockAmounts[msg.sender] > 0, "Must have a lock"); AuraVestedEscrow.sol:118: require(totalLocked[_recipient] > 0, "!funding"); BalLiquidityProvider.sol:57: require(bal > 0 && bal == _request.maxAmountsIn[i], "!bal"); BalLiquidityProvider.sol:70: require(balAfter > 0, "!mint"); AuraLocker.sol:210: require(rewardData[_rewardsToken].lastUpdateTime > 0, "Reward does not exist"); AuraLocker.sol:259: require(_amount > 0, "Cannot stake 0"); AuraLocker.sol:359: require(amt > 0, "Nothing locked"); AuraLocker.sol:385: require(length > 0, "no locks"); AuraLocker.sol:431: require(locked > 0, "no exp locks"); AuraLocker.sol:471: require(len > 0, "Nothing to delegate"); AuraLocker.sol:822: require(_rewards > 0, "No reward"); AuraLocker.sol:851: require(_reward > 0, "No reward"); AuraMerkleDrop.sol:122: require(_amount > 0, "!amount"); Aura.sol:68: require(_amount > 0, "Must mint something"); ExtraRewardsDistributor.sol:171: require(_index > 0 && _index < rewardEpochs[_token].length - 1, "!past"); AuraBalRewardPool.sol:121: require(_amount > 0, "RewardPool : Cannot stake 0"); AuraBalRewardPool.sol:139: require(_amount > 0, "RewardPool : Cannot stake 0"); AuraBalRewardPool.sol:157: require(amount > 0, "RewardPool : Cannot withdraw 0"); AuraBalRewardPool.sol:210: require(rewardsAvailable > 0, "!balance"); AuraPenaltyForwarder.sol:52: require(bal > 0, "!empty");
It is recommended to replace > 0
with != 0
, as they do the same thing for unsigned integers, and '!= 0' costs less gas compared to > 0
in require statements with the optimizer enabled, also enable the optimizer.
For example :
mocks/curve/MockCurveVoteEscrow.sol:43: require(amount != 0, "!amount");
If the divisor/multiplier x
is a power of 2, it can be calculated by shifting log2(x)
to the right/left. Division with /
cost more gas compared to bitwise shifting.
AuraMath.sol:36: return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2); AuraBalRewardPool.sol:183: uint256 penalty = (reward * 2) / 10;
It is recommended to replace /
and *
with >>
and <<
respectively and divisor/multiplier x
to log2(x)
, for division/multiplication where the divisor/multiplier is a power of 2, for example :
AuraBalRewardPool.sol:183: uint256 penalty = (reward << 1) / 10;
Prefix increment ++i
returns the updated value after it's incremented and postfix increment i++
returns the original value then increments it. Prefix increment costs less gas compared to postfix increment.
mocks/balancer/MockFeeDistro.sol:19: for (uint256 i = 0; i < _tokens.length; i++) { mocks/balancer/MockFeeDistro.sol:38: for (uint256 i = 0; i < tokens.length; i++) { mocks/MockVoteStorage.sol:64: len++; mocks/curve/MockVoting.sol:23: votesFor[voteId]++; mocks/curve/MockVoting.sol:25: votesAgainst[voteId]++; mocks/curve/MockCurveGauge.sol:36: for (uint256 i = 0; i < reward_tokens.length; i++) { AuraVestedEscrow.sol:100: for (uint256 i = 0; i < _recipient.length; i++) { BalLiquidityProvider.sol:51: for (uint256 i = 0; i < 2; i++) { AuraLocker.sol:174: for (uint256 i = 0; i < rewardTokensLength; i++) { AuraLocker.sol:306: for (uint256 i; i < rewardTokensLength; i++) { AuraLocker.sol:410: for (uint256 i = nextUnlockIndex; i < length; i++) { AuraLocker.sol:426: nextUnlockIndex++; AuraLocker.sol:696: for (uint256 i = nextUnlockIndex; i < locks.length; i++) { AuraLocker.sol:702: idx++; AuraLocker.sol:773: for (uint256 i = 0; i < userRewardsLength; i++) { ExtraRewardsDistributor.sol:233: for (uint256 i = epochIndex; i < tokenEpochs; i++) { AuraClaimZap.sol:143: for (uint256 i = 0; i < rewardContracts.length; i++) { AuraClaimZap.sol:147: for (uint256 i = 0; i < extraRewardContracts.length; i++) { AuraClaimZap.sol:151: for (uint256 i = 0; i < tokenRewardContracts.length; i++) { AuraLocker.sol:497: i--; AuraLocker.sol:664: for (uint256 i = locksLength; i > 0; i--) { AuraLocker.sol:726: for (uint256 i = epochIndex + 1; i > 0; i--) {
It is recommended to use prefix increment instead of postfix one when the return value is not needed, as both of them will give the same result and prefix increment costs less gas.
For example :
mocks/balancer/MockFeeDistro.sol:19: for (uint256 i = 0; i < _tokens.length; ++i) {
Comparing a boolean to a constant costs more gas than directly checking the returned value of the boolean.
AuraMerkleDrop.sol: require(hasClaimed[msg.sender] == false, "already claimed");
For example in an if statement, it is recommended to use if(directValue)
instead of if(directValue == true)
and if(!directValue)
instead of if(directValue == false)
Changes :
AuraMerkleDrop.sol: require(!hasClaimed[msg.sender], "already claimed");
#0 - kartoonjoy
2022-05-24T18:42:27Z
Per warden, Kaiziron, the additional finding from Don't compare a boolean to a constant was to be appended to the gas report.