github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/contract/ballot/Ballot.sol (about)

     1  pragma solidity >=0.4.22;
     2  
     3  /// @title Voting with delegation.
     4  contract Ballot {
     5      // This declares a new complex type which will
     6      // be used for variables later.
     7      // It will represent a single voter.
     8      struct Voter {
     9          uint weight; // weight is accumulated by delegation
    10          bool voted;  // if true, that person already voted
    11          address delegate; // person delegated to
    12          uint vote;   // index of the voted proposal
    13      }
    14  
    15      // This is a type for a single proposal.
    16      struct Proposal {
    17          bytes32 name;   // short name (up to 32 bytes)
    18          uint voteCount; // number of accumulated votes
    19      }
    20  
    21      address public chairperson;
    22  
    23      // This declares a state variable that
    24      // stores a `Voter` struct for each possible address.
    25      mapping(address => Voter) public voters;
    26  
    27      // A dynamically-sized array of `Proposal` structs.
    28      Proposal[] public proposals;
    29  
    30      // Emit event 
    31      event NewProposal(address indexed from, bytes32 name, uint voteCount);
    32  
    33      /// Create a new ballot to choose one of `proposalNames`.
    34      constructor(bytes32[] memory proposalNames) public {
    35          chairperson = msg.sender;
    36          voters[chairperson].weight = 1;
    37  
    38          // For each of the provided proposal names,
    39          // create a new proposal object and add it
    40          // to the end of the array.
    41          for (uint i = 0; i < proposalNames.length; i++) {
    42              // `Proposal({...})` creates a temporary
    43              // Proposal object and `proposals.push(...)`
    44              // appends it to the end of `proposals`.
    45              proposals.push(Proposal({
    46                  name: proposalNames[i],
    47                  voteCount: 0
    48              }));
    49  
    50              emit NewProposal(msg.sender, proposalNames[i], 0);
    51          }
    52      }
    53  
    54      // Give `voter` the right to vote on this ballot.
    55      // May only be called by `chairperson`.
    56      function giveRightToVote(address voter) public {
    57          // If the first argument of `require` evaluates
    58          // to `false`, execution terminates and all
    59          // changes to the state and to Ether balances
    60          // are reverted.
    61          // This used to consume all gas in old EVM versions, but
    62          // not anymore.
    63          // It is often a good idea to use `require` to check if
    64          // functions are called correctly.
    65          // As a second argument, you can also provide an
    66          // explanation about what went wrong.
    67          require(
    68              msg.sender == chairperson,
    69              "Only chairperson can give right to vote."
    70          );
    71          require(
    72              !voters[voter].voted,
    73              "The voter already voted."
    74          );
    75          require(voters[voter].weight == 0);
    76          voters[voter].weight = 1;
    77      }
    78  
    79      /// Delegate your vote to the voter `to`.
    80      function delegate(address to) public {
    81          // assigns reference
    82          Voter storage sender = voters[msg.sender];
    83          require(!sender.voted, "You already voted.");
    84  
    85          require(to != msg.sender, "Self-delegation is disallowed.");
    86  
    87          // Forward the delegation as long as
    88          // `to` also delegated.
    89          // In general, such loops are very dangerous,
    90          // because if they run too long, they might
    91          // need more gas than is available in a block.
    92          // In this case, the delegation will not be executed,
    93          // but in other situations, such loops might
    94          // cause a contract to get "stuck" completely.
    95          while (voters[to].delegate != address(0)) {
    96              to = voters[to].delegate;
    97  
    98              // We found a loop in the delegation, not allowed.
    99              require(to != msg.sender, "Found loop in delegation.");
   100          }
   101  
   102          // Since `sender` is a reference, this
   103          // modifies `voters[msg.sender].voted`
   104          sender.voted = true;
   105          sender.delegate = to;
   106          Voter storage delegate_ = voters[to];
   107          if (delegate_.voted) {
   108              // If the delegate already voted,
   109              // directly add to the number of votes
   110              proposals[delegate_.vote].voteCount += sender.weight;
   111          } else {
   112              // If the delegate did not vote yet,
   113              // add to her weight.
   114              delegate_.weight += sender.weight;
   115          }
   116      }
   117  
   118      /// Give your vote (including votes delegated to you)
   119      /// to proposal `proposals[proposal].name`.
   120      function vote(uint proposal) public {
   121          Voter storage sender = voters[msg.sender];
   122          require(sender.weight != 0, "Has no right to vote");
   123          require(!sender.voted, "Already voted.");
   124          sender.voted = true;
   125          sender.vote = proposal;
   126  
   127          // If `proposal` is out of the range of the array,
   128          // this will throw automatically and revert all
   129          // changes.
   130          proposals[proposal].voteCount += sender.weight;
   131      }
   132  
   133      /// @dev Computes the winning proposal taking all
   134      /// previous votes into account.
   135      function winningProposal() public view
   136              returns (uint winningProposal_)
   137      {
   138          uint winningVoteCount = 0;
   139          for (uint p = 0; p < proposals.length; p++) {
   140              if (proposals[p].voteCount > winningVoteCount) {
   141                  winningVoteCount = proposals[p].voteCount;
   142                  winningProposal_ = p;
   143              }
   144          }
   145      }
   146  
   147      // Calls winningProposal() function to get the index
   148      // of the winner contained in the proposals array and then
   149      // returns the name of the winner
   150      function winnerName() public view
   151              returns (bytes32 winnerName_)
   152      {
   153          winnerName_ = proposals[winningProposal()].name;
   154      }
   155  }
   156