Gas

A unit measuring computational effort required to execute operations on Ethereum, paid by users to incentivize validators.

Gas is the fundamental unit of computation on Ethereum and EVM-compatible blockchains. Every operation—from simple transfers to complex smart contract interactions—consumes gas. Users pay for gas in the network's native currency (ETH on Ethereum), and this payment incentivizes validators to include transactions in blocks. Understanding gas is essential for smart contract development, as inefficient code directly translates to higher costs for users.

How Gas Works

Every EVM operation has an associated gas cost:

OperationGas CostExample
ADD3Adding two numbers
MUL5Multiplication
SSTORE (new slot)20,000Writing new storage
SSTORE (existing)5,000Updating storage
SLOAD2,100Reading storage
External call2,600+Calling another contract

The total gas for a transaction is the sum of all operations executed.

Gas Price and Transaction Cost

The actual cost users pay depends on two factors:

1Transaction Cost = Gas Used × Gas Price

Gas Used: Total computational work (measured in gas units) Gas Price: How much you pay per gas unit (in gwei, where 1 gwei = 0.000000001 ETH)

Example:

  • A token transfer uses ~65,000 gas
  • At 30 gwei gas price: 65,000 × 30 gwei = 1,950,000 gwei = 0.00195 ETH
  • At $3,000/ETH: Transaction costs ~$5.85

Gas Limit vs Gas Used

Gas Limit: Maximum gas you're willing to spend (set by user) Gas Used: Actual gas consumed by the transaction

If execution exceeds the gas limit, the transaction reverts but the gas is still consumed—incentivizing users to set appropriate limits and developers to write efficient code.

EIP-1559: Base Fee and Priority Fee

Since the London upgrade, Ethereum uses a dual fee structure:

1Total Fee = (Base Fee + Priority Fee) × Gas Used

Base Fee: Algorithmically determined based on network congestion. This portion is burned. Priority Fee (Tip): Optional payment to validators for faster inclusion.

Why Gas Optimization Matters

Gas-inefficient contracts cost users more:

1// INEFFICIENT: Multiple storage reads
2function getTotal() public view returns (uint256) {
3 return balances[msg.sender] + rewards[msg.sender] + bonus[msg.sender];
4 // 3 SLOAD operations = 6,300 gas
5}
6
7// OPTIMIZED: Cache in memory
8function getTotal() public view returns (uint256) {
9 uint256 balance = balances[msg.sender];
10 uint256 reward = rewards[msg.sender];
11 uint256 userBonus = bonus[msg.sender];
12 return balance + reward + userBonus;
13 // Still 3 SLOADs, but if used multiple times, memory is cheaper
14}

Common Gas Optimization Techniques

Storage vs Memory

Storage operations are expensive. Use memory for temporary data:

1// EXPENSIVE: Modifying storage in loop
2function sumArray(uint256[] storage arr) internal {
3 uint256 sum;
4 for (uint i = 0; i < arr.length; i++) {
5 sum += arr[i]; // Multiple SLOADs
6 }
7}
8
9// CHEAPER: Copy to memory first
10function sumArray(uint256[] storage arr) internal {
11 uint256[] memory memArr = arr;
12 uint256 sum;
13 for (uint i = 0; i < memArr.length; i++) {
14 sum += memArr[i]; // Memory reads are cheaper
15 }
16}

Packing Storage Variables

The EVM stores data in 32-byte slots. Pack smaller variables together:

1// INEFFICIENT: Uses 3 storage slots
2contract Inefficient {
3 uint256 a; // Slot 0
4 uint128 b; // Slot 1
5 uint128 c; // Slot 2
6}
7
8// EFFICIENT: Uses 2 storage slots
9contract Efficient {
10 uint256 a; // Slot 0
11 uint128 b; // Slot 1 (first half)
12 uint128 c; // Slot 1 (second half) - packed!
13}

Short-Circuit Evaluation

Order conditions by cost:

1// INEFFICIENT: Expensive check first
2if (complexCalculation() && simpleFlag) { }
3
4// EFFICIENT: Cheap check first (may skip expensive one)
5if (simpleFlag && complexCalculation()) { }

Use Events Instead of Storage

For data that doesn't need on-chain access:

1// EXPENSIVE: Store every action
2mapping(address => Action[]) public userActions;
3
4// CHEAPER: Emit events (indexed off-chain)
5event ActionPerformed(address indexed user, uint256 actionType);

Gas and Security Audits

Auditors check for:

  1. Gas griefing: Can attackers make functions prohibitively expensive?
  2. Unbounded loops: Loops over dynamic arrays can hit gas limits
  3. Storage optimization: Excessive storage costs burden users
  4. DoS vectors: Can gas limits be used to block functionality?

Gas Limits and Block Limits

Ethereum blocks have a gas limit (~30 million gas currently). This means:

  • No single transaction can use more than the block gas limit
  • Functions with unbounded loops may become uncallable as data grows
1// DANGEROUS: May exceed block gas limit
2function processAll() external {
3 for (uint i = 0; i < users.length; i++) {
4 // If users array grows large, this becomes uncallable
5 processUser(users[i]);
6 }
7}
8
9// SAFER: Paginated processing
10function processUsers(uint256 start, uint256 count) external {
11 uint256 end = start + count;
12 if (end > users.length) end = users.length;
13 for (uint i = start; i < end; i++) {
14 processUser(users[i]);
15 }
16}

Gas on Layer 2s

Layer 2 solutions like Arbitrum and Optimism have lower gas costs due to different execution models. However, they still charge for:

  • Calldata (data posted to L1)
  • L2 execution costs

Understanding the L2's specific gas model is important when deploying there.

Tools for Gas Analysis

  • Foundry: forge test --gas-report shows gas usage per function
  • Hardhat: Gas reporter plugin provides detailed breakdowns
  • Remix: Shows gas estimates during development
  • Tenderly: Simulates transactions and shows gas traces

Gas efficiency directly impacts user experience and protocol competitiveness. Well-optimized contracts save users money and demonstrate development quality.

Need expert guidance on Gas?

Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.

Get a Quote

oog
zealynx

Subscribe to Our Newsletter

Stay updated with our latest security insights and blog posts

© 2024 Zealynx