# User can get unlimited votes

ERC721Votes._afterTokenTransfer moves votes between token owner addresses instead of delegates, letting an attacker underflow _moveDelegateVotes unchecked and mint max voting power.

- Payout: Contest reward
- Severity: high
- Program: Nouns Builder
- Credited: saian
- Disclosed: 2022-11-03
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-09-nouns-builder-findings/issues/469
- Library page: https://bugbountylibrary.com/r/c4%3A2022-09-nouns-builder%3AH-01
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:governance

**Target:** ERC721Votes token voting/delegation contract
**Root cause:** _afterTokenTransfer calls _moveDelegateVotes(_from, _to, 1) using token owner addresses rather than their delegates, and _moveDelegateVotes subtracts balanceOf(_from) inside an unchecked block, so mismatched delegate balances underflow.
**Steps:**
1. Bidder1 wins token 2, holds 1 vote, delegates to bidder2 (bidder2 gets 1 vote).
2. Bidder1 wins token 3; balanceOf(bidder1)=2, getVotes(bidder1)=2, getVotes(bidder2)=1.
3. Bidder1 calls `token.delegate(bidder1)`; delegation moves balanceOf(bidder1)=2 votes from bidder2, whose balance is 1, underflowing unchecked subtraction.
4. getVotes(bidder1) becomes 4 and getVotes(bidder2) becomes 2^192-1 (max uint underflow).
**How found:** Code review of ERC721Votes delegation logic: noticed _afterTokenTransfer passes owner addresses instead of delegates(_from)/delegates(_to), and that _moveDelegateVotes uses unchecked arithmetic on balanceOf(_from), suggesting an underflow when delegate balances diverge from token balances.
**Exploitation:** Attacker acquires one token, delegates to a second address, acquires more tokens, then re-delegates to self; the unchecked subtraction in _moveDelegateVotes underflows the prior delegate's checkpoint to near-max uint, granting effectively unlimited voting power across accounts.
**Escalation:** Repeatable across multiple accounts to accumulate maximum voting power for governance attacks.
**Insight:** When a token contract tracks delegated votes, verify transfers move votes between the actual delegates, not owner addresses; and audit unchecked blocks for subtraction of balances that can diverge from the tracked checkpoint.
