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