Using vanilla ERC20 tokens or NFTs as tickets to calculate voting weight is not safe, because an attacker can vote with one address, transfer tokens to another address, and vote again from that address.
for example:
```
contract UnsafeBallot {
uint256 public proposal1VoteCount;
uint256 public proposal2VoteCount;
IERC20 immutable private governanceToken;
constructor(IERC20 _governanceToken) {
governanceToken = _governanceToken;
}
function voteFor1() external notAlreadyVoted {
proposal1VoteCount += governanceToken.balanceOf(msg.sender);
}
function voteFor2() external notAlreadyVoted {
proposal2VoteCount += governanceToken.balanceOf(msg.sender);
}
// prevent the same address from voting twice,
// however the attacker can simply
// transfer to a new address
modifier notAlreadyVoted {
require(!alreadyVoted[msg.sender], "already voted");
_;
alreadyVoted[msg.sender] = true;
}
}
```
To prevent this attack, ERC20 Snapshot or ERC20 Votes should be used. By taking a snapshot of a point in time in the past, current token balances cannot be manipulated to gain illegal voting rights.