aboutsummaryrefslogtreecommitdiffstats
path: root/contracts/Election.sol
blob: e535975832179c7518d0e181cace7b2b67a1204f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
pragma solidity ^0.5.0;

contract Election {

    address owner;
    uint public totalVote = 0;
    bool public isVoting = false;
    uint public round = 0;
    uint public guaranteedDeposit = 1000000000000000000;
    uint public refundRatio = 5; // more than 1/5 to get refund

    struct Candidate {
        uint vote;
        string name;
        bool isRegistered;
        uint candidateNumber;
    }

    address payable[] public candiatesList;
    mapping(uint => mapping(address => Candidate)) public candidateData;
    mapping(uint => mapping(address => bool)) public voted;

    event voteStart(uint round);
    event elected(uint round, address candidate, string name, uint vote);
    event reset(uint round);
    event registered(uint round, address candidate);
    event voteCandidate(uint round, address candidate, address voter);
    event sponsorCandidate(uint round, address candidate, string name, address sponsor, uint amount);
    event refund(address candidate, string name, uint amount, uint round);

    constructor() public {
        owner = msg.sender;
        resetElection();
    }

    // Announce the elected person and restart election
    function resetElection() public onlyOwner {
        if (round > 0) {
            refundDeposit();
            announceElectedPerson();
        }

        totalVote = 0;
        round += 1;
        isVoting = false;
        emit reset(round);
    }

    function startVoting() public onlyOwner {
        isVoting = true;
        emit voteStart(round);
    }

    function vote(address candidateAddr) public onlyInVote candidateShouldExist(candidateAddr) {
        require(voted[round][msg.sender] != true, "Already voted");
        Candidate storage candidate = candidateData[round][candidateAddr];
        candidate.vote += 1;
        voted[round][msg.sender] = true;
        emit voteCandidate(round, candidateAddr, msg.sender);

        totalVote += 1; // extra bonus
    }

    function register(string memory name) public onlyInRegister payable {
        Candidate storage candidate = candidateData[round][msg.sender];
        require(candidate.isRegistered != true, "Already registered");

        /* Extra bonus implementation */
        require(msg.value >= guaranteedDeposit, "Insufficient deposit");

        Candidate memory newCandidate;
        newCandidate.name = name;
        newCandidate.vote = 0;
        newCandidate.isRegistered = true;
        candidateData[round][msg.sender] = newCandidate;
        candiatesList.push(msg.sender);
        emit registered(round, msg.sender);
    }

    function refundDeposit() private {
        /* extra - refund guaranteedDeposit */
        uint numOfCandidates = candiatesList.length;
        for (uint x = 0; x < numOfCandidates; x++) {
            address payable currentAddr = candiatesList[x];
            Candidate storage currentCandidate = candidateData[round][currentAddr];
            if ((currentCandidate.vote * refundRatio) >= totalVote) {
                currentAddr.transfer(guaranteedDeposit);
                emit refund(currentAddr, currentCandidate.name, guaranteedDeposit, round);
            }
        }
    }

    function announceElectedPerson() private {
        uint numOfCandidates = candiatesList.length;
        uint maxVote = 0;
        address highestCandidate;
        for (uint x = 0; x < numOfCandidates; x++) {
            address currentAddr = candiatesList[x];
            Candidate memory currentCandidate = candidateData[round][currentAddr];
            if (currentCandidate.vote > maxVote) {
                highestCandidate = currentAddr;
                maxVote = currentCandidate.vote;
            }
        }
        Candidate memory electedPerson = candidateData[round][highestCandidate];
        emit elected(round, highestCandidate, electedPerson.name, electedPerson.vote);
        delete candiatesList;
    }

    function sponsor(address payable candidateAddr) public onlyInRegister candidateShouldExist(candidateAddr) payable {
        Candidate storage candidate = candidateData[round][candidateAddr];
        candidateAddr.transfer(msg.value);
        emit sponsorCandidate(round, candidateAddr, candidate.name, msg.sender, msg.value);
    }

    function getCandidatesList() public view returns (address payable[] memory) {
        return candiatesList;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner is allowed");
        _;
    }

    modifier onlyInVote() {
        require(isVoting == true, "Voting should be started");
        _;
    }

    modifier onlyInRegister() {
        require(isVoting == false, "Only allowed before voting period");
        _;
    }
    modifier candidateShouldExist (address candidateAddr) {
        Candidate storage candidate = candidateData[round][candidateAddr];
        require(candidate.isRegistered == true, "Candidate not exists");
        _;
    }

}