Token transfers happen constantly, so gas efficiency compounds. The dominant cost is storage: an SSTORE (writing a slot) is vastly more expensive than arithmetic or memory. The main levers are: pack storage to write fewer slots, use custom errors instead of revert strings, use unchecked for math that cannot overflow, and cache repeated storage reads in memory.
1error InsufficientBalance();23function _transfer(address from, address to, uint256 amount) internal {4uint256 fromBal = _balances[from]; // single SLOAD, cached5if (fromBal < amount) revert InsufficientBalance(); // custom error6unchecked {7_balances[from] = fromBal - amount; // can't underflow: checked above8_balances[to] += amount; // can't overflow: bounded by supply9}10emit Transfer(from, to, amount);11}
Custom errors replace stored revert strings, cutting both deployment and revert gas. unchecked blocks skip Solidity 0.8's automatic overflow checks — only safe where overflow is provably impossible, like a subtraction guarded by a prior require. Storage packing fits multiple small values (e.g., two uint128, or a uint96 + an address) into one 32-byte slot so a single SSTORE updates both. Libraries like Solady push these patterns to the limit.
Danger: never reach for unchecked or aggressive packing at the cost of correctness. An unchecked block placed where overflow IS possible reintroduces exactly the silent wraparound bugs that checked arithmetic was added to prevent. Optimize hot paths, measure with gas reports, and keep the math provably safe.
1// Storage packing: these two fit in ONE 32-byte slot2struct Account {3uint128 balance; // 16 bytes4uint64 lastUpdate; // 8 bytes5// 8 bytes spare in the same slot6}7// vs. two separate uint256 fields = two slots = two SSTOREs
Connect your wallet to mark this lesson as complete
Earn 25 EFFORT tokens