The Business & Technology Network
Helping Business Interpret and Use Technology
«  
  »
S M T W T F S
 
 
 
 
 
1
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
 
 
 
 
 
 

Should You Care What Chain you’re On?

DATE POSTED:August 29, 2025
Building Lean and Efficient Ethereum Smart Contracts

Imagine you’re running programs on a powerful, shared, public supercomputer. Unlike your personal computer where simple actions like opening a document don’t cost you anything, on this supercomputer, every single instruction your program executes, every bit of data it saves, every calculation it performs — it all consumes a tiny amount of computing power, and you have to pay for that power. On the Ethereum and other EVM-compatible blockchains, this “computing power” is called gas, and it directly translates into real-world costs for your users. If your programs (smart contracts) are inefficient or wasteful, those high gas fees can deter users, limit what your decentralized application (dApp) can do, and make it less competitive.

This tutorial is your guide to building lean and efficient smart contracts. We’ll explore practical techniques for gas optimization to reduce user costs, ensuring your dApps are not just functional, but also economically viable and attractive to users. Let’s make your smart contracts consume less of that valuable computing power!

Why Gas Matters: The Economics of Smart Contracts

Gas is the unit of computational effort required to execute operations on the Ethereum Virtual Machine (EVM). Think of it as the “fuel” for your smart contract’s engine.

  • Cost: Every operation (like storing data, performing calculations, or calling another contract) has an associated gas cost. Users pay for this gas in the blockchain’s native currency (e.g., ETH on Ethereum). The more complex your contract, the more gas it consumes, and the more expensive it is for users.
  • Network Congestion: When the network is busy, demand for block space increases, driving up gas prices. An inefficient contract becomes even more costly during peak times.
  • Validator Compensation: Gas fees compensate the validators (formerly miners) who process and secure transactions on the blockchain. Without these fees, there would be no incentive to maintain the network.

The goal of gas optimization is to minimize the amount of computational work your smart contract performs, thereby reducing costs for users and increasing the contract’s overall efficiency.

Gas Optimization Techniques: Making Your Code Lean

Optimizing gas requires a deep understanding of how the EVM works and prioritizing storage and computation.

1. Minimize Storage Writes (SSTORE)

Writing to storage (state variables) is by far the most expensive operation on the EVM. An SSTORE operation can cost up to 20,000 gas when writing to an untouched storage slot (from zero to non-zero value), plus an additional 2,100 gas for "cold access" if it's the first time that storage slot is accessed in a transaction. This means a single, initial write to storage can total 22,100 gas. Subsequent writes to an already-modified slot (non-zero to non-zero) are cheaper, typically around 5,000 gas.

  • Avoid Unnecessary Updates: Only update storage variables when absolutely necessary.
  • Cache Values: If you read a storage variable multiple times in a function and then modify it, cache the value in a local memory variable first. Perform all operations on the memory variable, then write the final result back to storage only once.
  • Less Optimal:
// Less Gas-Efficient
uint256 public myValue;
function incrementTwice() public {
myValue += 1; // SSTORE (expensive)
myValue += 2; // SSTORE (expensive) }
  • More Optimal:
// More Gas-Efficient
uint256 public myValue;
function incrementTwiceOptimized() public {
uint256 tempValue = myValue; // SLOAD (cheaper than multiple SSTOREs)
tempValue += 1;
tempValue += 2;
myValue = tempValue; // SSTORE only once }2. Variable Packing

The EVM works with 256-bit (32-byte) “slots” in storage. If you declare multiple smaller variables (e.g., uint8, uint128, bool) consecutively in your contract's state, Solidity will try to "pack" them into a single storage slot, saving gas.

  • Group Smaller Variables: Declare variables of uint8, uint16, uint32, uint64, uint128, bool, address, and bytes types consecutively. The compiler tries to fit them into 32-byte slots.
  • Example:
// Not optimized for packing (each uint256 takes a full slot)
uint256 public var1; // Slot 0
uint256 public var2; // Slot 1 // Optimized for packing (both bools fit in the same slot if declared consecutively)
bool public isActive; // Slot 0 (part 1)
bool public isPaused; // Slot 0 (part 2, same slot)
uint256 public counter; // Slot 1 (new slot, as uint256 doesn't fit with bools)
  • Packing reduces the number of SSTORE and SLOAD operations.
3. Use constant and immutable

Variables declared as constant or immutable do not occupy storage slots.

  • constant: Values are known at compile time and hardcoded into the contract's bytecode. They don't cost any gas at runtime to read. Ideal for fixed values like a maximum supply or a contract name.
  • immutable: Values are set once in the constructor and then cannot be changed. They are stored in the contract's code, not in storage, saving gas on future reads. Ideal for values like the contract owner set during deployment.
uint256 public constant MAX_SUPPLY = 1_000_000 * (10 ** 18); // Gas efficient address public immutable deployer; // Gas efficient
constructor() {
deployer = msg.sender;
}4. Use external over public for External Calls
  • external functions: Can only be called by other contracts or external accounts. Their arguments are read directly from calldata (a cheaper location).
  • public functions: Can be called both externally and internally. The arguments are copied from calldata to memory first, incurring additional gas.

If a function is only intended to be called from outside the contract, use external.

5. Optimize Loops: Avoid Gas Traps

Loops that iterate over growing lists in your smart contract can become extremely expensive and even cause your functions to fail due to the block gas limit. If an attacker continuously adds items, the list could become so vast that the function will become too expensive to run, making it effectively unusable for anyone.

The Problem: Uncontrolled Loops

If your contract has a function that processes every item in a list that can grow endlessly (like a list of all users), it will eventually use too much gas and stop working.

Vulnerable Example (Simplified):

address[] public userList; // This list can grow forever
function addData(address _user) public {
userList.push(_user);
}
// This function tries to process ALL users at once.
// It will fail if 'userList' gets too big.
function processAllUsers() public {
for (uint i = 0; i < userList.length; i++) {
// ... (expensive operations for each user) ...
}
}The Solution: Pull Payments & Pagination

Instead of forcing the contract to do heavy lifting for everyone in one transaction, shift the burden to individual users or fetch data in chunks.

  • Pull Pattern (for Payments/Actions): Let each user trigger the action or withdraw their own funds. This puts the gas cost on the user benefiting, isolating issues.
  • Protected Example (Pull Pattern):
mapping(address => uint256) public balances; // Tracks individual balances

function deposit() public payable {
balances[msg.sender] += msg.value;
}

// User calls this to withdraw their own funds.
// Gas cost is on the user, not the contract for everyone.
function withdraw() public {
uint256 amount = balances[msg.sender];
require(amount > 0, "No funds to withdraw");
balances[msg.sender] = 0; // Update state first
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Transfer failed"); }
  • Pagination (for Data Display): If you need to show a list of items, let your frontend request small “pages” of data at a time.

Protected Example (Pagination):

address[] private storedItems; // A growing list of items
function addItem(address _item) public {
storedItems.push(_item); }

// Get total count (cheap read)
function getItemCount() public view
returns (uint256) { return storedItems.length;
}

// Get a specific 'page' of items.
// Frontend requests (start index, how many items).
function getItemsPaginated(uint256 _startIndex, uint256 _count)
public
view
returns (address[] memory)
{
// ... (logic to safely return _count items from _startIndex) ...
// This loop only runs for a small, controlled number of items.
}

By using these patterns, you ensure your contract remains efficient and usable, regardless of how large your user base or data collections become.

6. Events over Storage for Historical Data

If data only needs to be recorded for historical purposes or accessed off-chain (e.g., by block explorers or subgraphs), use events instead of storing it in contract state. Emitting an event is significantly cheaper than an SSTORE operation.

Conclusion: Engineering for Lean and Efficient Smart Contracts

Gas optimization is not optional; it is a fundamental pillar of responsible smart contract development. Neglecting this aspect can lead to exorbitant user fees, limit functionality, and make your decentralized application (dApp) less competitive.

By carefully minimizing storage operations, optimizing variable usage, and structuring loops thoughtfully, you can build smart contracts that are cost-efficient for your users. Remember, the blockchain is an immutable ledger. Inefficient code, especially concerning gas, can be incredibly difficult, if not impossible, to fix once deployed. Therefore, meticulous design, rigorous testing, and continuous auditing are paramount. Embrace these practices, and you’ll be well on your way to building the next generation of robust and successful decentralized applications!

Let’s build something incredible together.
Email us at
[email protected]
Explore more:
www.ancilar.com

Ethereum Gas Optimization: Build Cheaper, Faster Smart Contracts was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.