什么是以太坊DAO?(三)

Decentralized Autonomous Organization,简称DAO,以太坊中重要的概念。通常翻译为去中心化的自治组织。php

投票支付合约的全部费用和行动须要时间,并要求用户始终保持活跃,知情和专一。另外一个有趣的方法是选择一个能够控制合约的指定帐户,而后可以迅速作出决定。java

流动民主合约

咱们将实施一种一般称为流动民主Liquid Democracy的版本,这是一种更灵活的代议制民主。在这种民主制度下,任何选民均可以成为潜在的表明:你只需说出你信任哪位选民就能够为你处理这一决定。你的投票权重被委托给他们,他们能够将其委托给他们信任的另外一个选民,依此类推。最终结果应该是投票最多的帐户是与最大数量的选民有信任关系的帐户。node

代码:python

pragma solidity >=0.4.22 <0.6.0;

contract token {
    mapping (address => uint256) public balanceOf;
}

contract LiquidDemocracy {
    token public votingToken;
    bool  underExecution;
    address public appointee;
    mapping (address => uint) public voterId;
    mapping (address => uint256) public voteWeight;

    uint public delegatedPercent;
    uint public lastWeightCalculation;
    uint public numberOfDelegationRounds;

    uint public numberOfVotes;
    DelegatedVote[] public delegatedVotes;
    string public forbiddenFunction;

    event NewAppointee(address newAppointee, bool changed);

    struct DelegatedVote {
        address nominee;
        address voter;
    }

    /**
     * Constructor
     */
    constructor(
        address votingWeightToken,
        string memory forbiddenFunctionCall,
        uint percentLossInEachRound
    ) public {
        votingToken = token(votingWeightToken);
        delegatedVotes.length++;
        delegatedVotes[0] = DelegatedVote({nominee: address(0), voter: address(0)});
        forbiddenFunction = forbiddenFunctionCall;
        delegatedPercent = 100 - percentLossInEachRound;
        if (delegatedPercent > 100) delegatedPercent = 100;
    }

    /**
     * Vote for an address
     *
     * Send your vote weight to another address
     *
     * @param nominatedAddress the destination address receiving the sender's vote
     */
    function vote(address nominatedAddress) public returns (uint voteIndex) {
        if (voterId[msg.sender]== 0) {
            voterId[msg.sender] = delegatedVotes.length;
            numberOfVotes++;
            voteIndex = delegatedVotes.length++;
            numberOfVotes = voteIndex;
        }
        else {
            voteIndex = voterId[msg.sender];
        }

        delegatedVotes[voteIndex] = DelegatedVote({nominee: nominatedAddress, voter: msg.sender});

        return voteIndex;
    }

    /**
     * Perform Executive Action
     *
     * @param target the destination address to interact with
     * @param valueInWei the amount of ether to send along with the transaction
     * @param bytecode the data bytecode for the transaction
     */
    function execute(address target, uint valueInWei, bytes32 bytecode) public {
        require(msg.sender == appointee                             // If caller is the current appointee,
            && !underExecution                                      // if the call is being executed,
            && bytes4(bytecode) != bytes4(keccak256(abi.encodePacked(forbiddenFunction)))  // and it's not trying to do the forbidden function
            && numberOfDelegationRounds >= 4);                      // and delegation has been calculated enough

        underExecution = true;
        (bool success, ) = target.call.value(valueInWei)(abi.encode(bytecode)); // Then execute the command.
        require(success); 
        underExecution = false;
    }

    /**
     * Calculate Votes
     *
     * Go thruogh all the delegated vote logs and tally up each address's total rank
     */
    function calculateVotes()  public returns (address winner) {
        address currentWinner = appointee;
        uint currentMax = 0;
        uint weight = 0;
        DelegatedVote storage v = delegatedVotes[0];

        if (now > lastWeightCalculation + 90 minutes) {
            numberOfDelegationRounds = 0;
            lastWeightCalculation = now;

            // Distribute the initial weight
            for (uint i=1; i< delegatedVotes.length; i++) {
                voteWeight[delegatedVotes[i].nominee] = 0;
            }
            for (uint i=1; i< delegatedVotes.length; i++) {
                voteWeight[delegatedVotes[i].voter] = votingToken.balanceOf(delegatedVotes[i].voter);
            }
        }
        else {
            numberOfDelegationRounds++;
            uint lossRatio = 100 * delegatedPercent ** numberOfDelegationRounds / 100 ** numberOfDelegationRounds;
            if (lossRatio > 0) {
                for (uint i=1; i< delegatedVotes.length; i++){
                    v = delegatedVotes[i];

                    if (v.nominee != v.voter && voteWeight[v.voter] > 0) {
                        weight = voteWeight[v.voter] * lossRatio / 100;
                        voteWeight[v.voter] -= weight;
                        voteWeight[v.nominee] += weight;
                    }

                    if (numberOfDelegationRounds>3 && voteWeight[v.nominee] > currentMax) {
                        currentWinner = v.nominee;
                        currentMax = voteWeight[v.nominee];
                    }
                }
            }
        }

        if (numberOfDelegationRounds > 3) {
            emit NewAppointee(currentWinner, appointee == currentWinner);
            appointee = currentWinner;
        }

        return currentWinner;
    }
}

部署

首先,你须要一个代币。若是你已按照上面的股东协会Shareholder association教程,你可使用与以前相同的代币,不然只需部署新代币并在某些账户中分配。复制代币地址。android

部署民主合约,并将代币地址放在投票权重代币上 ,将75做为每轮中的百分比损失,并将转让全部权(地址)(没有任何空格或额外字符!)做为禁止功能 。程序员

选择表明

如今部署Liquid民主并转到其页面。首先,任何股东都会投票决定他们信任谁表明本合约作出决定。若是你想成为最终决策者,你能够本身投票,或者若是你宁愿没有人表明你担任这个角色,你能够在零地址上投票。web

在足够多的人投票后,你能够执行计算投票功能,以便计算每一个人的投票权重。这个功能须要屡次运行,因此第一次运行它只会将每一个人的体重设置为所选代币中的余额。在下一轮中,投票权重将转到你投票指定的人,在下一轮它会去由你选择的人投票的人等等。为了防止无限循环的投票受权,每次投票都会转发,它会失去一些权力,在percentLossInEachRound合约启动时设定。所以,若是损失设定为75%,则意味着你投票的人得到了100%的体重,但若是他们将投票委托给其余人,则只有75%的体重被转发。那我的能够委托给别人,但他们只能得到56%的投票权,依此类推。若是比率低于100%,将会有一个有限的时刻,从新计算投票受权将再也不改变结果,但若是它是100%,则意味着投票权重将简单地围绕任何潜在的循环进行循环。mongodb

若是这一轮调用计算投票开始已超过一个半小时,全部权重将重置并将根据原始代币余额从新计算,所以若是你最近收到更多代币,则应再次执行此功能。编程

众议机构

投票表明团的全部优势是什么?例如,你能够在关联上使用它而不是代币权重。首先,获取股东协会的代码,但替换描述代币的第一行:app

contract Token {
    mapping (address => uint256) public balanceOf;
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
}

进入这个:

contract Token {
    mapping (address => uint256) public voteWeight;
    uint public numberOfDelegationRounds;

    function balanceOf(address member) public view returns (uint256 balance) {
        if (numberOfDelegationRounds < 3)
            return 0;
        else
            return this.voteWeight(member);
    }
    
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
}

在编写合约时,你能够描述主合约使用的多个其余合约。有些多是已在目标合约上定义的函数和变量,如voteWeightnumberOfDelegationRounds。但请注意,balanceOf是一个新功能,它在Liquid DemocracyAssociation合约上都不存在,咱们如今正在定义它,做为一个函数,若是至少计算了三轮,它将返回voteWeight

使用Liquid democracy做为代币地址而不是原始代币,并像往常同样继续部署股东协会。就像之前同样,用户能够针对这些问题建立新的提案或投票,但如今,咱们使用委托流程,不是使用代币余额做为投票权。因此,若是你是一个代币持有者,你能够选择一个你信任的人并指定他们,而不是让你本身不断地通知全部问题,而后他们能够选择他们信任的人:结果就是你的表明,而不是被限制在给定的任意地理位置附近,将是你社交距离的人。

此外,这意味着你能够随时切换投票:若是你的表明在某些问题上投票反对你的利益,你能够在提案投票结算以前,转换你的被任命者,或者只是选择表明你本身处理问题并投本身投票。

行政部门

代议制民主国家是选择表明的一种很好的方式,但对于一些重要或简单的决策,对个别提案进行投票可能太慢:这就是为何大多数民主政府都有一个行政部门,而被任命的人有权表明国家。

在四轮表明以后,更多权重的地址将被设定为被任命者。若是有许多委托投票,那么可能须要再多几轮计算投票才能在最终指定的地址中解决。

被任命者是惟一能够调用Execute函数的地址,它能够执行(几乎)任何表明整个民主的函数。若是液体民主合约中存有任何以太或代币,被任命者将被容许在任何地方移动。

若是你遵循咱们的示例并使用此流动民主做为代币建立了股东协会 ,那么你应该可以以有趣的方式使用行政部门:转到主协会地址并执行转移全部权功能到流动民主。

传输完成后,将功能切换为更改投票规则。这容许你更改一些基本的投票规则,例如投票经过所需的最低法定人数或新提案须要留在场上的时间。尝试更改这些设置并单击执行:当弹出确认窗口时,它将告诉你该交易没法执行。固然,这种状况发生,由于只有设置为全部者的地址才能更改这些设置,合约将拒绝此交易尝试。所以,不是键入密码而是复制数据字段上的代码并将其保存到文本文件中。单击取消,滚动到顶部并单击复制地址,并将其保存到文本文件。

如今转到Liquid民族页面并选择执行。在目标上放置关联合约的地址,将ether amount保留为0并将先前复制的代码粘贴到字节码数据字段中。确保你从做为被任命者设置的账户执行它,而后单击执行。

一旦交易被收回,Liquid民主将把订单传递给协会,而且新的投票规则可能适用。被任命者有绝对的权力去作液体民主合约能够执行的任何事情。你可使用相同的技术建立委派民主所拥有的Mintable代币,而后容许被任命者填写代币或冻结账户。

为了防止滥用权力,你能够设置一个被禁止的人没法作的禁止功能。若是你按照咱们的例子,禁止的功能是transferOwnership(地址),以防止被任命者将协会的全部权转让给他们本身(在政治上,当总统利用他的行政权力转移给本身之前属于总统,这是政变或贪污)。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行帐号建立、交易、转帐、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括帐户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、帐户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如建立地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如建立地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合但愿使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文以太坊DAO之流动民主智能合约

相关文章
相关标签/搜索