Skip to content

Instantly share code, notes, and snippets.

@devender-yadav
Created August 6, 2018 05:02
Show Gist options
  • Save devender-yadav/1ad3c18b11861f8f90ce912b94e6c671 to your computer and use it in GitHub Desktop.
Save devender-yadav/1ad3c18b11861f8f90ce912b94e6c671 to your computer and use it in GitHub Desktop.
pragma solidity ^ 0.4 .24;
pragma experimental ABIEncoderV2;
contract DecentGov {
address public admin;
uint public proposalSubmissionStart;
uint public proposalSubmissionEnd;
uint public votingStart;
uint public votingEnd;
uint public resultDeclare;
uint public projectsStart;
uint public projectsEnd;
bool private hasResultDeclared;
uint public funds;
struct Member {
address addr;
string name;
// can be Aadhaar card for Indians
string uniqueId;
}
struct Vote {
address votedBy;
uint32 proposalId;
bool isUpvote;
}
struct Proposal {
uint proposalId;
string title;
string description;
bytes docs;
bool selected;
uint64 expectedBudget;
address submitter;
// points are upvotes - downvotes
int64 points;
}
uint[] public selectedProjectsId;
Proposal[] public proposals;
mapping(address => Member) public members;
//proposal id to votes map
mapping(uint32 => Vote[]) public proposalVotes;
mapping(address => Vote[]) memberVotes;
constructor(
uint _proposalSubmissionStart,
uint _proposalSubmissionEnd,
uint _votingStart,
uint _votingEnd,
uint _resultDeclare,
uint _projectsStart,
uint _projectsEnd,
uint _funds
) public {
require(_funds != 0 && _proposalSubmissionStart != 0 && (_proposalSubmissionEnd > _proposalSubmissionStart) && (_votingStart > _proposalSubmissionEnd) && (_votingEnd > _votingStart) && (_resultDeclare > _votingEnd) && (_projectsStart > _resultDeclare) && (_projectsEnd > _projectsStart), "invalid inputs");
proposalSubmissionStart = now + _proposalSubmissionStart;
proposalSubmissionEnd = now + _proposalSubmissionEnd;
votingStart = now + _votingStart;
votingEnd = now + _votingEnd;
resultDeclare = now + _resultDeclare;
projectsStart = now + _projectsStart;
projectsEnd = now + _projectsEnd;
hasResultDeclared = false;
funds = _funds;
admin = msg.sender;
}
function addMember(address _address, string _name, string _uniqueId) public {
require(msg.sender == admin, "only admin can add members!");
require(bytes(members[_address].name).length == 0, "member already added!");
require(votingStart > now, "Can't register now; voting has already started!");
members[_address] = Member(_address, _name, _uniqueId);
}
function addMembers(address[] _addresses, string[] _names, string[] _uniqueIds) public {
require(msg.sender == admin, "only admin can add members!");
for (uint i = 0; i < _addresses.length; i++) {
require(votingStart > now, "Can't register now; voting has already started!");
require(bytes(members[_addresses[i]].name).length == 0, "member already added!");
require(bytes( _names[i]).length == 0, "Name can't be empty!");
require(bytes(_uniqueIds[i]).length == 0, "Unique ID can't be empty!");
members[_addresses[i]] = Member(_addresses[i], _names[i], _uniqueIds[i]);
}
}
function getMemeberDetails() public view returns(string _uniqueId, string _name) {
Member memory member = members[msg.sender];
_uniqueId = member.uniqueId;
_name = member.name;
}
function getProposalsWithPoints() public view returns(string[] _proposalNames, int64[] _points) {
for (uint i = 0; i < proposals.length; i++) {
_proposalNames[i] = proposals[i].title;
_points[i] = getPoints(proposals[i].proposalId);
}
}
function saveProposal(string _title, string _description, uint64 _expectedBudget) public returns(uint _proposalId) {
// proposal submission must be started and not ended.
require(bytes(members[msg.sender].name).length != 0, "Not a registered member!");
require(proposalSubmissionStart < now, "Proposal submission hasn't started!");
require(proposalSubmissionEnd > now, "Proposal submission has ended!");
require(bytes(_title).length != 0 && bytes(_description).length != 0 && _expectedBudget != 0, "Invalid title/description/expectedBudget");
_proposalId = proposals.length;
proposals.push(Proposal(_proposalId, _title, _description, "", false, _expectedBudget, msg.sender, 0));
}
function updateProposal(uint32 _proposalId, string _title, string _description, uint64 _expectedBudget) public {
// proposal submission must be started and not ended.
require(bytes(members[msg.sender].name).length != 0, "Not a registered member!");
require(proposalSubmissionStart < now, "proposal submission hasn't started!");
require(proposalSubmissionEnd > now, "proposal submission has ended!");
require(bytes(_title).length != 0 && bytes(_description).length != 0 && _expectedBudget != 0, "invalid title/description/expectedBudget");
require(_proposalId <= proposals.length && bytes(proposals[_proposalId].title).length != 0, "No proposal exist for this Proposal Id");
// check if same user (who created proposal) is updating it.
require(proposals[_proposalId].submitter == msg.sender, "Can't update this proposal because it's created by another user");
proposals.push(Proposal(_proposalId, _title, _description, "", false, _expectedBudget, msg.sender, 0));
}
function castVote(bool _isUpvote, uint32 _proposalId) public {
require(bytes(members[msg.sender].name).length != 0, "Not a registered member!");
require(votingStart < now, "Proposal Voting hasn't started!");
require(votingEnd > now, "Proposal Voting has ended!");
require(_proposalId <= proposals.length && bytes(proposals[_proposalId].title).length != 0, "No Proposal exists for this Id!");
Vote[] memory votes = memberVotes[msg.sender];
if (votes.length > 0) {
for (uint i = 0; i < votes.length; i++) {
require(votes[i].proposalId != _proposalId, "Already voted for this proposal");
}
}
proposalVotes[_proposalId].push(Vote(msg.sender, _proposalId, _isUpvote));
memberVotes[msg.sender].push(Vote(msg.sender, _proposalId, _isUpvote));
// upvote will get +1 and downvote will get -1 point
_isUpvote ? proposals[_proposalId].points++ : proposals[_proposalId].points--;
}
function getPoints(uint _proposalId) public view returns(int64 count) {
require(_proposalId <= proposals.length && bytes(proposals[_proposalId].title).length != 0, "No Proposal exists for this Id!");
count = proposals[_proposalId].points;
}
function calculateResults() public {
require(resultDeclare < now, "results has't declared!");
if (!hasResultDeclared) {
sortProposals();
for (uint i = 0; i < proposals.length; i++) {
if (proposals[i].expectedBudget < funds) {
proposals[i].selected = true;
selectedProjectsId.push(proposals[i].proposalId);
funds -= proposals[i].expectedBudget;
}
break;
}
hasResultDeclared = true;
}
}
function addDocuments(uint _proposalId, bytes _docs) public {
require(proposals[_proposalId].submitter == msg.sender, "Only proposal owner can add documents!");
require(projectsStart < now, "projects has't started!");
require(projectsEnd > now, "projects has ended!");
require(_proposalId <= proposals.length && bytes(proposals[_proposalId].title).length != 0, "No Proposal exists for this Id!");
require(proposals[_proposalId].selected == true, "This project is not selected!");
require(_docs.length > 0, "Add document(s)");
for (uint i = 0; i < _docs.length; i++) {
proposals[i].docs.push(_docs[i]);
}
}
//bubble sort as of now.
function sortProposals() private {
uint len = proposals.length;
for (uint i = 0; i < (len - 1); i++) {
for (uint j = 0; j < len - i - 1; j++) {
if (proposals[j].points < proposals[j + 1].points) {
Proposal memory temp = proposals[j];
proposals[j] = proposals[j + 1];
proposals[j + 1] = temp;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment