5.13.5 民主DAO

优质
小牛编辑
147浏览
2023-12-01

民主DAO

到目前为止,您已经创建了一个可交易的令牌,并且您成功地将其分发给愿意帮助筹集100个ether的所有人。这一切都很有趣,但这些令牌究竟是什么呢?为什么有人想要拥有它或用它交易任何其他有价值的东西?如果你能说服你的新令牌是下一个有价值的货币,可能其他人会想要它,但到目前为止,你的令牌本身没有价值。我们将通过创建您的第一个分散式自治组织或DAO来改变这一点。

将DAO视为一个国家的体制,一个政府的行政部门,或者也许像一个机构的机器人经理。DAO收到您的组织募集的资金,保持安全,并使用它来资助任何需要资金的会员。机器人是清廉的,永远不会欺骗银行,永远不会制造秘密的计划,从来不会把这些钱用于未经其所有者投票的东西。DAO永远不会消失,永远不会逃跑,不能由其本国公民以外的任何人控制。

我们使用crowdsale分发的令牌是唯一需要的公民文件。任何持有任何令牌的人都可以创建投票和投票。与公司中的股东类似,令牌可以在公开市场上交易,选票与选民持有的令牌数成正比。

花一点时间来思考这革命性的可能性,现在你可以用下面的100行代码自己做一下

代码

contract token { mapping (address => uint) public coinBalanceOf;   function token() { }   function sendCoin(address receiver, uint amount) returns(bool sufficient) {  } }


contract Democracy {

    uint public minimumQuorum;
    uint public debatingPeriod;
    token public voterShare;
    address public founder;
    Proposal[] public proposals;
    uint public numProposals;

    event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description);
    event Voted(uint proposalID, int position, address voter);
    event ProposalTallied(uint proposalID, int result, uint quorum, bool active);

    struct Proposal {
        address recipient;
        uint amount;
        bytes32 data;
        string description;
        uint creationDate;
        bool active;
        Vote[] votes;
        mapping (address => bool) voted;
    }

    struct Vote {
        int position;
        address voter;
    }

    function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) {
        founder = msg.sender;  
        voterShare = token(_voterShareAddress);
        minimumQuorum = _minimumQuorum || 10;
        debatingPeriod = _debatingPeriod * 1 minutes || 30 days;
    }


    function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) {
        if (voterShare.coinBalanceOf(msg.sender)>0) {
            proposalID = proposals.length++;
            Proposal p = proposals[proposalID];
            p.recipient = _recipient;
            p.amount = _amount;
            p.data = _data;
            p.description = _description;
            p.creationDate = now;
            p.active = true;
            ProposalAdded(proposalID, _recipient, _amount, _data, _description);
            numProposals = proposalID+1;
        }
    }

    function vote(uint _proposalID, int _position) returns (uint voteID){
        if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) {
            Proposal p = proposals[_proposalID];
            if (p.voted[msg.sender] == true) return;
            voteID = p.votes.length++;
            p.votes[voteID] = Vote({position: _position, voter: msg.sender});
            p.voted[msg.sender] = true;
            Voted(_proposalID,  _position, msg.sender);
        }
    }

    function executeProposal(uint _proposalID) returns (int result) {
        Proposal p = proposals[_proposalID];
        /* Check if debating period is over */
        if (now > (p.creationDate + debatingPeriod) && p.active){   
            uint quorum = 0;
            /* tally the votes */
            for (uint i = 0; i <  p.votes.length; ++i) {
                Vote v = p.votes[i];
                uint voteWeight = voterShare.coinBalanceOf(v.voter);
                quorum += voteWeight;
                result += int(voteWeight) * v.position;
            }
            /* execute result */
            if (quorum > minimumQuorum && result > 0 ) {
                p.recipient.call.value(p.amount)(p.data);
                p.active = false;
            } else if (quorum > minimumQuorum && result < 0) {
                p.active = false;
            }
            ProposalTallied(_proposalID, result, quorum, p.active);
        }
    }
}

有很多事情要做,但它比看起来更简单。您的组织规则非常简单:任何有至少一个令牌的人都可以创建从国家帐户发送资金的提案。经过一周的辩论和投票,如果已经获得总共100个令牌或更多的票数,并且比反对更多的批准,这些资金将被发送。如果法定人数没有得到满足,或者结果不分胜负,那么投票将被保留,直到解决。否则,该提案被锁定并保存为历史记录。

所以让我们回顾一下这是什么意思:在最后两节中,你创建了10000个令牌,将其中的1000个发送给另一个你所控制的帐户,2,000个给一个叫Alice的朋友,并通过crowdsale分发了5,000个。这意味着您不再控制DAO中超过50%的投票,如果Alice和社区团结在一起,他们可以对迄今为止所募集的100个ether的支出做出决定。这正是民主应该如何运作的。如果你不想成为你国家的一部分,你唯一可以做的就是在一个分散的交换中出售自己的令牌,并选择退出,但是你不能阻止别人这样做。

建立你的组织

所以打开你的控制台,让我们准备好最终把你的国家放在网络上。首先,我们设置正确的参数,小心挑选:

var _voterShareAddress = token.address;
var _minimumQuorum = 10; // Minimun amount of voter tokens the proposal needs to pass
var _debatingPeriod = 60; // debating period, in minutes;

使用这些默认参数,任何具有任何令牌的人都可以提出如何花费组织的钱的建议。该提案有1小时的辩论时间,如果它有所有令牌中至少0.1%的票数,并且支持比反对多,它将被通过。仔细选择这些参数,因为您将来无法更改它们。

var daoCompiled = eth.compile.solidity('contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Democracy { uint public minimumQuorum; uint public debatingPeriod; token public voterShare; address public founder; Proposal[] public proposals; uint public numProposals; event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description); event Voted(uint proposalID, int position, address voter); event ProposalTallied(uint proposalID, int result, uint quorum, bool active); struct Proposal { address recipient; uint amount; bytes32 data; string description; uint creationDate; bool active; Vote[] votes; mapping (address => bool) voted; } struct Vote { int position; address voter; } function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) { founder = msg.sender; voterShare = token(_voterShareAddress); minimumQuorum = _minimumQuorum || 10; debatingPeriod = _debatingPeriod * 1 minutes || 30 days; } function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) { if (voterShare.coinBalanceOf(msg.sender)>0) { proposalID = proposals.length++; Proposal p = proposals[proposalID]; p.recipient = _recipient; p.amount = _amount; p.data = _data; p.description = _description; p.creationDate = now; p.active = true; ProposalAdded(proposalID, _recipient, _amount, _data, _description); numProposals = proposalID+1; } else { return 0; } } function vote(uint _proposalID, int _position) returns (uint voteID){ if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) { Proposal p = proposals[_proposalID]; if (p.voted[msg.sender] == true) return; voteID = p.votes.length++; Vote v = p.votes[voteID]; v.position = _position; v.voter = msg.sender; p.voted[msg.sender] = true; Voted(_proposalID, _position, msg.sender); } else { return 0; } } function executeProposal(uint _proposalID) returns (int result) { Proposal p = proposals[_proposalID]; /* Check if debating period is over */ if (now > (p.creationDate + debatingPeriod) && p.active){ uint quorum = 0; /* tally the votes */ for (uint i = 0; i < p.votes.length; ++i) { Vote v = p.votes[i]; uint voteWeight = voterShare.coinBalanceOf(v.voter); quorum += voteWeight; result += int(voteWeight) * v.position; } /* execute result */ if (quorum > minimumQuorum && result > 0 ) { p.recipient.call.value(p.amount)(p.data); p.active = false; } else if (quorum > minimumQuorum && result < 0) { p.active = false; } } ProposalTallied(_proposalID, result, quorum, p.active); } }');

var democracyContract = web3.eth.contract(daoCompiled.Democracy.info.abiDefinition);

var democracy = democracyContract.new(
    _voterShareAddress,
    _minimumQuorum,
    _debatingPeriod,
    {
      from:web3.eth.accounts[0],
      data:daoCompiled.Democracy.code,
      gas: 3000000
    }, function(e, contract){
      if(!e) {

        if(!contract.address) {
          console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined...");

        } else {
          console.log("Contract mined! Address: " + contract.address);
          console.log(contract);
        }

      }      
    })

如果您正在使用在线编译器,将合同代码复制到在线solidity编译器,然后获取标记为Geth Deploy文本框的内容。由于您已经设置了参数,因此您不需要更改任何文本,只需将生成的文本粘贴到您的geth窗口中即可。

等一会儿,直到矿工将其打包。这将耗费大约850k Gas。一旦被打包,现在是时间来实例化并设置它,将其指向您之前创建的令牌合约的正确地址。

如果一切顺利,您可以通过执行下面的字符串来查看整个组织:

"This organization has " +  democracy.numProposals() + " proposals and uses the token at the address " + democracy.voterShare() ;

如果一切都设置好了,那么你的DAO应该返回一个数量为0的提案和一个标记为“founder”的地址。虽然仍然没有提案,DAO的创始人可以将令牌的地址更改为任何需要的地址。

注册您的组织名称

我们还为您的合同注册一个名称,以便轻松访问(不要忘记在预订之前使用registrar.addr(“nameYouWant”)检查您的名称可用性!)

var name = "MyPersonalDemocracy"
registrar.reserve.sendTransaction(name, {from: eth.accounts[0]})
var democracy = eth.contract(daoCompiled.Democracy.info.abiDefinition).at(democracy.address);
democracy.setup.sendTransaction(registrar.addr("MyFirstCoin"),{from:eth.accounts[0]})

等待先前的交易被打包,然后:

registrar.setAddress.sendTransaction(name, democracy.address, true,{from: eth.accounts[0]});

民主监控者

var event = democracy.ProposalAdded({}, '', function(error, result){
  if (!error)
    console.log("New Proposal #"+ result.args.proposalID +"!\n Send " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.recipient.substring(2,8) + "... for " + result.args.description  )
});
var eventVote = democracy.Voted({}, '', function(error, result){
  if (!error)
    var opinion = "";
    if (result.args.position > 0) {
      opinion = "in favor"
    } else if (result.args.position < 0) {
      opinion = "against"
    } else {
      opinion = "abstaining"
    }

    console.log("Vote on Proposal #"+ result.args.proposalID +"!\n " + result.args.voter + " is " + opinion )
});
var eventTally = democracy.ProposalTallied({}, '', function(error, result){
  if (!error)
    var totalCount = "";
    if (result.args.result > 1) {
      totalCount = "passed"
    } else if (result.args.result < 1) {
      totalCount = "rejected"
    } else {
      totalCount = "a tie"
    }
    console.log("Votes counted on Proposal #"+ result.args.proposalID +"!\n With a total of " + Math.abs(result.args.result) + " out of " + result.args.quorum + ", proposal is " + totalCount + ". Proposal is " + (result.args.active? " still on the floor" : "archived") )
});

与DAO交互

在你对自己想要的满意之后,现在是把你从众筹中获得的所有的东西拿到你的新组织的时候了

eth.sendTransaction({from: eth.accounts[1], to: democracy.address, value: web3.toWei(100, "ether")})

这只需要一分钟,你的国家已经准备好了!现在,作为首要任务,您的组织需要一个不错的标志,但除非您是设计师,否则您不知道如何做到这一点。为了论证的缘故,我们假设你发现你的朋友鲍勃是一位伟大的设计师,他愿意只要10个ether来做这件事,所以你想提出聘请他。

recipient = registrar.addr("bob");
amount =  web3.toWei(10, "ether");
shortNote = "Logo Design";

democracy.newProposal.sendTransaction( recipient, amount, '', shortNote,  {from: eth.accounts[0], gas:1000000})

一分钟后,任何人都可以通过执行以下命令来检查提案的收件人和金额:

"This organization has " +  (Number(democracy.numProposals())+1) + " pending proposals";

关注组织

与大多数政府不同,贵国政府完全透明,易于编程。作为一个小型示范,这里有一段代码,列出所有当前的提案和打印他们的内容和目的:

function checkAllProposals() {
    console.log("Country Balance: " + web3.fromWei( eth.getBalance(democracy.address), "ether") );
    for (i = 0; i< (Number(democracy.numProposals())); i++ ) {
        var p = democracy.proposals(i);
        var timeleft = Math.floor(((Math.floor(Date.now() / 1000)) - Number(p[4]) - Number(democracy.debatingPeriod()))/60);  
        console.log("Proposal #" + i + " Send " + web3.fromWei( p[1], "ether") + " ether to address " + p[0].substring(2,6) + " for "+ p[3] + ".\t Deadline:"+ Math.abs(Math.floor(timeleft)) + (timeleft>0?" minutes ago ":" minutes left ") + (p[5]? " Active":" Archived") );
    }
}

checkAllProposals();

一个公民可以很容易地写一个机器人,定期ping那个blockchain,然后公布所提出的任何新提案,保证透明度。

现在当然你希望其他人能够对你的建议投票。您可以查看crowdsale教程关于注册合约APP的最佳方式,以便所有用户需要是一个名称,但现在让我们使用更简单的版本。任何人都应该能够使用下面的命令在计算机上实例化你的国家的本地副本:

democracy = eth.contract( [{ constant: true, inputs: [{ name: '', type: 'uint256' } ], name: 'proposals', outputs: [{ name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }, { name: 'data', type: 'bytes32' }, { name: 'descriptionHash', type: 'bytes32' }, { name: 'creationDate', type: 'uint256' }, { name: 'numVotes', type: 'uint256' }, { name: 'quorum', type: 'uint256' }, { name: 'active', type: 'bool' } ], type: 'function' }, { constant: false, inputs: [{ name: '_proposalID', type: 'uint256' } ], name: 'executeProposal', outputs: [{ name: 'result', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'debatingPeriod', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'numProposals', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'founder', outputs: [{ name: '', type: 'address' } ], type: 'function' }, { constant: false, inputs: [{ name: '_proposalID', type: 'uint256' }, { name: '_position', type: 'int256' } ], name: 'vote', outputs: [{ name: 'voteID', type: 'uint256' } ], type: 'function' }, { constant: false, inputs: [{ name: '_voterShareAddress', type: 'address' } ], name: 'setup', outputs: [ ], type: 'function' }, { constant: false, inputs: [{ name: '_recipient', type: 'address' }, { name: '_amount', type: 'uint256' }, { name: '_data', type: 'bytes32' }, { name: '_descriptionHash', type: 'bytes32' } ], name: 'newProposal', outputs: [{ name: 'proposalID', type: 'uint256' } ], type: 'function' }, { constant: true, inputs: [ ], name: 'minimumQuorum', outputs: [{ name: '', type: 'uint256' } ], type: 'function' }, { inputs: [ ], type: 'constructor' } ] ).at(registrar.addr('MyPersonalCountry'))

那么任何拥有任何你的令牌的人都可以通对投票表决:

var proposalID = 0;
var position = -1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum
democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000});

var proposalID = 1;
var position = 1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum
democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000});

除非您更改代码中的基本参数,否则任何提案至少需要一周时间才能被执行。之后,即使是非公民,也可以要求投票和执行的提案。投票在当时计算和加权,如果提案被接受,则ether将立即发送,并将提案归档。如果票数结束时不分上下或最低法定人数未达成,表决将保持开放,直到僵局解决。如果它丢失了,那么它被存档,不能再投票了。

var proposalID = 1;
democracy.executeProposal.sendTransaction(proposalID, {from: eth.accounts[0], gas: 1000000});

如果提案通过,那么你应该可以看到鲍勃的ether到达他的地址:

web3.fromWei(eth.getBalance(democracy.address), "ether") + " ether";
web3.fromWei(eth.getBalance(registrar.addr("bob")), "ether") + " ether";

尝试自己: 这是一个非常简单的民主合约,有很大改善空间。目前,所有提案都有相同的讨论时间,并以直接投票和简单多数获胜。你可以改变一下,这样会有一些情况,根据提议的数额,辩论可能会更长,还是需要更大的数目?还要考虑一些公民不需要对每个问题投票的方式,并可以临时将其投票授权给特别代表。您可能还注意到,我们为每个提案添加了一个细微的描述。这可以用作提案的标题,或者可以是详细描述其的较大文档的哈希。

我们去探索吧!

你已经到了本教程的最后,但它只是一个伟大的冒险的开始。回头看看你的成就:你创造了一个活的,谈话的机器人,你自己的加密货币,通过不可靠的众筹来募集资金,并用它来启动你自己的个人民主组织。

为了简单起见,我们只使用你所创造的民主组织来发送ether,他是ethereum中天生的货币。虽然这对一些人来说可能是足够好的,但这只是掀开可以做的事情的的面纱。在ethereum网络中,合约具有与任何普通用户相同的权利,这意味着您的组织可以执行您从自己的帐户执行的任何交易。

接下来会发生什么?

  • 您开始创建的greeter合约可以改进,以便为其服务收费,并可将这些资金纳入DAO。

  • 您仍然控制的令牌可以在分散的交易所上销售,也可以交易货物和服务,以进一步开发第一份合约并扩大组织。

  • 您的DAO可以在名称注册商上拥有自己的名称,然后更改其重定向的位置,以便在令牌持有人批准时进行更新。

  • 该组织不仅可以持有ethers,而且还可以拥有任何一种ethereum上产生的其他货币,包括价值与比特币或美元挂钩的资产。

  • DAO可以被编程为允许具有多个交易的提案,一些提案被预定在未来。它也可以拥有其他DAO的股份,这意味着它可以投票给更大的组织或成为DAO联合会的一部分。

  • 令牌合约可以重新编程,以保持ether或持有其他令牌并将其分配给令牌持有者。这将把令牌的价值与其他资产的价值联系起来,所以通过简单地将资金转移到令牌地址就能实现分红。

这一切都意味着你创造的这个小小的社会可以增长,从第三方获得资金,支付经常性工资,拥有任何种类的密码资产,甚至使用crowdsales资助其活动。所有这些都具有完全的透明度,完整的责任感和完全排除任何人为干扰。当网络存活的时候,合同将完全执行他们被创建用来执行的代码,无一例外地执行。

那么你的合同是什么?它会成为一个国家,一家公​​司,一个非营利组织?你的代码会做什么?

这取决于你。