vote.sol
部署合约设定投票人 [“aa”,”bb”,”cc”,”dd”] 编译器使用的0.4.24版本

pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;

contract VoteContract {

    struct Voter {
        uint voteNumber; //投票号
        bool isVoted; //是否投过票,已经过的不允许再次投票
        uint weight; //投票权重,初始时均为1,被委托后权重增加
        address delegate; //指定代理人
    }

    struct Houxuan {
        string name; //候选人名字
        uint voteCount; //获得的投票数
    }

    address public admin; //负责创建合约,授权给地址,使之成为投票人

    //候选人集合
    Houxuan[] public houxuans;

    //投票人集合
    mapping(address => Voter) public voters;

    //["aa","bb","cc","dd"]
    constructor(string[] houxuanNames) public {
        //创建合约者为管理员
        admin = msg.sender;

        //每一个名字都生成一个候选人,添加到候选人的集合中
        for (uint i = 0; i < houxuanNames.length; i++){ Houxuan memory tmp = Houxuan({name:houxuanNames[i], voteCount:0}); houxuans.push(tmp); } } //限定只有管理员才可以添加投票人权力 modifier adminOnly() { require(admin == msg.sender); _; } //添加投票人 function giveVoteRightTo(address addr) adminOnly public { //已有投票人不添加 if (voters[addr].weight > 0)
            revert();
        //将投票人加入到voters中
        voters[addr].weight = 1;
    }

    //投票
    function vote(uint voteNum) public {
        //读取投票人
        Voter voter = voters[msg.sender];

        //过滤条件 是否投票过和是否有投票权重
        if (voter.weight <= 0 || voter.isVoted)
            revert();
        
        //录入投票号并设置为已经投票
        voter.isVoted = true;
        voter.voteNumber = voteNum;

        //候选人的编号与存储位置一样,第[0]个候选人就是0
        houxuans[voteNum].voteCount += voter.weight;
    }

    function whoWin() view public returns (string, uint) {
        string winner;
        uint winnerVoteCount;

        //遍历候选人 寻找找到投票数最多的
        for (uint i = 0; i< houxuans.length; i++) { if(houxuans[i].voteCount > winnerVoteCount) {
                winnerVoteCount = houxuans[i].voteCount;
                winner = houxuans[i].name;
            }
        }

        return (winner,winnerVoteCount);
    }
}

代理投票功能
要先授权都是投票人,再选代理人(代理人也要是拥有投票权限)才能选,再进行投票。
代理人没投票就加权重+1,投票了就在候选人票数+1

    //代理人功能
    function dailiFunc(address to) public {
        //读取投票人
        Voter storage voter = voters[msg.sender];

        //不是投票人或者已经投过票的返回
        if (voter.weight <= 0 || voter.isVoted)
            revert();
        
        //再判断代理人是不是投票人 (这是我自行添加的判断)
        Voter storage voter2 = voters[to];
        if (voter2.weight <= 0 || voter2.isVoted)
            revert();
        
        //如果代理人也指定了代理人,那么需要轮询找到最终代理人,最终代理人不能是自己,否则死循环
        while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender){
            to = voters[to].delegate; //一层一层找到最终代理人
        }

        //代理是自己,退出
        require(msg.sender != to);

        if (msg.sender == to){
            revert();
        }

        voter.isVoted = true;
        voter.delegate = to;

        Voter storage finalDelegateVoter = voters[to];

        if(finalDelegateVoter.isVoted){
            //如果代理人已经投票,那么再代理人所投票候选人的票数加上自己的权重票数
            houxuans[finalDelegateVoter.voteNumber].voteCount += voter.weight;
        } else {
            //否则,在代理人权重上加上自己的权重
            finalDelegateVoter.weight += voter.weight;
        }


    }