以太坊开发------打造去中心化组织的投票系统

以太坊官方打造去中心化组织教程

Decentralized Autonomous Organization 去中心化组织

这篇文章我们一起来打造一个投票智能合约。
边看代码边进行讲解。

基础版的投票合约

设置父类合约和接口

这部分的代码主要设置合约创建者为owner,并且提供替换owner的方法。定义了接收ether代币的方法。如果有疑问建议先阅读之前的文章。

区块链开发(二十)代币示例及讲解

区块链开发(二十一)众筹合约示例及讲解

代码如下:

contract owned {
    address public owner;

    function owned()  public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    function transferOwnership(address newOwner) onlyOwner  public {
        owner = newOwner;
    }
}

contract tokenRecipient {
    event receivedEther(address sender, uint amount);
    event receivedTokens(address _from, uint256 _value, address _token, bytes _extraData);

    function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public {
        Token t = Token(_token);
        require(t.transferFrom(_from, this, _value));
        receivedTokens(_from, _value, _token, _extraData);
    }

    function () payable  public {
        receivedEther(msg.sender, msg.value);
    }
}

interface Token {
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
}

Congress合约

定义变量

  • 最小投票数:一个提案需要设置最小投票数。如果没有达到规定的投票数量,说明该提案是没有太大意义的。

  • 投票时间:设置一个允许投票的时间。到期后不允许投票。

  • 设定赞同票数的区间值:

    1. 一个投票可能是赞同或者反对。

    2. 如果想让一个提案通过,必须得到票数的50%加上这个设定的区间值。如果只要50%是赞同票就能通过,设为0就好了。如果要求全票通过,则设为members - 1。

    3. 提案的投票结果currentResult初始为0,在获得一张赞同票时,currentResult++,获得反对票时,currentResult--。一半赞同一半反对,currentResult最后为0。如果区间值设为0,意味该提案只需要半数人赞同便可通过。

    4. 假如设置赞同票数的区间值为2,共有10张投票,如果提案通过,则说明至少有7张是赞同票。因为需要currentResult大于2。

    // 最小的投票数
    uint public minimumQuorum;
    // 投票时间,以分钟为单位
    uint public debatingPeriodInMinutes;
    // 设定赞同票数的区间值
    int public majorityMargin;
    // 提案的数组
    Proposal[] public proposals;
    // 提案的个数
    uint public numProposals;
    // 成员id及地址
    mapping (address => uint) public memberId;
    // 成员的数组
    Member[] public members;

定义事件

    // 增加提案,传入提案id,受益人地址,价格,描述
    event ProposalAdded(uint proposalID, address recipient, uint amount, string description);

    // 投票,传入提案id,赞同/反对,投票人地址,陈述理由
    event Voted(uint proposalID, bool position, address voter, string justification);

    // 提案归档,传入提案id,结果,投票数,是否激活
    event ProposalTallied(uint proposalID, int result, uint quorum, bool active);

    // 设置某人是否为成员,传入地址,是否为组员
    event MembershipChanged(address member, bool isMember);

    // 改变规则,传入新的最小投票数,新的讨论时间,新的赞同票的区间值
    event ChangeOfRules(uint newMinimumQuorum, uint 
    newDebatingPeriodInMinutes, int newMajorityMargin);

定义结构体

    // 提案的结构体
    struct Proposal {
        // 受益人地址
        address recipient;
        // 金额
        uint amount;
        // 描述
        string description;
        // 投票截止时间
        uint votingDeadline;
        // 是否已执行
        bool executed;
        // 是否通过
        bool proposalPassed;
        // 得票数
        uint numberOfVotes;
        // 赞同票数
        int currentResult;
        // 哈希值
        bytes32 proposalHash;
        // 投票数组
        Vote[] votes;
        // 对应的地址是否已投票
        mapping (address => bool) voted;
    }

    // 成员结构体
    struct Member {
        // 地址
        address member;
        // 姓名
        string name;
        // 加入时间
        uint memberSince;
    }

    // 投票结构体
    struct Vote {
        // 支持还是反对
        bool inSupport;
        // 投票人地址
        address voter;
        // 理由描述
        string justification;
    }

修改器

增加一个判断当前合约调用者是否为成员的限制。

  // Modifier that allows only shareholders to vote and create new proposals
    // 限定了只有成员才可以投票及创建新提案
    modifier onlyMembers {
        require(memberId[msg.sender] != 0);
        _;
    }

构造函数

     /**
     * Constructor function
     * 构造函数
     */
    function Congress (

        // is the minimum amount of votes a proposal needs to have before it can be executed.
        // 设定提案被执行所需要的最少投票数
        uint minimumQuorumForProposals,

        // is the minimum amount of time (in minutes) that needs to pass before it can be executed.
        // 设定投票持续时间,如果时间到了之后没有通过,则提案不会被执行。以分钟为单位
        uint minutesForDebate,


        // A proposal passes if there are more than 50% of the votes plus the margin. Leave at 0 for simple majority, put it at the number of members - 1 to require an absolute consensus.
        // 如果想让一个提案通过,必须得到票数的50%加上这个设定的区间值。如果只要50%是赞同票就能通过,设为0就好了。如果要求全票通过,则设为members - 1。
        // 提案的投票结果currentResult初始为0,在获得一张赞同票时,currentResult++,获得反对票时,currentResult--。一半赞同一半反对,currentResult最后为0。如果区间值设为0,意味该提案只需要半数人赞同便可通过。
        // 假如设置赞同票数的区间值为2,共有10张投票,如果要想提案通过,则说明至少有7张是赞同票。
        // 设定赞同票数的区间值
        int marginOfVotesForMajority

    )  payable public {
        // 设定投票规则
        changeVotingRules(minimumQuorumForProposals, minutesForDebate, marginOfVotesForMajority);
        // It’s necessary to add an empty first member
        addMember(0, "");
        // and let's add the founder, to save a step later
        addMember(owner, 'founder');
    }

新增组员

    /**
     * Add member 添加一个成员,传入成员地址和名称
     * 限定了只有owner才能调用此方法
     *
     * Make `targetMember` a member named `memberName`
     *
     * @param targetMember ethereum address to be added
     * @param memberName public name for that member
     */
    function addMember(address targetMember, string memberName) onlyOwner public {
        uint id = memberId[targetMember];

        // 如果是新成员,将memberId设为members数组长度
        if (id == 0) {
            memberId[targetMember] = members.length;
            id = members.length++;
        }

        // 无论是否为新成员还是已有成员,都重新设置地址加入时间及姓名
        members[id] = Member({member: targetMember, memberSince: now, name: memberName});
        MembershipChanged(targetMember, true);
    }

删除组员

    /**
     * Remove member 删除一个成员,传入成员地址
     * 限定了只有owner才能调用此方法
     *
     * @notice Remove membership from `targetMember`
     *
     * @param targetMember ethereum address to be removed
     */
    function removeMember(address targetMember) onlyOwner public {
        require(memberId[targetMember] != 0);

        for (uint i = memberId[targetMember]; i<members.length-1; i++){
            members[i] = members[i+1];
        }
        delete members[members.length-1];
        members.length--;
    }

改变投票规则

    /**
     * Change voting rules 改变投票规则
     *
     * Make so that proposals need to be discussed for at least `minutesForDebate/60` hours,
     * 保证一个提案至少需要讨论的时间为`minutesForDebate/60`小时

     * have at least `minimumQuorumForProposals` votes, and have 50% + `marginOfVotesForMajority` votes to be executed
     * 提案需要的最少得票数和得票中的指定赞成票数才可被执行

     *
     * @param minimumQuorumForProposals how many members must vote on a proposal for it to be executed
     * 提案被执行的最少得票数
     *
     * @param minutesForDebate the minimum amount of delay between when a proposal is made and when it can be executed
     * 提案的最少投票时间
     *
     * @param marginOfVotesForMajority the proposal needs to have 50% plus this number
     * 提案需要50%赞同票加上这个区间值才可通过
     *
     */
    function changeVotingRules(
        uint minimumQuorumForProposals,
        uint minutesForDebate,
        int marginOfVotesForMajority
    ) onlyOwner public {
        minimumQuorum = minimumQuorumForProposals;
        debatingPeriodInMinutes = minutesForDebate;
        majorityMargin = marginOfVotesForMajority;

        ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, majorityMargin);
    }

新增提案

    /**
     * Add Proposal 增加提案
     *
     * Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
     *
     * @param beneficiary who to send the ether to
     * 受益人,如果提案顺利执行,可以获取到提案中的金额
     * @param weiAmount amount of ether to send, in wei
     * ether价格,单位是wei
     * @param jobDescription Description of job
     * 新提案的描述
     * @param transactionBytecode bytecode of transaction
     * 
     * 
     */
    function newProposal(
        address beneficiary,
        uint weiAmount,
        string jobDescription,
        bytes transactionBytecode
    )
        onlyMembers public
        returns (uint proposalID)
    {
        proposalID = proposals.length++;
        Proposal storage p = proposals[proposalID];
        p.recipient = beneficiary;
        p.amount = weiAmount;
        p.description = jobDescription;
        p.proposalHash = keccak256(beneficiary, weiAmount, transactionBytecode);
        p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
        p.executed = false;
        p.proposalPassed = false;
        p.numberOfVotes = 0
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值