Issue | Instances | |
---|---|---|
GAS-1 | Using bools for storage incurs overhead | 12 |
GAS-2 | Cache array length outside of loop | 5 |
GAS-3 | For Operations that will not overflow, you could use unchecked | 368 |
GAS-4 | Use Custom Errors | 32 |
GAS-5 | Don't initialize variables with default value | 41 |
GAS-6 | Long revert strings | 1 |
GAS-7 | Functions guaranteed to revert when called by normal users can be marked payable |
17 |
GAS-8 | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) |
20 |
GAS-9 | Using private rather than public for constants, saves gas |
4 |
GAS-10 | Use shift Right/Left instead of division/multiplication if possible | 4 |
GAS-11 | Splitting require() statements that use && saves gas | 2 |
GAS-12 | Use != 0 instead of > 0 for unsigned integer comparison | 19 |
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.
Instances (12):
File: VestedZeroLend.sol
18: mapping(address => bool) public whitelist;
19: mapping(address => bool) public blacklist;
20: bool public enableWhitelist;
21: bool public enableBlacklist;
File: ZLRewardsController.sol
29: bool public persistRewardsPerSecond;
48: mapping(address => bool) private validRTokens;
60: mapping(address => bool) public eligibilityExempt;
87: mapping(address => bool) public authorizedContracts;
90: mapping(address => bool) public whitelist;
92: bool public whitelistActive;
File: ZeroLend.sol
18: mapping(address => bool) public blacklisted;
File: ZeroLocker.sol
64: mapping(address => mapping(address => bool)) internal ownerToOperators;
If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).
Instances (5):
File: FeeDistributor.sol
291: for (uint256 index = 0; index < nftIds.length; index++) {
File: ZeroLockerTimelock.sol
118: for (uint256 i = 0; i < proposers.length; ++i) {
124: for (uint256 i = 0; i < executors.length; ++i) {
302: for (uint256 i = 0; i < targets.length; ++i) {
414: for (uint256 i = 0; i < targets.length; ++i) {
Instances (368):
File: BonusPool.sol
15: import {IBonusPool} from "./interfaces/IBonusPool.sol";
15: import {IBonusPool} from "./interfaces/IBonusPool.sol";
19: uint256 public immutable PCT_100 = 100000; // 100%
19: uint256 public immutable PCT_100 = 100000; // 100%
23: _setBonusBps(20000); // 20%
23: _setBonusBps(20000); // 20%
27: return (amount * bonusBps) / PCT_100;
27: return (amount * bonusBps) / PCT_100;
File: Epoch.sol
44: return (lastExecutedAt - startTime) / (period);
44: return (lastExecutedAt - startTime) / (period);
48: return (Math.max(startTime, block.timestamp) - (startTime)) / (period);
48: return (Math.max(startTime, block.timestamp) - (startTime)) / (period);
63: return _getLastEpoch() + (1);
72: return (Math.max(startTime, block.timestamp) - (startTime)) / (period);
72: return (Math.max(startTime, block.timestamp) - (startTime)) / (period);
80: return startTime + (_getNextEpoch() * (period));
80: return startTime + (_getNextEpoch() * (period));
File: FeeDistributor.sol
16: import {IFeeDistributor} from "./interfaces/IFeeDistributor.sol";
16: import {IFeeDistributor} from "./interfaces/IFeeDistributor.sol";
17: import {IZeroLocker} from "./interfaces/IZeroLocker.sol";
17: import {IZeroLocker} from "./interfaces/IZeroLocker.sol";
35: uint256[1000000000000000] public veSupply; // VE total supply at week bounds
35: uint256[1000000000000000] public veSupply; // VE total supply at week bounds
45: WEEK = 7 * 86400;
49: uint256 t = (block.timestamp / WEEK) * WEEK;
49: uint256 t = (block.timestamp / WEEK) * WEEK;
60: uint256 toDistribute = tokenBalance - tokenLastBalance;
64: uint256 sinceLast = timestamp - t;
67: uint256 thisWeek = (t / WEEK) * WEEK;
67: uint256 thisWeek = (t / WEEK) * WEEK;
70: for (uint256 index = 0; index < 20; index++) {
70: for (uint256 index = 0; index < 20; index++) {
71: nextWeek = thisWeek + WEEK;
74: tokensPerWeek[thisWeek] += toDistribute;
76: tokensPerWeek[thisWeek] +=
77: (toDistribute * (timestamp - t)) /
77: (toDistribute * (timestamp - t)) /
77: (toDistribute * (timestamp - t)) /
82: tokensPerWeek[thisWeek] += toDistribute;
84: tokensPerWeek[thisWeek] +=
85: (toDistribute * (nextWeek - t)) /
85: (toDistribute * (nextWeek - t)) /
85: (toDistribute * (nextWeek - t)) /
97: ((block.timestamp > lastTokenTime + TOKEN_CHECKPOINT_DEADLINE)),
109: for (uint256 index = 0; index < 128; index++) {
109: for (uint256 index = 0; index < 128; index++) {
113: uint256 mid = (min + max + 2) / 2;
113: uint256 mid = (min + max + 2) / 2;
113: uint256 mid = (min + max + 2) / 2;
117: else max = mid - 1;
131: for (uint256 index = 0; index < 128; index++) {
131: for (uint256 index = 0; index < 128; index++) {
135: uint256 mid = (min + max + 2) / 2;
135: uint256 mid = (min + max + 2) / 2;
135: uint256 mid = (min + max + 2) / 2;
139: else max = mid - 1;
147: uint256 roundedTimestamp = (timestamp / WEEK) * WEEK;
147: uint256 roundedTimestamp = (timestamp / WEEK) * WEEK;
151: for (uint256 index = 0; index < 20; index++) {
151: for (uint256 index = 0; index < 20; index++) {
159: if (t > pt.ts) dt = int128(uint128(t - pt.ts));
160: veSupply[t] = Math.max(uint128(pt.bias - pt.slope * dt), 0);
160: veSupply[t] = Math.max(uint128(pt.bias - pt.slope * dt), 0);
163: t += WEEK;
203: weekCursor = ((userPoint.ts + WEEK - 1) / WEEK) * WEEK;
203: weekCursor = ((userPoint.ts + WEEK - 1) / WEEK) * WEEK;
203: weekCursor = ((userPoint.ts + WEEK - 1) / WEEK) * WEEK;
203: weekCursor = ((userPoint.ts + WEEK - 1) / WEEK) * WEEK;
211: for (uint256 index = 0; index < 50; index++) {
211: for (uint256 index = 0; index < 50; index++) {
215: userEpoch += 1;
222: int128 dt = int128(uint128(weekCursor - oldUserPoint.ts));
224: uint128(oldUserPoint.bias - dt * oldUserPoint.slope),
224: uint128(oldUserPoint.bias - dt * oldUserPoint.slope),
230: toDistribute +=
231: (balanceOf * tokensPerWeek[weekCursor]) /
231: (balanceOf * tokensPerWeek[weekCursor]) /
234: weekCursor += WEEK;
238: userEpoch = Math.min(maxUserEpoch, userEpoch - 1);
252: if ((block.timestamp > lastTokenTime + TOKEN_CHECKPOINT_DEADLINE)) {
257: _lastTokenTime = (_lastTokenTime / WEEK) * WEEK;
257: _lastTokenTime = (_lastTokenTime / WEEK) * WEEK;
263: tokenLastBalance -= amount;
284: if ((block.timestamp > lastTokenTime + TOKEN_CHECKPOINT_DEADLINE)) {
289: _lastTokenTime = (_lastTokenTime / WEEK) * WEEK;
289: _lastTokenTime = (_lastTokenTime / WEEK) * WEEK;
291: for (uint256 index = 0; index < nftIds.length; index++) {
291: for (uint256 index = 0; index < nftIds.length; index++) {
296: tokenLastBalance -= amount;
File: StakingEmissions.sol
17: import {IFeeDistributor} from "./interfaces/IFeeDistributor.sol";
17: import {IFeeDistributor} from "./interfaces/IFeeDistributor.sol";
18: import {IZeroLocker} from "./interfaces/IZeroLocker.sol";
18: import {IZeroLocker} from "./interfaces/IZeroLocker.sol";
19: import {Epoch} from "./Epoch.sol";
45: initEpoch(86400 * 7, block.timestamp);
File: StreamedVesting.sol
28: uint256 public duration = 3 * 30 days; // 3 months vesting
28: uint256 public duration = 3 * 30 days; // 3 months vesting
28: uint256 public duration = 3 * 30 days; // 3 months vesting
75: lastId++;
75: lastId++;
87: userVestCounts[to] = userVestCount + 1;
96: uint256 lockAmount = vest.amount - vest.claimed;
110: lockAmount += bonusAmount;
114: locker.createLockFor(lockAmount, 86400 * 365 * 4, msg.sender);
114: locker.createLockFor(lockAmount, 86400 * 365 * 4, msg.sender);
125: vest.claimed += val;
137: uint256 pendingAmt = vest.amount - vest.claimed;
141: vest.claimed += pendingAmt;
146: uint256 penaltyAmt = ((pendingAmt * penaltyPct) / 1e18);
146: uint256 penaltyAmt = ((pendingAmt * penaltyPct) / 1e18);
147: underlying.transfer(msg.sender, pendingAmt - penaltyAmt);
178: uint256 pendingAmt = vest.amount - vest.claimed;
180: pendingAmt -
181: ((pendingAmt * _penaltyAmt) / 1e18);
181: ((pendingAmt * _penaltyAmt) / 1e18);
192: uint256 pendingAmt = vest.amount - vest.claimed;
195: return pendingAmt - ((pendingAmt * _penalty) / 1e18);
195: return pendingAmt - ((pendingAmt * _penalty) / 1e18);
195: return pendingAmt - ((pendingAmt * _penalty) / 1e18);
207: if (nowTime > startTime + duration) return 0;
210: if (nowTime < startTime) return 95e18 / 100;
212: uint256 percentage = ((nowTime - startTime) * 1e18) / duration;
212: uint256 percentage = ((nowTime - startTime) * 1e18) / duration;
212: uint256 percentage = ((nowTime - startTime) * 1e18) / duration;
214: uint256 penaltyE20 = 95e18 - (75e18 * percentage) / 1e18;
214: uint256 penaltyE20 = 95e18 - (75e18 * percentage) / 1e18;
214: uint256 penaltyE20 = 95e18 - (75e18 * percentage) / 1e18;
215: return penaltyE20 / 100;
221: _claimable(vest.amount, vest.startAt, block.timestamp) -
231: if (nowTime > startTime + duration) return amount;
237: return (amount * (nowTime - startTime)) / duration;
237: return (amount * (nowTime - startTime)) / duration;
237: return (amount * (nowTime - startTime)) / duration;
243: for (uint i = 0; i < userVestCounts[who]; i++) {
243: for (uint i = 0; i < userVestCounts[who]; i++) {
File: ZLRewardsController.sol
181: totalAllocPoint = totalAllocPoint + _allocPoint;
207: _totalAllocPoint -
208: pool.allocPoint +
212: i++;
212: i++;
242: uint128 offset = uint128(block.timestamp - startTime);
249: i++;
249: i++;
256: emissionSchedule[i - 1].rewardsPerSecond
276: i++;
276: i++;
298: if (_startTimeOffsets[i - 1] > _startTimeOffsets[i])
309: if (_startTimeOffsets[i] < block.timestamp - startTime)
319: i++;
319: i++;
361: i++;
361: i++;
389: accountedRewards = accountedRewards + reward;
390: pool.accRewardPerShare = pool.accRewardPerShare + newAccRewardPerShare;
418: accRewardPerShare = accRewardPerShare + newAccRewardPerShare;
421: (user.amount * accRewardPerShare) /
421: (user.amount * accRewardPerShare) /
422: ACC_REWARD_PRECISION -
425: i++;
425: i++;
454: uint256 rewardDebt = (user.amount * pool.accRewardPerShare) /
454: uint256 rewardDebt = (user.amount * pool.accRewardPerShare) /
456: pending = pending + rewardDebt - user.rewardDebt;
456: pending = pending + rewardDebt - user.rewardDebt;
460: i++;
460: i++;
537: uint256 pending = (amount * accRewardPerShare) /
537: uint256 pending = (amount * accRewardPerShare) /
538: ACC_REWARD_PRECISION -
541: userBaseClaimable[_user] = userBaseClaimable[_user] + pending;
544: pool.totalSupply = pool.totalSupply - user.amount;
546: user.rewardDebt = (_balance * accRewardPerShare) / ACC_REWARD_PRECISION;
546: user.rewardDebt = (_balance * accRewardPerShare) / ACC_REWARD_PRECISION;
547: pool.totalSupply = pool.totalSupply + _balance;
596: poolInfo[registeredTokens[i]].totalSupply +
597: newBal -
602: i++;
602: i++;
623: i++;
623: i++;
654: endingTime.lastUpdatedTime + endingTime.updateCadence >
667: extra +=
668: ((pool.lastRewardTime - lastAllPoolUpdate) *
668: ((pool.lastRewardTime - lastAllPoolUpdate) *
669: pool.allocPoint *
670: rewardsPerSecond) /
674: i++;
674: i++;
683: uint256 newEndTime = (unclaimedRewards + extra) /
683: uint256 newEndTime = (unclaimedRewards + extra) /
684: rewardsPerSecond +
708: depositedRewards = depositedRewards + _amount;
722: return depositedRewards - accountedRewards;
745: pending += claimable[i];
747: i++;
747: i++;
777: uint256 duration = block.timestamp - pool.lastRewardTime;
778: uint256 rawReward = duration * rewardsPerSecond;
784: newReward = (rawReward * pool.allocPoint) / _totalAllocPoint;
784: newReward = (rawReward * pool.allocPoint) / _totalAllocPoint;
786: (newReward * ACC_REWARD_PRECISION) /
786: (newReward * ACC_REWARD_PRECISION) /
File: ZeroLend.sol
23: _mint(msg.sender, 100_000_000_000 * 10 ** decimals());
23: _mint(msg.sender, 100_000_000_000 * 10 ** decimals());
23: _mint(msg.sender, 100_000_000_000 * 10 ** decimals());
File: ZeroLocker.sol
33: mapping(uint256 => Point) internal _pointHistory; // epoch -> unsigned point
33: mapping(uint256 => Point) internal _pointHistory; // epoch -> unsigned point
33: mapping(uint256 => Point) internal _pointHistory; // epoch -> unsigned point
34: mapping(uint256 => Point[1000000000]) internal _userPointHistory; // user -> Point[userEpoch]
34: mapping(uint256 => Point[1000000000]) internal _userPointHistory; // user -> Point[userEpoch]
34: mapping(uint256 => Point[1000000000]) internal _userPointHistory; // user -> Point[userEpoch]
37: mapping(uint256 => int128) public slopeChanges; // time -> signed slope change
37: mapping(uint256 => int128) public slopeChanges; // time -> signed slope change
37: mapping(uint256 => int128) public slopeChanges; // time -> signed slope change
73: MAXTIME = 4 * 365 * 86400;
73: MAXTIME = 4 * 365 * 86400;
74: iMAXTIME = 4 * 365 * 86400;
74: iMAXTIME = 4 * 365 * 86400;
93: bytes4(0x01ffc9a7) == _interfaceID || // ERC165
93: bytes4(0x01ffc9a7) == _interfaceID || // ERC165
94: bytes4(0x80ac58cd) == _interfaceID || // ERC721
94: bytes4(0x80ac58cd) == _interfaceID || // ERC721
95: bytes4(0x5b5e139f) == _interfaceID || // ERC721Metadata
95: bytes4(0x5b5e139f) == _interfaceID || // ERC721Metadata
183: for (uint256 index = 0; index < ownerToNFTokenCount[_owner]; index++) {
183: for (uint256 index = 0; index < ownerToNFTokenCount[_owner]; index++) {
185: _power += _balanceOfNFT(_tokenId, block.timestamp);
254: uint256 currentCount = _balance(_from) - 1;
289: ownerToNFTokenCount[_to] += 1;
302: ownerToNFTokenCount[_from] -= 1;
514: uOld.slope = oldLocked.amount / iMAXTIME;
516: uOld.slope *
517: int128(int256(oldLocked.end - block.timestamp));
520: uNew.slope = newLocked.amount / iMAXTIME;
522: uNew.slope *
523: int128(int256(newLocked.end - block.timestamp));
553: uint256 blockSlope = 0; // dblock/dt
553: uint256 blockSlope = 0; // dblock/dt
553: uint256 blockSlope = 0; // dblock/dt
556: (MULTIPLIER * (block.number - lastPoint.blk)) /
556: (MULTIPLIER * (block.number - lastPoint.blk)) /
556: (MULTIPLIER * (block.number - lastPoint.blk)) /
557: (block.timestamp - lastPoint.ts);
564: uint256 tI = (lastCheckpoint / WEEK) * WEEK;
564: uint256 tI = (lastCheckpoint / WEEK) * WEEK;
565: for (uint256 i = 0; i < 255; ++i) {
565: for (uint256 i = 0; i < 255; ++i) {
568: tI += WEEK;
575: lastPoint.bias -=
576: lastPoint.slope *
577: int128(int256(tI - lastCheckpoint));
578: lastPoint.slope += dSlope;
590: initialLastPoint.blk +
591: (blockSlope * (tI - initialLastPoint.ts)) /
591: (blockSlope * (tI - initialLastPoint.ts)) /
591: (blockSlope * (tI - initialLastPoint.ts)) /
593: _epoch += 1;
609: lastPoint.slope += (uNew.slope - uOld.slope);
609: lastPoint.slope += (uNew.slope - uOld.slope);
610: lastPoint.bias += (uNew.bias - uOld.bias);
610: lastPoint.bias += (uNew.bias - uOld.bias);
628: oldDslope += uOld.slope;
630: oldDslope -= uNew.slope; // It was a new deposit, not extension
630: oldDslope -= uNew.slope; // It was a new deposit, not extension
630: oldDslope -= uNew.slope; // It was a new deposit, not extension
637: newDslope -= uNew.slope; // old slope disappeared at this point
637: newDslope -= uNew.slope; // old slope disappeared at this point
637: newDslope -= uNew.slope; // old slope disappeared at this point
643: uint256 userEpoch = userPointEpoch[_tokenId] + 1;
668: supply = supplyBefore + _value;
673: _locked.amount += int128(int256(_value));
702: emit Supply(supplyBefore, supplyBefore + _value);
743: require(_value > 0, "value = 0"); // dev: need non-zero value
743: require(_value > 0, "value = 0"); // dev: need non-zero value
743: require(_value > 0, "value = 0"); // dev: need non-zero value
758: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
758: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
758: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
758: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
758: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
760: require(_value > 0, "value = 0"); // dev: need non-zero value
760: require(_value > 0, "value = 0"); // dev: need non-zero value
760: require(_value > 0, "value = 0"); // dev: need non-zero value
763: unlockTime <= block.timestamp + MAXTIME,
767: ++tokenId;
767: ++tokenId;
816: assert(_value > 0); // dev: need non-zero value
816: assert(_value > 0); // dev: need non-zero value
816: assert(_value > 0); // dev: need non-zero value
841: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
841: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
841: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
841: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
841: uint256 unlockTime = ((block.timestamp + _lockDuration) / WEEK) * WEEK; // Locktime is rounded down to weeks
847: unlockTime <= block.timestamp + MAXTIME,
851: unlockTime <= _locked.start + MAXTIME,
878: supply = supplyBefore - value;
891: emit Supply(supplyBefore, supplyBefore - value);
909: for (uint256 i = 0; i < 128; ++i) {
909: for (uint256 i = 0; i < 128; ++i) {
914: uint256 _mid = (_min + _max + 1) / 2;
914: uint256 _mid = (_min + _max + 1) / 2;
914: uint256 _mid = (_min + _max + 1) / 2;
918: _max = _mid - 1;
938: lastPoint.bias -=
939: lastPoint.slope *
940: int128(int256(_t) - int256(lastPoint.ts));
978: for (uint256 i = 0; i < 128; ++i) {
978: for (uint256 i = 0; i < 128; ++i) {
983: uint256 _mid = (_min + _max + 1) / 2;
983: uint256 _mid = (_min + _max + 1) / 2;
983: uint256 _mid = (_min + _max + 1) / 2;
987: _max = _mid - 1;
999: Point memory point1 = _pointHistory[_epoch + 1];
1000: dBlock = point1.blk - point0.blk;
1001: dT = point1.ts - point0.ts;
1003: dBlock = block.number - point0.blk;
1004: dT = block.timestamp - point0.ts;
1008: blockTime += (dT * (_block - point0.blk)) / dBlock;
1008: blockTime += (dT * (_block - point0.blk)) / dBlock;
1008: blockTime += (dT * (_block - point0.blk)) / dBlock;
1008: blockTime += (dT * (_block - point0.blk)) / dBlock;
1011: upoint.bias -= upoint.slope * int128(int256(blockTime - upoint.ts));
1011: upoint.bias -= upoint.slope * int128(int256(blockTime - upoint.ts));
1011: upoint.bias -= upoint.slope * int128(int256(blockTime - upoint.ts));
1035: uint256 tI = (lastPoint.ts / WEEK) * WEEK;
1035: uint256 tI = (lastPoint.ts / WEEK) * WEEK;
1036: for (uint256 i = 0; i < 255; ++i) {
1036: for (uint256 i = 0; i < 255; ++i) {
1037: tI += WEEK;
1044: lastPoint.bias -=
1045: lastPoint.slope *
1046: int128(int256(tI - lastPoint.ts));
1050: lastPoint.slope += dSlope;
1086: Point memory pointNext = _pointHistory[targetEpoch + 1];
1089: ((_block - point.blk) * (pointNext.ts - point.ts)) /
1089: ((_block - point.blk) * (pointNext.ts - point.ts)) /
1089: ((_block - point.blk) * (pointNext.ts - point.ts)) /
1089: ((_block - point.blk) * (pointNext.ts - point.ts)) /
1090: (pointNext.blk - point.blk);
1095: ((_block - point.blk) * (block.timestamp - point.ts)) /
1095: ((_block - point.blk) * (block.timestamp - point.ts)) /
1095: ((_block - point.blk) * (block.timestamp - point.ts)) /
1095: ((_block - point.blk) * (block.timestamp - point.ts)) /
1096: (block.number - point.blk);
1100: return _supplyAt(point, point.ts + dt);
File: ZeroLockerTimelock.sol
118: for (uint256 i = 0; i < proposers.length; ++i) {
118: for (uint256 i = 0; i < proposers.length; ++i) {
124: for (uint256 i = 0; i < executors.length; ++i) {
124: for (uint256 i = 0; i < executors.length; ++i) {
302: for (uint256 i = 0; i < targets.length; ++i) {
302: for (uint256 i = 0; i < targets.length; ++i) {
330: _timestamps[id] = block.timestamp + delay;
414: for (uint256 i = 0; i < targets.length; ++i) {
414: for (uint256 i = 0; i < targets.length; ++i) {
File: interfaces/IZLRewardsController.sol
4: import "./IIncentivesController.sol";
18: uint256 allocPoint; // How many allocation points assigned to this pool.
18: uint256 allocPoint; // How many allocation points assigned to this pool.
19: uint256 lastRewardTime; // Last second that reward distribution occurs.
19: uint256 lastRewardTime; // Last second that reward distribution occurs.
20: uint256 accRewardPerShare; // Accumulated rewards per share, times ACC_REWARD_PRECISION. See below.
20: uint256 accRewardPerShare; // Accumulated rewards per share, times ACC_REWARD_PRECISION. See below.
File: interfaces/IZeroLocker.sol
57: int128 slope; // # -dweight / dt
57: int128 slope; // # -dweight / dt
57: int128 slope; // # -dweight / dt
57: int128 slope; // # -dweight / dt
59: uint256 blk; // block
59: uint256 blk; // block
Source Instead of using error strings, to reduce deployment and runtime cost, you should use Custom Errors. This would save both deployment and runtime cost.
Instances (32):
File: BonusPool.sol
41: require(IERC20(tkn).balanceOf(address(this)) > 0, "No tokens");
48: require(bonusBps <= PCT_100, "bonus too high");
File: Epoch.sol
32: require(block.timestamp >= startTime, "Epoch: not started yet");
37: require(block.timestamp > startTime, "Epoch: not started yet");
38: require(_callable(), "Epoch: not allowed");
File: StreamedVesting.sol
94: require(msg.sender == vest.who, "not owner");
119: require(msg.sender == vest.who, "not owner");
122: require(val > 0, "no claimable amount");
135: require(msg.sender == vest.who, "not owner");
138: require(pendingAmt > 0, "no pending amount");
File: VestedZeroLend.sol
53: require(whitelist[from] || whitelist[to], "!whitelist");
57: require(!blacklist[to] && !blacklist[from], "blacklist");
File: ZeroLend.sol
39: require(!blacklisted[from] && !blacklisted[to], "blacklisted");
File: ZeroLocker.sol
329: require(_isApprovedOrOwner(_sender, _tokenId), "not approved sender");
442: require(owner != address(0), "owner is 0x0");
444: require(_approved != owner, "not owner");
448: require(senderIsOwner || senderIsApprovedForAll, "invalid sender");
706: require(_from != _to, "same nft");
707: require(_isApprovedOrOwner(msg.sender, _from), "from not approved");
708: require(_isApprovedOrOwner(msg.sender, _to), "to not approved");
743: require(_value > 0, "value = 0"); // dev: need non-zero value
744: require(_locked.amount > 0, "No existing lock found");
745: require(_locked.end > block.timestamp, "Cannot add to expired lock.");
760: require(_value > 0, "value = 0"); // dev: need non-zero value
761: require(unlockTime > block.timestamp, "Can only lock in the future");
817: require(_locked.amount > 0, "No existing lock found");
818: require(_locked.end > block.timestamp, "Cannot add to expired lock.");
843: require(_locked.end > block.timestamp, "Lock expired");
844: require(_locked.amount > 0, "Nothing is locked");
845: require(unlockTime > _locked.end, "Can only increase lock duration");
873: require(block.timestamp >= _locked.end, "The lock didn't expire");
File: ZeroLockerTimelock.sol
433: require(success, "TimelockController: underlying transaction reverted");
Instances (41):
File: FeeDistributor.sol
68: uint256 nextWeek = 0;
70: for (uint256 index = 0; index < 20; index++) {
106: uint256 min = 0;
109: for (uint256 index = 0; index < 128; index++) {
128: uint256 min = 0;
131: for (uint256 index = 0; index < 128; index++) {
151: for (uint256 index = 0; index < 20; index++) {
157: int128 dt = 0;
177: uint256 userEpoch = 0;
178: uint256 toDistribute = 0;
211: for (uint256 index = 0; index < 50; index++) {
291: for (uint256 index = 0; index < nftIds.length; index++) {
File: StreamedVesting.sol
243: for (uint i = 0; i < userVestCounts[who]; i++) {
File: ZLRewardsController.sol
271: for (uint256 i = 0; i < length; ) {
296: for (uint256 i = 0; i < length; ) {
661: uint256 extra = 0;
File: ZeroLocker.sol
183: for (uint256 index = 0; index < ownerToNFTokenCount[_owner]; index++) {
506: int128 oldDslope = 0;
507: int128 newDslope = 0;
553: uint256 blockSlope = 0; // dblock/dt
565: for (uint256 i = 0; i < 255; ++i) {
569: int128 dSlope = 0;
581: lastPoint.bias = 0;
585: lastPoint.slope = 0;
612: lastPoint.slope = 0;
615: lastPoint.bias = 0;
907: uint256 _min = 0;
909: for (uint256 i = 0; i < 128; ++i) {
942: lastPoint.bias = 0;
976: uint256 _min = 0;
978: for (uint256 i = 0; i < 128; ++i) {
996: uint256 dBlock = 0;
997: uint256 dT = 0;
1036: for (uint256 i = 0; i < 255; ++i) {
1038: int128 dSlope = 0;
1055: lastPoint.bias = 0;
1084: uint256 dt = 0;
File: ZeroLockerTimelock.sol
118: for (uint256 i = 0; i < proposers.length; ++i) {
124: for (uint256 i = 0; i < executors.length; ++i) {
302: for (uint256 i = 0; i < targets.length; ++i) {
414: for (uint256 i = 0; i < targets.length; ++i) {
Instances (1):
File: ZeroLockerTimelock.sol
433: require(success, "TimelockController: underlying transaction reverted");
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.
Instances (17):
File: BonusPool.sol
30: function setBonusBps(uint256 amount) external onlyOwner {
34: function withdrawStuckTokens(address tkn) public onlyOwner {
File: StakingEmissions.sol
44: function start() external onlyOwner {
File: StreamedVesting.sol
56: function start() external onlyOwner {
File: VestedZeroLend.sol
34: function addblacklist(address who, bool what) external onlyOwner {
38: function addwhitelist(address who, bool what) external onlyOwner {
42: function toggleWhitelist(bool from, bool to) external onlyOwner {
File: ZLRewardsController.sol
167: function start() public onlyOwner {
696: function setEndingTimeUpdateCadence(uint256 _lapse) external onlyOwner {
707: function registerRewardDeposit(uint256 _amount) external onlyOwner {
755: function pause() external onlyOwner {
762: function unpause() external onlyOwner {
796: function setAddressWLstatus(address user, bool status) external onlyOwner {
803: function toggleWhitelist() external onlyOwner {
File: ZeroLend.sol
26: function mint(uint256 amt) public onlyOwner {
30: function toggleBlacklist(address who, bool what) public onlyOwner {
File: ZeroLockerTimelock.sol
340: function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) {
Saves 5 gas per loop
Instances (20):
File: FeeDistributor.sol
70: for (uint256 index = 0; index < 20; index++) {
109: for (uint256 index = 0; index < 128; index++) {
131: for (uint256 index = 0; index < 128; index++) {
151: for (uint256 index = 0; index < 20; index++) {
211: for (uint256 index = 0; index < 50; index++) {
291: for (uint256 index = 0; index < nftIds.length; index++) {
File: StreamedVesting.sol
75: lastId++;
243: for (uint i = 0; i < userVestCounts[who]; i++) {
File: ZLRewardsController.sol
212: i++;
249: i++;
276: i++;
319: i++;
361: i++;
425: i++;
460: i++;
602: i++;
623: i++;
674: i++;
747: i++;
File: ZeroLocker.sol
183: for (uint256 index = 0; index < ownerToNFTokenCount[_owner]; index++) {
If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table
Instances (4):
File: ZeroLockerTimelock.sol
36: bytes32 public constant TIMELOCK_ADMIN_ROLE =
38: bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
39: bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
40: bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE");
Instances (4):
File: FeeDistributor.sol
113: uint256 mid = (min + max + 2) / 2;
135: uint256 mid = (min + max + 2) / 2;
File: ZeroLocker.sol
914: uint256 _mid = (_min + _max + 1) / 2;
983: uint256 _mid = (_min + _max + 1) / 2;
Instances (2):
File: VestedZeroLend.sol
57: require(!blacklist[to] && !blacklist[from], "blacklist");
File: ZeroLend.sol
39: require(!blacklisted[from] && !blacklisted[to], "blacklisted");
Instances (19):
File: BonusPool.sol
41: require(IERC20(tkn).balanceOf(address(this)) > 0, "No tokens");
File: FeeDistributor.sol
229: if (balanceOf > 0)
File: StreamedVesting.sol
122: require(val > 0, "no claimable amount");
138: require(pendingAmt > 0, "no pending amount");
File: ZLRewardsController.sol
297: if (i > 0) {
308: if (startTime > 0) {
710: if (rewardsPerSecond == 0 && lastRPS > 0) {
776: if (lpSupply > 0) {
File: ZeroLocker.sol
368: return size > 0;
513: if (oldLocked.end > block.timestamp && oldLocked.amount > 0) {
519: if (newLocked.end > block.timestamp && newLocked.amount > 0) {
545: if (_epoch > 0) {
743: require(_value > 0, "value = 0"); // dev: need non-zero value
744: require(_locked.amount > 0, "No existing lock found");
760: require(_value > 0, "value = 0"); // dev: need non-zero value
816: assert(_value > 0); // dev: need non-zero value
817: require(_locked.amount > 0, "No existing lock found");
844: require(_locked.amount > 0, "Nothing is locked");
File: ZeroLockerTimelock.sol
172: return getTimestamp(id) > 0;
Issue | Instances | |
---|---|---|
NC-1 | Return values of approve() not checked |
3 |
NC-2 | Event is missing indexed fields |
4 |
NC-3 | Constants should be defined rather than using magic numbers | 3 |
Not all IERC20 implementations revert()
when there's a failure in approve()
. The function signature has a boolean return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything
Instances (3):
File: BonusPool.sol
22: _underlying.approve(_vesting, type(uint256).max);
File: StreamedVesting.sol
48: underlying.approve(address(_locker), type(uint256).max);
File: ZeroLocker.sol
461: _approve(_approved, _tokenId);
Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.
Instances (4):
File: interfaces/IBonusPool.sol
12: event SetBonusBPS(uint256 oldValue, uint256 newValue);
File: interfaces/IZeroLocker.sol
72: event Deposit(
81: event Withdraw(
88: event Supply(uint256 prevSupply, uint256 supply);
Instances (3):
File: BonusPool.sol
23: _setBonusBps(20000); // 20%
File: StakingEmissions.sol
45: initEpoch(86400 * 7, block.timestamp);
File: StreamedVesting.sol
214: uint256 penaltyE20 = 95e18 - (75e18 * percentage) / 1e18;
Issue | Instances | |
---|---|---|
L-1 | Do not use deprecated library functions | 5 |
L-2 | Empty Function Body - Consider commenting why | 4 |
L-3 | Initializers could be front-run | 16 |
L-4 | Unsafe ERC20 operation(s) | 12 |
Instances (5):
File: ZeroLockerTimelock.sol
110: _setupRole(TIMELOCK_ADMIN_ROLE, address(this));
114: _setupRole(TIMELOCK_ADMIN_ROLE, admin);
119: _setupRole(PROPOSER_ROLE, proposers[i]);
120: _setupRole(CANCELLER_ROLE, proposers[i]);
125: _setupRole(EXECUTOR_ROLE, executors[i]);
Instances (4):
File: ZLRewardsController.sol
564: function handleActionBefore(address _user) external {}
571: function beforeLockUpdate(address _user) external {}
File: ZeroLocker.sol
400: returns (bytes4) {} catch (bytes memory reason) {
File: ZeroLockerTimelock.sol
148: receive() external payable {}
Initializers could be front-run, allowing an attacker to either set their own values, take ownership of the contract, and in the best case forcing a re-deployment
Instances (16):
File: FeeDistributor.sol
41: function initialize(
44: ) external initializer {
File: StakingEmissions.sol
30: function initialize(
34: ) external initializer {
39: __Ownable_init();
40: __Pausable_init();
File: StreamedVesting.sol
38: function initialize(
43: ) external initializer {
50: __Ownable_init();
51: __Pausable_init();
File: ZLRewardsController.sol
116: function initialize(
123: ) public initializer {
128: __Ownable_init();
129: __Pausable_init();
File: ZeroLocker.sol
71: function initialize(address _underlying) public initializer {
71: function initialize(address _underlying) public initializer {
Instances (12):
File: BonusPool.sol
22: _underlying.approve(_vesting, type(uint256).max);
43: IERC20(tkn).transfer(msg.sender, amount);
File: FeeDistributor.sol
264: token.transfer(who, amount);
297: token.transfer(who, amount);
File: StakingEmissions.sol
57: token.transfer(address(feeDistributor), amtPerEpoch);
File: StreamedVesting.sol
48: underlying.approve(address(_locker), type(uint256).max);
105: underlying.transferFrom(
129: underlying.transfer(msg.sender, val);
147: underlying.transfer(msg.sender, pendingAmt - penaltyAmt);
148: underlying.transfer(dead, penaltyAmt);
File: ZeroLocker.sol
691: assert(underlying.transferFrom(from, address(this), _value));
885: assert(underlying.transfer(msg.sender, value));
Issue | Instances | |
---|---|---|
M-1 | Centralization Risk for trusted owners | 28 |
Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.
Instances (28):
File: BonusPool.sol
17: contract BonusPool is Ownable, IBonusPool {
30: function setBonusBps(uint256 amount) external onlyOwner {
34: function withdrawStuckTokens(address tkn) public onlyOwner {
File: StakingEmissions.sol
44: function start() external onlyOwner {
File: StreamedVesting.sol
56: function start() external onlyOwner {
File: VestedZeroLend.sol
17: contract VestedZeroLend is ERC20, ERC20Burnable, Ownable {
34: function addblacklist(address who, bool what) external onlyOwner {
38: function addwhitelist(address who, bool what) external onlyOwner {
42: function toggleWhitelist(bool from, bool to) external onlyOwner {
File: ZLRewardsController.sol
155: ) external onlyOwner {
167: function start() public onlyOwner {
198: ) external onlyOwner {
228: ) external onlyOwner {
291: ) external onlyOwner {
333: ) external onlyOwner {
484: ) external onlyOwner {
696: function setEndingTimeUpdateCadence(uint256 _lapse) external onlyOwner {
707: function registerRewardDeposit(uint256 _amount) external onlyOwner {
755: function pause() external onlyOwner {
762: function unpause() external onlyOwner {
796: function setAddressWLstatus(address user, bool status) external onlyOwner {
803: function toggleWhitelist() external onlyOwner {
File: ZeroLend.sol
26: function mint(uint256 amt) public onlyOwner {
30: function toggleBlacklist(address who, bool what) public onlyOwner {
File: ZeroLockerTimelock.sol
32: AccessControlEnumerable,
259: ) public virtual onlyRole(PROPOSER_ROLE) {
284: ) public virtual onlyRole(PROPOSER_ROLE) {
340: function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) {