Author: BinnaDev (Obinna Franklin Duru)
Status: Audit-Ready
Solidity: ^0.8.24
Framework: Foundry
A modular, secure, and gas-efficient system for distributing ERC20 and ERC721 tokens. This repository provides a production-ready implementation of advanced airdrop patterns, built with a security-first and reliability-focused mindset.
This system is not a single contract but a set of modular components designed for flexibility and security.
- Modular Architecture: Choose the right tool for the job. Deploy a Merkle-based drop, a Signature-based drop, or both.
- Merkle Airdrops: A
MerkleAirdrop.solcontract for large-scale, one-time distributions. It's extremely gas-efficient for the deployer (only one bytes32 root is stored on-chain). - Signature Airdrops: A
SignatureAirdrop.solcontract for dynamic, off-chain, or authority-driven claims using EIP-712. - Gas-Efficient State: Uses
BitMaps.solfor Merkle claims, drastically reducing gas costs for users by packing 256 claims into a single storage slot. - Gasless Claims: Both contracts are fully ERC-2771 compatible, allowing a relayer to pay gas fees on behalf of users for a seamless UX.
- Robust Security: Built-in protection against re-entrancy (
nonReentrant), double-claims (Bitmap/Nonces), and replay attacks (EIP-712 Nonces). - Universal Token Support: A single, unified logic path handles both ERC20 and ERC721 token transfers.
- Auditable & Documented: Every line of code is fully documented with Natspec comments.
The system is split into two primary, independent contract modules.
This contract acts as a token vault secured by a Merkle root. It is designed for "pull" based airdrops where users prove their inclusion in a large, pre-computed list.
- Logic: The deployer generates a Merkle tree off-chain from a list of allocations (e.g.,
(index, claimant, token, amount)). The tree's root is set as immutable in the contract's constructor. - Claiming: A user calls
claim(), providing their allocation data and a valid proof. The contract verifies the proof against the root and checks aBitMaps.BitMapto prevent double-claims. - Best For: Large-scale, public airdrops (10k - 1M+ users) where the allocation list is fixed at deployment.
This contract acts as a token vault secured by EIP-712 signatures. It is designed for "push" based airdrops where a trusted authority (a "signer") approves claims individually.
- Logic: A trusted off-chain signer (e.g., a backend service) generates EIP-712 signatures for valid claims. The
Claimpayload is domain-separated and includes a nonce for replay protection. - Claiming: A user (or relayer) calls
claimWithSignature(), providing theClaimpayload and the signature. The contract usesECDSA.recoverto verify the signer and checks the nonce to prevent double-claims. - Best For: Dynamic airdrops, "claim-as-you-go" rewards, or any system where the allocation logic is complex and managed off-chain.
Our JavaScript tools are essential for managing the airdrop.
npm installThis script reads a CSV and generates the merkleRoot and airdrop-data.json proof file.
Format your allocations.csv:
claimant,tokenContract,tokenId,amount
0x709...79C8,0x5Fb...0aa3,0,100000000000000000000
0x3C4...0b0B,0x016...Eb8F,42,1Run the script:
# Reads from data/allocations.csv by default
npm run generate-merkleThis will create dist/airdrop-data.json. The merkleRoot printed in your console is what you need for deployment.
This script demonstrates how a backend would sign a claim. You must edit the file to point to your deployed contract address and chain ID.
# (After configuring contract address in the script)
npm run sign-claimThis will print a sample payload and signature that can be passed to claimWithSignature().
We use Foundry Scripts for reliable, repeatable deployments.
Your MERKLE_ROOT comes from the generate-merkle.js script. TRUSTED_FORWARDER is your ERC-2771 relayer, or 0x0000000000000000000000000000000000000000 if not used.
export MERKLE_ROOT=0x...
export TRUSTED_FORWARDER=0x...
export RPC_URL=...
export PRIVATE_KEY=...forge script scripts/foundry/Deploy.s.sol:DeployAirdropSystem \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast \
--verifyThis project uses Foundry for all testing.
# Run all tests
forge test
# Run a specific test suite with high verbosity
forge test --match-path test/MerkleAirdrop.t.sol -vvv
# Get a gas report
forge test --gas-reportSecurity is the primary value of this project.
- Natspec: All contracts are fully documented with Natspec comments.
- Checks-Effects-Interactions: This pattern is strictly followed to prevent re-entrancy.
- nonReentrant Guard: All claim functions use OpenZeppelin's
nonReentrantmodifier. - Immutable Root: The
MERKLEROOTis immutable and cannot be changed.
- Follow on X
- Open for smart contract audits and development roles.