# Users will never be able to withdraw their claimed airdrop fully in ERC20Airdrop2.sol contract

ERC20Airdrop2's ongoingWithdrawals modifier blocks withdraw() once the linear unlock window ends, so users can never withdraw their fully unlocked airdrop tokens.

- Payout: Contest reward
- Severity: high
- Program: Taiko
- Credited: MrPotatoMagic
- Disclosed: 2024-04-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-taiko-findings/issues/245
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-taiko%3AH-03
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:business-logic

**Target:** ERC20Airdrop2.sol airdrop withdrawal contract
**Root cause:** The ongoingWithdrawals modifier reverts when claimEnd + withdrawalWindow < block.timestamp, so withdraw() is disabled exactly at the moment tokens become 100% unlocked; no buffer window exists.
**Steps:**
1. Deploy ERC20Airdrop2 with claimEnd and withdrawalWindow set.
2. Alice calls `claim(Alice, 100, merkleProof)` before claimEnd.
3. Warp to `claimEnd + 5 days`; call `withdraw(Alice)` — succeeds, receives ~50 tokens (linear unlock).
4. Warp to `claimEnd + 11 days` (past withdrawalWindow); call `withdraw(Alice)` — reverts with `WITHDRAWALS_NOT_ONGOING`.
5. Remaining unlocked balance is permanently stuck.
**How found:** Code review of the modifier's strict inequality against block.timestamp versus the linear unlock schedule; noticed the boundary condition coincides with full unlock, then wrote a Foundry PoC to confirm the revert.
**Exploitation:** Any user who does not withdraw at the exact final instant of the withdrawal window loses the remainder of their unlocked allocation; timing precision is impractical, so partial or zero claims leave funds locked.
**Insight:** When a time-bounded modifier gates a linearly-unlocking withdrawal, check whether the window's closing boundary coincides with the moment funds become fully vested — off-by-one/boundary conditions on `block.timestamp` comparisons can permanently strand the last tranche.
