Skip to content
Snippets Groups Projects
Commit 3f05b145 authored by Robert Martin-Legene's avatar Robert Martin-Legene
Browse files

Ballot ahora es mucho mas util

parent 2c6119e1
No related branches found
No related tags found
No related merge requests found
// Basado en https://soliditycookbook.com/voting // Basado en https://soliditycookbook.com/voting
// vim:syntax:filetype=javascript:ai:sm // vim:syntax:filetype=javascript:ai:sm
// vim:expandtab:backspace=indent,eol,start:softtabstop=4 // vim:expandtab:backspace=indent,eol,start:softtabstop=4
pragma solidity ^0.4.25; pragma solidity ^0.4.25;
/// @title Voting with delegation. /// @title A single ballot contract which allows certain
contract Ballot { /// @title accounts to vote (one single vote).
// This declares a new complex type which will /// @author soliditycookbook.com & Robert Martin-Legene
// be used for variables later. /// @notice A Chairman will deploy the contract, setting up initial
// It will represent a single voter. /// @notice conditions. Before the voting period starts the Chairman
struct Voter { /// @notice must also tell the contract who is allowed to vote.
contract Ballot
{
/// @dev This is a struct for a single voter.
/// @dev Voter.vote is the index of the voted proposal or -1 if
/// @dev the account has not voted yet.
struct Voter
{
address voter; address voter;
int vote; // index of the voted proposal or -1 if not voted uint[] votedProposals;
} uint votesLeft;
// This is a type for a single proposal.
struct Proposal {
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
struct Votingrules {
string title;
address chairman;
uint voteStarts;
uint voteBefore;
// A NOTE ON PERCENTAGES
// At present floats do not exist. Since we merely use
// our floats to later present to the outside world,
// and then let them handle the math, this scenario will
// be used:
//
// A percentage will be multiplied with one million. Thus:
// 100% is represented as 100 million. I.e. "100000000".
// 2/3 is represented as "67777778" (see note later on
// two-thirds
// Which percentage of the registered voters must
// vote in order for the vote to be considered valid.
// e.g. 0
uint percentOfRegisteredVotersReqToBeValid;
// Which percentage of the cast votes are required
// for the motion/title to pass?
// MAJORITY VOTE:
// specify 50000001
// TWO-THIRDS:
// specify 67777777
uint percentOfVotesCastToWin;
// Counting registered voters who do not vote as blank
// votes, has the effect that it is more difficult
// to acquire the desired votes.
bool countNonvotesAsBlanks;
} }
string public ballotTitle;
address public ballotChairman;
uint public ballotVoteStarts;
uint public ballotVoteBefore;
uint public ballotPercentOfRegisteredVotersReqToBeValid;
uint public ballotPercentOfVotesCastToWin;
/// @dev Counting registered voters who do not vote as blank
/// @dev votes, has the effect that it is more difficult
/// @dev to acquire the desired votes.
bool public ballotCountNonvotesAsBlanks;
uint public ballotMaxVotesPerVoter;
uint public ballotMaxVotesPerProposal;
/// @dev The votermap points to the index(number) that the struct of the
/// @dev account can be found.
mapping( address => uint )
public voterMap;
Voter[] public voterList;
/// @dev Short name (up to 32 bytes)
bytes32[] public proposalList;
uint[] private emptyuintlist;
Votingrules public rules; /// @notice When the SC is being deployed, you must define initial conditions. When specifying percentages they are to have been multiplied with 100 million (5% is written as 5 million, since 5% is actially 0.05).
mapping( address => uint ) public voterMap; /// @param title Name of the things being voted for.
Voter[] public voterList; /// @param voteStarts Time in seconds (since Unix Epoch) when the voting starts (note that voters must be defined before voting starts).
uint public numvoters; /// @param voteBefore Time in seconds (since Unix Epoch) at/after which it is too late to vote. After this point, the Ballot is effectively readonly.
Proposal[] public proposalList; /// @param percentOfRegisteredVotersReqToBeValid How many of the registered voters must vote before the result of the Ballot can be considered valid. E.g. if 50% is set and only 40% votes, then the result of the Ballot can not be used.
uint public numproposals; /// @param percentOfVotesCastToWin How many of the votes that are cast are required to win. This is often 50.000001% ("more than half"), 67.777778% ("two thirds") or 0% (proposal with most votes - e.g. voting for most popular fruit).
/// @param countNonvotesAsBlanks Whether or not to count voters whom did not vote, as having voted blank.
/// Create a new ballot to choose one of `proposalNames`. /// @param maxVotesPerVoter How many votes can a voter cast. Often this is 1 (one).
/// @param maxVotesPerProposal How many votes one voter can cast on each proposal. I.e. can (s)he vote use all his votes on one proposal?
/// @param proposalNames 32 char "strings" listing all the options available to vote for.
constructor( constructor(
string ballotTitle, string title,
uint voteStarts, uint voteStarts,
uint voteBefore, uint voteBefore,
uint percentOfRegisteredVotersReqToBeValid, uint percentOfRegisteredVotersReqToBeValid,
uint percentOfVotesCastToWin, uint percentOfVotesCastToWin,
bool countNonvotesAsBlanks, bool countNonvotesAsBlanks,
uint maxVotesPerVoter,
uint maxVotesPerProposal,
bytes32[] proposalNames bytes32[] proposalNames
) )
public public
...@@ -72,61 +68,63 @@ contract Ballot { ...@@ -72,61 +68,63 @@ contract Ballot {
require( voteBefore > now ); require( voteBefore > now );
require( percentOfRegisteredVotersReqToBeValid <= 100000000 ); require( percentOfRegisteredVotersReqToBeValid <= 100000000 );
require( percentOfVotesCastToWin <= 100000000 ); require( percentOfVotesCastToWin <= 100000000 );
// chairman can not automatically vote. Chairman must // chairman can not automatically vote.
// giveRightToVote to himself if he wants to vote. // Chairman must giveRightToVote to himself if
rules.chairman = msg.sender; // he wants to vote.
rules.title = ballotTitle; ballotChairman = msg.sender;
rules.voteStarts = voteStarts; ballotTitle = title;
rules.voteBefore = voteBefore; ballotVoteStarts = voteStarts;
rules.percentOfRegisteredVotersReqToBeValid = percentOfRegisteredVotersReqToBeValid; ballotVoteBefore = voteBefore;
rules.percentOfVotesCastToWin = percentOfVotesCastToWin; ballotPercentOfRegisteredVotersReqToBeValid = percentOfRegisteredVotersReqToBeValid;
rules.countNonvotesAsBlanks = countNonvotesAsBlanks; ballotPercentOfVotesCastToWin = percentOfVotesCastToWin;
ballotCountNonvotesAsBlanks = countNonvotesAsBlanks;
// For each of the provided proposal names, ballotMaxVotesPerVoter = maxVotesPerVoter;
// create a new proposal object and add it ballotMaxVotesPerProposal = maxVotesPerProposal;
// to the end of the array. /// @dev For each of the provided proposal names,
numproposals = proposalNames.length; /// @dev add it to the end of the proposalList
uint incoming = proposalNames.length;
uint i = 0; uint i = 0;
while ( i < numproposals ) while ( i < incoming )
{ {
proposalList.push( proposalList.push( proposalNames[i] );
Proposal(
{
name: proposalNames[i],
voteCount: 0
}
)
);
i++; i++;
} }
} }
// Give `voter` the right to vote on this ballot. /// @notice Give 'voters' the right to vote on this ballot.
function giveRightToVote( address voter ) /// @param voters The list of voters to add to the list of allowed voters.
function giveRightToVote( address[] voters )
public public
{ {
// May only be called by chairman. // May only be called by chairman.
require( msg.sender == rules.chairman ); require( msg.sender == ballotChairman );
require( rules.voteBefore < now ); require( ballotVoteBefore < now );
uint idx = voterMap[voter]; uint len = voters.length;
// Can't add voters more than once. uint i = 0;
require( idx == 0 ); while ( i < len )
// Not even the voter listed in [0]. {
if ( voterList.length > 0 ) address voter = voters[i];
require( voterList[0].voter != voter ); uint idx = voterMap[voter];
// If the voter's address doesn't match, it is because /// @dev Can't add any voters more than once.
// he doesn't exist (and then we always have idx=0). require( idx == 0 );
// So we push him onto the voterList. /// @dev Not even the voter listed in [0] can vote more than once.
idx = voterList.push( if ( voterList.length > 0 )
Voter( require( voterList[0].voter != voter );
{ /// @dev If the voter's address doesn't match, it is because
voter: voter, /// @dev he doesn't exist (and then we always have idx=0).
vote: -1 /// @dev So we push him onto the voterList.
} idx = voterList.push(
) Voter(
) - 1; {
voterMap[voter] = idx; voter: voter,
numvoters++; votedProposals: emptyuintlist,
votesLeft: ballotMaxVotesPerVoter
}
)
) - 1;
voterMap[voter] = idx;
i++;
}
} }
function getVoterIdx( address voter ) function getVoterIdx( address voter )
...@@ -142,24 +140,26 @@ contract Ballot { ...@@ -142,24 +140,26 @@ contract Ballot {
return -1; return -1;
} }
/// Give your vote to proposal `proposals[proposal].name`.
function vote( uint proposal ) function vote( uint proposal )
public public
{ {
require( proposal < numproposals ); require( proposal < proposalList.length );
require( rules.voteStarts >= now ); require( ballotVoteStarts >= now );
require( rules.voteBefore < now ); require( ballotVoteBefore < now );
int idx = getVoterIdx( msg.sender ); int idx = getVoterIdx( msg.sender );
require( idx > -1 ); require( idx > -1 );
uint uidx = uint( idx ); uint uidx = uint( idx );
int formervote = voterList[uidx].vote; require( voterList[uidx].votesLeft > 0 );
require( formervote != int(proposal) ); uint proposalCounter = 0;
if ( formervote > -1 ) uint i = voterList[uidx].votedProposals.length;
while ( i > 0 )
{ {
// He changed his vote - this is normal for politicians, too. i--;
proposalList[ uint(formervote) ].voteCount--; if ( voterList[uidx].votedProposals[i] == proposal )
proposalCounter++;
} }
proposalList[ proposal ].voteCount++; require( proposalCounter < ballotMaxVotesPerProposal );
voterList[ uidx ].vote = int(proposal); voterList[uidx].votesLeft--;
voterList[uidx].votedProposals.push( proposal );
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment