Gas-Jitsu: Mastering Solidity Optimization
SolidityBlockchainSmart Contracts

Gas-Jitsu: Mastering Solidity Optimization

Gas-Jitsu: Mastering Solidity Optimization

In the world of Ethereum development, gas is money. Literally. Every computation, every storage update, and every byte of code costs real ETH (or Matic, or AVAX). writing gas-efficient Smart Contracts isn’t just best practice—it’s an economic necessity.
Welcome to Gas-Jitsu, the art of squeezing every ounce of efficiency from the Ethereum Virtual Machine (EVM).

1. Storage Packing: The Tetris of Solidity

The EVM works in 32-byte slots. When you define variables, Solidity tries to pack them into these slots. If you arrange them poorly, you pay for extra slots.
Bad Packing:
solidity
1uint128 a; // Slot 0 (16 bytes) 2uint256 b; // Slot 1 (32 bytes - doesn't fit in Slot 0) 3uint128 c; // Slot 2 (16 bytes) 4// Total slots uses: 3
Good Packing:
solidity
1uint128 a; // Slot 0 2uint128 c; // Slot 0 (Both fit in 32 bytes!) 3uint256 b; // Slot 1 4// Total slots uses: 2
Savings: ~20,000 gas per saved slot on deployment and writes.

2. Memory vs. Calldata

When passing arrays or strings to functions, the
text
1memory
keyword copies the data. For
text
1external
functions, using
text
1calldata
reads directly from the transaction input, avoiding an expensive copy.
Expensive:
solidity
1function process(uint[] memory data) external { 2 // Copies data to memory 3}
Cheap:
solidity
1function process(uint[] calldata data) external { 2 // Reads directly from calldata 3}
Savings: Significant reductions for large arrays.

3. Custom Errors vs. Strings

Prior to Solidity 0.8.4, we used detailed string messages in
text
1require
. These strings take up storage and cost gas to emit. Custom errors were introduced to solve this.
Before:
solidity
1require(balance >= amount, "Insufficient balance for transfer");
After:
solidity
1error InsufficientBalance(); 2 3if (balance < amount) { 4 revert InsufficientBalance(); 5}
Savings: Custom errors are much cheaper to deploy and execute because they are just a 4-byte selector, not a long string.

4. Unchecked Arithmetic

Solidity 0.8.0+ includes built-in overflow protection. This is great for security but adds overhead. If you are 100% sure a calculation won't overflow (like incrementing a counter in a bounded loop), use
text
1unchecked
.
Standard Loop:
solidity
1for (uint i = 0; i < length; i++) { 2 // Hidden standard check: i++ checks for overflow 3}
Gas-Jitsu Loop:
solidity
1for (uint i = 0; i < length;) { 2 // do work 3 unchecked { i++; } // No overflow check 4}
Savings: ~30-40 gas per iteration. It adds up in long loops!

5. Short-Circuiting

The EVM stops evaluating boolean expressions as soon as the result is determined. Order your conditions by cost!
Inefficient:
solidity
1// heavyOperation() runs even if condition is false 2if (heavyOperation() && condition)
Efficient:
solidity
1// heavyOperation() never runs if condition is false 2if (condition && heavyOperation())
Put cheap checks (like boolean flags or simple comparisons) before expensive checks (like external calls or hashing).

Conclusion

Gas optimization is a balancing act between readability, security, and efficiency. Never sacrifice security for gas—saving $5 isn't worth a $5M hack. But with these Gas-Jitsu techniques, you can write contracts that are lean, mean, and cheap to execute.
Go forth and optimize!

Discussion

Powered by Giscus