# Multiple vote checkpoints per block will lead to incorrect vote accounting

ERC721Votes writes multiple checkpoints with identical timestamps per block, so getPastVotes binary search returns wrong vote weight, enabling governance manipulation.

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

**Target:** ERC721Votes checkpointing / Governor vote weight lookup
**Root cause:** _writeCheckpoint appends a new checkpoint per interaction without batching by block.timestamp, so multiple checkpoints share the same timestamp and the binary search in getPastVotes can land on any of them.
**Steps:**
1. Mint 1 NFT to a contract at t=0 -> checkpoint[0]=(0,1)
2. Mint another NFT at t=1 -> checkpoint[1]=(1,2)
3. Delegate 2 votes to Alice in same tx -> checkpoint[2]=(1,0)
4. Self-delegate again -> checkpoint[3]=(1,2)
5. Buy another NFT at t=2 -> checkpoint[4]=(2,3)
6. Call Governor._castVote for proposal with timeCreated=1; getPastVotes binary search hits index 2 (timestamp 1) and returns 0 instead of 2
7. Attacker can spam checkpoints to make binary search return an inflated balance instead
**How found:** Code review of _writeCheckpoint noticed no batching by timestamp; traced getPastVotes binary search and constructed a multi-interaction same-block scenario to show it returns a stale/incorrect checkpoint.
**Exploitation:** Attacker manipulates their balance within a single block to create many same-timestamp checkpoints, then votes on a proposal whose timeCreated matches that timestamp; the binary search may return an inflated vote weight, breaking quorum/execution thresholds and enabling governance takeover.
**Escalation:** Judge notes flashloan-funded balance inflation plus checkpoint spam can yield infinite voting power and full governance takeover.
**Insight:** When auditing checkpoint/timestamp voting systems, check whether multiple writes in one block are batched to the latest value; unbatched writes let an attacker spam checkpoints to steer binary search results.
