# Malicious users can prevent holders from claiming their rewards during a reward cycle by skipping it.

Anyone can call distribute(1) with zero rewards to set LockedForDistribution, blocking withdrawFromManagedNFTs and skipping a whole reward cycle for holders.

- Payout: Contest reward
- Severity: medium
- Program: Althea Liquid Infrastructure
- Credited: Fassi\_Security
- Disclosed: 2024-04-08
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-02-althea-liquid-infrastructure-findings/issues/119
- Library page: https://bugbountylibrary.com/r/c4%3A2024-02-althea-liquid-infrastructure%3AM-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos vuln:reward-distribution

**Target:** LiquidInfrastructureERC20 reward distribution contract
**Root cause:** distribute() sets LockedForDistribution=true without requiring any rewards to be present, and withdrawFromManagedNFTs() reverts while locked, so a zero-value distribution blocks reward withdrawal for the whole MinDistributionPeriod.
**Steps:**
1. Deploy LiquidInfrastructureERC20 with MinDistributionPeriod=210000 blocks and a managed NFT holding reward tokens.
2. Advance to a block where a new distribution is allowed (block.number >= lastDistribution + MinDistributionPeriod).
3. Attacker calls `liquidERC20.distribute(1)` with no rewards withdrawn; LockedForDistribution becomes true.
4. Any call to `withdrawFromAllManagedNFTs()` now reverts with 'cannot withdraw during distribution'.
5. Owner calls `distributeToAllHolders()` and `withdrawFromAllManagedNFTs()`; next distribution is pushed to block.number + MinDistributionPeriod.
6. Holders cannot claim the accumulated rewards until the next cycle (~30 days later).
**How found:** Reading withdrawFromManagedNFTs revealed the `require(!LockedForDistribution)` guard; noting distribute() has no minimum-reward check and that MinDistributionPeriod is ~weekly/monthly with a mempool, the researcher hypothesized a zero-reward distribute() could lock out withdrawals and confirmed with a Foundry PoC.
**Exploitation:** Attacker front-runs or simply calls distribute(1) at the start of a reward cycle before anyone withdraws from managed NFTs, locking the contract and forcing the cycle to be skipped; repeated calls each cycle can indefinitely deny rewards.
**Insight:** When a state flag gates a withdrawal path, check whether the function that sets the flag enforces any meaningful precondition (e.g. nonzero rewards); a permissionless no-op call that flips the flag can grief the gated path for the entire cooldown period.
