Skip to content

Instantly share code, notes, and snippets.

@KittenYang
Created May 9, 2022 07:54
Show Gist options
  • Save KittenYang/3acea90ba7f4ebf74e49ed7a6f44cc31 to your computer and use it in GitHub Desktop.
Save KittenYang/3acea90ba7f4ebf74e49ed7a6f44cc31 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=undefined&optimize=false&runs=200&gist=
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/// @title 委托投票项目
///为每个选项提供简称, 然后作为合约的创造者——即主席,将给予每个独立的地址以投票权。
///地址后面的人可以选择自己投票,或者委托给他们信任的人来投票。
///在投票时间结束时,winningProposal() 将返回获得最多投票的提案。
contract Ballot {
struct Voter {
address selfAddr;
address delegate;
uint weight;
bool voted;
uint propocalIndex; // 投票提案的索引
}
struct Proposal {
uint voteCount; //票数
string name; //提案名字(最长32个字节)
}
// 创始人
Voter public firstMan;
// 所有提案数组
Proposal[] public proposals;
// 所有地址对应的投票者
mapping(address => Voter) public voters;
//初始化方法,入参:所有提案的名字
constructor(string[] memory allAvaliableProposalNames) {
firstMan = Voter({selfAddr: msg.sender, delegate:address(0), weight: 1, voted: false, propocalIndex:0});
voters[firstMan.selfAddr]=firstMan;
for (uint i = 0; i < allAvaliableProposalNames.length; i++) {
Proposal memory temp = Proposal({name: allAvaliableProposalNames[i], voteCount:0});
proposals.push(temp);
}
}
// 授权 `voter` 对这个(投票)表决进行投票;只有创始人可以指定谁有权限
function getRightToVoter(address voterAddress) public {
require(msg.sender == firstMan.selfAddr, "only first man can decide who have rights");
require(!voters[voterAddress].voted, "Already voted");
require(voters[voterAddress].weight==0);
voters[voterAddress]=Voter({selfAddr: voterAddress, delegate:address(0), weight: 1, voted: false, propocalIndex:0});
// voters[voterAddress].weight = 1;
}
/// 把你的投票委托到投票者 `to`
/// 若委托者也设置了委托,需要传递,不能超过5个(太长了,可能超过 gas limit)
/// 不能存在闭环
/// 若最后的被委托者已经投过票了,直接给提案加票;如果还没,加权重。
function setDelegateTo(address to) public {
// 投过不能再设置代理了,会导致权重重复增加
require(!voters[msg.sender].voted, "You are already voted");
address delegate = voters[to].delegate;
while (delegate != address(0)) {
delegate = voters[delegate].delegate;
require(msg.sender!=delegate,"can not have circle");
}
voters[msg.sender].delegate = delegate;
voters[msg.sender].voted = true;
if (voters[delegate].voted) {
proposals[voters[delegate].propocalIndex].voteCount ++;
} else {
voters[delegate].weight ++;
}
}
/// 把你的票(包括委托给你的票),投给提案,入参:提案索引uint
function voteToProposal(uint proposalIndex) public {
// 修改信息
Voter storage vter = voters[msg.sender];
require(!vter.voted,"already voted");
vter.voted = true;
vter.propocalIndex = proposalIndex;
// 找出对应的地址对应的 vote,因此全局需要一个映射表
proposals[proposalIndex].voteCount += vter.weight;
}
/// @dev 结合之前所有的投票,计算出最终胜出的提案
function winningProposal() public view returns (uint) {
uint maxIndex = 0;
uint _nowMax = 0;
for (uint index = 0; index<proposals.length; index++) {
uint _temp = proposals[index].voteCount;
if (_temp > _nowMax) {
_nowMax = _temp;
maxIndex = index;
}
}
return maxIndex;
}
// 调用 winningProposal() 函数以获取提案数组中获胜者的索引,并以此返回获胜者的名称
function winPropocalName() external view returns (string memory) {
uint index = winningProposal();
return proposals[index].name;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment