AirDropper

AI First Flight #5
Beginner FriendlyDeFiFoundry
EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

MerkleAirdrop declares a MerkleRootUpdated event that is never emitted, misleading integrators and leaving dead code in the contract

Root + Impact

Description

  • MerkleAirdrop is intended to emit events to allow off-chain systems and integrators to track meaningful state changes.

The contract declares MerkleRootUpdated but i_merkleRoot is immutable — it can only be set in the constructor and can never change after deployment. There is no setter function anywhere in the contract. The event therefore can never be emitted under any circumstances. It is dead code that signals a capability the contract does not have.

// @> merkleRoot is immutable — set once in constructor, never changes
bytes32 private immutable i_merkleRoot;
// @> event declared for a state change that cannot occur
event MerkleRootUpdated(bytes32 newMerkleRoot);
constructor(bytes32 merkleRoot, IERC20 airdropToken) Ownable(msg.sender) {
i_merkleRoot = merkleRoot; // @> only assignment — no setter exists
i_airdropToken = airdropToken;
}n

Risk

Likelihood:

  • This does not affect runtime behavior — no funds are at risk and no execution path is broken

Impact:

  • Off-chain integrators or monitoring tools that listen for MerkleRootUpdated will never receive it, potentially causing silent failures in downstream systems

The presence of the event implies the Merkle root is updatable, which could mislead auditors or users into believing the owner can silently swap the root to redirect funds — a trust concern even if not currently exploitable

  • Wasted bytecode increases deployment gas cost marginally

Proof of Concept

This is statically verifiable from the source — no test is required. A search for all emit statements in the contract confirms MerkleRootUpdated is never referenced outside its declaration:

// All emit statements in MerkleAirdrop.sol:
emit Claimed(account, amount); // line 41 — used
// MerkleRootUpdated is declared but appears in zero emit statements

Recommended Mitigation

Either remove the event entirely, or replace immutable with a private variable, add an owner-only setter, and emit the event correctly. The first option is preferred given the current design intent of a fixed-root airdrop.

- bytes32 private immutable i_merkleRoot;
+ bytes32 private i_merkleRoot;
- event MerkleRootUpdated(bytes32 newMerkleRoot);
// Option A — remove the event, keep immutable (preferred for fixed airdrops):
+ bytes32 private immutable i_merkleRoot;
// Option B — make root updatable and emit the event correctly:
+ function setMerkleRoot(bytes32 newMerkleRoot) external onlyOwner {
+ i_merkleRoot = newMerkleRoot;
+ emit MerkleRootUpdated(newMerkleRoot);
+ }
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 4 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!