# TrufVesting.cancelVesting calculates end of vesting incorrectly

TrufVesting.cancelVesting computed vesting end using only the post-cliff period, omitting initialReleasePeriod and cliff, so owner could not cancel ongoing vesting.

- Payout: Contest reward
- Severity: medium
- Program: Truflation
- Credited: UbiquitousComputing
- Disclosed: 2023-12-22
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-12-truflation-judging/issues/11
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-truflation%3AM-1
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:evm tech:solidity vuln:accounting-error vuln:business-logic

**Target:** TrufVesting.sol vesting contract
**Root cause:** cancelVesting's 'already vested' check uses only startTime + period, ignoring initialReleasePeriod and cliff, so it treats vesting as finished before the actual end.
**Steps:**
1. Read claimable(): distribution starts at startTime, initialRelease after initialReleasePeriod, final distribution after cliff, ending at startTime+initialReleasePeriod+cliff+period.
2. Read cancelVesting revert check: startTime + period <= block.timestamp.
3. Call cancelVesting during an ongoing vesting where startTime+period has passed but startTime+initialReleasePeriod+cliff+period has not; it reverts AlreadyVested.
4. Owner cannot stop vesting for that account.
**How found:** Code reading: compared the end-of-vesting formula in claimable() (startTime + initialReleasePeriod + cliff + period) against the simpler check in cancelVesting (startTime + period), spotting the mismatch.
**Insight:** When a contract has a claimable/schedule function and an admin cancel function, diff their end-time formulas; cancel checks often omit cliff or initial-release offsets, blocking legitimate admin actions.
