主页 > imtoken国内版下载 > Ethereum DAO 股东协会的智能合约如何实现
Ethereum DAO 股东协会的智能合约如何实现
本文主要讲解《以太坊DAO股东协会智能合约如何实现》,感兴趣的朋友不妨看看。 本文介绍的方法简单、快捷、实用。 接下来就让小编带大家一起来学习《Ethereum DAO股东协会智能合约如何实现》吧!
去中心化自治组织,简称DAO,是以太坊中的一个重要概念。 一般翻译为分散的自治组织。
股东协会智能合约
我们将修改我们的合约,将其连接到一个特定的代币,该代币将作为合约的控股份额。 首先,我们需要创建这个代币:转到代币教程并创建一个初始供应量为 100、小数为 0 和百分号 (%) 的简单代币。 如果您希望能够按百分比进行交易以太坊合约代码最长,请将供应量乘以 100 或 1000 倍,然后将相应数量的零添加为小数。 部署此合约并将其地址保存在文本文件中。
那么修改后的股东会合约代码:
pragma solidity >=0.4.22 <0.6.0; contract owned { address public owner; constructor() 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 memory _extraData) public { Token t = Token(_token); require(t.transferFrom(_from, address(this), _value)); emit receivedTokens(_from, _value, _token, _extraData); } function () payable external { emit receivedEther(msg.sender, msg.value); } } contract Token { mapping (address => uint256) public balanceOf; function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); } /** * The shareholder association contract itself */ contract Association is owned, tokenRecipient { uint public minimumQuorum; uint public debatingPeriodInMinutes; Proposal[] public proposals; uint public numProposals; Token public sharesTokenAddress; event ProposalAdded(uint proposalID, address recipient, uint amount, string description); event Voted(uint proposalID, bool position, address voter); event ProposalTallied(uint proposalID, uint result, uint quorum, bool active); event ChangeOfRules(uint newMinimumQuorum, uint newDebatingPeriodInMinutes, address newSharesTokenAddress); struct Proposal { address recipient; uint amount; string description; uint minExecutionDate; bool executed; bool proposalPassed; uint numberOfVotes; bytes32 proposalHash; Vote[] votes; mapping (address => bool) voted; } struct Vote { bool inSupport; address voter; } // Modifier that allows only shareholders to vote and create new proposals modifier onlyShareholders { require(sharesTokenAddress.balanceOf(msg.sender) > 0); _; } /** * Constructor * * First time setup */ constructor(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) payable public { changeVotingRules(sharesAddress, minimumSharesToPassAVote, minutesForDebate); } /** * Change voting rules * * Make so that proposals need to be discussed for at least `minutesForDebate/60` hours * and all voters combined must own more than `minimumSharesToPassAVote` shares of token `sharesAddress` to be executed * * @param sharesAddress token address * @param minimumSharesToPassAVote proposal can vote only if the sum of shares held by all voters exceed this number * @param minutesForDebate the minimum amount of delay between when a proposal is made and when it can be executed */ function changeVotingRules(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) onlyOwner public { sharesTokenAddress = Token(sharesAddress); if (minimumSharesToPassAVote == 0 ) minimumSharesToPassAVote = 1; minimumQuorum = minimumSharesToPassAVote; debatingPeriodInMinutes = minutesForDebate; emit ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, address(sharesTokenAddress)); } /** * 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 * @param jobDescription Description of job * @param transactionBytecode bytecode of transaction */ function newProposal( address beneficiary, uint weiAmount, string memory jobDescription, bytes memory transactionBytecode ) onlyShareholders public returns (uint proposalID) { proposalID = proposals.length++; Proposal storage p = proposals[proposalID]; p.recipient = beneficiary; p.amount = weiAmount; p.description = jobDescription; p.proposalHash = keccak256(abi.encodePacked(beneficiary, weiAmount, transactionBytecode)); p.minExecutionDate = now + debatingPeriodInMinutes * 1 minutes; p.executed = false; p.proposalPassed = false; p.numberOfVotes = 0; emit ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription); numProposals = proposalID+1; return proposalID; } /** * Add proposal in Ether * * Propose to send `etherAmount` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code. * This is a convenience function to use if the amount to be given is in round number of ether units. * * @param beneficiary who to send the ether to * @param etherAmount amount of ether to send * @param jobDescription Description of job * @param transactionBytecode bytecode of transaction */ function newProposalInEther( address beneficiary, uint etherAmount, string memory jobDescription, bytes memory transactionBytecode ) onlyShareholders public returns (uint proposalID) { return newProposal(beneficiary, etherAmount * 1 ether, jobDescription, transactionBytecode); } /** * Check if a proposal code matches * * @param proposalNumber ID number of the proposal to query * @param beneficiary who to send the ether to * @param weiAmount amount of ether to send * @param transactionBytecode bytecode of transaction */ function checkProposalCode( uint proposalNumber, address beneficiary, uint weiAmount, bytes memory transactionBytecode ) view public returns (bool codeChecksOut) { Proposal storage p = proposals[proposalNumber]; return p.proposalHash == keccak256(abi.encodePacked(beneficiary, weiAmount, transactionBytecode)); } /** * Log a vote for a proposal * * Vote `supportsProposal? in support of : against` proposal #`proposalNumber` * * @param proposalNumber number of proposal * @param supportsProposal either in favor or against it */ function vote( uint proposalNumber, bool supportsProposal ) onlyShareholders public returns (uint voteID) { Proposal storage p = proposals[proposalNumber]; require(p.voted[msg.sender] != true); voteID = p.votes.length++; p.votes[voteID] = Vote({inSupport: supportsProposal, voter: msg.sender}); p.voted[msg.sender] = true; p.numberOfVotes = voteID +1; emit Voted(proposalNumber, supportsProposal, msg.sender); return voteID; } /** * Finish vote * * Count the votes proposal #`proposalNumber` and execute it if approved * * @param proposalNumber proposal number * @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it */ function executeProposal(uint proposalNumber, bytes memory transactionBytecode) public { Proposal storage p = proposals[proposalNumber]; require(now > p.minExecutionDate // If it is past the voting deadline && !p.executed // and it has not already been executed && p.proposalHash == keccak256(abi.encodePacked(p.recipient, p.amount, transactionBytecode))); // and the supplied code matches the proposal... // ...then tally the results uint quorum = 0; uint yea = 0; uint nay = 0; for (uint i = 0; i < p.votes.length; ++i) { Vote storage v = p.votes[i]; uint voteWeight = sharesTokenAddress.balanceOf(v.voter); quorum += voteWeight; if (v.inSupport) { yea += voteWeight; } else { nay += voteWeight; } } require(quorum >= minimumQuorum); // Check if a minimum quorum has been reached if (yea > nay ) { // Proposal passed; execute the transaction p.executed = true; (bool success, ) = p.recipient.call.value(p.amount)(transactionBytecode); require(success); p.proposalPassed = true; } else { // Proposal failed p.proposalPassed = false; } // Fire Events emit ProposalTallied(proposalNumber, yea - nay, quorum, p.proposalPassed); } }
部署和使用
代码的部署和前面的代码几乎一模一样,但是还需要放一个shares token地址,也就是token的地址,它会作为一个有投票权的share。
请注意这些代码行:首先我们描述新合约的代币合约。 因为它只使用 balanceOf 函数,所以我们只需要添加那一行。
contract Token { mapping (address => uint256) public balanceOf; }
然后我们定义一个tag类型的变量,这意味着它将继承我们之前描述的所有功能。 最后,我们将令牌变量指向区块链上的一个地址,这样它就可以使用它并请求实时信息。 这是在以太坊中让一个合约理解另一个合约的最简单方法。
contract Association { token public sharesTokenAddress; // ... constructor(token sharesAddress, uint minimumSharesForVoting, uint minutesForDebate) { sharesTokenAddress = token(sharesAddress);
这个协会提出了一个上届大会没有的挑战:由于任何有代币的人都可以投票,余额可以快速变化,当股东投票时,无法计算提案的实际得分,否则有人可以将他的股份发送给不同的人多次投票的地址。 因此,在这个合约中,只记录投票位置,然后在提案阶段执行时计算实际得分。
uint quorum = 0; uint yea = 0; uint nay = 0; for (uint i = 0; i < p.votes.length; ++i) { Vote v = p.votes[i]; uint voteWeight = sharesTokenAddress.balanceOf(v.voter); quorum += voteWeight; if (v.inSupport) { yea += voteWeight; } else { nay += voteWeight; } }
另一种计算加权投票的方法是创建一个有符号整数来保存投票分数并检查结果是正面还是负面,但是您必须使用 int score = int(voteWeight); 将无符号整数 voteWeight 转换为有符号整数;
使用这个 DAO 就像以前一样:成员创建新提案,对其进行投票,等到截止日期过去,然后任何人都可以计算选票并执行它。
但是如何限制所有者的权力呢?
在这个合约中,被设置为所有者的地址拥有一些特殊的权力:他们可以随意添加或禁止成员,更改获胜所需的保证金,更改辩论所需的时间以及投票通过所需的法定人数。 但这可以通过使用所有者拥有的另一种权力来解决:改变所有权。
所有者可以通过将新所有者指向 0x00000 来将所有权更改为任何人......这将保证规则永远不会改变,但这是一个不可逆的动作。 所有者还可以将所有权更改为合约本身:只需单击复制地址并将其添加到新所有者字段。 这将使所有者的所有权力都可以通过创建提案来执行。
如果你愿意,你也可以设置一个合约成为另一个合约的所有者:比如说你想要一个公司结构,你想要一个有权任命董事会成员的终身总裁,然后可以发行更多的股票以太坊合约代码最长,最后这些分享 就如何花费预算进行投票。 您可以创建一个协会合约,其中可铸造代币使用最终由单一账户拥有的国会拥有的可铸造代币。
但是如果你想要不同的投票规则怎么办? 也许要改变投票规则你需要 80% 的共识,或者成员可能不同。 在这种情况下,您可以创建另一个相同的 DAO 或使用其他源代码并将其作为第一个 DAO 的所有者插入。
至此,相信大家对“Ethereum DAO 股东协会的智能合约如何实现”有了更深的理解,下面就来实践一下吧! 这里是编程笔记的网站。 更多相关内容,可进入相关渠道查询,关注我们,继续学习!