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

Mass token payouts often face high blockchain data recording fees, making airdrops costly and inefficient. We build a Merkle Distributor based on Merkle Tree that reduces deployment costs and makes each payout gas-fixed. Our team delivers a turnkey solution—from tree construction to contract deployment with ongoing support, ensuring reliability and scalability for your business.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1335
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1293
  • B2B Advance company logo design
    B2B Advance company logo design
    738
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1031
  • AIDER company logo development
    AIDER company logo development
    978
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1087

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.