# update_market() nextEpoch calculation incorrect

update_market() computed nextEpoch as i+BLOCK_EPOCH instead of epoch+BLOCK_EPOCH, over-crediting accCantoPerShare when reward epochs cross boundaries.

- Payout: Contest reward
- Severity: high
- Program: Canto
- Credited: bin2chen
- Disclosed: 2024-02-07
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2024-01-canto-findings/issues/9
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-canto%3AH-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:business-logic vuln:reward-distribution

**Target:** LendingLedger.update_market() reward accounting
**Root cause:** nextEpoch is derived from the loop cursor i rather than the aligned epoch start, so blockDelta spans into the next epoch while still using the current epoch's cantoPerBlock rate.
**Steps:**
1. Set cantoPerBlock[fromEpoch]=amountPerBlock, later epochs 0.
2. vm.roll to fromEpoch+BLOCK_EPOCH-10 and call `ledger.update_market(lendingMarket)`.
3. vm.roll past boundary to fromEpoch+BLOCK_EPOCH+10 and call `update_market` again.
4. Observe accCantoPerShare exceeds amountPerEpoch by ~100000000000000 due to `nextEpoch = i + BLOCK_EPOCH`.
**How found:** Reasoned about epoch-boundary math: when lastRewardBlock sits just before a boundary, the loop should split delta at epoch+BLOCK_EPOCH, but code used i+BLOCK_EPOCH, applying the old epoch's rate across the whole span.
**Insight:** In reward-accrual loops that segment by epoch, verify the segment endpoint is derived from the aligned epoch start, not the moving cursor; test with a rate change at the boundary.
