Agent skill

gas-optimization

Advanced gas optimization techniques for EVM smart contracts. Covers storage packing, memory vs calldata optimization, assembly/Yul, efficient data structures, batch operations, and benchmark-driven optimization strategies.

Stars 514
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/a5c-ai/babysitter/tree/main/library/specializations/cryptography-blockchain/skills/gas-optimization

SKILL.md

Gas Optimization Skill

Advanced gas optimization techniques for EVM smart contracts with benchmark-driven analysis.

Capabilities

  • Storage Optimization: Storage packing, slot management, SLOAD/SSTORE minimization
  • Memory Management: Memory vs calldata optimization, expansion costs
  • Assembly/Yul: Low-level optimization for critical paths
  • Data Structures: Gas-efficient mappings, arrays, and structs
  • Batch Operations: Multi-call patterns, bulk transfers
  • Benchmarking: Gas profiling, comparison analysis

MCP/Tool Integration

Tool Purpose Reference
Foundry MCP Gas reports, testing foundry-mcp-server
EVM MCP Tools Opcode analysis evm-mcp-tools

Storage Optimization

Storage Layout Packing

solidity
// BAD: 3 storage slots (96 bytes used, 96 bytes allocated)
contract BadPacking {
    uint128 a;  // slot 0 (16 bytes)
    uint256 b;  // slot 1 (32 bytes) - can't pack with a
    uint128 c;  // slot 2 (16 bytes)
}

// GOOD: 2 storage slots (80 bytes used, 64 bytes allocated)
contract GoodPacking {
    uint128 a;  // slot 0, bytes 0-15
    uint128 c;  // slot 0, bytes 16-31
    uint256 b;  // slot 1
}

// Gas savings: ~20,000 gas per SSTORE avoided

Minimize Storage Writes

solidity
// BAD: Multiple storage writes
function badUpdate(uint256 newA, uint256 newB) external {
    a = newA;  // SSTORE: 20,000 gas (cold) or 2,900 gas (warm)
    b = newB;  // SSTORE: 2,900 gas (warm slot in same tx)
}

// GOOD: Single storage write with packed struct
struct Data {
    uint128 a;
    uint128 b;
}
Data public data;

function goodUpdate(uint128 newA, uint128 newB) external {
    data = Data(newA, newB);  // Single SSTORE: 20,000 gas
}

Use Mappings Over Arrays for Lookups

solidity
// BAD: O(n) lookup, expensive for large arrays
uint256[] public values;
function exists(uint256 value) public view returns (bool) {
    for (uint i = 0; i < values.length; i++) {
        if (values[i] == value) return true;  // SLOAD per iteration
    }
    return false;
}

// GOOD: O(1) lookup
mapping(uint256 => bool) public valueExists;
function exists(uint256 value) public view returns (bool) {
    return valueExists[value];  // Single SLOAD
}

Memory vs Calldata

Function Parameters

solidity
// BAD: Copies array to memory
function processArray(uint256[] memory data) external {
    // Memory copy cost: 3 gas per word + expansion
}

// GOOD: Read directly from calldata
function processArray(uint256[] calldata data) external {
    // No copy, just pointer to calldata
    // Savings: ~60 gas per 32 bytes
}

// Note: Use memory if you need to modify the array

String/Bytes Handling

solidity
// For read-only operations, use calldata
function validate(string calldata input) external pure returns (bool) {
    return bytes(input).length > 0;
}

// For modifications, use memory
function transform(string memory input) internal pure returns (string memory) {
    bytes memory b = bytes(input);
    b[0] = 'X';
    return string(b);
}

Unchecked Arithmetic

solidity
// BAD: Overflow checks on every operation (Solidity 0.8+)
function sumArray(uint256[] calldata arr) external pure returns (uint256) {
    uint256 sum = 0;
    for (uint256 i = 0; i < arr.length; i++) {
        sum += arr[i];  // Overflow check: ~40 gas per operation
    }
    return sum;
}

// GOOD: Unchecked when overflow is impossible
function sumArray(uint256[] calldata arr) external pure returns (uint256) {
    uint256 sum = 0;
    uint256 length = arr.length;
    for (uint256 i = 0; i < length;) {
        unchecked {
            sum += arr[i];
            ++i;  // ++i is cheaper than i++
        }
    }
    return sum;
}
// Savings: ~40 gas per iteration

Loop Optimizations

Cache Array Length

solidity
// BAD: Length read from storage each iteration
for (uint i = 0; i < array.length; i++) { }  // SLOAD per iteration

// GOOD: Cache length
uint256 length = array.length;
for (uint i = 0; i < length; i++) { }  // Single SLOAD

Pre-increment

solidity
// BAD: Post-increment creates temporary
for (uint i = 0; i < length; i++) { }

// GOOD: Pre-increment is cheaper
for (uint i = 0; i < length; ++i) { }
// Savings: ~5 gas per iteration

Custom Errors

solidity
// BAD: String error messages
require(balance >= amount, "Insufficient balance");
// Cost: ~50 gas per character + memory expansion

// GOOD: Custom errors (Solidity 0.8.4+)
error InsufficientBalance(uint256 available, uint256 required);
if (balance < amount) revert InsufficientBalance(balance, amount);
// Cost: Fixed ~24 gas for error selector
// Savings: ~50+ gas for typical error messages

Assembly/Yul Optimization

Efficient Balance Check

solidity
// Solidity
function getBalance(address account) external view returns (uint256) {
    return account.balance;
}

// Assembly (slightly cheaper)
function getBalance(address account) external view returns (uint256 bal) {
    assembly {
        bal := balance(account)
    }
}

Efficient Memory Operations

solidity
// Copy 32 bytes efficiently
function copy32(bytes32 source) internal pure returns (bytes32 dest) {
    assembly {
        dest := source
    }
}

// Efficient keccak256
function efficientHash(bytes32 a, bytes32 b) internal pure returns (bytes32 result) {
    assembly {
        mstore(0x00, a)
        mstore(0x20, b)
        result := keccak256(0x00, 0x40)
    }
}

Batch Operations

Batch Transfers

solidity
// BAD: Individual transfers
function transferToMany(address[] calldata recipients, uint256 amount) external {
    for (uint i = 0; i < recipients.length; ++i) {
        token.transfer(recipients[i], amount);  // 21000 base + transfer cost
    }
}

// GOOD: Batch transfer (if supported)
function batchTransfer(
    address[] calldata recipients,
    uint256[] calldata amounts
) external {
    // Single function call overhead
    // Reduced SLOAD for token state
}

Multicall Pattern

solidity
function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
    results = new bytes[](data.length);
    for (uint256 i = 0; i < data.length; ++i) {
        (bool success, bytes memory result) = address(this).delegatecall(data[i]);
        require(success);
        results[i] = result;
    }
}
// Combines multiple operations in single transaction

Benchmarking Workflow

Using Foundry Gas Reports

bash
# Run tests with gas report
forge test --gas-report

# Snapshot gas usage
forge snapshot

# Compare against previous snapshot
forge snapshot --check

Gas Snapshot Format

| Contract | Function | Min | Avg | Max | # Calls |
|----------|----------|-----|-----|-----|---------|
| Token    | transfer | 51234 | 54123 | 65432 | 100 |
| Token    | approve  | 24356 | 24356 | 24356 | 50  |

Comparison Testing

solidity
contract GasComparison is Test {
    function test_gasComparison_approach1() public {
        uint256 gasBefore = gasleft();
        // Approach 1
        uint256 gasUsed = gasBefore - gasleft();
        emit log_named_uint("Approach 1 gas", gasUsed);
    }

    function test_gasComparison_approach2() public {
        uint256 gasBefore = gasleft();
        // Approach 2
        uint256 gasUsed = gasBefore - gasleft();
        emit log_named_uint("Approach 2 gas", gasUsed);
    }
}

Common Optimizations Summary

Technique Savings Risk
Storage packing 20,000 gas/slot Low
Calldata vs memory 60 gas/32 bytes Low
Unchecked arithmetic 40 gas/op Medium
Custom errors 50+ gas/error Low
Cache storage reads 100-2100 gas Low
Loop pre-increment 5 gas/iteration Low
Assembly Varies High

Process Integration

This skill integrates with:

  • gas-optimization.js - Full optimization process
  • smart-contract-development-lifecycle.js - Development best practices
  • amm-pool-development.js - DeFi-specific optimizations

Tools Reference

Tool Purpose URL
Foundry Gas reporting foundry-rs
Hardhat Gas Reporter Gas reports hardhat-gas-reporter
evm.codes Opcode costs evm.codes
Solidity Optimizer Compiler optimization Solidity Docs

See Also

  • skills/evm-analysis/SKILL.md - Bytecode analysis
  • agents/gas-optimizer/AGENT.md - Gas optimization agent
  • references.md - Gas optimization resources

Expand your agent's capabilities with these related and highly-rated skills.

a5c-ai/babysitter

gsd-tools

Central utility skill for GSD operations. Provides config parsing, slug generation, timestamps, path operations, and orchestrates calls to other specialized skills. Acts as the unified entry point that the original gsd-tools.cjs provided via its lib/ modules (commands, config, core, init).

514 31
Explore
a5c-ai/babysitter

model-profile-resolution

Resolve model profile (quality/balanced/budget) at orchestration start and map agents to specific models. Enables cost/quality tradeoffs by selecting appropriate AI models for each agent role.

514 31
Explore
a5c-ai/babysitter

verification-suite

Plan structure validation, phase completeness checks, reference integrity verification, and artifact existence confirmation. Provides the structured verification layer ensuring GSD artifacts are well-formed and complete.

514 31
Explore
a5c-ai/babysitter

state-management

STATE.md reading, writing, and field-level updates. Provides cross-session state persistence via .planning/STATE.md with structured fields for current task, completed phases, blockers, decisions, and quick tasks.

514 31
Explore
a5c-ai/babysitter

git-integration

Git commit patterns, formats, and conventions for GSD methodology. Provides atomic commits per task, structured commit messages, planning file commits, branch management, and milestone tag operations.

514 31
Explore
a5c-ai/babysitter

frontmatter-parsing

YAML frontmatter parsing and manipulation for .planning/ documents. Provides read, write, update, query, and validation operations on frontmatter blocks in GSD markdown artifacts.

514 31
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results