Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings
zkPorterIsAvailable
can be put after or before one of the address variables to make the struct smaller and save gas
2. expressions for constant values such as a call to keccak256(), should use immutable rather than constant
even if they are for readability, consider making them comments instead
Using the addition operator instead of plus-equals saves gas
here ++s.diamondCutStorage.currentProposalId
would be even cheaper
logSender
priorityOp
currentBlockCommitment
facetAddr
facetToSelectors
hashedBytecode
this will have a large deployment gas cost but with enough runtime calls the split require version will be 3 gas cheaper
Checks that involve constants should come before checks that involve state variables, function calls, and calculations. By doing these checks first, the function is able to revert before wasting a Gcoldsload (2100 gas*) in a function that may ultimately revert in the unhappy case.
bring this require before the 2 requires before it because of possible gas saves
first part of the require() is being repeated so under no circumstances it will happen
Use a solidity version of at least 0.8.2 to get compiler automatic inlining
Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads
Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings
Use a solidity version of at least 0.8.10 to have external
calls skip contract existence checks if the external call has a return value
Use a solidity version of at least 0.8.12 to get string.concat() to be used instead of abi.encodePacked(,)
Use a solidity version of at least 0.8.13 to get the ability to use using for
with a list of free functions
When a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution.
_lastCommittedBlockData
_log
Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.
_collectOperationsFromPriorityQueue
_executeOneBlock
_getBlockProofPublicInput
_verifyRecursivePartOfProof
_maxU256
_createBlockCommitment
_blockPassThroughData
_blockMetaParameters
_blockAuxilaryOutput
_L2MessageToLog
_requestL2Transaction
_writePriorityOp
_hashFactoryDeps
_depositFunds
_getDepositL2Calldata
_getERC20Getters
_parseL2WithdrawalMessage
if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key’s keccak256 hash (Gkeccak256 - 30 gas) and that calculation’s associated stack operations.
When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size. Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so. Use a larger size then downcast where needed https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed
Contracts are allowed to override their parents’ functions and change the visibility from external to public and can save gas by doing so.
l2TokenAddress
use newTotalBlocksCommitted
instead of s.totalBlocksCommitted