Intermediate

Gas Optimisation Basics — Hands-on lab

Write cheaper, cleaner code.

Developer Intermediate
4/6 — Gas Optimisation Basics — Hands-on lab

Measured steps Benchmark first. Apply one change at a time and keep the ones that meaningfully help. Add tests/invariants that encode any assumptions (like bounds for unchecked math).

The root problem with conventional currency is all the trust that’s required to make it work.
— Satoshi Nakamoto

Documentation Inline comment why an unchecked block is safe or why packing is used. Include before/after gas numbers in PR descriptions for future readers.

Guardrails Avoid unbounded loops over user-controlled arrays; consider batching. Keep CEI and reentrancy guards intact even if they cost a few gas.

function sum(uint256[] memory xs) internal pure returns (uint256 total) {
    uint256 len = xs.length;
    for (uint256 i; i < len; ) {
        total += xs[i];
        unchecked { ++i; } // safe because i<len is loop guard
    }
}

function transferMany(address[] calldata to, uint256 amount) external {
    uint256 len = to.length;
    for (uint256 i; i < len; ) {
        _transfer(msg.sender, to[i], amount);
        unchecked { ++i; }
    }
}
Steps
  1. Identify a hot path:(e.g., transfer/loop); record baseline gas with a test or benchmark.
  2. Apply one change at:A time calldata inputs, cache storage reads in memory, pack small types, cache array length; re-measure.
  3. Add unchecked only when:You can prove bounds; write tests/invariants to enforce assumptions; document why unchecked is safe.
  4. Review external calls:Keep CEI/reentrancy guards; ensure batching doesn’t open DoS. Remove unsafe “optimizations.”
  5. Capture before/after gas numbers;:Remove changes that save little but hurt readability. Commit rationale in code comments/PR notes.
← Previous section
Next section →