Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas Optimizations #182

Open
code423n4 opened this issue Oct 1, 2022 · 0 comments
Open

Gas Optimizations #182

code423n4 opened this issue Oct 1, 2022 · 0 comments
Labels
bug Something isn't working G (Gas Optimization)

Comments

@code423n4
Copy link
Contributor

code423n4 commented Oct 1, 2022

Gas Optimizations List

Number Optimization Details Per gas saved Context
[G-01] Use assembly to write address storage values 33 3
[G-02] Function ordering via Method ID 22 All contracts
[G-03] x += y costs more gas than x = x + y for state variables 16 4
[G-04] Use assembly to check for address(0) 6 2
[G-05] Deploy the contract with clone instead of new 1
[G-06] Setting the constructor to payable 13 4
[G-07] Free gas savings for using solidity 0.8.10+ All contracts
[G-08] Use Custom Errors rather than revert() / require() strings to save deployment gas  68 4
[G-09] Functions guaranteed to revert when callled by normal users can be marked payable  24 5
[G-10] Change to setOwner function 5.6k 1
[G-11] Remove to require(factory == address(0)); 1
[G-12] Use double require instead of using && 1

Total 12 issues

[G-01] Use assembly to write address storage values [33 gas per instance]

Context:
BuyCrowdfundBase.sol#L127
AlgebraFactory.sol#L87
AlgebraFactory.sol#L94

Proof Of Concept:
The optimizer was turned on and set to 10000 runs.

contract GasTestFoundry is DSTest {
    Contract1 c1;
    Contract2 c2;
    
    function setUp() public {
        c1 = new Contract1();
        c2 = new Contract2();
    }
    
    function testGas() public {
        c1.setRewardTokenAndAmount(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 356);
        c2.setRewardTokenAndAmount(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 356);
    }
}

contract Contract1  {
    address rewardToken ;
    uint256 reward;

    function setRewardTokenAndAmount(address token_, uint256 reward_) external {
        rewardToken = token_;
        reward = reward_;
    }
}

contract Contract2  {
    address rewardToken ;
    uint256 reward;

    function setRewardTokenAndAmount(address token_, uint256 reward_) external {
        assembly {
            sstore(rewardToken.slot, token_)
            sstore(reward.slot, reward_)           

        }
    }
}

Gas Report:

╭───────────────────────────────────────────┬─────────────────┬───────┬────────┬───────┬─────────╮
 src/test/GasTest.t.sol:Contract1 contract                                                 
╞═══════════════════════════════════════════╪═════════════════╪═══════╪════════╪═══════╪═════════╡
 Deployment Cost                            Deployment Size                                
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 50899                                      285                                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg    median  max    # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 setRewardTokenAndAmount                    44490            44490  44490   44490  1       
╰───────────────────────────────────────────┴─────────────────┴───────┴────────┴───────┴─────────╯
╭───────────────────────────────────────────┬─────────────────┬───────┬────────┬───────┬─────────╮
 src/test/GasTest.t.sol:Contract2 contract                                                 
╞═══════════════════════════════════════════╪═════════════════╪═══════╪════════╪═══════╪═════════╡
 Deployment Cost                            Deployment Size                                
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 38087                                      221                                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg    median  max    # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 setRewardTokenAndAmount                    44457            44457  44457   44457  1       
╰───────────────────────────────────────────┴─────────────────┴───────┴────────┴───────┴─────────╯

[G-02] Function ordering via Method ID [22 gas per instance]

Context: 
All Contracts

Description: 
Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions. 

Recommendation: 
Find a lower method ID name for the most called functions for example Call() vs. Call1() is cheaper by 22 gas
For example, the function IDs in the AlgebraPool.sol contract will be the most used; A lower method ID may be given.

Proof of Consept:
https://coinsbench.com/advanced-gas-optimizations-tips-for-solidity-85c47f413dc5

AlgebraPool.sol function names can be named and sorted according to METHOD ID

Sighash   |   Function Signature
========================
71334694  =>  swapSupportingFeeOnInputTokens(address,address,bool,int256,uint160,bytes)
54429aa9  =>  balanceToken0()
f81fb785  =>  balanceToken1()
74eceae6  =>  timepoints(uint256)
920c34e5  =>  getInnerCumulatives(int24,int24)
9d3a5241  =>  getTimepoints(uint32[])
f637731d  =>  initialize(uint160)
378934af  =>  _recalculatePosition(Position,int128,uint256,uint256)
37c50c53  =>  _updatePositionTicksAndFees(address,int24,int24,int128)
341a44dd  =>  _getAmountsForLiquidity(int24,int24,int128,int24,uint160)
8525eb6e  =>  getOrCreatePosition(address,int24,int24)
aafe29c0  =>  mint(address,address,int24,int24,uint128,bytes)
4f1eb3d8  =>  collect(address,int24,int24,uint128,uint128)
a34123a7  =>  burn(int24,int24,uint128)
2609fee3  =>  _getNewFee(uint32,int24,uint16,uint128)
10ff8907  =>  _payCommunityFee(address,uint256)
3dce4c59  =>  _writeTimepoint(uint16,uint32,int24,uint128,uint128)
4f1e3721  =>  _getSingleTimepoint(uint32,uint32,int24,uint16,uint128)
38e6ef28  =>  _swapCallback(int256,int256,bytes)
128acb08  =>  swap(address,bool,int256,uint160,bytes)
6607d5c2  =>  _calculateSwapAndLock(bool,int256,uint160)
545da887  =>  require(unlocked,'LOK')
490e6cbc  =>  flash(address,uint256,uint256,bytes)
7c0112b7  =>  setCommunityFee(uint8,uint8)
7c1fe0c8  =>  setIncentive(address)
289fe9b0  =>  setLiquidityCooldown(uint32)

[G-03] x += y costs more gas than x = x + y for state variables [16 gas per instance]

Context:
AlgebraPool.sol#L257
AlgebraPool.sol#L258
AlgebraPool.sol#L811
AlgebraPool.sol#L931

Description:
x += y costs more gas than x = x + y for state variables.

Proof Of Concept:
The optimizer was turned on and set to 10000 runs.

contract GasTest is DSTest {
    Contract0 c0;
    Contract1 c1;
    
    function setUp() public {
        c0 = new Contract0();
        c1 = new Contract1();
    }
    
    function testGas() public {
        c0.foo(33);
        c1.foo(33);
    }
}

contract Contract0 {
    uint256 _totalBorrow = 60;
    
    function foo(uint256 _interestEarned) public {
        _totalBorrow += interestEarned;
    }
}

contract Contract1 {
    uint256 _totalBorrow = 60;
    function foo(uint256 _interestEarned) public {
        _totalBorrow = _totalBorrow + interestEarned;
    }
}

Gas Report:

╭───────────────────────────────────────────┬─────────────────┬──────┬────────┬──────┬─────────╮
 src/test/GasTest.t.sol:Contract0 contract                                               
╞═══════════════════════════════════════════╪═════════════════╪══════╪════════╪══════╪═════════╡
 Deployment Cost                            Deployment Size                              
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 70805                                      279                                          
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg   median  max   # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 foo                                        5302             5302  5302    5302  1       
╰───────────────────────────────────────────┴─────────────────┴──────┴────────┴──────┴─────────╯
╭───────────────────────────────────────────┬─────────────────┬──────┬────────┬──────┬─────────╮
 src/test/GasTest.t.sol:Contract1 contract                                               
╞═══════════════════════════════════════════╪═════════════════╪══════╪════════╪══════╪═════════╡
 Deployment Cost                            Deployment Size                              
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 69805                                      274                                          
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg   median  max   # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 foo                                        5286             5286  5286    5286  1       
╰───────────────────────────────────────────┴─────────────────┴──────┴────────┴──────┴─────────╯

[G-04] Use assembly to check for address(0) [6 gas per instance]

Context: 
AlgebraFactory.sol#L62
AlgebraPoolDeployer.sol#L38

Proof Of Concept:
The optimizer was turned on and set to 10000 runs.

contract GasTest is DSTest {
    Contract0 c0;
    Contract1 c1;
    function setUp() public {
        c0 = new Contract0();
        c1 = new Contract1();
    }
    function testGas() public view {
        c0.setOperator(address(this));
        c1.setOperator(address(this));
    }
}
contract Contract0 {
    error Callback_InvalidParams();
    function setOperator(address operator_) public pure {
        if (address(operator_) == address(0)) revert Callback_InvalidParams();
    }
}
contract Contract1 {
    function setOperator(address operator_) public pure {
        assembly {
            if iszero(operator_) {
                mstore(0x00, "Callback_InvalidParams")
                revert(0x00, 0x20)
            }
        }
    }
}

Gas Report:

╭───────────────────────────────────────────┬─────────────────┬─────┬────────┬─────┬─────────╮
 src/test/GasTest.t.sol:Contract0 contract                                             
╞═══════════════════════════════════════════╪═════════════════╪═════╪════════╪═════╪═════════╡
 Deployment Cost                            Deployment Size                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 50899                                      285                                        
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg  median  max  # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 setOperator                                258              258  258     258  1       
╰───────────────────────────────────────────┴─────────────────┴─────┴────────┴─────┴─────────╯
╭───────────────────────────────────────────┬─────────────────┬─────┬────────┬─────┬─────────╮
 src/test/GasTest.t.sol:Contract1 contract                                             
╞═══════════════════════════════════════════╪═════════════════╪═════╪════════╪═════╪═════════╡
 Deployment Cost                            Deployment Size                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 44893                                      255                                        
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg  median  max  # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 setOperator                                252              252  252     252  1       
╰───────────────────────────────────────────┴─────────────────┴─────┴────────┴─────┴─────────╯

[G-05] Deploy the contract with clone instead of new

Context:
AlgebraFactory.sol#L65

Proof Of Concept:
There’s a way to save a significant amount of gas on deployment using Clones: 
https://www.youtube.com/watch?v=3Mw-pMmJ7TA .
It is extremely inexpensive to distribute by Cloneing with Create2.

Gas usage difference between the two? (answer: a new clone is 10x cheaper)

[G-06] Setting the constructor to payable [13 gas per instance]

Context:
AlgebraFactory.sol#L50
AlgebraPool.sol#L66
AlgebraPoolDeployer.sol#L31
PoolImmutables.sol#L29

Description:
You can cut out 10 opcodes in the creation-time EVM bytecode if you declare a constructor payable. Making the constructor payable eliminates the need for an initial check of msg.value == 0 and saves 13 gas on deployment with no security risks.

Recommendation:
Set the constructor to payable

Proof Of Concept:
https://forum.openzeppelin.com/t/a-collection-of-gas-optimisation-tricks/19966/5?u=pcaversaccio

The optimizer was turned on and set to 10000 runs.

contract GasTestFoundry is DSTest {
    
    Contract1 c1;
    Contract2 c2;
    
    function setUp() public {
        c1 = new Contract1();
        c2 = new Contract2();
    }
    
    function testGas() public {
        c1.x();
        c2.x();
    }
}

contract Contract1 {
    
    uint256 public dummy;
    constructor() payable {
        dummy = 1;
    }
    
    function x() public {

    }
}

contract Contract2 {
    
    uint256 public dummy;
    constructor() {
        dummy = 1;
    }
    
    function x() public {
    }
}

Gas Report:

╭───────────────────────────────────────────┬─────────────────┬─────┬────────┬─────┬─────────╮
 src/test/GasTest.t.sol:Contract1 contract                                             
╞═══════════════════════════════════════════╪═════════════════╪═════╪════════╪═════╪═════════╡
 Deployment Cost                            Deployment Size                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 49563                                      159                                        
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤

╭───────────────────────────────────────────┬─────────────────┬─────┬────────┬─────┬─────────╮
 src/test/GasTest.t.sol:Contract2 contract                                             
╞═══════════════════════════════════════════╪═════════════════╪═════╪════════╪═════╪═════════╡
 Deployment Cost                            Deployment Size                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 49587                                      172                                        
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤

[G-07] Free gas savings for using solidity 0.8.10+

Context:
All Contracts

Description:
Solidity 0.8.10 has a useful change which reduced gas costs of external calls which expect a return value: https://blog.soliditylang.org/2021/11/09/solidity-0.8.10-release-announcement/

Code Generator: Skip existence check for external contract if return data is expected. In this case, the ABI decoder will revert if the contract does not exist.

Recommendation:
Consider to upgrade pragma to at least 0.8.10

[G-08] Use Custom Errors rather than revert() / require() strings to save deployment gas [68 gas per instance]

Context: 
AlgebraPool.sol – 58 instances
AlgebraFactory.sol – 9 instances
AlgebraPoolDeployer.sol – 4 instances
DataStorageOperator.sol – 4 instances

Description:
Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they’re hitby avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas.
https://blog.soliditylang.org/2021/04/21/custom-errors/

Proof Of Concept:
The optimizer was turned on and set to 10000 runs.

contract GasTest is DSTest {
    Contract0 c0;
    Contract1 c1;

    function setUp() public {
        c0 = new Contract0();
        c1 = new Contract1();
    }
    
    function testGas() public {
       c0.foo();
       c1.foo();
       }
    }

contract Contract0 {

    uint256 version;
    error Error_Message();

    function foo() external {
        if (version != 0) {
        revert Error_Message();
        }
    }
}

contract Contract1 {
 
    uint256 version;

    function foo() external {
    require(version == 0, "error");
    }
}

Gas Report:

╭───────────────────────────────────────────┬─────────────────┬──────┬────────┬──────┬─────────╮
 src/test/GasTest.t.sol:Contract0 contract                                               
╞═══════════════════════════════════════════╪═════════════════╪══════╪════════╪══════╪═════════╡
 Deployment Cost                            Deployment Size                              
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 33287                                      196                                          
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg   median  max   # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 foo                                        2242             2242  2242    2242  1       
╰───────────────────────────────────────────┴─────────────────┴──────┴────────┴──────┴─────────╯
╭───────────────────────────────────────────┬─────────────────┬──────┬────────┬──────┬─────────╮
 src/test/GasTest.t.sol:Contract1 contract                                               
╞═══════════════════════════════════════════╪═════════════════╪══════╪════════╪══════╪═════════╡
 Deployment Cost                            Deployment Size                              
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 41693                                      239                                          
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg   median  max   # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 foo                                        2310             2310  2310    2310  1       
╰───────────────────────────────────────────┴─────────────────┴──────┴────────┴──────┴─────────╯

[G-09] Functions guaranteed to revert when callled by normal users can be marked payable [24 gas per instance]

Context: 
AlgebraFactory.sol#L77
AlgebraFactory.sol#L84
AlgebraFactory.sol#L91
AlgebraFactory.sol#L108
AlgebraPoolDeployer.sol#L36

Description:
If a function modifier or require such as onlyOwner-admin 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.

Recommendation:
Functions guaranteed to revert when called by normal users can be marked payable  (for only onlyowner or admin functions)

Proof Of Concept:
The optimizer was turned on and set to 10000 runs.

contract GasTest is DSTest {
    Contract0 c0;
    Contract1 c1;
    
    function setUp() public {
        c0 = new Contract0();
        c1 = new Contract1();
    }
    
    function testGas() public {
        c0.foo();
        c1.foo();
    }
}

contract Contract0 {
    uint256 versionNFTDropCollection;
    
    function foo() external {
        versionNFTDropCollection++;
    }
}

contract Contract1 {
    uint256 versionNFTDropCollection;
    
    function foo() external payable {
        versionNFTDropCollection++;
    }
}

Gas Report:

╭───────────────────────────────────────────┬─────────────────┬───────┬────────┬───────┬─────────╮
 src/test/GasTest.t.sol:Contract0 contract                                                 
╞═══════════════════════════════════════════╪═════════════════╪═══════╪════════╪═══════╪═════════╡
 Deployment Cost                            Deployment Size                                
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 44293                                      252                                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg    median  max    # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 foo                                        22308            22308  22308   22308  1       
╰───────────────────────────────────────────┴─────────────────┴───────┴────────┴───────┴─────────╯
╭───────────────────────────────────────────┬─────────────────┬───────┬────────┬───────┬─────────╮
 src/test/GasTest.t.sol:Contract1 contract                                                 
╞═══════════════════════════════════════════╪═════════════════╪═══════╪════════╪═══════╪═════════╡
 Deployment Cost                            Deployment Size                                
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 41893                                      240                                            
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                              min              avg    median  max    # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 foo                                        22284            22284  22284   22284  1       
╰───────────────────────────────────────────┴─────────────────┴───────┴────────┴───────┴─────────╯

[G-10] Change to setOwner function [Save 5606 gas with a simpler design]

Context: 
AlgebraFactory.sol#L77-L81

Recommendation:
Current Code : (Deployment Gas Cost : 114876)

 modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

    address public owner = msg.sender;
    event Owner (address oldown);

   function setOwner(address _owner) external  onlyOwner {
        require(owner != _owner);
        emit Owner(_owner);
        owner = _owner;
    }

Recommendation Code : : (Deployment Gas Cost : 109270)

    address public owner= msg.sender;
    event OwnerChanged (address oldown, address newown);

      function setOwner(address _owner) external  {
        require(msg.sender == owner);
        emit OwnerChanged(owner, _owner);
        owner = _owner;
    }

[G-11] Remove to require(factory == address(0));

Context: 
AlgebraPoolDeployer.sol#L38

Recommendation:
setFactory require(factory == address(0)); query allows the function to be executed only once and restricts the set property, remove this from the code for gas saving.
If it needs to be run once, add initalize or assign value from Constrcutor

 function setFactory(address _factory) external override onlyOwner {
    require(_factory != address(0));
    require(factory == address(0));  //remove this
    emit Factory(_factory);
    factory = _factory;
  }

[G-12] Use double require instead of using &&

Context: 
AlgebraFactory.sol#L110

Recommendation:
Using double require instead of operator && can save more gas.
When having a require statement with 2 or more expressions needed, place the expression that cost less gas first.

Current Code:

require(gamma1 != 0 && gamma2 != 0 && volumeGamma != 0, 'Gammas must be > 0’);

Recommendation Code:

require(gamma1 != 0 && gamma2 != 0, 'Gammas must be > 0’);
require(volumeGamma != 0, 'Gammas must be > 0’);
@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels Oct 1, 2022
code423n4 added a commit that referenced this issue Oct 1, 2022
code423n4 added a commit that referenced this issue Oct 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working G (Gas Optimization)
Projects
None yet
Development

No branches or pull requests

1 participant