# Attacker can prevent vesting for a very long time

RToken issuance queue's allVestAt is never reduced on cancel, so an attacker can issue large amounts and cancel repeatedly to push vesting far into the future, griefing all issuers for gas only.

- Payout: Contest reward
- Severity: medium
- Program: Reserve
- Credited: immeas
- Disclosed: 2023-04-27
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-01-reserve-findings/issues/267
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-reserve%3AM-13
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** RToken issuance/vesting queue (RToken.sol whenFinished/cancel)
**Root cause:** cancel() returns deposited tokens but does not decrease the allVestAt state variable, so subsequent issuances are still scheduled after the inflated vesting block.
**Steps:**
1. Obtain large amount of collateral tokens (flash loan or rich account) and approve RToken contract.
2. Call `issue(addr2, issueAmount)` with a large amtRToken to push `allVestAt` far into the future via `whenFinished`.
3. Call `cancel(1, true)` to reclaim deposited tokens; `allVestAt` remains inflated.
4. Repeat issue/cancel loop (PoC does 100 iterations) to push `allVestAt` arbitrarily high.
5. Observe that a legitimate small `issue(instantIssue)` that should be immediate is now queued instead of instant.
**How found:** Code reading of whenFinished/allVestAt and cancel: noticed cancel returns tokens but never decrements allVestAt, so the griefing state persists across cancellations.
**Exploitation:** Attacker flash-loans or holds collateral, issues a huge RToken amount to inflate allVestAt, then cancels to recover collateral. Repeating costs only gas and pushes allVestAt to a huge block number, forcing every subsequent issuance into the queue and delaying vesting for a very long time.
**Insight:** When a queue/vesting schedule uses a global monotonic timestamp updated on enqueue, check whether the corresponding cancel/rollback path decrements it; if not, enqueue+cancel becomes a cheap griefing primitive.
