pragma solidity >=0.4.22 <0.7.0; pragma experimental ABIEncoderV2; import "./Time.sol"; import "./Provable.sol"; contract Quadratic is usingProvable{ string public contractType = 'quadratic-voting'; struct Voter{ bool registered; uint tokensLeft; uint[] votes; } struct Proposal{ string name; string description; uint voteCount; } event proposalAdded( Proposal proposal ); event voterRegistered( address voterAddress ); event voted( address voterAddress ); event LogQueryResult(string price); event LogNewProvableQuery(string description); uint public registrationStartTimeStamp; uint public registrationEndTimeStamp; uint public votingStartTimeStamp; uint public votingEndTimeStamp; address public chairPerson; mapping(address => Voter) public voters; Proposal[] public proposals; uint public tokensAllowed; constructor(address admin, uint tokensAllowance, string memory registrationStart, string memory registrationEnd, string memory votingStart, string memory votingEnd) public { chairPerson = admin; tokensAllowed = tokensAllowance; registrationStartTimeStamp = Time.ToTimeStamp(registrationStart); registrationEndTimeStamp = Time.ToTimeStamp(registrationEnd); votingStartTimeStamp = Time.ToTimeStamp(votingStart); votingEndTimeStamp = Time.ToTimeStamp(votingEnd); } function getProposalNumber() public view returns(uint) { return proposals.length; } function addProposal(string memory name, string memory desc) public restricted registrationOpen{ Proposal memory proposal; proposal = Proposal({name: name, description: desc, voteCount: 0}); proposals.push(proposal); emit proposalAdded(proposal); } function getElectionPhase() public view returns(bool, bool, bool, bool){ return (Time._now() > registrationStartTimeStamp, Time._now() > registrationEndTimeStamp, Time._now() > votingStartTimeStamp, Time._now() > votingEndTimeStamp); } function registrationStarted() public view returns(bool){ return Time._now() > registrationStartTimeStamp; } function registrationEnded() public view returns(bool){ return Time._now() > registrationEndTimeStamp; } function votingStarted() public view returns(bool) { return Time._now() > votingStartTimeStamp; } function votingEnded() public view returns(bool) { return Time._now() > votingEndTimeStamp; } function currentTime() public view returns(uint) { return now; } function register(string memory voterAddress, string memory mobileNumber, string memory contractName, string memory imageUrl) public payable registrationOpen { if (provable_getPrice("URL") > address(this).balance) { emit LogNewProvableQuery("Provable query was NOT sent, please add some ETH to cover for the query fee"); } else{ // "\"0x0a6e4f08E057AE4ed3E2F4F23a628B9c187EC243\"" // "\"01015740042\"" // "\"https://www.egypttoday.com/images/larg/65917.jpg\"" bytes memory a = bytes("{\"address\": "); bytes memory b = bytes(voterAddress); bytes memory c = bytes(", \"mobileNumber\": "); bytes memory d = bytes(mobileNumber); bytes memory e = getContractBytes(contractName); bytes memory f = bytes("\"https://res.cloudinary.com/dyanfi1fh/image/upload/v1588534192/"); bytes memory ff = bytes(imageUrl); bytes memory g = bytes("\"}"); string memory abc = new string(a.length + b.length + c.length + d.length + e.length + f.length + ff.length + g.length); bytes memory data = bytes(abc); uint k = 0; for (uint i = 0; i < a.length; i++) data[k++] = a[i]; for (uint i = 0; i < b.length; i++) data[k++] = b[i]; for (uint i = 0; i < c.length; i++) data[k++] = c[i]; for (uint i = 0; i < d.length; i++) data[k++] = d[i]; for (uint i = 0; i < e.length; i++) data[k++] = e[i]; for (uint i = 0; i < f.length; i++) data[k++] = f[i]; for (uint i = 0; i < ff.length; i++) data[k++] = ff[i]; for (uint i = 0; i < g.length; i++) data[k++] = g[i]; // string memory data = '{"address": "0xb158b49644896fd23fd044a8f086181627571eb6", "mobileNumber": "01015740042", "imageUrl": "https://i.imgur.com/k2XWprH.jpg?1"}'; string memory queryData = string(data); emit LogNewProvableQuery("Provable query was sent, standing by for the answer..."); provable_query("URL", "json(https://ancient-anchorage-24374.herokuapp.com/verify).result", queryData); } } function __callback ( bytes32 _myid, string memory _result ) override public { require(msg.sender == provable_cbAddress()); emit LogQueryResult(_result); string memory result = _result; // moot = 'd5allt __callback'; string memory queryResult = substring(result, 0, 4); if(keccak256(abi.encodePacked((queryResult))) == keccak256(abi.encodePacked(("True")))){ string memory voterAddress = substring(result, 4, bytes(result).length); address ad = parseAddress(voterAddress); Voter storage voter = voters[ad]; voter.registered = true; voter.tokensLeft = tokensAllowed; emit voterRegistered(msg.sender); } } function vote(uint proposal) public registered votingOpen{ Voter storage sender = voters[msg.sender]; require(sender.tokensLeft != 0, "No Tokens Left"); uint proposalVotes = 0; for(uint i=0;i<sender.votes.length;i++){ if(sender.votes[i] == proposal){ proposalVotes++; } } uint prop1 = proposalVotes + 1; uint tokensRequired = (prop1 * prop1) - (proposalVotes * proposalVotes); require(tokensRequired <= sender.tokensLeft, "You don't have enough tokens to perform this operation"); sender.votes.push(proposal); sender.tokensLeft -= tokensRequired; proposals[proposal].voteCount++; emit voted(msg.sender); } function hasEnoughTokens(address voter, uint proposal) public view returns(bool){ Voter storage sender = voters[voter]; uint proposalVotes = 0; for(uint i=0;i<sender.votes.length;i++){ if(sender.votes[i] == proposal){ proposalVotes++; } } uint prop1 = proposalVotes + 1; uint tokensRequired = (prop1 * prop1) - (proposalVotes * proposalVotes); if(tokensRequired > sender.tokensLeft){ return false; } else{ return true; } } function winningProposal() public view votingOver returns (uint winningProposal_) { uint winningVoteCount = 0; for (uint p = 0; p < proposals.length; p++) { if (proposals[p].voteCount > winningVoteCount) { winningVoteCount = proposals[p].voteCount; winningProposal_ = p; } } } function winnerName() public view votingOver returns (string memory winnerName_) { winnerName_ = proposals[winningProposal()].name; } function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { return Time.timestampToDateTime(timestamp); } function substring(string memory str, uint startIndex, uint endIndex) public pure returns (string memory) { bytes memory strBytes = bytes(str); bytes memory result = new bytes(endIndex-startIndex); for(uint i = startIndex; i < endIndex; i++) { result[i-startIndex] = strBytes[i]; } return string(result); } function parseAddress(string memory _a) internal pure returns (address _parsedAddress) { bytes memory tmp = bytes(_a); uint160 iaddr = 0; uint160 b1; uint160 b2; for (uint i = 2; i < 2 + 2 * 20; i += 2) { iaddr *= 256; b1 = uint160(uint8(tmp[i])); b2 = uint160(uint8(tmp[i + 1])); if ((b1 >= 97) && (b1 <= 102)) { b1 -= 87; } else if ((b1 >= 65) && (b1 <= 70)) { b1 -= 55; } else if ((b1 >= 48) && (b1 <= 57)) { b1 -= 48; } if ((b2 >= 97) && (b2 <= 102)) { b2 -= 87; } else if ((b2 >= 65) && (b2 <= 70)) { b2 -= 55; } else if ((b2 >= 48) && (b2 <= 57)) { b2 -= 48; } iaddr += (b1 * 16 + b2); } return address(iaddr); } function getContractBytes(string memory contractName) public pure returns(bytes memory){ bytes memory a = bytes(", \"contractName\": "); bytes memory b = bytes(contractName); bytes memory c = bytes(", \"imageUrl\": "); string memory abc = new string(a.length + b.length + c.length); bytes memory data = bytes(abc); uint k = 0; for (uint i = 0; i < a.length; i++) data[k++] = a[i]; for (uint i = 0; i < b.length; i++) data[k++] = b[i]; for (uint i = 0; i < c.length; i++) data[k++] = c[i]; return data; } modifier restricted(){ require( msg.sender == chairPerson, "Only chairperson can add proposals" ); _; } modifier registered() { require(voters[msg.sender].registered,"Only Registerd voters are allowed to vote"); _; } modifier registrationOpen() { require(Time._now() > registrationStartTimeStamp && Time._now() < registrationEndTimeStamp , "Registration closed"); _; } modifier votingOpen() { require(Time._now() > votingStartTimeStamp && Time._now() < votingEndTimeStamp , "Voting closed"); _; } modifier votingOver(){ require(Time._now() > votingEndTimeStamp , "Voting is still open"); _; } }
0.4.18