Gas Optimization in Solidity

Yamen Merhi
6 min readJun 25, 2021
BTCMANAGER Copyrights

This article is going to give you a couple of tips to reduce gas consumption in your smart contracts.

It’s very important to understand how to do this because if it costs too much money to execute a function in your smart contract, fewer users will be willing to run your Dapp.

It’s important to know that some information were taken from several resources that will be mentioned in the end.

Tip #1: Pack your variables

Solidity stores data in 256-bit memory slots. Variables less than 256 bits will be stored in a single slot, Data that does not fit in a single slot is spread over several slots.
Each storage slot costs gas, packing the variables helps you optimize your gas usage by reducing the number of slots our contract requires.

Example :

The Solidity compiler is only able to put 2 uint128 in the same 256-bit memory slots when they are declared next to each other. Otherwise, uint128 variables each occupies a separate uint256 just for themselves, wasting 128 bits for each slot (Like the first contract):

Difference Between Variable Packing

Tip #2: Turn On Solidity Optimizer

When you compile Solidity smart contracts, you can specify an optimization flag to tell the Solidity compiler to produce highly optimized bytecode. This bytecode will consume less gas than if you don’t use the optimization flag.

You can enable optimization with this setting in your truffle-config.js file:

Truffle-config.js

Tip #3: Delete variables that you don’t need

In Ethereum, you get a gas refund for freeing up storage space.
Deleting a variable refund 15,000 gas up to a maximum of half the gas cost of the transaction. Deleting with the delete keyword is equivalent to assigning the initial value for the data type, such as 0 for integers.

Tip #4: Compute known value off-chain

If You know what data to hash, there is no need to consume more computational power to hash it using keccak256 , you’ll end up consuming
2x amount of gas.

Tip #5: Do not shrink Variables

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.

Tip #6: Use Events

Data that does not need to be accessed on-chain can be stored in events to save gas.

Tip #7: Use Assembly

When you compile a Solidity smart contract, it is transformed into a series of EVM (Ethereum virtual machine) opcodes.
With assembly, you write code very close to the opcode level. It’s not very easy to write code at such a low level, but the benefit is that you can manually optimize the opcode and outperform Solidity bytecode in some cases.

Tip #8: Use Libraries

If you have several contracts that use the same functionalities, you can extract these common functions into a single library, and then you’re gonna deploy this library just once and all your contracts will point to this library to execute the shared functionalities.

Tip #9: Minimize on-chain data

The less you put on-chain, the less your gas costs.
When you design a Dapp you don’t have to put 100% of your data on the blockchain, usually, you have part of the system (Unnecessary data (metadata, etc .. ) ) on a centralized server.

Tip #10: Avoid manipulating storage data

Performing operations on memory or call data, which is similar to memory is always cheaper than storage.

The following solidity code will help you understand the difference between a poor code and a better-optimized code

In the Second contract, before running the for loop we’re assigning the value of a storage data d to _d to avoid accessing the storage each time we iterate.

Tip #11: Use eth-gas-reporter

This reporter displays gas consumption changes to each function in your smart contract.

Tip #12: Use Short-Circuiting rules to your advantage

When using logical disjunction (||), logical conjunction (&&), make sure to order your functions correctly for optimal gas usage. In logical disjunction (OR), if the first function resolves to true, the second one won’t be executed and hence save you gas. In logical disjunction (AND), if the first function evaluates to false, the next function won’t be evaluated. Therefore, you should order your functions accordingly in your solidity code to reduce the probability of needing to evaluate the second function.

Tip #13: Use ERC1167 To Deploy the same Contract many time

EIP1167 minimal proxy contract is a standardized, gas-efficient way to deploy a bunch of contract clones from a factory.EIP1167 not only minimizes length, but it is also literally a “minimal” proxy that does nothing but proxying. It minimizes trust. Unlike other upgradable proxy contracts that rely on the honesty of their administrator (who can change the implementation), the address in EIP1167 is hardcoded in bytecode and remain unchangeable.

Tip #14: Avoid assigning values that You’ll never use

Every variable assignment in Solidity costs gas. When initializing variables, we often waste gas by assigning default values that will never be used.

uint256 value; is cheaper than uint256 value = 0;.

Tip #15: Use Mappings instead of Arrays

Solidity is the first language in which mappings are less expensive than arrays.
Most of the time it will be better to use a mapping instead of an array because of its cheaper operations.

Tip #16: Limit the string length in the Require Statements

If we are adding message strings to require statements, we can make them cheaper by limiting the string length to 32 bytes.

Tip #17: Fixed-size Arrays are cheaper than dynamic ones

If we know how long an array should be, we specify a fixed size:

uint256[12] monthlyTransfers;

This same rule applies to strings. A string or bytes variable is dynamically sized; we should use a byte32 if our string is short enough to fit.

If we absolutely need a dynamic array, it is best to structure our functions to be additive instead of subtractive. Extending an array costs constant gas whereas truncating an array costs linear gas.

Connect with me on LinkedIn , Github, and Twitter.

End of the article

References :

--

--

Yamen Merhi

Smart Contracts Engineer @LUKSO Twitter: 0xYamen Github: YamenMerhi