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
// vim:syntax:filetype=javascript:ai:sm
// vim:expandtab:backspace=indent,eol,start:softtabstop=4
pragma solidity ^0.4.25;
/// @title Voting with delegation.
contract Ballot {
// This declares a new complex type which will
// be used for variables later.
// It will represent a single voter.
struct Voter {
/// @title A single ballot contract which allows certain
/// @title accounts to vote (one single vote).
/// @author soliditycookbook.com & Robert Martin-Legene
/// @notice A Chairman will deploy the contract, setting up initial
/// @notice conditions. Before the voting period starts the Chairman
/// @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;
int vote; // index of the voted proposal or -1 if not voted
}
// 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;
uint[] votedProposals;
uint votesLeft;
}
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;
mapping( address => uint ) public voterMap;
Voter[] public voterList;
uint public numvoters;
Proposal[] public proposalList;
uint public numproposals;
/// Create a new ballot to choose one of `proposalNames`.
/// @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).
/// @param title Name of the things being voted for.
/// @param voteStarts Time in seconds (since Unix Epoch) when the voting starts (note that voters must be defined before voting starts).
/// @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.
/// @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.
/// @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.
/// @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(
string ballotTitle,
string title,
uint voteStarts,
uint voteBefore,
uint percentOfRegisteredVotersReqToBeValid,
uint percentOfVotesCastToWin,
bool countNonvotesAsBlanks,
uint maxVotesPerVoter,
uint maxVotesPerProposal,
bytes32[] proposalNames
)
public
......@@ -72,61 +68,63 @@ contract Ballot {
require( voteBefore > now );
require( percentOfRegisteredVotersReqToBeValid <= 100000000 );
require( percentOfVotesCastToWin <= 100000000 );
// chairman can not automatically vote. Chairman must
// giveRightToVote to himself if he wants to vote.
rules.chairman = msg.sender;
rules.title = ballotTitle;
rules.voteStarts = voteStarts;
rules.voteBefore = voteBefore;
rules.percentOfRegisteredVotersReqToBeValid = percentOfRegisteredVotersReqToBeValid;
rules.percentOfVotesCastToWin = percentOfVotesCastToWin;
rules.countNonvotesAsBlanks = countNonvotesAsBlanks;
// For each of the provided proposal names,
// create a new proposal object and add it
// to the end of the array.
numproposals = proposalNames.length;
// chairman can not automatically vote.
// Chairman must giveRightToVote to himself if
// he wants to vote.
ballotChairman = msg.sender;
ballotTitle = title;
ballotVoteStarts = voteStarts;
ballotVoteBefore = voteBefore;
ballotPercentOfRegisteredVotersReqToBeValid = percentOfRegisteredVotersReqToBeValid;
ballotPercentOfVotesCastToWin = percentOfVotesCastToWin;
ballotCountNonvotesAsBlanks = countNonvotesAsBlanks;
ballotMaxVotesPerVoter = maxVotesPerVoter;
ballotMaxVotesPerProposal = maxVotesPerProposal;
/// @dev For each of the provided proposal names,
/// @dev add it to the end of the proposalList
uint incoming = proposalNames.length;
uint i = 0;
while ( i < numproposals )
while ( i < incoming )
{
proposalList.push(
Proposal(
{
name: proposalNames[i],
voteCount: 0
}
)
);
proposalList.push( proposalNames[i] );
i++;
}
}
// Give `voter` the right to vote on this ballot.
function giveRightToVote( address voter )
/// @notice Give 'voters' the right to vote on this ballot.
/// @param voters The list of voters to add to the list of allowed voters.
function giveRightToVote( address[] voters )
public
{
// May only be called by chairman.
require( msg.sender == rules.chairman );
require( rules.voteBefore < now );
uint idx = voterMap[voter];
// Can't add voters more than once.
require( idx == 0 );
// Not even the voter listed in [0].
if ( voterList.length > 0 )
require( voterList[0].voter != voter );
// If the voter's address doesn't match, it is because
// he doesn't exist (and then we always have idx=0).
// So we push him onto the voterList.
idx = voterList.push(
Voter(
{
voter: voter,
vote: -1
}
)
) - 1;
voterMap[voter] = idx;
numvoters++;
require( msg.sender == ballotChairman );
require( ballotVoteBefore < now );
uint len = voters.length;
uint i = 0;
while ( i < len )
{
address voter = voters[i];
uint idx = voterMap[voter];
/// @dev Can't add any voters more than once.
require( idx == 0 );
/// @dev Not even the voter listed in [0] can vote more than once.
if ( voterList.length > 0 )
require( voterList[0].voter != voter );
/// @dev If the voter's address doesn't match, it is because
/// @dev he doesn't exist (and then we always have idx=0).
/// @dev So we push him onto the voterList.
idx = voterList.push(
Voter(
{
voter: voter,
votedProposals: emptyuintlist,
votesLeft: ballotMaxVotesPerVoter
}
)
) - 1;
voterMap[voter] = idx;
i++;
}
}
function getVoterIdx( address voter )
......@@ -142,24 +140,26 @@ contract Ballot {
return -1;
}
/// Give your vote to proposal `proposals[proposal].name`.
function vote( uint proposal )
public
{
require( proposal < numproposals );
require( rules.voteStarts >= now );
require( rules.voteBefore < now );
require( proposal < proposalList.length );
require( ballotVoteStarts >= now );
require( ballotVoteBefore < now );
int idx = getVoterIdx( msg.sender );
require( idx > -1 );
uint uidx = uint( idx );
int formervote = voterList[uidx].vote;
require( formervote != int(proposal) );
if ( formervote > -1 )
require( voterList[uidx].votesLeft > 0 );
uint proposalCounter = 0;
uint i = voterList[uidx].votedProposals.length;
while ( i > 0 )
{
// He changed his vote - this is normal for politicians, too.
proposalList[ uint(formervote) ].voteCount--;
i--;
if ( voterList[uidx].votedProposals[i] == proposal )
proposalCounter++;
}
proposalList[ proposal ].voteCount++;
voterList[ uidx ].vote = int(proposal);
require( proposalCounter < ballotMaxVotesPerProposal );
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