# The time available for a canceled withdrawal should not impact future unstaking processes

Canceled StRSR withdrawal drafts still set lastAvailableAt, so after unstakingDelay is lowered, new unstakes stay locked to the old longer delay.

- Payout: Audit contest
- Severity: medium
- Program: Reserve
- Found by: ether_sky
- Disclosed: 2024-10-03
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2024-07-reserve#m-06
- Library page: https://bugbountylibrary.com/r/c4%3A2024-07-reserve%3AM-06
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:incomplete-fix technique:source-review vuln:business-logic vuln:dos

**Target:** StRSR.sol staking/unstaking queue (pushDraft, cancelUnstake)
**Root cause:** cancelUnstake only advances firstRemainingDraft without removing the queue entry, and pushDraft reads queue[index-1].availableAt unconditionally, so a canceled draft's old availableAt still caps new drafts.
**Steps:**
1. Set unstakingDelay=1 day; addr1 stakes 100e18 RSR and calls `unstake(amount)` -> draft index 0, availableAt=T+1day.
2. addr1 calls `cancelUnstake(1)`; firstRemainingDraft advances but queue still holds the draft.
3. Owner calls `setUnstakingDelay(3600)` (1 hour).
4. addr2 unstakes -> availableAt=T+1hour (fresh queue).
5. addr1 unstakes again -> index=1, lastAvailableAt=T+1day from canceled draft, so availableAt=T+1day instead of T+1hour.
**How found:** Code reading of pushDraft/cancelUnstake: noticed cancel only bumps firstRemainingDraft rather than deleting the queue entry, then reasoned the stale availableAt would still be read by pushDraft after a delay change.
**Exploitation:** No attacker profit; a staker who cancels and re-unstakes after the owner lowers unstakingDelay remains locked for the original longer delay, causing fund lockup/DoS for all affected stakers.
**Escalation:** Impact scales with gap between old and new delay (e.g. 1 year -> 1 month), locking all stakers' funds for the old period.
**Insight:** When a cancel/refund only advances a pointer instead of removing queue state, check every later read of that stale entry (here availableAt) for lingering effects on new entries.
