# Services can earn undeserved rewards by manipulating checkpoint timing during reward droughts

StakingBase skips checkpoints when rewards are zero, so inactive services can stay idle during droughts and transact only when rewards return, earning undeserved payouts.

- Payout: Contest reward
- Severity: medium
- Program: Olas
- Credited: Takarez
- Disclosed: 2026-05-18
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2026-01-olas#m-10
- Library page: https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-10
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** StakingBase.sol staking reward checkpoint contract
**Root cause:** Checkpoint logic is gated on lastAvailableRewards > 0, so tsCheckpoint is not advanced during reward droughts; activity ratio is later computed over the entire unmeasured gap, diluting required liveness.
**Steps:**
1. Deploy staking with livenessPeriod and livenessRatio; service registered and staked.
2. Drain availableRewards to 0 so `block.timestamp - tsCheckpointLast >= livenessPeriod && lastAvailableRewards > 0` is false and tsCheckpoint stays stale.
3. Service performs no transactions during the drought.
4. Rewards refill; service submits a single transaction batch before next checkpoint.
5. `_checkRatioPass` computes ratio = (curNonces-lastNonces)*1e18 / (block.timestamp - staleCheckpoint), passing livenessRatio over the long gap.
6. Service claims rewards for the inactive period.
**How found:** Code reading of the checkpoint guard revealed that tsCheckpoint is only updated when rewards exist, and tracing the activity ratio computation showed it uses the stale timestamp, creating an unmeasured gap.
**Exploitation:** Service operator waits out reward drought without activity, then executes minimal nonce-increasing transactions right before rewards resume, so the averaged liveness ratio over the stale checkpoint window passes and rewards are claimed for time no service was provided.
**Insight:** When a liveness/activity ratio is averaged over a timestamp that is only advanced conditionally, look for states that freeze that timestamp (zero rewards, paused distribution) to dilute the ratio; check every early-return guard for whether it also skips accounting state updates.
