diff --git a/solidity/Ballot.sol b/solidity/Ballot.sol index fce11edd69255d526404bf11f861e50189f49cfc..d858051e323608757c40446cef6dcad3f8defb1c 100644 --- a/solidity/Ballot.sol +++ b/solidity/Ballot.sol @@ -65,38 +65,42 @@ contract Ballot bool countNonvotesAsBlanks, uint maxVotesPerVoter, uint maxVotesPerProposal, - bytes32[] memory proposalNames + bytes32[] memory proposalNames, + address[] memory voters ) public { - require( voteBefore > now ); - require( percentOfRegisteredVotersReqToBeValid <= 100000000 ); - require( percentOfVotesCastToWin <= 100000000 ); + require(voters.length > 0, "Debe registrar al menos un votante."); + require(voteBefore > now, "La fecha de cierre de la votación tiene que ser posterior a hoy"); + require(percentOfRegisteredVotersReqToBeValid <= 100000000, "El porcentaje de votantes tiene que ser menor a 100"); + require(percentOfVotesCastToWin <= 100000000, "El porcentaje de votos para ganar tiene que ser menor a 100"); // chairman can not automatically vote. // Chairman must giveRightToVote to himself if // he wants to vote. - ballotChairman = tx.origin; - ballotTitle = title; - ballotVoteStarts = voteStarts; - ballotVoteBefore = voteBefore; - ballotPercentOfRegisteredVotersReqToBeValid = percentOfRegisteredVotersReqToBeValid; - ballotPercentOfVotesCastToWin = percentOfVotesCastToWin; - ballotCountNonvotesAsBlanks = countNonvotesAsBlanks; - ballotMaxVotesPerVoter = maxVotesPerVoter; - ballotMaxVotesPerProposal = maxVotesPerProposal; + ballotChairman = tx.origin; + 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; - uint idp = 0; - proposalListLength = 0; + uint incoming = proposalNames.length; + uint i = 0; + uint idp = 0; + proposalListLength = 0; while ( i < incoming ) { - idp = proposalList.push( proposalNames[i] ); + idp = proposalList.push(proposalNames[i]); proposalListLength++; votedProposalList[idp] = 0; i++; } + giveRightToVote(voters); + } /// @notice Give 'voters' the right to vote on this ballot. @@ -105,32 +109,32 @@ contract Ballot public { // May only be called by chairman. - require( msg.sender == ballotChairman ); - require( ballotVoteBefore > now ); - uint len = voters.length; - uint i = 0; + require(msg.sender == ballotChairman || tx.origin == ballotChairman, "Solo el creador de la votación puede agregar votantes."); + require(ballotVoteBefore > now, "La votación ha finalizado, no se puede agregar votantes."); + uint len = voters.length; + uint i = 0; while ( i < len ) { - address voter = voters[i]; - uint idx = voterMap[voter]; + address voter = voters[i]; + uint idx = voterMap[voter]; /// @dev Can't add any voters more than once. - require( idx == 0 ); + require(idx == 0, "No puede haber votantes duplicados"); /// @dev Not even the voter listed in [0] can vote more than once. if ( voterList.length > 0 ) - require( voterList[0].voter != voter ); + require(voterList[0].voter != voter, "No puede haber votantes duplicados"); /// @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( + idx = voterList.push( Voter( { - voter: voter, - votedProposals: emptyuintlist, - votesLeft: ballotMaxVotesPerVoter + voter: voter, + votedProposals: emptyuintlist, + votesLeft: ballotMaxVotesPerVoter } ) ) - 1; - voterMap[voter] = idx; + voterMap[voter] = idx; i++; } } @@ -140,7 +144,7 @@ contract Ballot view returns( int ) { - uint idx = voterMap[voter]; + uint idx = voterMap[voter]; if ( idx > 0 ) return int(idx); if ( voterList[0].voter == voter ) @@ -151,15 +155,15 @@ contract Ballot function vote( uint proposal ) public { - require( proposal < proposalList.length ); - require( ballotVoteStarts <= now ); - require( ballotVoteBefore > now ); - int idx = getVoterIdx( msg.sender ); - require( idx > -1 ); - uint uidx = uint( idx ); - require( voterList[uidx].votesLeft > 0 ); - uint proposalCounter = 0; - uint i = voterList[uidx].votedProposals.length; + require(proposal < proposalList.length, "No existe la opción de votación elegida."); + require(ballotVoteStarts <= now, "La votación no ha comenzado aún."); + require(ballotVoteBefore > now, "La votacÃon ha finalizado."); + int idx = getVoterIdx(msg.sender); + require(idx > -1, "No tiene permisos para votar."); + uint uidx = uint(idx); + require(voterList[uidx].votesLeft > 0, "Ya ha agotado la cantidad de votos asignada."); + uint proposalCounter = 0; + uint i = voterList[uidx].votedProposals.length; while ( i > 0 ) { i--; @@ -167,9 +171,9 @@ contract Ballot proposalCounter++; } - require( proposalCounter < ballotMaxVotesPerProposal ); + require(proposalCounter < ballotMaxVotesPerProposal, "Se ha agotado la cantidad de votos para la opción elegida."); voterList[uidx].votesLeft--; - voterList[uidx].votedProposals.push( proposal ); + voterList[uidx].votedProposals.push(proposal); votedProposalList[proposal]++; } @@ -188,7 +192,7 @@ contract Ballot return; if ( ballotVoteStarts <= now ) return; - selfdestruct( ballotChairman ); + selfdestruct(ballotChairman); } } @@ -204,7 +208,8 @@ contract NewBallot bool countNonvotesAsBlanks, uint maxVotesPerVoter, uint maxVotesPerProposal, - bytes32[] memory proposalNames + bytes32[] memory proposalNames, + address[] memory voters ) public { @@ -219,7 +224,8 @@ contract NewBallot countNonvotesAsBlanks, maxVotesPerVoter, maxVotesPerProposal, - proposalNames + proposalNames, + voters )); emit contratocreado(ballot); } diff --git a/web/dist/js/vendor/abi.js b/web/dist/js/vendor/abi.js index 1e5c383374723895c9f97b6e43ab613979fb26ff..3715006e5498a70ec3b7131f262b32a1fe593c85 100644 --- a/web/dist/js/vendor/abi.js +++ b/web/dist/js/vendor/abi.js @@ -329,6 +329,10 @@ var abiBallot = [ { "name": "proposalNames", "type": "bytes32[]" + }, + { + "name": "voters", + "type": "address[]" } ], "payable": false, @@ -377,6 +381,10 @@ var abiNew = [ { "name": "proposalNames", "type": "bytes32[]" + }, + { + "name": "voters", + "type": "address[]" } ], "name": "newBallot", diff --git a/web/dist/js/vendor/ballot.js b/web/dist/js/vendor/ballot.js index 1ff997efefb326cb31169034d0486555d90b846e..b1c8c3e7e8132aaa3e3ce7975976d40235918383 100644 --- a/web/dist/js/vendor/ballot.js +++ b/web/dist/js/vendor/ballot.js @@ -22,13 +22,14 @@ var netnames = { var mainaddr = { '5445': '0xe5bf7c3e8aa529e42fbd99428137b68db75d85f9', '47525974938': '0xe3e08934b6fa0b68972c08e0f545cee31ed039c6', - '5777': '0x99845b94609F0285527ee11a0C9664532ddE0428' + '5777': '0xB1427B0147175ea6c6e35eA8c258b7e844ECa66A' }; -/// Ballot address: 0x999d06fcc0a2380e0e0038b6d186275e754dd2b4 -var ballot_keccak3 = '0x27fdf9b1c0d27b6143d49147cf30b3f7f09ac1c2cb2b7115a1633e0b8551c6a9'; var contract_event; +// Deprecated +var ballot_keccak3 = '0x27fdf9b1c0d27b6143d49147cf30b3f7f09ac1c2cb2b7115a1633e0b8551c6a9'; + window.addEventListener('load', page_loaded); function addchild(parent, childtype, childText, attributes) { @@ -397,7 +398,7 @@ async function ask_for_ballot_details() { }); } -async function nueva_votacion(arguments,proposals) { +async function nueva_votacion(arguments, proposals, voters) { if (mainaddr[netid] == undefined) return; @@ -413,14 +414,14 @@ async function nueva_votacion(arguments,proposals) { if (!contract) return; - console.log(arguments,proposals); + console.log(arguments, proposals, voters); try { contract_event = contract.contratocreado(); contract_event.watch(function(error, result){ if (!error){ console.log(result); - alertarSuccess('Ballot was successfuly created. Here, its address: ' + result.args.contrato); // the contract address + alertarSuccess('La votación se creó correctamente, tome nota de su dirección: ' + result.args.contrato); // the contract address }else{ alertar(error); } @@ -428,7 +429,7 @@ async function nueva_votacion(arguments,proposals) { contract.newBallot.sendTransaction( arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], - proposals, { gas: 2111000 }, contract_created + proposals, voters, { gas: 2111000 }, contract_created ); } catch (error) @@ -499,6 +500,32 @@ async function ver_votacion2(addr, code) { } } +function getTransactionReceiptMined(txHash, interval) { + const self = window.web3.eth; + const transactionReceiptAsync = function(resolve, reject) { + self.getTransactionReceipt(txHash, (error, receipt) => { + if (error) { + reject(error); + } else if (receipt == null) { + setTimeout( + () => transactionReceiptAsync(resolve, reject), + interval ? interval : 500); + } else { + resolve(receipt); + } + }); + }; + + if (Array.isArray(txHash)) { + return Promise.all(txHash.map( + oneTxHash => self.getTransactionReceiptMined(oneTxHash, interval))); + } else if (typeof txHash === "string") { + return new Promise(transactionReceiptAsync); + } else { + throw new Error("Invalid Type: " + txHash); + } +}; + async function votar(addr, proposal){ await access_accounts(); return new Promise (function (resolve, reject) { @@ -516,13 +543,24 @@ async function votar(addr, proposal){ reject("No existe un contrato en esa dirección"); } + /*contract.vote.sendTransaction(proposal, { gas: 2111000 }, function (error, result) { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + */ + contract.vote.sendTransaction(proposal, { gas: 2111000 }, function (error, result) { if (error) { reject(error); } else { + var receipt = getTransactionReceiptMined(result, 1); resolve(result); } }); + }); @@ -543,10 +581,8 @@ async function resultados(addr){ var results = []; for(var i=0;i<proposalLength;i++){ results[i] = await getProposalResults(contract, i); - /*contract.votedProposalList.call(i, { gas: 2111000 }, function(error, rcpt){ - getProposalResults(error, rcpt, totalVotes, i); - });*/ } + console.log("Total votos:", totalVotes.toString(10)); showProposalResults(totalVotes, proposalLength, results); //close_alertar(); @@ -655,9 +691,9 @@ function getProposalResults(contract, option){ }); } -async function showProposalResults(totalVotes, proposalLength, results){ +async function showProposalResults(_totalVotes, proposalLength, results){ for(var i = 0; i<proposalLength; i++){ - var percentage = (totalVotes.toString(10) > 0) ? results[i].toString(10) / totalVotes.toString(10) * 100 : 0; + var percentage = (_totalVotes.toString(10) > 0) ? results[i].toString(10) / _totalVotes.toString(10) * 100 : 0; console.log(i, percentage); $('#result_'+i).text(percentage.toFixed(2)); diff --git a/web/dist/smartNewvote.html b/web/dist/smartNewvote.html index 410f4001ad40674aeeb4ed8a31c4a4ec2d550b84..334f35cecee014813ab17dda13c3fc3413d8cd6d 100644 --- a/web/dist/smartNewvote.html +++ b/web/dist/smartNewvote.html @@ -303,7 +303,7 @@ }); //console.log(arguments,proposalNames,voters); - nueva_votacion(arguments,proposalNames); + nueva_votacion(arguments, proposalNames, voters); } $("form").validate({ diff --git a/web/dist/smartVotar.html b/web/dist/smartVotar.html index 2b5b0c266971aeb6ba712004b238296d026bb12c..414c31c64adb3957b351b70943230a1d0b5e98b2 100644 --- a/web/dist/smartVotar.html +++ b/web/dist/smartVotar.html @@ -144,10 +144,9 @@ $("#contract_address").text(input_address); ver_votacion(input_address); - //TEST - /*$("form").hide(); - $(".resultados").show(); - resultados(input_address);*/ + //TEST showing the results bargraph + //$(".resultados").show(); + //resultados(input_address); } function viewVotacion(){ @@ -179,7 +178,9 @@ } }catch (error){ - alertar(error); + var message = error.message.substring(error.message.indexOf('revert') + 7); + if(message.length < 1){message = error;} + alertar(message); $("#voterow .btn").show(); return false; }