code-423n4 / 2022-05-vetoken-findings

1 stars 1 forks source link

Gas Optimizations #240

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

Gas

[G-01] No need to initialize variables with default values

Impact

If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

Proof of Concept

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/BaseRewardPool.sol#L66-L72

    uint256 public periodFinish = 0;
    uint256 public rewardRate = 0;
    uint256 public queuedRewards = 0;
    uint256 public currentRewards = 0;
    uint256 public historicalRewards = 0;
  BaseRewardPool.sol::176 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::199 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::218 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::245 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::282 => for (uint256 i = 0; i < extraRewards.length; i++) {
  Booster.sol::110 => isShutdown = false;
  Booster.sol::329 => for (uint256 i = 0; i < poolInfo.length; i++) {
  VE3DRewardPool.sol::148 => for (uint256 i = 0; i < rewardTokens.length(); i++) {
  VE3DRewardPool.sol::214 => for (uint256 i = 0; i < length; i++) {
  VE3DRewardPool.sol::238 => for (uint256 i = 0; i < length; i++) {
  VE3DRewardPool.sol::257 => for (uint256 i = 0; i < length; i++) {
  VE3DRewardPool.sol::281 => for (uint256 i = 0; i < rewardTokens.length(); i++) {
  VE3DRewardPool.sol::326 => for (uint256 i = 0; i < length; i++) {
  VoterProxy.sol::217 => for (uint256 i = 0; i < _tokenVote.length; i++) {
  VoterProxy.sol::227 => uint256 _balance = 0;

Recommendation

Remove explicit default initializations.

[G-02] Use != 0 instead of > 0 for Unsigned Integer Comparison in require statements.

Impact

!= 0 is cheapear than > 0 when comparing unsigned integers in require statements.

Proof of Concept

  BaseRewardPool.sol::173 => require(_amount > 0, "RewardPool : Cannot stake 0");
  BaseRewardPool.sol::196 => require(_amount > 0, "RewardPool : Cannot stake 0");
  BaseRewardPool.sol::215 => require(amount > 0, "RewardPool : Cannot withdraw 0");
  VE3DRewardPool.sol::210 => require(_amount > 0, "RewardPool : Cannot stake 0");
  VE3DRewardPool.sol::234 => require(_amount > 0, "RewardPool : Cannot stake 0");
  VE3DRewardPool.sol::253 => require(_amount > 0, "RewardPool : Cannot withdraw 0");
  VeAssetDepositor.sol::132 => require(_amount > 0, "!>0");

Recommendation

Use != 0 instead of > 0.

[G-03] Cache Array Length Outside of Loop.

Impact

Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration.

Proof of Concept

  BaseRewardPool.sol::176 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::199 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::218 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::245 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::282 => for (uint256 i = 0; i < extraRewards.length; i++) {
  Booster.sol::329 => for (uint256 i = 0; i < poolInfo.length; i++) {
  VE3DRewardPool.sol::148 => for (uint256 i = 0; i < rewardTokens.length(); i++) {
  VE3DRewardPool.sol::281 => for (uint256 i = 0; i < rewardTokens.length(); i++) {
  VoterProxy.sol::217 => for (uint256 i = 0; i < _tokenVote.length; i++) {

Recommendation

Store the array’s length in a variable before the for-loop.

[G-04] ++i costs less gas compared to i++ or i += 1

Impact

++i costs less gas compared to i++ or i += 1 for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.

Proof of Concept

  BaseRewardPool.sol::176 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::199 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::218 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::245 => for (uint256 i = 0; i < extraRewards.length; i++) {
  BaseRewardPool.sol::282 => for (uint256 i = 0; i < extraRewards.length; i++) {
  Booster.sol::329 => for (uint256 i = 0; i < poolInfo.length; i++) {
  VE3DRewardPool.sol::148 => for (uint256 i = 0; i < rewardTokens.length(); i++) {
  VE3DRewardPool.sol::214 => for (uint256 i = 0; i < length; i++) {
  VE3DRewardPool.sol::238 => for (uint256 i = 0; i < length; i++) {
  VE3DRewardPool.sol::257 => for (uint256 i = 0; i < length; i++) {
  VE3DRewardPool.sol::281 => for (uint256 i = 0; i < rewardTokens.length(); i++) {
  VE3DRewardPool.sol::326 => for (uint256 i = 0; i < length; i++) {
  VoterProxy.sol::217 => for (uint256 i = 0; i < _tokenVote.length; i++) {

Recommendation

Use ++i instead of i++ to increment the value of an uint variable. Same thing for --i and i--.

[G-05] SafeMath is unnecessary in solidity versions >0.8.0.

Impact

Arithmetic operations revert on underflow and overflow in solidity versions >0.8.0. Using SafeMath is redundant and a waste of gas.

Proof of Concept

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/Booster.sol#L2-L4

pragma solidity 0.8.7;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/VeAssetDepositor.sol#L2-L4

pragma solidity 0.8.7;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/BaseRewardPool.sol#L42

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/VE3DRewardPool.sol#L42-L43

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/VoterProxy.sol#L2-L4

pragma solidity 0.8.7;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-05-vetoken/blob/2d7cd1f6780a9bcc8387dea8fecfbd758462c152/contracts/VeTokenMinter.sol#L8

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

Recommendation

Get rid of SafeMath.sol.

Tools used

c4udit, manual, slither

GalloDaSballo commented 2 years ago

Less than 500 gas