Babysitter 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.
install
source · Clone the upstream repo
git clone https://github.com/a5c-ai/babysitter
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/cryptography-blockchain/skills/gas-optimization" ~/.claude/skills/a5c-ai-babysitter-gas-optimization && rm -rf "$T"
manifest:
library/specializations/cryptography-blockchain/skills/gas-optimization/SKILL.mdsource content
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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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 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
// 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
// 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
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
# 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
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:
- Full optimization processgas-optimization.js
- Development best practicessmart-contract-development-lifecycle.js
- DeFi-specific optimizationsamm-pool-development.js
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
- Bytecode analysisskills/evm-analysis/SKILL.md
- Gas optimization agentagents/gas-optimizer/AGENT.md
- Gas optimization resourcesreferences.md