Merkle Distributor Development for Mass Token Payouts - Save 95% on Gas

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 $48

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    717
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1008

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
  1. Prepare data: list of recipients with indices, addresses, and amounts.
  2. Form leaves: leaf = keccak256(abi.encodePacked(index, address, amount)) — double hashing protects against second preimage attacks.
  3. Build the tree: use the @openzeppelin/merkle-tree library (JS/TS) or rs_merkle (Rust). Each internal node = keccak256(abi.encodePacked(left, right)) with canonical ordering (smaller hash on the left).
  4. Obtain the root: tree.root — the single value stored in the contract.
  5. 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.