跳转至

投票系统

功能梳理

通过智能合约实现去中心化投票

  1. 主持人创建投票主题与内容
  2. 给予“选民”在选票上投票的权利
  3. 把你的投票委托给投票人.
  4. 投票

数据结构

image-20231026102911221

合约代码

定义结构体

    // 构建投票人数据结构体
    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部署

image-20231026124004891

image-20231026124041368

image-20231026124111076

查看0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2投票情况

image-20231026124156368

切换到0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2进行投票

image-20231026124227962

image-20231026124259486

切换到0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db,把投票权利授权给0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB

授权前

image-20231026124356904

授权后

image-20231026124419955

切换到0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB投票

它有两票(自己的和被授权的)

image-20231026124458946

image-20231026124524579

部署到metamask上,并且下载json,准备前端开发

image-20231026125023824

web3与智能合约

前端布置

https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart

完整代码

https://github.com/sonichen/Web3.0_Project_Demo/tree/main/voting_system