The deploy script should construct MerkleAirdrop with the USDC token address and then move the airdrop funds into the contract using that same token.
The constructor receives s_zkSyncUSDC = 0x1D17...be9..., but the funding transfer is called on a different hardcoded literal 0x1d17...ae9.... The two addresses differ by one hex digit (b vs a), so they are different tokens. The MerkleAirdrop is configured for token A while the funds are sent in token B, leaving the airdrop contract with a zero balance of its configured token — every claim then reverts.
Likelihood: HIGH
The two hardcoded addresses differ by one character and are both used unconditionally in run(); the mismatch happens on every deployment, with no attacker or special condition required.
Impact: HIGH
The airdrop contract is never funded in its configured token, so all four recipients' claims revert and the intended distribution never happens.
If token B exists and the deployer holds a balance of it, the funding transfer moves real value into a contract that can never distribute it, locking those funds.
Severity: HIGH (High likelihood × High impact)
The two address literals used in Deploy.s.sol are not equal, proving the constructor token and the funding token differ (test/PoC_H3_Address.t.sol). A chisel/cast comparison of the lowercased addresses shows the difference at the be9… vs ae9… position.
Use the single, verified USDC address consistently — reuse the s_zkSyncUSDC variable instead of a second hardcoded literal, and confirm it is the real USDC on zkSync Era. Also check the transfer return value (or use SafeERC20), since the compiler flags this line for an unchecked ERC20 transfer.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.