投票系统
功能梳理¶
通过智能合约实现去中心化投票
- 主持人创建投票主题与内容
- 给予“选民”在选票上投票的权利
- 把你的投票委托给投票人.
- 投票
数据结构¶
合约代码¶
定义结构体
// 构建投票人数据结构体
struct Voter{
uint256 amount; //可以投的票数
bool isVoted; //是否投过票
address delegator; // 代理人地址
uint256 targetId; // 目标ID
}
// 投票看板结构体
struct Board{
string name; // 目标名字
uint256 totalAmount; // 票数
}
// 主持人信息
address public host;
// 投票人集合
mapping (address=>Voter) public voters;
// 主题集合
Board [] public board;
数据初始化
// 数据初始化
constructor(string[]memory nameList){
host=msg.sender;
// 给主持人初始化一票
voters[host].amount=1;
// 初始化board
for(uint i=0;i<nameList.length;i++){
Board memory item=Board(nameList[i],0);
board.push(item);
}
}
// 返回看板合集
function getBoardInfo() public view returns (Board[]memory){
return board;
}
赋予选票和选票
//给地址赋予选票
function mandate(address[] calldata addressList) public {
// 只有主持人可以调用
require(msg.sender==host,"Only the owner has permissions.");
for (uint256 i=0; i<addressList.length;i++){
//如果地址投票过,不做处理
if(!voters[addressList[i]].isVoted){
voters[addressList[i]].amount=1;
}
}
}
// 投票
function vote(uint256 targetId) public {
Voter storage sender=voters[msg.sender];
require(sender.amount!=0,"Have no right to vote");
require(!sender.isVoted,"Already Voted");
sender.isVoted=true;
sender.targetId=targetId;
board[targetId].totalAmount+=sender.amount;
emit voteSuccess(unicode"投票成功");
}
// 投票成功事件
event voteSuccess(string);
投票委托
// 将投票权委托给别人
function delegate(address to) public {
// 获取委托人的地址
Voter storage sender=voters[msg.sender];
// 如果委托人投票了,不能再委托
require(!sender.isVoted,"You have already voted");
// 不能委托给自己
require(msg.sender!=to, "cannot delegate to yourself");
// 避免循环委托
while (voters[to].delegator!=address(0)){
to=voters[to].delegator;
require(to==msg.sender,"Non-cyclic authorization");
}
// 开始授权
sender.isVoted=true;
sender.delegator=to;
//代理人的数据修改
Voter storage delegator_=voters[to];
if(delegator_.isVoted){
//追票
board[delegator_.targetId].totalAmount+=sender.amount;
}else{
delegator_.amount+=sender.amount;
}
}
完整代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract Vote{
// 构建投票人数据结构体
struct Voter{
uint256 amount; //可以投的票数
bool isVoted; //是否投过票
address delegator; // 代理人地址
uint256 targetId; // 目标ID
}
// 投票看板结构体
struct Board{
string name; // 目标名字
uint256 totalAmount; // 票数
}
// 主持人信息
address public host;
// 投票人集合
mapping (address=>Voter) public voters;
// 主题集合
Board [] public board;
// 数据初始化
constructor(string[]memory nameList){
host=msg.sender;
// 给主持人初始化一票
voters[host].amount=1;
// 初始化board
for(uint i=0;i<nameList.length;i++){
Board memory item=Board(nameList[i],0);
board.push(item);
}
}
// 返回看板合集
function getBoardInfo() public view returns (Board[]memory){
return board;
}
//给地址赋予选票
function mandate(address[] calldata addressList) public {
// 只有主持人可以调用
require(msg.sender==host,"Only the owner has permissions.");
for (uint256 i=0; i<addressList.length;i++){
//如果地址投票过,不做处理
if(!voters[addressList[i]].isVoted){
voters[addressList[i]].amount=1;
}
}
}
// 将投票权委托给别人
function delegate(address to) public {
// 获取委托人的地址
Voter storage sender=voters[msg.sender];
// 如果委托人投票了,不能再委托
require(!sender.isVoted,"You have already voted");
// 不能委托给自己
require(msg.sender!=to, "cannot delegate to yourself");
// 避免循环委托
while (voters[to].delegator!=address(0)){
to=voters[to].delegator;
require(to==msg.sender,"Non-cyclic authorization");
}
// 开始授权
sender.isVoted=true;
sender.delegator=to;
//代理人的数据修改
Voter storage delegator_=voters[to];
if(delegator_.isVoted){
//追票
board[delegator_.targetId].totalAmount+=sender.amount;
}else{
delegator_.amount+=sender.amount;
}
}
// 投票
function vote(uint256 targetId) public {
Voter storage sender=voters[msg.sender];
require(sender.amount!=0,"Have no right to vote");
require(!sender.isVoted,"Already Voted");
sender.isVoted=true;
sender.targetId=targetId;
board[targetId].totalAmount+=sender.amount;
emit voteSuccess(unicode"投票成功");
}
// 投票成功事件
event voteSuccess(string);
}
/**
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db
0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB
["0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db", "0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB"]
["路人甲","路人乙","路人丙","路人丁"]
*/
代码测试
用地址0x5B38Da6a701c568545dCfcB03FcB875f56beddC4部署
查看0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2投票情况
切换到0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2进行投票
切换到0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db,把投票权利授权给0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB
授权前
授权后
切换到0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB投票
它有两票(自己的和被授权的)
投
部署到metamask上,并且下载json,准备前端开发
web3与智能合约¶
前端布置
https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart
完整代码¶
https://github.com/sonichen/Web3.0_Project_Demo/tree/main/voting_system