# Improper parallel time system

LendingLedger estimates epoch time from block number and average block time; overestimation yields a future timestamp, making GaugeController return zero relative weight and nullifying up to a week of rewards.

- Payout: Contest reward
- Severity: medium
- Program: Canto
- Credited: 0xsomeone
- Disclosed: 2024-04-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-neobase-findings/issues/10
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-neobase%3AM-06
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:oracle-manipulation vuln:reward-distribution

**Target:** LendingLedger::update_market / GaugeController reward accounting
**Root cause:** LendingLedger derives epochTime from referenceBlockTime + (block.number - referenceBlockNumber) * averageBlockTime, an imprecise approximation of elapsed time. When this overestimates and lands in a future week, GaugeController::_gauge_relative_weight returns 0 because that week's total weight is not yet tracked.
**Steps:**
1. Note LendingLedger uses reward-per-block while VotingEscrow/GaugeController use time-based accounting.
2. Observe update_market computes epochTime via referenceBlockTime, referenceBlockNumber, averageBlockTime.
3. When actual block times are faster than averageBlockTime, computed epochTime exceeds block.timestamp and can fall into the next WEEK.
4. Call `IGaugeController::gauge_relative_weight_write(gauge, epochTime)` with that future timestamp.
5. _get_weight/_get_total only update up to block.timestamp, so the future week's points_total is 0 and _gauge_relative_weight returns 0.
6. Rewards for that epoch are recorded as 0, losing up to 1 week of rewards.
**How found:** Code reading of the parallel time systems: noticed LendingLedger uses per-block rewards while GaugeController is time-based, traced the epochTime approximation in update_market, and reasoned that any overestimation pushes the query into a future week where GaugeController returns zero.
**Escalation:** If administrative re-adjustment is excluded, secRewardDebt becomes corrupted: accCantoPerShare increments by 0 while secRewardsPerShare increments non-zero, raising severity toward High.
**Insight:** When a contract converts block numbers to timestamps via an average block time, treat the result as unbounded in both directions; check downstream consumers that assume the timestamp is <= block.timestamp (e.g. weekly epoch lookups returning zero for untracked future weeks).
