# _newrewards does not take endrewardtime into account, which may lead to incorrect alloca- tion of rewards

_newRewards uses block.timestamp instead of capped endRewardTime, so pools accrue rewards past emission end, misallocating rewards between pools.

- Payout: Contest reward
- Severity: medium
- Program: Zerolend
- Credited: cccz
- Disclosed: 2024-09-16
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_zerolend_jan2024.pdf#3.2.6
- Library page: https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.2.6
- Tags: domain:web3 impact:integrity kind:contest platform:cantina sev:medium tech:evm tech:solidity vuln:business-logic vuln:reward-distribution

**Target:** Solidity staking/incentive reward distributor (_updatePool/_newRewards)
**Root cause:** _updatePool caps its local timestamp at endRewardTime() before calling _newRewards, but _newRewards recomputes duration from block.timestamp, so it counts time beyond the emission end.
**Steps:**
1. Set PoolA allocPoint=100, totalAllocPoint=100, rewardsPerSecond=20, availableRewards=3000, endRewardTime=t150, updateCadence=200.
2. At t150 owner calls registerRewardDeposit making availableRewards=4000; since elapsed < updateCadence, endRewardTime stays t150; _massUpdatePools sets poolA.lastRewardTime=t150, accountedRewards=3000.
3. Call _updatePool at t190: _newRewards computes duration = 190-150 = 40, rawReward = 40*20 = 800, capped by availableRewards=1000, newReward=800.
4. PoolA is credited 800 despite endRewardTime=t150, over-distributing rewards relative to other pools.
**How found:** Code reading: noticed _updatePool caps timestamp at endRewardTime but _newRewards independently uses block.timestamp, creating a mismatch when endRewardTime is stale (within updateCadence).
**Insight:** When a caller caps a timestamp before delegating, verify the callee doesn't recompute time from block.timestamp itself; stale cached end-time getters with update cadence are a classic source of accounting drift.
