温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

以太坊DAO股东协会智能合约怎么实现

发布时间:2022-01-15 14:41:25 来源:亿速云 阅读:143 作者:iii 栏目:互联网科技

本篇内容主要讲解“以太坊DAO股东协会智能合约怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“以太坊DAO股东协会智能合约怎么实现”吧!

Decentralized Autonomous Organization,简称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 address,该地址是代币的地址,它将作为具有投票权的共享。

注意这些代码行:首先我们描述新合约的代币合约。由于它只使用了balanceOf函数,我们只需要添加那一行。

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

然后我们定义一个类型标记的变量,这意味着它将继承我们之前描述的所有函数。最后,我们将代币变量指向区块链上的地址,因此它可以使用它并请求实时信息。这是使一个合约在以太坊中理解另一个的最简单方法。

contract Association {
    token public sharesTokenAddress;
// ...
constructor(token sharesAddress, uint minimumSharesForVoting, uint minutesForDebate) {
        sharesTokenAddress = token(sharesAddress);

这个协会association提出了前一届大会congress没有的挑战:因为任何拥有代币的人都可以投票而且余额可以很快变化,当股东投票时,提案的实际分数不能计算,否则有人能够通过简单地将他的份额发送到不同的地址来多次投票。因此,在本合约中,仅记录投票位置,然后在执行提案阶段计算实际得分。

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将无符号整数 voteWeight转换为有符号整数 得分= int(voteWeight);

使用这个DAO就像以前一样:成员创建新的提案,对它们进行投票,等到截止日期过去,然后任何人都可以计算投票并执行它。

以太坊DAO股东协会智能合约怎么实现

但是我如何限制所有者的权力呢?

在此合约中,设置为所有者owner的地址具有一些特殊权力:他们可以随意添加或禁止成员,更改获胜所需的保证金,更改辩论所需的时间以及投票通过所需的法定人数。但这可以通过使用业主拥有的另一种权力来解决:改变所有权。

所有者可以通过将新所有者指向0x00000来将所有权更改为任何人....这将保证规则永远不会改变,但这是不可逆转的行动。所有者还可以将所有权更改为合约本身:只需单击复制地址copy address并将其添加到新所有者new owner字段即可。这将使得所有者的所有权力都可以通过创建提案来执行。

如果你愿意,你也可以设置一个合约作为另一个合约的所有者:假设你想要一个公司结构,你想要一个有权任命董事会成员的终身总统,然后可以发行更多的股票,最后这些股票被投票关于如何花费预算。你可以创建一个关联合约Association,该合约mintable token使用最终由单个帐户拥有的会议congress所拥有的mintable代币。

但是如果你想要不同的投票规则呢?也许改变投票规则你需要80%的共识,或者成员可能不同。在这种情况下,你可以创建另一个相同的DAO或使用其他一些源代码并将其作为第一个的所有者插入。

到此,相信大家对“以太坊DAO股东协会智能合约怎么实现”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI