# Owner's delegates should be decreased in _burn()

VotingEscrow._burn() never removes tokenId from delegate arrays, so an attacker depositing 1 wei MAX_DELEGATES times permanently blocks a victim from depositing.

- Payout: Contest reward
- Severity: medium
- Program: Velodrome Finance
- Credited: WatchPug
- Disclosed: 2022-08-08
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-05-velodrome-findings/issues/153
- Library page: https://bugbountylibrary.com/r/c4%3A2022-05-velodrome%3AM-09
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** VotingEscrow.sol _burn / _moveTokenDelegates
**Root cause:** _burn() clears approval and removes the token but never calls _moveTokenDelegates to remove the tokenId from the owner's delegate array, so dstRep only grows.
**Steps:**
1. Attacker calls deposit_for(victim, 1 wei) repeatedly, each creating a new tokenId delegated to victim
2. Each deposit appends to victim's dstRep via _moveTokenDelegates
3. Repeat MAX_DELEGATES times until dstRep.length == MAX_DELEGATES
4. Victim's subsequent deposits revert on `dstRepOld.length + 1 <= MAX_DELEGATES`
5. Victim cannot recover by merging or burning since _burn does not shrink dstRep
**How found:** Code review of _burn() noting the `// TODO add delegates` comment and absence of _moveTokenDelegates, then tracing the MAX_DELEGATES require in _moveTokenDelegates to see the array only grows.
**Exploitation:** Griefing: attacker spends dust (1 wei per deposit) to fill victim's delegate array to the MAX_DELEGATES cap, permanently blocking the victim from depositing/merging/burning to escape.
**Insight:** When a contract caps a per-user array (MAX_DELEGATES), audit every path that adds to it AND every path that should remove from it—burn/transfer/merge—for asymmetric cleanup enabling cheap griefing.
