Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

Setting Up On-Chain Eligibility Verification for Airdrops

A developer-focused guide on implementing secure, gas-efficient, and privacy-conscious on-chain verification for token airdrop eligibility.
Chainscore © 2026
introduction
DEVELOPER GUIDE

Introduction to On-Chain Airdrop Verification

Learn how to programmatically verify user eligibility for token airdrops by analyzing their on-chain activity, moving beyond simple snapshot checks.

On-chain airdrop verification is the process of programmatically confirming a user's eligibility for a token distribution by analyzing their historical blockchain activity. Unlike a simple snapshot that records wallet balances at a single block height, verification involves querying a wallet's complete interaction history with a protocol. This method is essential for rewarding genuine users based on complex criteria like total value locked (TVL), transaction volume, governance participation, or specific smart contract calls. For developers, building a verifier means moving from a static list of addresses to a dynamic, queryable eligibility engine.

The core technical challenge involves efficiently querying and processing blockchain data. You'll need to interact with a node provider or indexing service like The Graph, Covalent, or a dedicated RPC endpoint. The verification logic typically checks for: - Wallet interactions with target smart contracts (e.g., depositing into a liquidity pool). - Cumulative metrics over time (e.g., total swap volume > $1,000). - Specific event logs emitted by contracts (e.g., Staked or Voted events). - Adherence to time-bound criteria (e.g., activity before a certain block). This requires writing scripts that can parse transaction data and event logs to calculate user-specific metrics.

A basic verification script in JavaScript using ethers.js might start by fetching all transactions for a wallet and a specific contract. You would filter for relevant function calls and sum up values from transaction inputs or decoded event logs. For more complex analysis, using a subgraph from The Graph is often more efficient, as it allows querying pre-indexed data with GraphQL. For example, you could query a user's total liquidity provided to a Uniswap V3 pool without scanning every transaction manually. The key is to design queries that are both accurate for the eligibility rules and cost-effective to run, as blockchain queries can become expensive at scale.

Security and accuracy are paramount in verification. Common pitfalls include: - Sybil attacks: Users creating multiple wallets to farm airdrops. Mitigation involves analyzing transaction graphs or using proof-of-personhood systems. - Data freshness: Relying on outdated chain state. Always verify against the finalized block height for the snapshot. - Gas sponsorship: Filtering out transactions paid for by a third party, which may indicate bot activity. - Contract upgrades: Ensuring your verifier accounts for proxy contracts and multiple contract addresses for the same protocol. Thorough testing with known eligible and ineligible wallets is crucial before deploying a verifier in production.

For production systems, consider building a verifier as a serverless function or microservice that can be triggered via an API. This allows your airdrop claim site to programmatically verify a connecting wallet's eligibility in real-time. The response should be a simple boolean or a detailed breakdown of the user's qualifying actions. Documenting the exact verification logic and criteria transparently builds trust within your community. As the ecosystem evolves, standardized frameworks for on-chain credential verification, like Ethereum Attestation Service (EAS), may simplify this process by providing a reusable schema for proving historical on-chain behavior.

prerequisites
GETTING STARTED

Prerequisites and Tools

Before verifying on-chain eligibility for airdrops, you need the right tools and a foundational understanding of blockchain interaction. This guide covers the essential software and knowledge required.

The core tool for on-chain verification is a blockchain explorer. For Ethereum and EVM-compatible chains (like Arbitrum, Optimism, Base), use Etherscan or its chain-specific equivalents (e.g., Arbiscan). For Solana, use Solana Explorer or Solscan. These explorers allow you to query any wallet address to view its transaction history, token holdings, and interactions with specific smart contracts, which is the primary method for checking airdrop criteria.

You will also need a crypto wallet to interact with dApps and sign messages. Browser extension wallets like MetaMask (for EVM chains) or Phantom (for Solana) are standard. Ensure your wallet is connected to the correct network (e.g., Ethereum Mainnet, Arbitrum One) when checking eligibility. Some verification processes may require you to sign a message to prove wallet ownership or generate a Merkle proof, which your wallet will handle.

For advanced verification or automating checks, familiarity with command-line tools and JavaScript libraries is beneficial. The ethers.js or web3.js libraries can programmatically fetch transaction data. For example, using ethers to check if an address called a specific contract function: await provider.getLogs({ address: contractAddress, topics: [eventSignature] }). Python developers can use web3.py. Always use a reliable RPC provider endpoint from services like Alchemy, Infura, or QuickNode for consistent data access.

Understanding common on-chain eligibility criteria is crucial. Projects often snapshot activity based on: - Minimum token balance held at a past block height. - Volume or frequency of transactions with a protocol. - Specific interactions, like providing liquidity or voting in governance. - Owning certain NFTs or completing quests. These data points are permanently recorded on-chain and can be queried via the explorer's API or directly through an RPC call to a node.

Finally, maintain security best practices. Never enter your private key or seed phrase into any website for "eligibility checking." Legitimate verification happens by reading public blockchain data or through official project portals that request a harmless signature. Use a dedicated wallet for airdrop hunting to separate funds and minimize risk. Bookmark the official project documentation and Twitter account to avoid phishing sites mimicking eligibility checkers.

key-concepts-text
CORE TECHNICAL CONCEPTS

Setting Up On-Chain Eligibility Verification for Airdrops

A guide to implementing secure, gas-efficient on-chain checks to validate user eligibility for token distributions.

On-chain eligibility verification is the process of validating a user's right to claim an airdrop directly within a smart contract. This moves the logic from a centralized server to the blockchain, ensuring transparency and immutability. The core mechanism involves the airdrop contract checking predefined conditions—such as holding a specific NFT, having a minimum token balance at a historical snapshot, or completing on-chain interactions—before allowing a claim. This prevents Sybil attacks and ensures only legitimate users receive tokens, while allowing anyone to publicly audit the distribution criteria.

Implementing verification starts with defining the eligibility logic. Common patterns include merkle tree proofs, state snapshots, and dynamic checks. A merkle proof, used by protocols like Uniswap and Optimism, allows users to submit a cryptographic proof that their address is included in a pre-computed list of eligible recipients, minimizing on-chain storage. A snapshot involves storing a mapping of addresses to claimable amounts in the contract state after a specific block. Dynamic checks query live on-chain data, such as an ERC-721 balanceOf call, to verify conditions in real-time.

Here is a basic Solidity example using a merkle proof for verification:

solidity
function claim(bytes32[] calldata merkleProof, uint256 amount) external {
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
    require(MerkleProof.verify(merkleProof, merkleRoot, leaf), "Invalid proof");
    // Transfer logic here
}

The contract stores a single merkleRoot (a 32-byte hash representing all eligible addresses and amounts). Users call claim with a proof generated off-chain. The verify function recomputes the leaf hash from the caller's address and amount, checking it against the root. This pattern is gas-efficient for large distributions.

For dynamic, state-based checks, you might verify a user held a specific ERC-20 token during a historical snapshot. While you cannot query past balances directly, you can use a tool like EVM storage proofs (via protocols like Ethereum Attestation Service or Lagrange) or rely on an oracle that recorded the state. A simpler, more common approach is to take a snapshot by saving each eligible address and its claimable balance into your contract's storage at the time of the airdrop announcement, often done via a privileged setMerkleRoot or setClaimable function.

Key considerations for production systems include gas optimization, revocability, and multi-chain logic. Use merkle proofs for large lists to save storage costs. Consider adding a claim deadline and a sweep function for unclaimed tokens. For cross-chain airdrops, the verification logic often resides on a source chain, with a message bridge like LayerZero or Wormhole relaying proof of eligibility to destination chains. Always include access controls and allow pausing in case of critical bugs.

Testing is critical. Use forked mainnet environments in Foundry or Hardhat to simulate real snapshots. Verify edge cases: zero balances, duplicate claims, and expired deadlines. Tools like OpenZeppelin's MerkleProof library provide audited utilities. Ultimately, robust on-chain verification creates trustless, self-executing distributions that align with Web3 principles, moving away from opaque, server-side validation. For further reading, review the Uniswap Merkle Distributor or Optimism's airdrop contract on GitHub.

verification-methods
DEVELOPER TOOLS

Eligibility Verification Methods

Verify user eligibility for airdrops, allowlists, and token-gated access directly on-chain. These methods ensure transparency and prevent Sybil attacks.

05

On-Chain Activity & Score Checks

Verify eligibility by querying on-chain activity metrics directly in the contract, often using a pre-computed score from a verifier contract.

  • Implementation: A separate contract (e.g., a Chainscore verifier) calculates a score based on transaction history, gas spent, or protocol interactions. The airdrop contract reads this score.
  • Example: Eligibility for users with a "loyalty score" above 500, calculated from their last 100 transactions on Arbitrum.
  • Benefit: Dynamic, real-time eligibility based on transparent, on-chain rules.
< 100k gas
Typical Verification Cost
METHODS

Airdrop Verification Method Comparison

A comparison of on-chain techniques for verifying user eligibility for airdrop claims.

Verification MethodMerkle ProofSignature VerificationOn-Chain State Check

Gas Cost for Claim

$5-15

$2-5

$10-50+

Developer Overhead

High

Medium

Low

Frontend Complexity

High (proof generation)

Medium (signature handling)

Low (simple call)

Data Finality Required

Real-Time Eligibility Updates

Prevents Sybil Attacks

Example Protocol

Uniswap, Arbitrum

Ethereum Name Service

Optimism AttestationStation

merkle-tree-implementation
GUIDE

Step-by-Step: Implementing a Merkle Tree Airdrop

This guide explains how to implement a gas-efficient, on-chain airdrop using a Merkle tree for eligibility verification, including smart contract and frontend integration.

A Merkle tree airdrop is a standard method for distributing tokens to a large list of eligible addresses while minimizing on-chain storage and gas costs. Instead of storing every recipient address in the contract—which is prohibitively expensive—you store a single cryptographic hash, the Merkle root. This root is computed from a tree of hashes representing all eligible address-amount pairs. Users then submit a Merkle proof to claim their tokens, proving their inclusion in the list without revealing the entire dataset. This approach is used by major protocols like Uniswap and Optimism for their distributions.

The implementation involves three core steps. First, generate the Merkle tree data off-chain. Create a list of objects containing each recipient's address and claimable amount. Hash each entry, then recursively hash pairs to build the tree until you derive the final root. Use libraries like merkletreejs in JavaScript or merkletree in Solidity for this process. Second, deploy the claim contract with the computed Merkle root. The contract needs a claim function that verifies a user's provided proof against the stored root. Third, build a claiming interface where users can connect their wallet, automatically generate their proof, and execute the claim transaction.

Here is a simplified Solidity example for the core claim logic using OpenZeppelin's MerkleProof library:

solidity
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract MerkleAirdrop {
    bytes32 public merkleRoot;
    mapping(address => bool) public hasClaimed;
    constructor(bytes32 _merkleRoot) { merkleRoot = _merkleRoot; }
    function claim(address recipient, uint256 amount, bytes32[] calldata proof) external {
        require(!hasClaimed[recipient], "Already claimed");
        bytes32 leaf = keccak256(abi.encodePacked(recipient, amount));
        require(MerkleProof.verify(proof, merkleRoot, leaf), "Invalid proof");
        hasClaimed[recipient] = true;
        // Transfer logic here
    }
}

The leaf is the hash of the recipient and amount. The proof is the array of sibling hashes needed to reconstruct the path from the leaf to the root.

For the frontend, you need to serve the correct proof to each user. After generating the tree, save the data—typically a JSON file mapping addresses to their proof and amount. Your web app should fetch this data for the connected wallet address. A common pattern is to host a static JSON file or use an API endpoint. When a user connects, the dApp looks up their entry, constructs the transaction parameters, and enables the claim button. Always include a claim deadline in your contract to recover unclaimed funds and prevent the contract from being permanently active.

Security considerations are critical. Use a commit-reveal scheme if the eligibility list must be hidden before the airdrop starts; publish only the root initially, then reveal the tree later. Guard against replay attacks by marking addresses as claimed. Ensure the off-chain generation script is deterministic and run in a secure environment, as any error in the tree creation will render proofs invalid. For large distributions, consider using incremental merkle trees or alternative structures like Verkle trees for even greater efficiency, though standard Merkle trees remain the most battle-tested option for most use cases.

on-chain-data-query
GUIDE

Setting Up On-Chain Eligibility Verification for Airdrops

A practical guide for developers to programmatically verify user eligibility for token airdrops by querying historical blockchain state.

Airdrop eligibility is typically determined by a user's historical on-chain activity, such as holding a specific NFT, using a protocol before a certain block, or meeting transaction volume thresholds. Manually checking wallets is impractical at scale. Instead, developers need to query historical state data from an archive node or indexing service. This process involves reconstructing the state of an address at a past block height, which is not possible with a standard Ethereum JSON-RPC node alone. Services like Chainscore, The Graph, or Alchemy's archive nodes provide the necessary historical APIs.

The core technical challenge is accessing state from a historical block. A standard eth_getBalance call defaults to the 'latest' block. To check past eligibility, you must specify the exact block number from the snapshot. For example, to verify if an address held an ERC-20 token during a snapshot, you would call the token contract's balanceOf function at that block. Using web3.js or ethers.js, you can query a specific past block by including the block number in the call. Failing to use an archive-enabled node for this will result in errors for older blocks.

A common pattern is to verify membership in a Merkle tree distributed by the airdropping project. The project generates a Merkle root from eligible addresses and balances, which is stored on-chain. Your verification script must check if a user's address and claimable amount are part of this tree. This involves hashing the user's data, generating the Merkle proof (often provided by the project's API), and verifying it against the on-chain root using a library like @openzeppelin/merkle-tree. This method is gas-efficient and a standard for large-scale airdrops like Uniswap and Arbitrum.

For more complex eligibility rules—such as calculating total swap volume on a DEX or days an NFT was held—you need to process historical event logs. This requires filtering Transfer, Swap, or Stake events for the user's address within a specific block range. While you can use eth_getLogs with an archive node, for production applications it's more efficient to use a dedicated indexing solution like Chainscore's Historical API or The Graph subgraphs, which pre-index this data and offer faster, more complex queries without managing your own infrastructure.

When building your verifier, always include rate limiting and error handling. Archive node requests are resource-intensive. Cache results where possible and implement retry logic for failed RPC calls. Your final script should output a simple boolean for eligibility and the verifiable claim amount. Always double-check the snapshot block number and contract addresses against the official airdrop announcement to prevent errors. For a complete, production-ready example, refer to the Chainscore Airdrop Verification Tutorial.

privacy-frontrunning
PRIVACY AND ANTI-FRONT-RUNNING MEASURES

Setting Up On-Chain Eligibility Verification for Airdrops

A guide to implementing verifiable, privacy-preserving eligibility checks to prevent front-running and Sybil attacks in token distributions.

On-chain eligibility verification is a critical component for fair airdrop distribution. The goal is to allow users to cryptographically prove they meet predefined criteria—like holding a specific NFT, interacting with a protocol, or being on an allowlist—without revealing their identity or wallet address until the claim moment. This prevents front-running bots from scanning the mempool for eligible addresses and claiming tokens before legitimate users. Common verification methods include Merkle proofs, zero-knowledge proofs (ZKPs), and commit-reveal schemes, each offering different trade-offs between privacy, gas cost, and complexity.

A Merkle proof is the most widely used method due to its simplicity and low gas cost. The airdrop organizer generates a Merkle tree off-chain where each leaf is a hash of an eligible address and its token allocation. The Merkle root is stored on-chain. To claim, a user submits a Merkle proof—a path of hashes from their leaf to the root—along with their address and allocation. The contract verifies the proof against the stored root. While effective, this method leaks the user's address in the transaction, leaving a small window for front-running unless combined with a commit-reveal phase or direct minting to the claimant.

For enhanced privacy, zero-knowledge proofs (e.g., using Circom or SnarkJS) allow a user to prove eligibility without revealing which specific criterion they satisfied. For instance, a ZK circuit could prove that a user's address is a member of a private allowlist or that they performed a required action before a snapshot, with only the proof and a nullifier (to prevent double-claims) submitted on-chain. Projects like Semaphore or zkSNARKs-based systems enable this. While more complex to implement, ZKPs offer strong privacy and are increasingly viable with layer-2 scaling solutions that reduce proof verification costs.

A commit-reveal scheme adds a time-delayed barrier against front-running. In the first phase (commit), users submit a hash of their address and a secret salt. In the second phase (reveal), after the commit phase closes, eligible users reveal their address and salt, which the contract hashes to verify it matches the commit. Since front-runners cannot generate the correct hash for an unknown address during the commit phase, this method effectively blocks last-second attacks. This can be combined with a Merkle tree, where the commit is the leaf hash, adding an extra layer of security.

Implementing a basic Merkle claim contract in Solidity involves a few key steps. First, generate the tree off-chain using a library like @openzeppelin/merkle-tree. Store the root in your contract. The claim function should verify the proof using OpenZeppelin's MerkleProof library, mark the address as claimed, and transfer tokens. Always include a check for duplicate claims and a deadline. For anti-Sybil measures, consider integrating a proof-of-personhood system like World ID or requiring a minimum token balance or transaction history from a trusted provider like Chainscore to validate unique human users.

Best practices for secure airdrop verification include using a multisig or timelock to set the Merkle root, implementing a claim deadline to return unclaimed tokens, and conducting thorough testing on a testnet. For large distributions, estimate gas costs and consider deploying on an L2 like Arbitrum or Optimism. Always audit your contract, and consider making the verification logic upgradeable via a proxy pattern to fix issues. Transparent communication about eligibility criteria and the verification process is essential for user trust and successful adoption of the airdrop.

ON-CHAIN ELIGIBILITY

Frequently Asked Questions

Common technical questions and solutions for developers implementing on-chain verification for airdrop campaigns.

On-chain eligibility verification is a method for programmatically determining user qualification for an airdrop by checking their historical blockchain activity directly on-chain, rather than relying on off-chain lists. It works by deploying a verification smart contract that contains the eligibility logic. When a user claims, this contract executes a function (like verifyEligibility(address user)) which queries the chain's state—checking past transaction history, token holdings, NFT ownership, or participation in specific protocols—and returns a boolean result.

This approach is trustless and transparent; the rules are immutable and publicly auditable. For example, a contract could verify that an address held a minimum of 10 UNI tokens in a specific vault contract before a snapshot block number. This eliminates the need for a centralized server to validate claims, reducing points of failure and manipulation.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have configured a system to programmatically verify on-chain eligibility for airdrops. This guide covered the core concepts and a practical implementation.

The system you've built demonstrates a fundamental pattern in Web3: using smart contract data to determine user eligibility. By querying a user's historical interactions—such as token holdings, transaction volume, or governance participation—you can create a verifiable, transparent, and automated eligibility check. This approach is superior to manual verification or off-chain lists, as it is provably fair and resistant to manipulation. The core logic resides in the checkEligibility function, which serves as the single source of truth for your airdrop criteria.

To extend this system, consider implementing more sophisticated checks. For example, you could verify time-weighted average balances using a service like Chainlink Data Streams or check for participation in specific protocol events by parsing transaction logs with a library like ethers.js. For gas-efficient batch verification, you could deploy a contract that uses Multicall to aggregate multiple eligibility queries into a single on-chain call, significantly reducing costs when checking many users.

Your next steps should focus on security and scalability. Thoroughly test your eligibility logic with a wide range of wallet addresses, including edge cases. Consider adding a merkle proof mechanism for large-scale airdrops, where you pre-compute a merkle root of eligible addresses off-chain and allow users to submit a proof for verification, which is far more gas-efficient than storing a full list on-chain. Always publish your final eligibility criteria and contract addresses clearly to users to maintain transparency and trust.

Finally, integrate this verification into your broader application flow. The eligibility result can gate access to a claim interface, trigger an automated distribution, or be used to assign roles within a DAO. By mastering on-chain verification, you build airdrops that are not just rewards, but trustless primitives that enhance your protocol's composability and fairness in the decentralized ecosystem.