Gas Optimization Patterns in Solidity¶
This example demonstrates common gas optimization techniques and patterns in Solidity.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GasOptimization {
// Pack variables to use less storage slots
// These variables pack into a single 256-bit slot
uint128 public number1; // 16 bytes
uint96 public number2; // 12 bytes
uint16 public number3; // 2 bytes
uint8 public number4; // 1 byte
bool public flag; // 1 byte
// Unpacked - each uses a full slot
uint256 public bigNumber; // 32 bytes
uint8 public smallNumber; // 1 byte but uses full slot
// Fixed size array is cheaper than dynamic
uint[10] public fixedArray;
// Cheaper than string
bytes32 public constant HASH = keccak256("MyString");
// Events for cheaper storage
event ValueChanged(uint256 newValue);
// Use unchecked for known safe math
function sumArray(uint256[] calldata arr) public pure returns (uint256) {
uint256 sum;
unchecked {
for(uint256 i = 0; i < arr.length; i++) {
sum += arr[i];
}
}
return sum;
}
// Short circuit to save gas
function complexCheck(uint256 x, uint256 y) public pure returns (bool) {
// Put cheaper check first
return x < 100 && complexOperation(y);
}
function complexOperation(uint256 y) private pure returns (bool) {
// Expensive operation
return keccak256(abi.encodePacked(y)) > bytes32(0);
}
// Use calldata instead of memory for read-only arrays
function processArray(uint256[] calldata arr) public pure returns (uint256) {
return arr[0];
}
// Replace memory with calldata for read-only strings
function processString(string calldata str) public pure returns (bytes32) {
return keccak256(bytes(str));
}
// Batch operations to save gas
uint256[] public values;
function addMultipleValues(uint256[] calldata newValues) public {
uint256 len = newValues.length;
for(uint256 i = 0; i < len; i++) {
values.push(newValues[i]);
}
}
}
Key Gas Optimization Techniques¶
-
Variable Packing
- Pack multiple variables into single storage slots
- Use smallest possible uint sizes
- Group similar sized variables together
-
Memory vs Calldata
- Use calldata for read-only arrays and strings
- Calldata is cheaper than memory
- Memory needed for modifiable data
-
Fixed vs Dynamic Arrays
- Fixed size arrays are cheaper
- Consider using fixed arrays when size is known
- Dynamic arrays have overhead
-
Loops and Math
- Use unchecked blocks for safe math
- Cache array length in loops
- Short circuit expensive operations
-
Storage vs Events
- Use events instead of storage when possible
- Events are cheaper than storage
- Good for historical data
Best Practices¶
- Always measure gas savings
- Consider trade-offs with readability
- Document optimization patterns
- Use appropriate data types
- Batch operations when possible