# addpool doesn't always call _massupdatepools, which can lead to incorrect reward allocation

addPool increases totalAllocPoint without calling _massUpdatePools, retroactively diluting existing pools' accrued rewards by up to 33% in the example.

- 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.7
- Library page: https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.2.7
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:medium tech:solidity technique:source-review vuln:business-logic vuln:precision-loss vuln:reward-distribution

**Target:** Staking/reward incentive contract addPool function
**Root cause:** addPool mutates totalAllocPoint before accruing pending rewards; _updateEmissions only calls _massUpdatePools after endRewardTime, so existing pools' unaccrued rewards are recomputed against the larger denominator.
**Steps:**
1. Observe addPool sets totalAllocPoint += _allocPoint and only calls _updateEmissions()
2. Note _updateEmissions calls _massUpdatePools only when block.timestamp > endRewardTime()
3. Setup: PoolA allocPoint=100, totalAllocPoint=100, rewardsPerSecond=20, endRewardTime=t200
4. At t150 PoolA accrued 20*150*100/100=3000
5. Owner calls addPool(PoolB, 50) before endRewardTime; no mass update runs
6. PoolA rewards recompute as 20*150*100/150=2000, losing 1000
**How found:** Code reading of addPool vs _newRewards: noticed totalAllocPoint is a divisor in reward math and that accrual is skipped on the non-expired path of _updateEmissions.
**Exploitation:** Not attacker-triggered; requires privileged poolConfigurator to add a pool mid-emission, silently reducing already-earned rewards of existing stakers.
**Insight:** When a global denominator (totalAllocPoint, totalShares, totalStaked) is mutated, check every path that changes it for a missing accrue-before-mutate call; the expiry-gated mass-update branch is a classic place for this gap.
