代理投票
需求
实现一个带有代理功能的投票智能合约。
思路
- 定义投票者 Voter 的结构体,定义提案 Proposal 的结构体。
- Voter 可以对 Proposal 进行投票,同时 VoterA 可以把自己的代理权给 VoterB,但是必须可以追踪到。例如 A->B->C ,从 C 的投票权追溯到 A。
- 要有一个投票管理者 Chairman。
投票流程
- 有一系列 Proposal,用数组 Proposals 来存储。
- 同时也有 Voters 数组,来存储 Voter
- 每个 Voter 可以自己投票,也可以让别人帮自己投票(代理)
- 最后统计当前最高票的提案
pragma solidity ^0.8.0;
contract Ballot{
struct Voter{
uint weight;
bool voted;
address delegate;
uint vote;
}
struct Proposal{
bytes32 name;
uint voteCount;
}
address public chairman;
mapping(address => Voter) public voters;
Proposal [] public proposals;
function Ballot(bytes32[] proposalNames) public{
chairperson = msg.sender;
voters[chairperson].weight = 1;
// Create Proposals
for(uint i = 0; i < proposalNames.length; i++)
{
proposals.push(Proposal({
name: proposalNames[i],
voteCount:0
}));
}
}
function giveRight2Vote(address voter) public{
require(
msg.sender == chairman;
"Only chairman can give right to vore."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
function delegate(address to) public{
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while(voters[to].delegate != address(0))
{
to = voters[to].delegate;
require(to != msg.sender, "Found loop in delegation.");
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if(delegate_.voted){
proposal[delegate_.vote].voteCOunt += sender.weight;
} else {
delegate_.weight += sender.weight;
}
}
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// 如果proposals的数组越界,会自动失败,并且还原变化
proposals[proposal].voteCount += sender.weight;
}
function winningProposal() public view
returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}