Gas Surgery: Reducing Merkle Mixer Costs by 25% on Base
Building a privacy mixer is a challenge of balance. You want strong anonymity, but you don't want the user to pay a fortune in gas for a single withdrawal. After stabilizing the Merkle Tree logic, I decided to put the contract on a strict gas diet.
The results? A drop from 72,332 to 53,897 average gas. Here is how I did it.
1. The Power of Bitmaps
Initially, I used a standard mapping(bytes32 => bool) to track nullifiers. Every bool in Solidity occupies a full 256-bit slot.
By switching to a Bitmap implementation, we pack 256 nullifiers into a single uint256 storage slot. Bitwise operations are significantly cheaper than cold storage writes.
2. Calldata: Stop Copying Data
In the first version, the Merkle Proof was passed as a memory array. This forced the EVM to copy the entire proof into memory.
By switching to calldata, the contract reads the proof directly from the input, saving thousands of gas units.
3. Custom Errors
Replacing require(condition, "Very long error message") with if (condition) revert AlreadySpent() reduces the deployment size and makes execution cheaper.
The Benchmarks (Foundry)
| Implementation | Avg Gas | Max Gas |
|---|---|---|
| Initial | 72,332 | 98,105 |
| Optimized | 53,897 | 81,204 |
Check out the full source code on my GitHub:
👉 https://github.com/rdin777/merkle-mixer-research
#solidity, #web3, #blockchain, #programming

Top comments (0)