使用vanilla ERC20代币或NFT作为门票来计算投票权重是不安全的,因为攻击者可以用一个地址投票,将代币转账到另一个地址,并从该地址再次投票。
举个例子:
```
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;
}
}
```
为了防止这种攻击,应该使用ERC20 Snapshot或ERC20 Votes。通过对过去的一个时间点进行快照,当前的代币余额不能被操纵以获得非法投票权。