# LinearDistributor.declareReward: previouslyVested may update incorrectly, which will cause some rewards to be lost

LinearDistributor.declareReward caps distributed at balance but sets previouslyVested to currentlyVested, permanently skipping unvested rewards and inflating forfeits.

- Payout: Contest reward
- Severity: medium
- Program: Malt Protocol
- Credited: cccz
- Disclosed: 2023-05-01
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-02-malt-findings/issues/6
- Library page: https://bugbountylibrary.com/r/c4%3A2023-02-malt%3AM-15
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity vuln:accounting-error vuln:reward-distribution

**Target:** LinearDistributor reward vesting contract
**Root cause:** When distributed is capped to balance, previouslyVested is still set to currentlyVested rather than the amount actually distributed, so the shortfall is never paid out in later distributions.
**Steps:**
1. Call `declareReward()` when `linearBondedValue * netVest / vestingBondedValue` exceeds `collateralToken.balanceOf(address(this))`.
2. Observe `distributed` is clamped to `balance`.
3. Observe `previouslyVested = currentlyVested` skips the undistributed remainder.
4. Next call computes smaller `netVest`, so lost rewards are never distributed; smaller `distributed` also lowers `bufferRequirement`, causing more `_forfeit`.
**How found:** Code reading of declareReward: noticed the balance clamp on distributed but unconditional assignment of previouslyVested to currentlyVested, meaning the clamped remainder is dropped.
**Insight:** When a payout is clamped by available balance, check whether the vesting/accounting cursor is advanced by the requested amount or the actually-paid amount; mismatches silently burn user rewards and can cascade into forfeiture logic.
