Master gas optimization techniques for Solidity including storage patterns, function optimization, and batch operations.
## ROLE
You are a gas optimization specialist who has reduced transaction costs by 50%+ for major DeFi protocols.
## CONTEXT
I need to optimize my smart contract for gas efficiency.
## CONTRACT INFO
- Contract code: ${{CODE_SUMMARY}}
- Main operations: ${{OPERATIONS}}
- User frequency: ${{FREQUENCY}}
- Current gas costs: ${{CURRENT_GAS}}
- Optimization priority: ${{PRIORITY}}
## TASK
Provide gas optimization strategies:
**1. STORAGE OPTIMIZATIONS**
```solidity
// BEFORE: Inefficient storage
contract Inefficient {
bool public flag1; // Slot 0 (wastes 31 bytes)
uint256 public value; // Slot 1
bool public flag2; // Slot 2 (wastes 31 bytes)
address public owner; // Slot 3
}
// AFTER: Packed storage
contract Efficient {
uint256 public value; // Slot 0
address public owner; // Slot 1 (20 bytes)
bool public flag1; // Slot 1 (1 byte) - packed!
bool public flag2; // Slot 1 (1 byte) - packed!
}
// Savings: 2 storage slots = ~40,000 gas on deployment
```
**2. VARIABLE PACKING RULES**
| Type | Size | Pack With |
|------|------|-----------|
| bool | 1 byte | Other small types |
| uint8 | 1 byte | Other small types |
| address | 20 bytes | Up to 12 bytes |
| uint256 | 32 bytes | Nothing |
**3. FUNCTION OPTIMIZATIONS**
```solidity
// BEFORE
function inefficient(uint256[] memory data) public {
for (uint256 i = 0; i < data.length; i++) {
// data.length read each iteration
}
}
// AFTER
function efficient(uint256[] memory data) public {
uint256 len = data.length; // Cache length
for (uint256 i; i < len; ) { // No initialization
// logic
unchecked { ++i; } // Unchecked increment
}
}
```
**4. CALLDATA VS MEMORY**
```solidity
// BEFORE: Memory (copies data)
function process(uint256[] memory data) external {
// Costs more gas
}
// AFTER: Calldata (reads directly)
function process(uint256[] calldata data) external {
// Cheaper for read-only external data
}
```
**5. CUSTOM ERRORS**
```solidity
// BEFORE: String errors (expensive)
require(balance >= amount, "Insufficient balance");
// AFTER: Custom errors (cheaper)
error InsufficientBalance(uint256 available, uint256 required);
if (balance < amount) revert InsufficientBalance(balance, amount);
// Saves ~50 gas per error
```
**6. SHORT-CIRCUITING**
```solidity
// Order conditions by likelihood and cost
// Cheap checks first, expensive last
if (simpleCheck && expensiveCheck) { }
```
**7. BATCH OPERATIONS**
```solidity
// Instead of multiple transactions
function batchTransfer(
address[] calldata recipients,
uint256[] calldata amounts
) external {
uint256 len = recipients.length;
for (uint256 i; i < len; ) {
_transfer(msg.sender, recipients[i], amounts[i]);
unchecked { ++i; }
}
}
```
**8. EVENTS OPTIMIZATION**
```solidity
// Use indexed sparingly (costs more)
event Transfer(
address indexed from, // Indexed for filtering
address indexed to, // Indexed for filtering
uint256 amount // Not indexed (cheaper)
);
```
**9. IMMUTABLE & CONSTANT**
```solidity
// Constants: Known at compile time
uint256 constant FEE = 100; // No storage slot
// Immutable: Set once in constructor
address immutable owner; // No storage slot after deployment
```
**10. OPTIMIZATION CHECKLIST**
| Technique | Savings | Applied |
|-----------|---------|---------|
| Storage packing | ~20,000/slot | |
| Calldata over memory | ~60/param | |
| Custom errors | ~50/error | |
| Unchecked math | ~40/op | |
| Cache storage reads | ~100/read | |
| Short-circuit | Variable | |Or press ⌘C to copy
Replace these placeholders with your own content before using the prompt.
[{CODE_SUMMARY][{OPERATIONS][{FREQUENCY][{CURRENT_GAS][{PRIORITY]{
bool public flag1; // Slot 0 (wastes 31 bytes)
uint256 public value; // Slot 1
bool public flag2; // Slot 2 (wastes 31 bytes)
address public owner; // Slot 3
}{
uint256 public value; // Slot 0
address public owner; // Slot 1 (20 bytes)
bool public flag1; // Slot 1 (1 byte) - packed!
bool public flag2; // Slot 1 (1 byte) - packed!
}{
for (uint256 i = 0; i < data.length; i++) {
// data.length read each iteration
}{
uint256 len = data.length; // Cache length
for (uint256 i; i < len; ) { // No initialization
// logic
unchecked { ++i; }{
// Costs more gas
}{
// Cheaper for read-only external data
}[ ]{
uint256 len = recipients.length;
for (uint256 i; i < len; ) {
_transfer(msg.sender, recipients[i], amounts[i]);
unchecked { ++i; }