Blockchain smart contract – how solidity can effectively save gas costs

Hits: 0

At present, many people have encountered a headache, that is, the gas cost is too high, so how do we reduce the gas cost? We can start with [smart contracts] and optimize the code to greatly reduce the gas cost, so how to reduce the gas cost Well, here’s my summary

1. Remove unnecessary libraries Solidity library

  • The libraries we introduce usually only need some of the functionality, which means that they may contain a lot of solidity code that is actually redundant to your smart contract. If you can safely and effectively implement the library functions you depend on in your own contracts, you can achieve the purpose of optimizing the gas utilization of solidity contracts

2. How to choose variable data type storage

Storage consumption differs for different data types. In the case of satisfying the business, we should choose a data type that consumes less gas.

When there is no way to put multiple variables into the same slot, try to use 256-bit variables, such as  uint256 and bytes32

When using variable data types smaller than 32 bytes, the gas usage of the contract may be higher than when using 32 bytes types. This is because the EVM operates 32 bytes per operation, so if the variable size is smaller than 32 bytes, the EVM must perform additional operations to reduce the 32 bytes size to the desired size

For specific instructions, please refer to [: State Variable Storage Structure — Solidity Chinese Documentation — Chainlink Community]

We deploy the following two contracts on the test chain:

//Consume 69324  gas 
contract  A{ 
    uint256  age=0; 
}

//Consume 69825  gas 
contract  B{ 
    uint32  age=0; 
}

It can be clearly seen that the deployment cost of uint32 is higher than that of uint256

In addition, additional operations are required to perform calculations in the EVM  uint256 , and other  uint types other than those require additional gas for conversion during calculation.

3. Use a short reason string

Append the error reason string with the require statement to make it easier to understand why the contract call failed. However, these strings take up space in the deployed bytecode. Each reason string needs at least 32 bytes, so make sure your strings fit within 32 bytes, otherwise it will get more expensive

4. Events

The event without parameters is 750 GAS. In theory each additional parameter will add 256 GAS, but in reality, it will be more

5. Hash

You can use several built-in hash functions in smart contracts: keccak256, sha256 and ripemd160. The more parameters, the more gas is consumed. Air consumption:ripemd160>sha256>keccak256. So if there is no other purpose, it is recommended to use the keccak256 function

6. Explicitly declare the visibility of Solidity contract functions

Explicitly declaring the visibility of functions can not only improve the security of smart contracts, but also help optimize the gas cost of contract execution. For example, by explicitly marking a function as External, it is possible to force the storage location of function parameters to be set to calldata, which saves the cost of Ethereum gas each time the function executes.

7. Use the optimizer when compiling the contract

Use the compiler solc to start the optimizer optimizer when compiling a contract. It will simplify complex expressions and reduce the size of the compiled contract bytecode, thereby reducing the gas consumption during deployment, and also reducing the consumption of contract calls.

// Store multiple variables together when encoding. 
function  encode ( uint64 _a, uint64 _b, uint64 _c, uint64 _d ) internal  pure  returns ( bytes32 x ) {
    assembly {
        let y := 0
        mstore(0x20, _d)
        mstore(0x18, _c)
        mstore(0x10, _b)
        mstore(0x8, _a)
        x := mload(0x20)
    }
}

function decode(bytes32 x) internal pure returns (uint64 a, uint64 b, uint64 c, uint64 d) {
    assembly {
        d := x
        mstore(0x18, x)
        a := mload(0)
        mstore(0x10, x)
        b := mload(0)
        mstore(0x8, x)
        c := mload(0)
    }
}

The number of runs --optimize-runsspecifies the approximate frequency at which each opcode of the deployed code will be executed during the lifetime of the contract. This means that it is a trade-off parameter between code size (deployment cost) and code execution cost (post-deployment cost). The smaller the number of times, the smaller the compiled bytecode, but more gas may be required to call the contract function.

There’s also a Yul-based optimizer, which is more powerful because it works across function calls

8. Inline assembly packing variables

Write inline assembly [to] manually stack multiple variables together into a single slot.

Syntax: use  assembly{ ... } to embed assembly code sections

//  deployment consumes gas 67054 
contract  Test { 
    uint256  x; 
}

//  deployment consumes gas 67912 
contract  Test { 
    uint256  x = 0; 
}

Although this method saves gas, it sacrifices the readability of the code and is prone to errors

9. No need to initialize variables with default values

No need to initialize variables with default values

//  deployment consumes gas 67054 
contract  Test { 
    uint256  x; 
}

//  deployment consumes gas 67912 
contract  Test { 
    uint256  x = 0; 
}

10. Separation of operation contracts and data contracts

In the case of creating a contract using a factory contract, the created contract can be separated into an operation contract and a data contract.

The operation contract is created only once, and the factory contract only creates the data contract each time, instead of creating an entire contract each time, thereby reducing gas consumption.

You may also like...

Leave a Reply

Your email address will not be published.