2022-04-26|閱讀時間 ‧ 約 15 分鐘

solidity實現voting

使用solidity實現基本的投票並且去操作功能,像是投票,發票或是委託票等。
創建contract
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/// @title Voting with delegation.
contract Voting {
   
   // 選民
   struct Voter {
       uint weight; // weight is accumulated by delegation
       bool voted;  // if true, that person already voted
       address delegate; // 被委託人 person delegated to
       uint vote;   // 投票提案的索引 index of the voted proposal
   }

   // This is a type for a single proposal.
   struct Proposal {
       string name;   // short name (up to 32 bytes)
       uint voteCount; // number of accumulated votes
   }

   address public chairperson;

   // This declares a state variable that
   // stores a `Voter` struct for each possible address.
   mapping(address => Voter) public voters;

   // A dynamically-sized array of `Proposal` structs.
   Proposal[] public proposals;

   // 為`proposalNames` 中的每個提案,創建一個新投票表決 Create a new ballot to choose one of `proposalNames`.
   constructor(string[] memory proposalNames) {
       chairperson = msg.sender;
       voters[chairperson].weight = 1;

       // 對每一提案名稱,創建一個新的Proposal並添加到array
       for (uint i = 0; i < proposalNames.length; i++) {
           // `Proposal({...})` creates a temporary
           // Proposal object and `proposals.push(...)`
           // appends it to the end of `proposals`.
           proposals.push(Proposal({
               name: proposalNames[i],
               voteCount: 0
           }));
       }
   }

   // 授權voter對這個表決進行投票,只有chairperson能調用此函數
   function giveRightToVote(address voter) external {
       // If the first argument of `require` evaluates
       // to `false`, execution terminates and all
       // changes to the state and to Ether balances
       // are reverted.
       // This used to consume all gas in old EVM versions, but
       // not anymore.
       // It is often a good idea to use `require` to check if
       // functions are called correctly.
       // As a second argument, you can also provide an
       // explanation about what went wrong.
       require(
           msg.sender == chairperson,
           "Only chairperson can give right to vote."
       );
       require(
           !voters[voter].voted,
           "The voter already voted."
       );
       require(voters[voter].weight == 0);
       voters[voter].weight = 1;
   }

   /// 將您的投票委託給選民 voter `to`.
   function delegate(address to) external {
       // assigns reference
       Voter storage sender = voters[msg.sender];
       require(!sender.voted, "You already voted.");

       require(to != msg.sender, "Self-delegation is disallowed.");

       // Forward the delegation as long as
       // `to` also delegated.
       // In general, such loops are very dangerous,
       // because if they run too long, they might
       // need more gas than is available in a block.
       // In this case, the delegation will not be executed,
       // but in other situations, such loops might
       // cause a contract to get "stuck" completely.
       while (voters[to].delegate != address(0)) {
           to = voters[to].delegate;

           // We found a loop in the delegation, not allowed.
           require(to != msg.sender, "Found loop in delegation.");
       }

       // Since `sender` is a reference, this modifies `voters[msg.sender].voted`
       sender.voted = true;
       sender.delegate = to;
       Voter storage delegate_ = voters[to];
       if (delegate_.voted) {
           // If the delegate already voted,
           // directly add to the number of votes
           proposals[delegate_.vote].voteCount += sender.weight;
       } else {
           // If the delegate did not vote yet,
           // add to her weight.
           delegate_.weight += sender.weight;
       }
   }

   /// 把你的票(包括委託給你的票),投給提案`proposals[proposal].name`.
   function vote(uint proposal) external {
       Voter storage sender = voters[msg.sender];
       require(sender.weight != 0, "Has no right to vote");
       require(!sender.voted, "Already voted.");
       sender.voted = true;
       sender.vote = proposal;

       // If `proposal` is out of the range of the array,
       // this will throw automatically and revert all
       // changes.
       proposals[proposal].voteCount += sender.weight;
   }

   /// @dev Computes the winning proposal taking all
   /// previous votes into account.
   function winningProposal() public view
           returns (uint winningProposal_)
   {
       uint winningVoteCount = 0;
       for (uint p = 0; p < proposals.length; p++) {
           if (proposals[p].voteCount > winningVoteCount) {
               winningVoteCount = proposals[p].voteCount;
               winningProposal_ = p;
           }
       }
   }

   // Calls winningProposal() function to get the index
   // of the winner contained in the proposals array and then
   // returns the name of the winner
   function winnerName() external view
           returns (string memory winnerName_)
   {
       winnerName_ = proposals[winningProposal()].name;
   }
}

測試

啟動節點模擬
使用Remix
Compile
Deploy合約
Output:

測試環節

測試Proposals
結果
chairperson
chairperson(0xac55502aF00E1F405f115C17F45D43c36C47F7C3)給其他人票:
其他也是: 0xF197FFB0422d7026809210826325bfa719105251 0x7CB7374abE10dDd7e16b3dfe5E68623DAb1b13F3 0x9AD3eB9367f6B123a843AcF946e4D360c445FB9d
測試非Chairperson給其他人票:
出現ERROR:
Output
測試Voter:
接著切換帳戶: 0xF197FFB0422d7026809210826325bfa719105251 將自己的票委託給他人(0x7CB7374abE10dDd7e16b3dfe5E68623DAb1b13F3):
使用看Voter函數來觀察:
測試投票: 0xF197FFB0422d7026809210826325bfa719105251
(我們把票給別人了,無法投,並且先看一下propsal)
能看到沒有投成功
切換成其他人開始投票: 0x7CB7374abE10dDd7e16b3dfe5E68623DAb1b13F3 0x9AD3eB9367f6B123a843AcF946e4D360c445FB9d 執行vote
接著看proposal(Alice, Bob):
呼叫WINNERNAME和WINNINGPROPOSAL
合約內的東西都測試完畢
Reference:

歡迎大家來我的Blog看:
1.Blog: 文章連結
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.