# Inflated GaugeV3 rewards when period is skipped

Ramses GaugeV3 overcounts seconds-per-liquidity when a period is skipped, letting an attacker inflate and claim double their period rewards at other LPs' expense.

- Payout: Audit contest
- Severity: medium
- Program: Ramses Exchange
- Found by: rileyholterhus
- Disclosed: 2024-12-03
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2024-10-ramses-exchange#m-01
- Library page: https://bugbountylibrary.com/r/c4%3A2024-10-ramses-exchange%3AM-01
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** GaugeV3 / RamsesV3Pool periodCumulativesInside reward accounting
**Root cause:** endSecondsPerLiquidityPeriodX128 is set to the seconds-per-liquidity at the start of the next period rather than the end of the current period; if a period is skipped, _advancePeriod extrapolates one extra week, inflating the past-period cumulative used in periodCumulativesInside.
**Steps:**
1. Mint two equal 100-liquidity positions in range [-10,10] for wallet and attacker at start of period p.
2. Call `clGauge.notifyRewardAmount(usdc, 10e18)` to fund period p rewards.
3. Advance time to period p+1; both positions show ~50% earned.
4. Call `clGauge.cachePeriodEarned(p, usdc, wallet, 0, -10, 10, true)` to lock wallet's ~50% share.
5. Advance time to period p+2 with no pool activity, then call `clPool._advancePeriod()`.
6. Query `clGauge.periodEarned(p, usdc, attacker, ...)` — now ~100% instead of 50%.
7. Call `clGauge.getPeriodReward(p, [usdc], attacker, 0, -10, 10, attacker)` to drain full reward; wallet's claim reverts with ERC20InsufficientBalance.
**How found:** Code-reading of periodCumulativesInside's past-period branch relying on endSecondsPerLiquidityPeriodX128, then tracing _advancePeriod/newPeriod to see the value is actually the start of the next period, implying a skipped period adds a full extra week.
**Exploitation:** Attacker deploys/identifies an obsolete pool, provides dust liquidity in the active tick as sole in-range LP, calls permissionless notifyRewardAmount at the last second of a period (self-transfer, no cost), then waits for a skipped period so _advancePeriod over-extrapolates endSecondsPerLiquidityPeriodX128, inflating their cached period share to 100% and draining rewards that would otherwise belong to other LPs or remain unclaimed.
**Escalation:** Repeated skipped periods compound the inflation; targeting obsolete pools with stale out-of-range liquidity lets attacker steal unclaimed past rewards.
**Insight:** When a cumulative snapshot is named 'end of period' but is written at the start of the next period, any gap between periods silently inflates it — audit time-indexed accumulators for off-by-one-period semantics, especially where a public advance function can be triggered after inactivity.

