Gas Optimization Race
The same contract, deployed twice on Base Sepolia. One written the way most people write it; one with four optimizations applied. Their function ABI is identical and compiler-enforced, and a single test suite runs against both to prove they behave the same. Race an operation against both in one transaction and read the two gas figures straight out of the receipt.
Base Sepolia · testnet only
Everything below renders without a wallet. Connect one only to run a race — it costs testnet gas and signs a single transaction.
What is being compared
Both contracts implement the same interface, and neither declares an external function outside it, so a drift in any signature fails the build rather than quietly producing two different programs. The runner calls both in one transaction, so they face the same block, the same base fee and the same caller.
- GasNaive 0xfa2Ac3799Bf26001C40E6556bfA7cd048b06FB48
- GasOptimized 0xD283cE65702CF9Ed1F30A8617BBf1b73E421Cec6
- GasRace (runner) 0xfD936cD7b6Dd247C4034DD107A7b6717a891148d
The runner's two targets are constructor-set immutables — no setter, no owner, no upgrade path — so the addresses above cannot be repointed after you have read a result. Source, tests and recorded measurements: github.com/pigfox/gas-optimization.
The four operations
Two of these four barely save anything, and they are listed anyway. A gas demo where every technique wins is a curated one. The figures below are execution gas from a previously recorded run — see the note under the table — and each links to the transaction it came from.
| Operation | Technique | Naive | Optimized | Saving |
|---|---|---|---|---|
writeRecord |
Packed struct Four separate mappings become one struct whose fields sum to 232 bits, so a record occupies one storage slot instead of four. |
92195 | 25976 |
−71.8%
−66219 gas |
writeBatch |
Calldata instead of memory The array parameter stays in calldata rather than being copied into memory. Real, but the eight cold storage writes in the same call dwarf it. |
207006 | 206640 |
−0.1%
−366 gas |
validate |
Custom error instead of a revert string Raced on the REVERTING path, which is the only place this saves anything — a revert string costs nothing until it reverts. |
3390 | 3324 |
−1.9%
−66 gas |
setFlagRange |
Bitmap instead of a bool mapping A mapping spends a whole 256-bit slot per flag; packing them as bits puts 256 flags in one slot, so setting eight touches one slot instead of eight. |
181783 | 26121 |
−85.6%
−155662 gas |
Every figure on this page is execution gas — what the contract code costs, measured as a gasleft() delta inside the runner. It excludes the 21,000 gas base transaction cost and the calldata cost that your wallet also pays, and it includes about 2,600 gas of cold-account access which both contracts pay identically, so it cancels in the difference. A standalone transaction to either contract costs roughly 19,000 gas more than the numbers here. Neither measurement is the “true” one: the standalone figure is what a wallet is charged, execution gas is what the code costs.
The counterpoint: deployment
Optimizing is not free. Packing logic and the bitmap word loop are code, and the optimized contract is the more expensive one to deploy — 399594 gas against 362886, or 10.1% more. You pay once at deployment to save on every call afterwards, which is the right trade for a contract that gets used and the wrong one for a contract that does not.
Run a race
Not connected.
Each race uses a fresh random run id, so both contracts start from cold storage. That is what makes the comparison fair.
This run only — both figures read from the RaceRun log in your transaction receipt.
How the measurement stays honest
- A fresh run id every race. Every function keys all of its storage under a 32-byte id generated in your browser. A cold storage write costs 20,000 gas and a warm one 2,900 — reusing an id would measure a warm write against a cold one and report the difference as an optimization.
- One transaction, both contracts. Same block, same base fee, same caller. Two separate transactions could differ in any of those.
- Read from the receipt, never recomputed. The figures come out of the event log your transaction emitted. If the log cannot be read, this page shows an error rather than a number.
- Both contracts pay the same overheads. Each is called exactly once per race, so the cold-account charge is identical on both sides and cancels in the difference.