The airdrop eligibility is determined by addresses "based on their activity on the Ethereum L1" (per README), but the contract deploys to zkSync Era which has native account abstraction. Users with AA wallets have different addresses on zkSync than on Ethereum L1, making their airdrop allocations permanently inaccessible.
The Issue:
The merkle tree encodes Ethereum L1 addresses of eligible users
The contract deploys to zkSync Era, which supports native account abstraction
AA wallets (common on zkSync) derive addresses differently than EOAs
An AA wallet's zkSync address ≠ its Ethereum L1 address
Users with AA wallets cannot produce valid merkle proofs on zkSync
What Happens:
User has address 0xAABB...1234 on Ethereum L1 (where activity was tracked)
This address is included in the merkle tree
User's AA wallet on zkSync Era has address 0xCCDD...5678 (different derivation)
User calls claim() from their zkSync address 0xCCDD...5678
The merkle proof fails because 0xCCDD...5678 is not in the tree
User's 25 USDC allocation is locked forever with no recovery mechanism
Why This is Critical:
The merkle root is immutable - it cannot be updated to include zkSync addresses
No migration function exists to re-register addresses
No admin capability to manually process claims
Affected users have zero recourse to claim their legitimate allocation
Account Abstraction Context:
zkSync Era natively supports account abstraction (EIP-4337). AA wallets on zkSync:
Use CREATE2 with different salt/deployer than L1
Have contract-based accounts with custom verification logic
Generate addresses based on zkSync-specific deployment parameters
Are NOT deterministic across chains like EOAs
This is a Pattern 28 violation (Cross-Chain Address Compatibility) where address assumptions valid on one chain break when deployed to another chain with different account models, causing permanent fund loss for affected users.
The root cause is the cross-chain address assumption: The system assumes Ethereum L1 addresses will work identically on zkSync Era, but zkSync's native AA support breaks this assumption for contract-based wallets. The immutable merkle root locks in L1 addresses permanently.
Likelihood:
Account abstraction wallets are increasingly common on zkSync Era due to native protocol support and superior UX (gasless transactions, social recovery, multi-sig). zkSync Era actively promotes AA adoption through ecosystem partnerships (Argent, Ambire, Safe). Any eligible user utilizing an AA wallet on zkSync will encounter this vulnerability immediately upon attempting to claim.
The vulnerability is discoverable during normal usage. An affected user will attempt to claim their airdrop from their zkSync AA wallet, receive MerkleAirdrop__InvalidProof(), and realize their L1 activity doesn't translate to zkSync eligibility. With no migration path documented and the merkle root immutable, affected users have zero recourse.
Impact:
Permanent fund loss for AA wallet users. Any eligible user with an account abstraction wallet loses their entire 25 USDC allocation with zero recovery mechanism. The funds remain locked in the contract indefinitely since the merkle root is immutable and no admin withdrawal function exists. Affected users are penalized for using zkSync's native AA features.
Discriminatory protocol failure and reputational damage. The airdrop excludes users based on wallet type rather than legitimate activity. Users who were most active on L1 (qualifying criteria) but use AA wallets on zkSync (the deployment chain) are systematically denied rewards. This creates a two-tier system where EOA users can claim but AA users cannot, violating fairness principles and causing severe trust erosion
// File: MerkleAirdrop.sol Add signature-based address migration
## Description The users that use account abstraction wallets have different addresses across chains for the same account. ## Vulnerability Details In the docs is said: ```javascript "Our team is looking to airdrop 100 USDC tokens on the zkSync era chain to 4 lucky addresses based on their activity on the Ethereum L1. The Ethereum addresses are: 0x20F41376c713072937eb02Be70ee1eD0D639966C 0x277D26a45Add5775F21256159F089769892CEa5B 0x0c8Ca207e27a1a8224D1b602bf856479b03319e7 0xf6dBa02C01AF48Cf926579F77C9f874Ca640D91D" ``` The user can claim his/her USDC tokens through the `MerkleAirdrop::claim` function. This function requires `account, amount and proof array`. With the help of this three arguments the merkle proof will ensure that the caller is eligible to claim. But in the generated merkle root are used the Ethereum addresses of the lucky users. But the protocol will be deployed on the zkSync era chain. If any of them uses account abstraction wallet, this lucky user will not be able to claim his/her tokens. The account abstraction wallets have different addresses in the different chains for the same account. ## Impact The users that use account abstraction wallets have different addresses on the zkSync era chain. That means these users will not be able to claim their USDC tokens, because the merkle root will require another account address (this on Ethereum). ## Recommendations Ensure that the addresses in `makeMerkle` file for the lucky users are their addresses for the zkSync era chain.
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.