Solidity Gas Optimization: Stop Using uint256 for Everything
All posts
Solidity Gas Optimization Smart Contracts Ethereum

Solidity Gas Optimization: Stop Using uint256 for Everything

Tim IllguthDecember 5, 202310 min read

Gas optimization is crucial in Solidity development. One of the most common mistakes developers make is using uint256 for every integer variable, regardless of the actual value range needed.

Understanding Storage Slots

The EVM stores data in 32-byte (256-bit) slots. When you use smaller uint types strategically, you can pack multiple variables into a single storage slot, dramatically reducing gas costs.

The Problem with uint256 Everywhere

// Inefficient - each variable uses a full storage slot contract Inefficient { uint256 public count; // Slot 0 uint256 public isActive; // Slot 1 (wastes 255 bits!) uint256 public timestamp; // Slot 2 }

The Optimized Approach

// Efficient - all three variables fit in one slot! contract Efficient { uint64 public timestamp; // 8 bytes uint32 public count; // 4 bytes bool public isActive; // 1 byte // Total: 13 bytes in Slot 0 (saves 2 storage slots!) }

Real-World Savings

  • Reading from storage: ~2,100 gas per slot
  • Writing to storage: ~20,000 gas for new slot, ~5,000 for existing
  • Packing 3 variables into 1 slot can save 40,000+ gas on initialization

Byte Packing Chart
Byte Packing Chart

Best Practices

  1. Group related variables that can be packed together
  2. Use appropriate sizes: uint8 for small counters, uint32 for timestamps
  3. Order matters: Solidity packs variables in declaration order
  4. Test your optimizations: Use gas reporters to verify savings

Advanced Packing Patterns

Struct Packing

// Unoptimized struct — 3 slots struct UserBad { uint256 id; // 32 bytes — slot 0 bool active; // 32 bytes — slot 1 (padded!) uint256 timestamp; // 32 bytes — slot 2 } // Optimized struct — 2 slots struct UserGood { uint256 id; // 32 bytes — slot 0 uint64 timestamp; // 8 bytes \ bool active; // 1 byte > packed into slot 1 // 23 bytes remaining for future fields }

Bitmap Patterns for Flags

When you have many boolean flags, pack them into a single uint256 using bitwise operations:

contract FlagManager { uint256 private flags; uint256 constant FLAG_ACTIVE = 1 << 0; uint256 constant FLAG_VERIFIED = 1 << 1; uint256 constant FLAG_PREMIUM = 1 << 2; function setActive(bool value) external { if (value) flags |= FLAG_ACTIVE; else flags &= ~FLAG_ACTIVE; } function isActive() external view returns (bool) { return (flags & FLAG_ACTIVE) != 0; } }

One uint256 holds 256 boolean flags — zero extra storage slots.

Conclusion

Smart gas optimization can reduce deployment and interaction costs by 50% or more. Understanding storage packing is essential for building cost-effective smart contracts that users will actually want to use.

Start with struct packing, measure the savings with a gas reporter, and work from there. The EVM rewards developers who understand how it stores data.