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

0 stars 0 forks source link

Gas Optimizations #180

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

1. Unnecessary initialising with default values

When a variable is created it contains the default value, explicitly initialising variables with default values wastes gas

Proof of concept

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Velo.sol#L9

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1168

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1192

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Pair.sol#L20

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Pair.sol#L61-L62

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Router.sol#L112

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L222

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L254

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L286

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L481

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Voter.sol#L139-L141

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/RewardsDistributor.sol#L170-L171

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/RewardsDistributor.sol#L227-L228

Mitigation

Remove initialisation of default values

2. Cache storage values and re-use to save gas

When a storage value is read multiple times in a code block, it can be cached in a local variable to avoid expensive SLOADs and save gas

Proof of concept

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Velo.sol#L76

variable weekly is read multiple times in Minter.sol

        uint _growth = calculate_growth(weekly);             
        uint _teamEmissions = (teamRate * (_growth + weekly)) /
            (PRECISION - teamRate);
        uint _required = _growth + weekly + _teamEmissions;
        uint _balanceOf = _velo.balanceOf(address(this));
        if (_balanceOf < _required) {
            _velo.mint(address(this), _required - _balanceOf);
        }

        require(_velo.transfer(team, _teamEmissions));
        require(_velo.transfer(address(_rewards_distributor), _growth));
        _rewards_distributor.checkpoint_token(); // checkpoint token balance that was just minted in rewards distributor
        _rewards_distributor.checkpoint_total_supply(); // checkpoint supply

        _velo.approve(address(_voter), weekly);
        _voter.notifyRewardAmount(weekly);

        emit Mint(msg.sender, weekly, circulating_supply(), circulating_emission());

derivedBalances[account] can be replaced with _derivedBalance in

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L370

    _derivedBalance = derivedBalance(account);
    derivedBalances[account] = _derivedBalance;
    derivedSupply += _derivedBalance;

    _writeCheckpoint(account, derivedBalances[account]);

fantomSender can be cached and re-used

    require(fantomSender != address(0), "NOT_INITIALIZED");
    require(
        msg.sender == endpoint &&
            srcChainId == fantomChainId &&
            addressFromPackedBytes(srcAddress) == fantomSender,
        "UNAUTHORIZED_CALLER"
    );

Mitigation

Cache storage variable in a local variable and re-use

3. Cache array length to save gas

Array length can be stored in a local variable and re-used instead of querying it in every loop to save gas

Proof of concept

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Minter.sol#L57

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Voter.sol#L76

Mitigation

Store array length in a local variable and re-use

4. storage variable can be replaced with msg.sender

In VotingEscrow.sol#mintToRedemption since msg.sender is validation in the require statement, the second storage read of redemptionReceiver can be replaced with msg.sender as it consumes only 2 gas

Proof of concept

    require(msg.sender == redemptionReceiver);
    _mint(redemptionReceiver, amount);

Similarly in PairFactory.sol

L46        require(msg.sender == pendingPauser);
L47        pauser = pendingPauser;

L61    require(msg.sender == pendingFeeManager, 'not pending fee manager');
L62    feeManager = pendingFeeManager;

Minter.sol

L70        require(msg.sender == pendingTeam, "not pending team"); 
L71        team = pendingTeam; 

Mitigation

Replace second storage read with msg.sender

5. Shorten revert strings

Revert string takes a minimum of 32 bytes, longer strings increases deployment gas as well as runtime gas when the require condition is met

Proof of concept

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L398

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L518

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L774

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L786

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L821

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L886

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L942

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1017

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1146

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1317

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1380

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1384

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L1388

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Router.sol#L341

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Router.sol#L406

Mitigation

Reduce revert strings to 32 bytes

6. != 0 is more efficient than > 0 for unsigned integers

!= 0 costs less compared to >0 for unsigned integers in require statements with optimizer enabled

Proof of concept

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L772

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/PairFees.sol#L20

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Router.sol#L58-L59

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L512

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L592

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L613

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L665

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L672

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Gauge.sol#L679

https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/Voter.sol#L352

7. i++ can be replaced with ++i

pre-increment costs less compared to post-increment for unsigned integers.

Proof of concept

VotingEscrow.sol#L632
VotingEscrow.sol#L1193
VotingEscrow.sol#L1225
VotingEscrow.sol#L1249
VotingEscrow.sol#L1295
VotingEscrow.sol#L1320
VotingEscrow.sol#L1326
Router.sol#L90
Router.sol#L316
RewardsDistributor.sol#L75
RewardsDistributor.sol#L105
RewardsDistributor.sol#L121
RewardsDistributor.sol#L148
RewardsDistributor.sol#L195
RewardsDistributor.sol#L252
RewardsDistributor.sol#L301
Gauge.sol#L179
Gauge.sol#L353
Voter.sol#L143
Voter.sol#L147
Voter.sol#L266
Voter.sol#L304
Voter.sol#L310
Voter.sol#L346

Mitigation

Replace post-increment with pre-increment

GalloDaSballo commented 2 years ago

Findings would save between 1k and 2k gas