# Users can fully drain the `TrufVesting` contract

TrufVesting.claimable returns full initialRelease during cliff window ignoring already-claimed amount, letting any user repeatedly claim and drain the contract.

- Payout: Contest reward
- Severity: high
- Program: Truflation
- Credited: 0xLogos
- Disclosed: 2023-12-22
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-12-truflation-judging/issues/1
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-truflation%3AH-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** TrufVesting.sol vesting claim logic
**Root cause:** claimable() returns initialRelease whenever block.timestamp is before startTime+cliff, without subtracting userVesting.claimed, so the initial release is re-claimable every call during the cliff window.
**Steps:**
1. Deploy/setup vesting plan with initialReleasePeriod=10 days, cliff=20 days, initialReleasePct=5%.
2. setUserVesting(categoryId, vestingId, alice, 0, 10e18).
3. vm.warp(block.timestamp + 11 days) to land between initialReleasePeriod and cliff.
4. As alice call `vesting.claim(alice, categoryId, vestingId, type(uint256).max)` -> receives 5% (0.5e18).
5. Loop claim 39 more times; each returns initialRelease again.
6. Alice balance reaches 2x stakeAmount (20e18) and can continue until contract drained.
**How found:** Code review of claimable() state machine: noticed stage 2 (between initialReleasePeriod and cliff) returns initialRelease unconditionally, then checked claim() only compares claimAmount to claimableAmount and never subtracts claimed, revealing repeat-claim.
**Exploitation:** Any user with a vesting position calls claim repeatedly during the cliff window; claimable() keeps returning initialRelease because claimed is never deducted, so each call transfers another initialRelease of TRUF tokens until the contract balance is exhausted.
**Insight:** When auditing vesting/streaming contracts, verify claimable() is a pure function of remaining entitlement (total minus claimed), not just a time-based schedule; any branch returning a fixed amount without subtracting claimed is a repeat-claim drain.
