Airdrop Contract Development via Merkle Distributor
We often see the classic mistake – trying to distribute tokens through a loop with on-chain sending to each address. With 10,000 recipients, that's 10,000 transactions, tens of thousands of dollars in gas, and several hours of work. Our team, with over 5 years of blockchain experience and 50+ token launch projects, recommends a different approach – a Merkle distributor. You set the Merkle root on-chain once, and each recipient claims their tokens individually, paying only for their own inclusion. This reduces your gas bill by hundreds of times – a Merkle distributor saves up to 99% of gas compared to direct transfers. The base library for implementation is OpenZeppelin MerkleProof.
Problems We Solve
- Exorbitant gas for large lists. An on-chain airdrop to 50,000 addresses can cost >$20,000 in gas alone. Our Merkle distributor saved one client 99% of the cost: from $25,000 to under $250.
- Second preimage attack vulnerability. We use a double-hashed leaf as in OpenZeppelin, which completely blocks the attack.
- Token lock without deadline. We add a deadline with the possibility to recover remaining tokens to the owner.
- Lack of vesting. We embed linear vesting directly into the distributor.
Airdrop Approach Comparison
| Parameter | On-chain loop | Merkle distributor |
|---|---|---|
| Transactions | N (each recipient – separate call) | 1 (set root) + N (each claim – paid by recipient) |
| Gas (10k users, ETH mainnet) | ~30 ETH | ~0.1 ETH (for root) + ~0.02 ETH per user |
| Execution time | Hours | Minutes (after deploy) |
| Security | Gas-dependent | Proven MerkleProof library |
The gas saving factor is up to 300x for 10,000 addresses, a significant improvement for teams with limited token launch budgets.
How the Merkle Distributor Works
Moving to L2 further reduces gas costs: on Arbitrum or Base, a claim costs pennies, not dollars. Contact us for a detailed estimate for your audience.
Our Guarantees & Experience
We are an experienced team with over 5 years in blockchain development and 50+ token launch projects audited by Certik and Consensys Diligence. We offer a warranty on our contracts and provide post-launch support.
How We Do It
We use a proven stack: Solidity 0.8.x + OpenZeppelin libraries (MerkleProof, ERC20), for off-chain – TypeScript + @openzeppelin/merkle-tree. We deploy on Ethereum L1 or L2 (Arbitrum, Base, Optimism) per your choice. Example implementation with bit packing for claimed status:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; contract MerkleAirdrop { IERC20 public immutable token; bytes32 public immutable merkleRoot; mapping(uint256 => uint256) private claimedBitMap; constructor(address _token, bytes32 _merkleRoot) { token = IERC20(_token); merkleRoot = _merkleRoot; } function isClaimed(uint256 index) public view returns (bool) { uint256 claimedWordIndex = index / 256; uint256 claimedBitIndex = index % 256; uint256 claimedWord = claimedBitMap[claimedWordIndex]; uint256 mask = (1 << claimedBitIndex); return claimedWord & mask == mask; } function claim( uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof ) external { require(!isClaimed(index), "Already claimed"); bytes32 leaf = keccak256(bytes.concat( keccak256(abi.encode(index, account, amount)) )); require( MerkleProof.verify(merkleProof, merkleRoot, leaf), "Invalid proof" ); _setClaimed(index); require(token.transfer(account, amount), "Transfer failed"); emit Claimed(index, account, amount); } } Off-Chain Merkle Tree Generation
import { StandardMerkleTree } from "@openzeppelin/merkle-tree" const values = [ [0, "0xAddress1...", ethers.parseEther("100")], [1, "0xAddress2...", ethers.parseEther("250")], ] const tree = StandardMerkleTree.of(values, ["uint256", "address", "uint256"]) console.log("Merkle Root:", tree.root) for (const [i, v] of tree.entries()) { if (v[1] === "0xAddress1...") { const proof = tree.getProof(i) } } import fs from "fs" fs.writeFileSync("tree.json", JSON.stringify(tree.dump())) You distribute proofs via a simple API: GET /proof?address=0x... → returns { index, amount, proof[] }. The API can be implemented with Fastify or Express – typical code is about 50 lines.
Why Choose L2 for Airdrop?
On Ethereum mainnet, a claim costs ~$2–10 per transaction. On Arbitrum, Base, or Optimism – cents. If your audience is mass, L2 lowers the entry barrier. We help select the right rollup and configure the token bridge.
| Network | Average claim cost | Confirmation time |
|---|---|---|
| Ethereum L1 | $2–10 | ~15 seconds |
| Arbitrum | $0.01–0.05 | ~1 minute |
| Base | $0.01–0.03 | ~1 second |
| Optimism | $0.01–0.05 | ~1 minute |
Our Work Process
- Analysis – discuss the address list, token, L1/L2, need for vesting, deadline.
- Design – choose Merkle tree structure, write contract specification.
- Development – write the contract using OpenZeppelin, off-chain scripts, API.
- Testing – unit tests, fuzzing (Echidna), simulation in Tenderly.
- Deployment – to the chosen network, contract verification, test claim.
- Support – monitoring, helping users with claim issues.
What's Included
- Smart contract (Merkle distributor with optional deadline/vesting)
- Off-chain Merkle tree generator + TypeScript scripts
- API for distributing proofs (Fastify/Express)
- Example UI integration (React + viem)
- Deployment and operational documentation
- 2 weeks of post-launch support
We use Echidna for fuzzing the contract, checking proof correctness, preventing double claims, and gas limits. Simulation in Tenderly allows us to reproduce any transaction before deployment.
Timeline and Pricing
A standard turnkey implementation takes 1 to 2 weeks. Pricing is calculated individually based on options (vesting, gasless claim, custom UI). We assess your project in one business day – just write to us, and we'll prepare a proposal.







