# Unlock remainder carryover accounting bug

Accumulator fields (remainder, leftover time) not reset or carried correctly across lock/unlock or period boundaries

_Area: DeFi accounting and math bugs. Seen in 2 disclosed reports; latest 2026-03-07. Updated 2026-10-23._

## How it works
A value that should be consumed or reset at the end of a cycle is instead left in storage and re-added to the next cycle. The assumption that breaks: that a paired quantity field and its accumulator move together. When one is decremented (quantity) and the other (remainder) is not, the leftover is counted twice — once in the past cycle and again in the next. The same root cause appears in time math: a leftover period is dropped or a mutable period retroactively rescales past epochs.

## Where it shows up
- Struct fields like `remainder`, `remainingPeriod`, `leftover` that persist across calls while a sibling field is reset.
- `unlock()`/`release()` paths that decrement quantity but never zero the accumulator.
- Smoothing/vesting branches computing `period - timeElapsed` without adding the prior nonzero remainder.
- Timestamps derived as `genesis + counter * mutable_period` where period is admin-settable.
- Any `_lock()` that adds a stored remainder back into the new quantity.

## How to review
The invariant: after any state transition that ends a cycle, the accumulator must be either fully consumed or explicitly carried into the next cycle — never silently retained and re-added. Check every decrement of a paired quantity for a matching reset of its accumulator. For time math, verify that when `timeElapsed` crosses a boundary, overflow is added to the fresh period, and that changing a period only affects future epochs, not past ones. Test multi-cycle sequences where the remainder is nonzero and smaller than the new elapsed time.

## Variants seen
- NFT minting counts stale remainder toward next lock, minting extra NFTs [E1](https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AM-03.md).
- Yield smoothing drops leftover time when `remainingPeriod < timeElapsed`, skewing the denominator [E2](https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.2.1.md).
- Mutable `fundingDuration` retroactively shifts all epoch boundaries by `pointer*delta`, causing time travel and skipped epochs [E3](https://bugbountylibrary.com/r/c4%3A2023-08-dopex%3AM-10.md).

## Impact and severity
Over-minting of NFTs beyond tokens locked [E1](https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AM-03.md), uneven yield distribution [E2](https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.2.1.md), and overpriced premiums from skipped epochs [E3](https://bugbountylibrary.com/r/c4%3A2023-08-dopex%3AM-10.md). Severity rises when the accumulator feeds a mint or payout directly, and when admin-mutable periods amplify drift across all historical epochs.

## Why fixes fail
No fix evidence provided; the recurring failure mode is resetting one field while leaving its accumulator, or patching the current cycle without auditing multi-cycle carryover.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AM-03.md
- E2: https://bugbountylibrary.com/r/cantina%3Avii_finance_jan2026%3A3.2.1.md
- E3: https://bugbountylibrary.com/r/c4%3A2023-08-dopex%3AM-10.md
