AirDropper

AI First Flight #5
Beginner FriendlyDeFiFoundry
EXP
View results
Submission Details
Severity: high
Valid

Incorrect USDC Address will lead to zero USDC Airdrop for Users

Incorrect USDC address being used in Deploy.s.sol will basically result in zero airdrop to users

Description

  • Normal behaviour: The code in Deploy.s.sol will be used to deploy the MerkleAirDrop contract to zkSync blockchain as well as fund it with USDC in order to have USDC to airdrop to the selected users

  • Issue: During the deployment of the MerkleAirDrop.solsome parameters are required to be passed in the constructor and they are : the merkle root which is going to be of type bytes32 and the airdroptoken which is going to be usdc as IERC20(usdcAddress). However, it is critical to be cautious with the values being passed during deployment since one wrong character is going to be crucial. And in this case the usdc address on zkSync is not the correct one.

@> address public s_zkSyncUSDC = 0x1D17CbCf0D6d143135be902365d2e5E2a16538d4; // @audit H-1 this is not USDC

Risk

Likelihood:

  • Likelihood: High. This occurs during normal system operation. Whenever a valid recipient attempts to claim their airdrop via MerkleAirDrop.sol::claim(), the function calls i_airdropToken.safeTransfer(account, amount). If the configured airdrop token is the incorrect USDC address, this transfer will fail or either succeed but definetly not transfering USDC tokens.


Impact:

  • Impact: High. Legitimate users won't receive the usdc airdrop.


Proof of Concept

  1. Deployer runs the deploy script

  2. Valid claimer interacts with the smart contract by providing his address, the amount he should receive and the merkle proof

  3. Transaction reverts since at address 0x1D17CbCf0D6d143135be902365d2e5E2a16538d4 there is not a deployed ERC20 contract on zkSync Era.

Recommended Mitigation

Use the real USDC address on zkSync Era - 0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4. As we can see in the one used in the deploy script it has some of the letters lowercase or uppercase instead the opposite.

- address public s_zkSyncUSDC = 0x1D17CbCf0D6d143135be902365d2e5E2a16538d4; // @audit H-1 this is not USDC
+ address public s_zkSyncUSDC = 0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours ago
Submission Judgement Published
Validated
Assigned finding tags:

[H-01] Address of USDC token in `Deploy.s.sol` is wrong causing the claiming process to fail

## 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; ```

Support

FAQs

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

Give us feedback!