Solidity--实现投票治理管理DAO

 


提示:以下是本篇文章正文内容,下面案例可供参考

一、需求分析

需求描述:

创建投票提案的门槛:

此发起的提案必须先持有一定量的token总量5% (可治理的参数) 才可发起提案 。

投票的是否成功的判断阈值:

① 参与投票的vetoken的权益票数超过token总量的30% (在发起提案时创建快照token总量数据)

② 投票通过的票数占据60%

满足以上两个条件则意味着该投票通过,反之则表示不通过。

链上治理提案的类型:

可自行在治理模板调用(安全方面需要自行考虑优化)

求描述:

正常提案在创建成功后,将在下个区块直接进入4天的投票期。在此期间,持有大于等于1token权益票数的用户都可以参与投票,4天投票期结束时,统计赞同与反对的票数,当赞同票数满足投票成功的标准时,此时提案变更为成功状态,反之则更新为失败状态。

① 在投票期结束后,提案为成功状态时,此时提案将进入为期3天的缓冲期。在缓冲期内,原有提案不可再次投票,但可以针对该提案发起否决提案的投票(发起条件跟创建提案的门槛一样),否决提案发起后将缓冲期再次延长3天,在缓冲期内否绝提案可参与投票决议。

在缓冲期结束前,如果没有否决提案发起,则正常提案将进入执行期,此时期将不允许再发起否绝提案和参与投票,等待出发链上的提案结果执行。

在缓冲期结束前,如果有否决提案发起,则缓冲期延长3天(变为6天),在此期间可以参与否决提案的投票。

当缓冲期结束时,如果否提案的赞同票数超过原有正常提案的赞同票数,此时,否决提案生效,原有提案状态变为被否决状态(失败状态),,则提案关闭,不会被执行。

当缓冲期结束时,如果否提案的赞同票数不超过原有正常提案的赞同票数,此时,否决提案不生效,原有提案将进入执行期,此时期将不允许再发起否绝提案和参与投票,等待出发链上的提案结果执行。

② 在投票期结束后,提案为失败状态时,则提案关闭,不会被执行

二、代码

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./VeToken.sol";
 

contract Vote {
      //1 投票中 ,2成功 ,3失败,4缓冲期 5 否决期 6执行期
    enum VoteStatus {uninitialized, isvoting, succeed, 
      faild,bufferTime,secondBallot,executeTime}
 
    //This field records the voting time
    uint256 constant  voteTime = 1 minutes;
    //This field records the counterview
    uint256 constant  bufferTime = 1 minutes;
    
    address public owner;
    VeToken public veToken;
    uint public voteTatola;
    uint256[] public  executeQueue;
    uint256  public  TemplateTotal;
    mapping(uint256 => VoteStruct) voteMapp;
    mapping(uint256=> GgovernanceTemplate) Template;
    mapping(uint256 => bool) public executeQueueMap;
  
    struct VoteStruct{
        uint256 totalsupply;
        uint256 voteId;
        uint256 time;
        string  voteTopic;
        address initiator;
        string  describe;
        uint256 supPopel;
        uint256 againstPopel;
        VoteStatus   status;  
        uint256   codeModel;
        uint256   value;
        mapping(address => Delegate)  VoterAddress;
        SecondBallot  svote;
    }                                                                                                                                                                                       
   
    struct SecondBallot {
        address vetoer;
        string describe;
        uint256 supPopel;
        uint256 againstPopel;
        mapping(address => Delegate)  VoterAddress;
    }

    struct Delegate {
        // If true, the voter has voted.。
        bool voted;  
        address[] bailor;      
    }
    
    struct GgovernanceTemplate {
        string toppic;
        address targetAddress;
        string functionName;
       
    }

    modifier onlyOwner() {
        require(owner == msg.sender , "Ownable: caller is not the owner");
        _;
    }

    constructor(address _veToken){
        veToken = VeToken(_veToken);
        owner = msg.sender;
    }
  
    function createVote(
        string memory _voteTopic,
        string memory _describe,
        uint256  _codeModel,
        uint256  _valaue
         ) public {
        uint256 _totalsupply = veToken.totalSupply()/1000*50;
        require(veToken.balanceOf(msg.sender) >= _totalsupply,"veToken Less than 30 percent of the total");

        voteTatola ++;
        VoteStruct  storage _VoteStruct = voteMapp[voteTatola];
        _VoteStruct.totalsupply = _totalsupply;
        _VoteStruct.voteTopic = _voteTopic;
        _VoteStruct.voteId = voteTatola;
        _VoteStruct.time = block.timestamp + voteTime;
        _VoteStruct.initiator =msg.sender;
        _VoteStruct.describe = _describe;
        _VoteStruct.status = VoteStatus.isvoting;
        _VoteStruct.codeModel = _codeModel;
        _VoteStruct.value = _valaue;
    }

    /** 
     * @dev participate in voting
    */
    function toVote(uint256 _voteId,bool _result) public {
        uint256 weight;
        VoteStruct storage  _vote  = voteMapp[_voteId];
        require(_vote.status != VoteStatus.uninitialized,"VoteId is null");
        //In the vote
        if(_vote.status == VoteStatus.isvoting){
        require(_vote.VoterAddress[msg.sender].voted == false,"Vote before");
        require(veToken.balanceOf(msg.sender) >= 1,"veToken less than 1 ");
        require(block.timestamp <= _vote.time ,"Not within the allotted time");
       _vote.VoterAddress[msg.sender].voted = true;

        if(_result){
          if(_vote.VoterAddress[msg.sender].bailor.length != 0){
              for(uint i= 0; i< _vote.VoterAddress[msg.sender].bailor.length; ++i){
                  address deleAdd = _vote.VoterAddress[msg.sender].bailor[i];
                   weight +=veToken.balanceOf(deleAdd);
                } 
            } 
          _vote.supPopel +=veToken.balanceOf(msg.sender);
        }else{
            _vote.againstPopel += veToken.balanceOf(msg.sender);
        }
        //secondBallot
        }else if(_vote.status == VoteStatus.secondBallot) {
            require(_vote.svote.VoterAddress[msg.sender].voted == false,"Vote before");
            require(block.timestamp < _vote.time ,"Not within the allotted time");
            _vote.svote.VoterAddress[msg.sender].voted = true;
            if(_vote.VoterAddress[msg.sender].bailor.length != 0){
              for(uint i= 0; i< _vote.VoterAddress[msg.sender].bailor.length; ++i){
                  address deleAdd = _vote.VoterAddress[msg.sender].bailor[i];
                   weight +=veToken.balanceOf(deleAdd);
                } 
            } 
          _vote.svote.supPopel  += veToken.balanceOf(msg.sender);
        }else{
            _vote.svote.againstPopel += veToken.balanceOf(msg.sender);
        }                  
    }

    /** 
     * @dev You can veto a vote if you are not happy with it
    */
    function reject(uint256 _voteId,string memory _reasons) public {
        uint256 _totalsupply = veToken.totalSupply()/1000*50;
        require(veToken.balanceOf(msg.sender) >= _totalsupply,"veToken Less than 30 percent of the total");

        VoteStruct storage  _vote  = voteMapp[_voteId];
         
        require(block.timestamp >= _vote.time && block.timestamp < _vote.time + bufferTime,"Still in the voting phase");
        require(_vote.status == VoteStatus.isvoting,"Not at the voting stage");

        _vote.status =VoteStatus.secondBallot;
        _vote.svote.describe = _reasons;
        _vote.svote.vetoer = msg.sender;
        _vote.time = block.timestamp + bufferTime;
    }  
    
    /** 
     * @dev When the vote is completed, manual click to execute
    */
    function execute(uint256 _voteId)public onlyOwner() {
        VoteStruct storage  _vote  = voteMapp[_voteId];
        require(executeQueueMap[_voteId] == false,"repetitive execution");
        require(_vote.status != VoteStatus.uninitialized ,"VoteId is null");
        if(_vote.status ==  VoteStatus.isvoting){

            require(block.timestamp > _vote.time,"Still in the voting phase");
            require(_vote.againstPopel+_vote.supPopel >= _vote.totalsupply/1000*300,"votes is less than 30 percent");
            require(_vote.supPopel/(_vote.againstPopel+_vote.supPopel) * 100 >= 60,"Less than 60% of the votes passed");
          
             _execute(_voteId,_vote.codeModel,_vote.value);
            _vote.status =  VoteStatus.succeed ;                     
       } else  if(_vote.status == VoteStatus.secondBallot){
             require(block.timestamp >= _vote.time,"Still in the voting phase");
            require(_vote.svote.supPopel >= _vote.supPopel,"The vote passed with fewer votes than the original");
           
            _execute(_voteId,_vote.codeModel,_vote.value);
            _vote.status = VoteStatus.succeed;  
        }     
    } 
    
    function _execute(uint256 _voteId,uint256 _codeModel,uint256 _value)private onlyOwner(){
       executeQueue.push(_voteId);
       executeQueueMap[_voteId] = true;
       address tarGet = Template[_codeModel].targetAddress;
       require(tarGet != address(0) ,"Governance Template is null");
       _governanceTemplate(_codeModel,_value);
    }   

    function _getTemplate(uint256 _codeModel)public view  returns(GgovernanceTemplate [] memory re){
        GgovernanceTemplate []  memory arr =new GgovernanceTemplate [] (TemplateTotal);
        for(uint i =0; i<TemplateTotal; ++i){
                arr[i] = Template[i] ;
        }
        return arr ;
    }
  
    function _governanceTemplate(uint256 num,uint256  valaue) private {
        address tarGet = Template[num].targetAddress;
        string memory functionName = Template[num].functionName;
        (bool _ok, bytes memory returnData)  = tarGet.call(abi.encodeWithSignature(functionName,valaue));
        require(_ok, string(returnData));
    }

    /** 
     * @dev Entrust someone else to vote
    */
    function delegateTo(uint256 _voteId,address _to)public {
        VoteStruct storage  _vote  = voteMapp[_voteId];

        require(_vote.VoterAddress[msg.sender].voted == false,"Have voted");
        require(_to != msg.sender ,"can't delegate to yourself");
        require(veToken.balanceOf(msg.sender) > 0,"There is no token ");

        _vote.VoterAddress[_to].bailor.push(msg.sender);
        _vote.VoterAddress[msg.sender].voted = true;
        _vote.svote.VoterAddress[_to].bailor.push(msg.sender);
        _vote.svote.VoterAddress[msg.sender].voted =true;
   }

    function setGovernanceTemplate(string memory _topic,address _targetAddress,string memory  _functionName) public onlyOwner(){
            GgovernanceTemplate storage _Template = Template[TemplateTotal] ;
            _Template.targetAddress = _targetAddress;
            _Template.functionName = _functionName;
            _Template.toppic = _topic ;
            TemplateTotal ++;
           
   }

    function getVoteStatuswithVoteId(uint256 _voteId) public view returns (uint256  status){
         VoteStruct storage  _vote  = voteMapp[_voteId];
         return uint256(_vote.status);
    }
 
    function getVoteDetailwithVoteId(uint256 _voteId) public view returns(
        string memory voteTopic,
        string memory describe,
        address initiator)
        {
         VoteStruct storage  _vote  = voteMapp[_voteId];
         return  (_vote.voteTopic,_vote.describe,_vote.initiator);
    }

    /** 
     * @dev calculates the current winning proposal based on all the current votes
     */
    function winningProposal(uint256 _voteId) public view returns(uint256 forVote,
        uint256 againstVote,
        uint256 forVote2,
        uint256 againstVote2,
        uint256 time)
        {
        VoteStruct storage  _vote  = voteMapp[_voteId];
        forVote = _vote.supPopel;
        againstVote = _vote.againstPopel;
        forVote2 = _vote.svote.supPopel;
        againstVote2 = _vote.svote.againstPopel;
        time =_vote.time;
    }
  }

总结

以上只是部分思路代码,需要具体的完整代码和了解更多需求交流,可联系我luo425116243

猜你喜欢

转载自blog.csdn.net/qq_33842966/article/details/125590372