How to save on gas with SmartContracts: comprehensive guide.
When developing smart contracts on the Ethereum blockchain, one of the most crucial aspects to consider is the gas consumption. Gas is a measure of computational work on Ethereum, and it costs real money to users. Therefore, optimizing your smart contracts to use less gas is not just a performance improvement but also a cost-saving strategy.
The total gas cost is calculated as: Total Gas Cost=Gas Used×Gas Price
The gas price fluctuates based on network congestion, while the gas used depends on your smart contract’s operations. Let’s dive into various techniques to optimize the gas usage in a Solidity smart contract.
The Scenario
We’ll start with a simple Solidity smart contract that calculates the sum of even numbers less than 99 from an array of integers. Below is the initial code:
Initial Code
Gas used before any optimization: 297069 (when using [1,2,3,4,5,6,7,8,9,10,53,44,76,32,100,400,500]
as the argument).
1. Use calldata
Instead of memory
In Solidity, calldata
is a data location that is cheaper than memory
because it’s read-only and external to the smart contract. This makes it suitable for function parameters that don’t need to be modified within the function.
Optimized Code
Gas used: 59585
2. Use Local Variables Instead of State Variables
State variables are stored on the blockchain, making them more expensive to use than local variables. By using a local variable, you can reduce the gas cost.
Optimized Code
Gas used: 58729
3. Short-Circuit Condition Checks
You can combine multiple conditions into a single if
statement to short-circuit unnecessary checks.
Optimized Code
When two conditions are combined with an &&, the second condition won't be evaluated if the first one is false, due to short-circuiting.
This short-circuiting behavior also applies to nested if statements: if the outer if condition is false, the inner if condition won't be evaluated.
There's no significant gas optimization to be gained from using nested if statements over a combined if condition with an && operator. Both will have approximately the same gas cost since they both leverage short-circuiting.
Gas used: 57450
4. Use ++i
Instead of i++
Prefix increment (++i
) is slightly more efficient than postfix (i++
) because it doesn’t require a temporary variable.
Optimized Code
Gas used: 56400
5. Cache Array Length
Caching the length of the array can save gas as it avoids multiple calls to retrieve the array’s length.
Optimized Code
Gas used: 55200
6. Load Array Elements to Memory
Loading array elements into a memory variable can save gas when the element is used multiple times.
Optimized Code
Gas used: 54300
Additional Tools for Optimization
Unchecked Increment
Since we are sure that the loop won’t iterate more than (2^{256} - 1) times, we can use the unchecked
block to skip overflow checks, saving some gas.
Use Custom Errors Instead of Revert
Starting from Solidity v0.8.4, custom errors can be defined to provide more information about failures in a gas-efficient way.
Bit Shifting Instead of Division/Multiplication
Bit shifting can be more efficient than division or multiplication when dealing with powers of 2.
Function Prioritization
The order of functions in a contract can impact gas consumption due to how the Ethereum Virtual Machine (EVM) handles method IDs. Place the most frequently used functions earlier in the contract to save some gas.
Solidity compiler’s optimizer
You can also use the Solidity compiler’s optimizer by adding the following snippet to your truffle-config.js
if you’re using Truffle:
Or if you’re using Hardhat, add it to your hardhat.config.js
:
These settings enable the optimizer and set it to run 200 times, a number that aims to balance deployment cost against runtime costs.
Conclusion
Gas optimization is crucial for the efficient execution and interaction of smart contracts on the Ethereum blockchain. By applying these techniques, you can significantly reduce the gas cost, making your smart contracts more efficient and user-friendly. Always remember to test thoroughly to ensure that optimizations do not introduce bugs or vulnerabilities.