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 #224

Open
code423n4 opened this issue Oct 23, 2022 · 1 comment
Open

Gas Optimizations #224

code423n4 opened this issue Oct 23, 2022 · 1 comment
Labels

Comments

@code423n4
Copy link
Contributor

code423n4 commented Oct 23, 2022

Gas Optimizations List

Number Optimization Details Context
[G-01] Changing state variables to Immutable is gas-optimized 2
[G-02] Using storage instead of memory for struct saves gas 7
[G-03] Functions guaranteed to revert when callled by normal users can be marked payable 6
[G-04] x -= y (x += y) costs more gas than x = x – y (x = x + y) for state variables 7
[G-05] Optimize names to save gas All contracts
[G-06] Use assembly to check for address(0) 4
[G-07] The solady Library's Ownable contract is significantly gas-optimized, which can be used 
[G-08] Setting the constructor to payable 3

Total 14 issues

Suggestions

Number Suggestion Details
[S-01] Use v4.8.0 OpenZeppelin contracts
[S-02] Missing zero-address check in constructor

Total 2 suggestions

[G-01] Changing state variables to Immutable is gas-optimized

Context:

contracts\abstract\JB721Delegate.sol:
   
   56:   uint256 public override projectId;
   57  

   62:   IJBDirectory public override directory;
   63  

Description:
Changing state variables to immutable is ~16k gas-optimized in terms of deployment cost.

Gas Report:
Deployment

╭──────────────────────────────────────┬─────────────────╮
 src/test/test.sol:Contract0 contract                  
╞══════════════════════════════════════╪═════════════════╡
 Deployment Cost                       Deployment Size 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
 49587                                 172             
╰──────────────────────────────────────┴─────────────────╯
╭──────────────────────────────────────┬─────────────────╮
 src/test/test.sol:Contract1 contract                  
╞══════════════════════════════════════╪═════════════════╡
 Deployment Cost                       Deployment Size 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
 33514                                 213             
╰──────────────────────────────────────┴─────────────────╯

[G-02] Using storage instead of memory for struct saves gas

Context:

contracts\JB721TieredGovernance.sol:

  156:     JBTiered721SetTierDelegatesData memory _data;

contracts\JBTiered721Delegate.sol:

  272        // Get a reference to the data being iterated on.
  273:       JBTiered721MintReservesForTiersData memory _data = _mintReservesForTiersData[_i];

  299        // Get a reference to the data being iterated on.
  300:       JBTiered721MintForTiersData memory _data = _mintForTiersData[_i];

  348        // Record the added tiers in the store.
  349:       uint256[] memory _tierIdsAdded = store.recordAddTiers(_tiersToAdd);


  437      // Get a reference to the project's current funding cycle.
  438:     JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(projectId);
  439  

  447      // Record the minted reserves for the tier.
  448:     uint256[] memory _tokenIds = store.recordMintReservesFor(_tierId, _count);

  557        // Keep a reference to the the specific tier IDs to mint.
  558:       uint16[] memory _tierIdsToMint;

Description:
When fetching data from a storage location, assigning the data to a memory variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD rather than a cheap stack read.

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

Context: 

contracts\JBTiered721Delegate.sol:

  320    */
  321:   function adjustTiers(JB721TierParams[] calldata _tiersToAdd, uint256[] calldata _tierIdsToRemove) external override onlyOwner
  322    {

  366    */
  367:   function setDefaultReservedTokenBeneficiary(address _beneficiary) external override onlyOwner {
  368      // Set the beneficiary.

  382    */
  383:   function setBaseUri(string memory _baseUri) external override onlyOwner {
  384      // Store the new value.

  398    */
  399:   function setContractUri(string calldata _contractUri) external override onlyOwner {
  400      // Store the new value.

  414    */
  415:   function setTokenUriResolver(IJBTokenUriResolver _tokenUriResolver) external override onlyOwner {
  416      // Store the new value.

  476    */
  477:   function mintFor(uint16[] memory _tierIds, address _beneficiary) public override onlyOwner
  478      returns (uint256[] memory tokenIds)

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-04] x -= y (x += y) costs more gas than x = x – y (x = x + y) for state variables [32 gas per instance]

Context:

contracts\JBTiered721DelegateStore.sol:
  353        // Increment the total supply with the amount used already.
  354:       supply += _storedTier.initialQuantity - _storedTier.remainingQuantity;
  355  

  408          // Add the tier's voting units.
  409:         units += _balance * _storedTierOf[_nft][_i].votingUnits;
  410  

  505        // Get a reference to the account's balance in this tier.
  506:       balance += tierBalanceOf[_nft][_owner][_i];
  507  

  533      for (uint256 _i; _i < _numberOfTokenIds; ) {
  534:       weight += _storedTierOf[_nft][tierIdOfToken(_tokenIds[_i])].contributionFloor;
  535  

  562        // Add the tier's contribution floor multiplied by the quantity minted.
  563:       weight +=
  564          (_storedTier.contributionFloor *

  826      // Increment the number of reserved tokens minted.
  827:     numberOfReservesMintedFor[msg.sender][_tierId] += _count;
  828  


contracts\libraries\JBIpfsDecoder.sol:
  51        for (uint256 j = 0; j < digitlength; ++j) {
  52:         carry += uint256(digits[j]) * 256;
  53          digits[j] = uint8(carry % 58);

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.swap(2,3);
        c1.swap1(2,3);
    }
}
contract Contract0 {
    uint256 public amountIn = 10;
    
    
    function swap(uint256 amountInToBin, uint256 fee)  external returns (uint256 ) {
       
       return amountIn -= amountInToBin + fee;
    }
}

contract Contract1 {
    uint256 public amountIn = 10;
    
    function swap1(uint256 amountInToBin, uint256 fee)  external returns (uint256 result1) {
       return (amountIn = amountIn - (amountInToBin + fee));
    }
}

Gas Report:

╭──────────────────────────────────────┬─────────────────┬──────┬────────┬──────┬─────────╮
 src/test/test.sol:Contract0 contract                                               
╞══════════════════════════════════════╪═════════════════╪══════╪════════╪══════╪═════════╡
 Deployment Cost                       Deployment Size                              
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 83017                                 341                                          
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                         min              avg   median  max   # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 swap                                  5454             5454  5454    5454  1       
╰──────────────────────────────────────┴─────────────────┴──────┴────────┴──────┴─────────╯
╭──────────────────────────────────────┬─────────────────┬──────┬────────┬──────┬─────────╮
 src/test/test.sol:Contract1 contract                                               
╞══════════════════════════════════════╪═════════════════╪══════╪════════╪══════╪═════════╡
 Deployment Cost                       Deployment Size                              
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 83017                                 341                                          
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 Function Name                         min              avg   median  max   # calls 
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
 swap1                                 5431             5431  5431    5431  1       
╰──────────────────────────────────────┴─────────────────┴──────┴────────┴──────┴─────────╯

[G-05] Optimize names to save gas [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 JBTiered721Delegate.sol contract will be the most used; A lower method ID may be given.

Proof of Consept:
https://medium.com/joyso/solidity-how-does-function-name-affect-gas-consumption-in-smart-contract-47d270d8ac92

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

Sighash   |   Function Signature
========================
59283268  =>  _totalRedemptionWeight()
54c6d1f5  =>  firstOwnerOf(uint256)
70a08231  =>  balanceOf(address)
c87b56dd  =>  tokenURI(uint256)
e8a3d485  =>  contractURI()
01ffc9a7  =>  supportsInterface(bytes4)
982e177c  =>  initialize(uint256,IJBDirectory,string,string,IJBFundingCycleStore,string,)
aa35d9c3  =>  mintReservesFor(JBTiered721MintReservesForTiersData[])
980ed8a8  =>  mintFor(JBTiered721MintForTiersData[])
70d4fddb  =>  adjustTiers(JB721TierParams[],uint256[])
df487e26  =>  setDefaultReservedTokenBeneficiary(address)
a0bcfc7f  =>  setBaseUri(string)
ccb4807b  =>  setContractUri(string)
b6bcc40e  =>  setTokenUriResolver(IJBTokenUriResolver)
aa4fb15b  =>  mintReservesFor(uint256,uint256)
6ac6d941  =>  mintFor(uint16[],address)
8c63c8cd  =>  _processPayment(JBDidPayData)
c8fd1720  =>  _didBurn(uint256[])
b9162928  =>  _mintBestAvailableTier(uint256,address,bool)
515dcef0  =>  _mintAll(uint256,uint16[],address)
a8f32397  =>  _redemptionWeightOf(uint256[])
cad3be83  =>  _beforeTokenTransfer(address,address,uint256)
8f811a1c  =>  _afterTokenTransfer(address,address,uint256)
ce650c23  =>  _afterTokenTransferAccounting(address,address,uint256,JB721Tier)

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

Context:

contracts\JBTiered721Delegate.sol:
  369    */
  370:   function setDefaultReservedTokenBeneficiary(address _beneficiary) external override onlyOwner {
  371      // Set the beneficiary.

  385    */
  386:   function setBaseUri(string memory _baseUri) external override onlyOwner {
  387      // Store the new value.

  401    */
  402:   function setContractUri(string calldata _contractUri) external override onlyOwner {
  403      // Store the new value.

  417    */
  418:   function setTokenUriResolver(IJBTokenUriResolver _tokenUriResolver) external override onlyOwner {
  419      // Store the new value.

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-07] The solady Library's Ownable contract is significantly gas-optimized, which can be used

Description:
The project uses the onlyOwner authorization model with the PendingOwnable.sol contract. I recommend using Solady's highly gas optimized contract.

https://github.com/Vectorized/solady/blob/main/src/auth/OwnableRoles.sol

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

Context:

contracts\JBTiered721Delegate.sol:
  184  
  185:   constructor() {
  186      codeOrigin = address(this);

contracts\JBTiered721DelegateDeployer.sol:
  45  
  46:   constructor(
  47      JB721GlobalGovernance _globalGovernance,

contracts\JBTiered721DelegateProjectDeployer.sol:
  46    */
  47:   constructor(
  48      IJBController _controller,

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                                        
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤

[S-01] Use v4.8.0 OpenZeppelin contracts

Description:
The upcoming v4.8.0 version of OpenZeppelin provides many small gas optimizations.

https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v4.8.0-rc.0

v4.8.0-rc.0
 Many small optimizations

[S-02] Missing zero-address check in constructor

Description:
Missing checks for zero-addresses may lead to infunctional protocol, if the variable addresses are updated incorrectly. It also wast gas as it requires the redeployment of the contract.

contracts\JBTiered721DelegateDeployer.sol:
  45  
  46:   constructor(
  47:     JB721GlobalGovernance _globalGovernance,
  48:     JB721TieredGovernance _tieredGovernance,
  49:     JBTiered721Delegate _noGovernance
  50:   ) {
  51:     globalGovernance = _globalGovernance;
  52:     tieredGovernance = _tieredGovernance;
  53:     noGovernance = _noGovernance;
  54:   }
  55 
@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels Oct 23, 2022
code423n4 added a commit that referenced this issue Oct 23, 2022
code423n4 added a commit that referenced this issue Oct 23, 2022
@c4-judge
Copy link
Contributor

c4-judge commented Nov 8, 2022

Picodes marked the issue as grade-b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants