# recoverTokens doesn't work when isSale is true

recoverTokens excess calculation ignores creatorClaimSoldTokens, so after a sale the contract miscomputes excess deposit tokens, reverting or under-sending recovery.

- Payout: Audit contest
- Severity: high
- Program: Streaming Protocol
- Found by: harleythedog
- Disclosed: 2022-02-11
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-11-streaming-findings/issues/121
- Library page: https://bugbountylibrary.com/r/c4%3A2021-11-streaming%3AH-10
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error

**Target:** Locke.sol recoverTokens / creatorClaimSoldTokens
**Root cause:** creatorClaimSoldTokens transfers sold deposit tokens out but never updates depositTokenAmount or redeemedDepositTokens, so recoverTokens' excess = balanceOf - (depositTokenAmount - redeemedDepositTokens) still assumes full deposit tokens remain.
**Steps:**
1. Deploy stream with isSale true; deposit tokens held in Locke contract.
2. Stream ends; creator calls `creatorClaimSoldTokens` to withdraw sold deposit tokens (redeemedDepositTokens stays 0, depositTokenAmount unchanged).
3. Call `recoverTokens(token)`; excess computed as balanceOf - (depositTokenAmount - 0), which exceeds actual balance.
4. Recovery reverts on underflow or sends fewer tokens than the true excess.
**How found:** Code inspection of recoverTokens excess formula and cross-checking that creatorClaimSoldTokens does not mutate depositTokenAmount or redeemedDepositTokens.
**Insight:** When auditing accounting invariants, check every function that moves tokens out of the contract against the state variables used by later balance-derived calculations; a claim path that skips bookkeeping breaks downstream excess math.
