Skip to content

Latest commit

 

History

History
66 lines (41 loc) · 4.52 KB

Awesome-G.md

File metadata and controls

66 lines (41 loc) · 4.52 KB

Uncheck arithmetics operations that can’t underflow/overflow

Solidity version 0.8+ comes with implicit overflow and underflow checks on unsigned integers. When an overflow or an underflow isn’t possible, some gas can be saved by using an unchecked block. For example:

Line 173-179

        for (uint256 i = 0; i < selectorsLength; ++i) {
            bytes4 selector = _selectors[i];
            SelectorToFacet memory oldFacet = ds.selectorToFacet[selector];
            require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet


            _removeOneFunction(oldFacet.facetAddress, selector);
        }

Pre-increment is cheaper

It is cheaper to use pre-increment (++i) than using shorthand addition/subtraction assignment operators (+=, -=) for example:

Line 29

Line 29:    s.diamondCutStorage.currentProposalId += 1;

Could be refactored to

Line 29:    ++s.diamondCutStorage.currentProposalId;

Functions With Access Control Cheaper if Payable

A function with access control marked as payable will be cheaper for legitimate callers: the compiler removes checks for msg.value, saving approximately 20 gas per function call.

For example: Line 46 Line 78 Line 225

uint8 is not always cheaper than uint256

The EVM only operates on 32 bytes/ 256 bits at a time. This means that if you use uint8, EVM has to first convert it uint256 to work on it and the conversion costs extra gas! You may wonder, What were the devs thinking? Why did they create smaller variables then? The answer lies in packing. In solidity, you can pack multiple small variables into one slot, but if you are defining a lone variable and can’t pack it, it’s optimal to use a uint256 rather than uint8.

Line 367, Line 30

Using Calldata Instead of Memory for Read-Only Arguments in External Functions Saves Gas

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. Note that even if an interface defines a function as having memory arguments, it’s still valid for implementation contracts to use calldata arguments instead.

Suppose the array is passed to an internal function which passes the array to another internal function where the array is modified and therefore memory is used in the external call. In that case, it’s still more gas-efficient to use calldata when the external function uses modifiers, since the modifiers may prevent the internal functions from being called. Structs have the same overhead as an array of length one

For example:

Line 89,

Line 121,

Line 80

Function Order Affects Gas Consumption

public/external function names and public member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted