Impact: H
Likelihood: H
There are 2 different USDC token addresses used in Deploy.s.sol - one for MerkleAirdrop.sol deploy and another for funding this contract. The issue is with the token address that is used for deploy - the address does not have a code associated with it. This means that a claimer will not be able to claim her airdropped tokens because the function MerkleAirdrop::claim() calls ERC20::safeTransfer() function and this will lead to the error: "[FAIL: call to non-contract address 0x1D17CbCf0D6d143135be902365d2e5E2a16538d4]"
Since nobody can claim tokens from the MerkleAirdrop.sol, the USDC will be locked in the contract forever.
The different USDC token addresses that are used are marked in the code:
Likelihood:
The issue occurs when the MerkleAirdrop.sol is being deployed and funded using Deploy.s.sol script.
Impact:
Users will not be able to claim their airdropped tokens.
USDC funds are locked inside MerkleAirdrop.sol forever.
To proof the issue, some changes are necessary in Deploy.s.sol:
Vm cheatcodes vm.startBroadcast(); and vm.stopBroadcast(); should be removed because they do not work correctly on ZkSync;
Return value MerkleAirdrop is added to Deploy::run() to use it in the test;
Deploy.s.sol:
Please, add the following DeployTest.t.sol contract and run test_differentTokenAddress_whenDeployAndFundMerkleAirdropContract test as a fork test on ZKsync Era Mainnet using the command forge test --mt test_differentTokenAddress_whenDeployAndFundMerkleAirdropContract --fork-url $ZK_SYNC_MAINNET_URL --zksync -vvvvv:
Introduce a constant for the correct token address.
Use this constant for both - deploy and funding the MerkleAirdrop.sol.
Avoid using literals without well-named variables.
## Description The `s_zkSyncUSDC` address in `Deploy.s.sol` is incorrectly set, leading to a failure in the claiming process. This error results in funds being stuck in the `MerkleAirdrop` contract due to the immutability of the token address. ## Impact All funds become permanently trapped in the `MerkleAirdrop` contract, rendering them inaccessible for claiming or transfer. **Proof of Concept:** To demonstrate the issue, a test contract can be added and executed using the following command: `forge test --zksync --rpc-url $RPC_ZKSYNC --mt testDeployOnZkSync` Use the RPC URL `https://mainnet.era.zksync.io` for testing. <details> <summary>Proof Of Code</summary> ```javascript // SPDX-License-Identifier: MIT pragma solidity 0.8.24; import { MerkleAirdrop, IERC20 } from "../src/MerkleAirdrop.sol"; import { Test, console2 } from "forge-std/Test.sol"; contract MerkleAirdropTest is Test { MerkleAirdrop public s_airdrop; uint256 s_amountToCollect = (25 * 1e6); // 25.000000 address s_collectorOne = 0x20F41376c713072937eb02Be70ee1eD0D639966C; bytes32 s_proofOne = 0x32cee63464b09930b5c3f59f955c86694a4c640a03aa57e6f743d8a3ca5c8838; bytes32 s_proofTwo = 0x8ff683185668cbe035a18fccec4080d7a0331bb1bbc532324f40501de5e8ea5c; bytes32[] s_proof = [s_proofOne, s_proofTwo]; address public deployer; // From Deploy.t.sol bytes32 public s_merkleRoot = 0x3b2e22da63ae414086bec9c9da6b685f790c6fab200c7918f2879f08793d77bd; address public s_zkSyncUSDC = 0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4; uint256 public s_amountToAirdrop = 4 * (25 * 1e6); function setUp() public { deployer = makeAddr("deployer"); deal(0x1D17CbCf0D6d143135be902365d2e5E2a16538d4, deployer, 100 * 1e6); vm.deal(s_collectorOne, 100 ether); } function testDeployOnZkSync() public { if (block.chainid != 324) { return; } vm.startPrank(deployer); // From here there is the code from run() s_airdrop = deployMerkleDropper(s_merkleRoot, IERC20(s_zkSyncUSDC)); // Send USDC -> Merkle Air Dropper IERC20(0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4).transfer(address(s_airdrop), s_amountToAirdrop); // end code from run vm.stopPrank(); vm.startPrank(s_collectorOne); s_airdrop.claim{ value: s_airdrop.getFee() }(s_collectorOne, s_amountToCollect, s_proof); vm.stopPrank(); } function deployMerkleDropper(bytes32 merkleRoot, IERC20 zkSyncUSDC) public returns (MerkleAirdrop) { return (new MerkleAirdrop(merkleRoot, zkSyncUSDC)); } } ``` </details> ## Recommendations To resolve the issue, update the s_zkSyncUSDC address in Deploy.s.sol to the correct value: ```diff - address public s_zkSyncUSDC = 0x1D17CbCf0D6d143135be902365d2e5E2a16538d4; + address public s_zkSyncUSDC = 0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4; ```
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.