As a solidity developer, it is important to understand the concept of gas in Ethereum and how to optimize smart contracts. Gas is the unit of measurement for the amount of computational work required to execute a transaction on Ethereum. Awareness of solidity gas optimization best practices is essential if you want to be a great Solidity developer.
Every operation in a so smart contract requires a certain amount of gas. The total gas cost of a transaction is the sum of the gas costs of all the operations it contains.
When a user sends a transaction to the Ethereum network, they must specify the maximum amount of gas. This is based on what the user is willing to pay for the transaction to be processed. If the gas limit is reached before the transaction is complete, the transaction will fail. Ultimately, the user will lose the gas that was used.
It is important to optimize your smart contracts to minimize gas costs. Gas optimization makes transactions efficient and cost-effective for users.
In this blog post, we will cover several tips and best practices for gas optimization in solidity. We will discuss how to optimize your contract code, how to use the Solidity compiler to optimize gas usage, and how to test your contracts to ensure they are gas efficient.
Optimize smart contract code
One of the most important ways to optimize gas usage in your contracts is to write efficient and optimized code. Here are a few tips for optimizing your contract code:
Use the latest version of Solidity
The Solidity compiler is constantly being updated with new optimization features and improvements. By using the latest version of Solidity, you can take advantage of these improvements and potentially reduce gas costs.
Avoid unnecessary operations
Every operation in a smart contract requires gas, so it is important to avoid unnecessary operations whenever possible. For example, if you are iterating through an array, consider using a for loop instead of a for-each loop as the latter requires more gas.
Use built-in functions whenever possible
Solidity has a number of built-in functions that can be used to perform common operations, such as checking if a value is within a certain range or calculating the length of an array. These functions are optimized for gas efficiency and should be used whenever possible.
Avoid nested function calls
Every time a function is called, it requires gas. If a function calls another function, which then calls another function, and so on, the gas cost can quickly add up. Try to avoid nested function calls whenever possible.
Remember, just because a function is “view” or “pure” or an internal function, you are still going to incur gas usage if you call this variable from within a function or other smart contracts.
Libraries are smart contracts that can be called by other contracts, allowing you to reuse code and reduce the amount of gas needed for a particular operation.
Use memory until you absolutely need to update storage variables
When using local variables, you generally do not need to write them to storage variables. Writing data to storage is a high gas consumption task.
Leverage memory instead of storage whenever possible. Remember, the cost of storage variables will get exponentially more expensive over time.
Saving variables to storage can be expensive. Expect to pay around 20,000 gas to save a variable. You’ll pay about 5,000 gas to overwrite the variable. Keep in mind writing multiple variables will incur more gas. Reading from storage will cost you about 800 gas while reading from memory will be about 3 gas. Memory variables are truly the way to go for smart contract gas optimization.
Keep function parameters small
Having fewer function parameters will reduce gas consumption because there is less to store in memory. Keeping your functions small is a great way of optimizing gas.
Use the payable modifier
Any function sending or receiving Ether should use the “payable” modifier within the smart contract code. This tells the compiler that the function can send and receive Ether, which will save on gas usage.
Use external instead of public (most of the time)
Public functions write parameters to storage, while external functions read directly from the calldata. Reading from memory is expensive compared to reading from calldata. Use external whenever you need a publicly available method.
Use arrays sparingly
An unbounded array can ruin a smart contract. Whenever possible, use mappings instead of arrays. If you are using an array, make sure it’s a fixed-size array, so the storage costs are known upfront. Using smaller, fixed-sized arrays, are gas optimized.
Name the function return value
Naming the function return value does not require one to initialize the variable in the code. You also don’t have to explicitly return the variable. This helps out the compiler and will save you precious gas. This is a little-known smart contract gas optimization that is very easy to implement.
Use events rather than data storage whenever possible
Events in Solidity are useful for broadcasting messages from smart contracts. Since you are not writing to storage, and merely broadcasting a massage, they incur minimal gas usage.
You can also index events by a certain value, so they are easily searchable. If you do not need the data directly in the smart contracts, and you can read the values off-chain, then events are a very attractive Solidity gas optimization.
Set your variable access correctly
Leverage global variables with private visibility over public variables.
Use pointers instead of copying
Copying variables between memory and storage incurs gas consumption. Use a pointer whenever possible to cut back on those gas fees.
Use structs over multiple storage variables
As we know, writing to memory instead of storage is one of the best gas optimizations you can be alert for. Similarly, if your smart contract is writing to multiple variables at the same time, then it will probably save gas to use a struct. The gas fees required to update two storage variables are usually greater than writing one storage variable for a struct.
Get a gas refund
Did you know you can get a refund of gas costs when you set a variable back to the default value of zero? This will return about 15,000 gas and reduce gas costs for other functions.
You can remove a contract using the Selfdestruct opcodes. This will refund about 24,000 gas.
Use bytes32 instead of string
If you have a known length of string, consider using bytes32 instead of string because bytes32 is the most optimized type.
Optimize your unit type
Storing a small number? Consider a uint1, uint8, or other value. There’s no sense in using the space required for a uint256 when you know the numbers will never get that high.
Bonus nerd tip: Order functions alphabetically in order of most usage
Due to how the ethereum virtual machine stores functions, you will get a small gas benefit by ordering your functions by usage AND in alphabetical order. The Ethereum Virtual Machine (EVM) stores function names in a jump table alphabetically. You will slightly reduce gas fees using this strategy, but you may sacrifice readability. This is certainly not a common gas optimization…
Use the Solidity compiler to optimize gas usage
The Solidity compiler has several optimization options that can be used to reduce gas costs. These options can be specified when compiling your contract using the Solidity compiler’s command line interface.
- The “–optimize” flag: This flag enables the optimization of the contract code. The Solidity compiler will perform various optimization techniques, such as inlining functions and removing unnecessary code, to reduce gas costs.
- The “–optimize-runs” flag: This flag allows you to specify the number of times the compiler should run the optimization pass. The more times the optimization pass is run, the more optimization will be performed and the lower the gas costs will be. However, note that increasing the number of optimization runs will also increase the compilation time.
- The “–optimize-yul” flag: This flag enables the Yul optimizer, which is a low-level intermediate representation (IR) optimizer that can further reduce gas costs by optimizing the IR code generated by the Solidity compiler.
Test your smart contract for gas optimization
We recommend using the Hardhat framework, which has built-in support for the ETH Gas Reporting module. This will allow you to see how code changes affect the gas costs in your functions.
Gas optimization will set you apart from other Solidity developers and make users happier with your protocol.