We develop Merkle Distributors for mass token payouts – gas-efficient airdrop contracts that use Merkle trees. A direct mapping of 50,000 addresses costs ~2.5 ETH in deployment gas, while our Merkle-based solution costs only ~0.08 ETH – a 32x reduction. At ETH $2000, that’s $5000 vs $160, saving $4840. Each claim costs 80k gas fixed, compared to 300k+ for batch mapping. This is why Merkle Distributor is the industry standard for large-scale airdrops.
How Does the Merkle Distributor Work?
The contract stores only a single bytes32 merkleRoot — the root of the tree. The entire payout table (address → amount) remains off-chain. Recipients claim their tokens by providing a merkleProof — a set of hashes proving their inclusion in the tree.
On-chain verification:
function claim(
uint256 index,
address account,
uint256 amount,
bytes32[] calldata merkleProof
) external {
require(!isClaimed(index), "Already claimed");
bytes32 node = keccak256(abi.encodePacked(index, account, amount));
require(MerkleProof.verify(merkleProof, merkleRoot, node), "Invalid proof");
_setClaimed(index);
require(IERC20(token).transfer(account, amount), "Transfer failed");
emit Claimed(index, account, amount);
}
isClaimed(index) checks one bit in a mapping(uint256 => uint256) — a packed bitmask. 50,000 recipients = ~1,563 uint256 slots instead of 50,000. Storage savings — by orders of magnitude. We employ assembly optimizations for bitmask operations to further reduce gas.
Why the Tree-Based Method Is the Standard for Airdrops
Compare deployment costs for 50,000 recipients:
| Approach | Storage Slots | Approximate Gas Cost | USD at $2000 ETH |
|---|---|---|---|
| Direct mapping | 50,000 | ~2.5 ETH | $5,000 |
| Merkle Distributor | ~1,563 | ~0.08 ETH | $160 |
Savings over 95%. Additionally, the off-chain table is easily updated without redeploying the contract. Per-claim costs are also lower:
| Method | Gas per Claim | Notes |
|---|---|---|
| Mapping + batch | ~300k+ | Depends on number of recipients |
| Merkle Distributor | ~80k | Fixed cost |
With 50,000 claims, savings amount to tens of ETH. The tree-based distributor outperforms direct storage by 32x in deployment gas.
How to Build a Merkle Tree: Step-by-Step Guide
Detailed tree construction instructions
- Prepare data: list of recipients with indices, addresses, and amounts.
-
Form leaves:
leaf = keccak256(abi.encodePacked(index, address, amount))— double hashing protects against second preimage attacks. -
Build the tree: use the
@openzeppelin/merkle-treelibrary (JS/TS) orrs_merkle(Rust). Each internal node =keccak256(abi.encodePacked(left, right))with canonical ordering (smaller hash on the left). - Obtain the root:
tree.root— the single value stored in the contract. - Generate proofs: for each recipient using
tree.getProof(...). Distribute proofs via API or publish them on IPFS along with the full table.
Typical script:
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
const values = recipients.map(([address, amount], index) => [
index, address, amount
]);
const tree = StandardMerkleTree.of(values, ["uint256", "address", "uint256"]);
console.log("Root:", tree.root);
// proof for a specific recipient
const proof = tree.getProof([index, address, amount]);
Common Mistakes in Merkle Distributor Implementation
The first and most common mistake is an incorrect bitmask for double-spend protection. If _setClaimed sets the bit incorrectly, a repeat claim is possible. Use the proven pattern from the OpenZeppelin MerkleDistributor. The second issue — leaf collision: if leaves are formed without index (keccak256(abi.encodePacked(address, amount))), two recipients with the same amount could prove a claim on each other — though this gives them a different address, in practice the collision is unsafe. Adding index guarantees uniqueness. The third mistake — encoding mismatch: abi.encodePacked off-chain and abi.encodePacked in Solidity must match. Uniswap and Optimism use abi.encodePacked for leaves.
Advanced Patterns
Multi-round distributor. A new merkleRoot each week/epoch. Instead of deploying a new contract, an updatable root via updateMerkleRoot(bytes32) with onlyOwner or governance. The claimed bitmask is reset for the new epoch or indexed by epoch: mapping(uint256 epoch => mapping(uint256 wordIndex => uint256 bitmask)).
Delegated claiming. The recipient signs a permission to claim on their behalf — useful for gasless UX via a relayer or ERC-2771 meta-transactions. Pattern: claimFor(address account, uint256 amount, bytes32[] calldata proof, bytes calldata signature).
Testing with Foundry
function test_ClaimValidProof() public {
// build tree in test
bytes32[] memory leaves = new bytes32[](3);
leaves[0] = keccak256(abi.encodePacked(uint256(0), alice, uint256(100e18)));
// merkle proof computed manually or via FFI to JS script
distributor.claim(0, alice, 100e18, proof);
assertEq(token.balanceOf(alice), 100e18);
vm.expectRevert("Already claimed");
distributor.claim(0, alice, 100e18, proof); // double claim
}
To generate proofs in Foundry tests: vm.ffi calling a TypeScript script with @openzeppelin/merkle-tree. Or write a pure Solidity implementation in setUp() — slower but without external dependencies.
What Our Development Includes
With over 5 years in blockchain development and 20+ distributor contracts deployed, we deliver robust solutions. Our package includes:
- Smart contract source code in Solidity (tested with Foundry, including fuzz tests).
- Off-chain scripts: tree construction, proof generation, deployment and verification (TypeScript, ethers.js).
- Documentation: architecture description, deployment instructions, API description.
- Adaptation to your token: ERC-20, ERC-721, ERC-1155, or cross-chain via bridge.
- One month of post-launch support: bug fixes, integration consultations.
Timeline and Cost
Basic Merkle Distributor with single root: 2-3 days including off-chain scripts. Multi-round with governance and gasless claiming: 4-5 days. Contract deployment and verification on mainnet — additional few hours. Cost is calculated individually after clarifying details. Contact us for an estimate of your project — we'll analyze recipient count, epoch requirements, and UX. Order Merkle Distributor development and we'll help you save thousands of dollars on gas. Get a consultation right now.







