Writing a Simple Smart Contract for Ethereum Network

Share:
Writing a Simple Smart Contract for Ethereum Network

In this lesson, I am going to build a simple smart contract that can be called useful at some point. The contract will represent a not complicated voting system.


Use Case: Voting System


Voters will be blockchain public keys - addresses, each address will be able to vote only once. There will be only two possible options to vote, ‘For’ or ‘Against’. Everyone who voted will be saved in storage for a few reasons. Firstly information on voted addresses can't be lost after function executing. Secondly, data saved in storage can be accessed publicly from any address in the network, so everyone will be able to check what any specific address voted for, which makes the voting process completely trusted. The only problem with such a voting system is that the process of connecting a real person to its address can be difficult and not completely safe. But it is not the problem that we solve here.

The right to vote can be given by an administrator, in our case, it will be the owner of the contract. Only registered addresses will be able to vote. Any registered address which did not vote will be counted as a negative vote. So it will make voters only vote ‘for’ if they want. If a voter is against than it can just skip voting and vote will count ‘against’. Such a method will reduce the cost of gas that is needed to be spent on sending voting transactions.

Information about the total number of registered votes along with the total number of votes ‘for’ will be publicly available, so anyone will be able to check the situation at any time. Also, not only the owner of the contract but anyone will have an ability to close the voting contract but it will NOT be possible before some exact date. This date will be set at the time of contract creation.

It will ensure that the contract will be closed at the needed time. Once the contract is closed the ability of voting becomes unavailable and only options left will be functions that will show the results. From the number of the total registered voters and the number of the total votes ‘for’ percent of voting will be calculated and if after the contract is closed it will be 51% or more proposal or whatever voting was for will pass, otherwise, it will fail. 

Let’s now take a look at the fully completed contract and then disassemble it to part and figure out what each part does along.


Our Smart Contract


For developing my smart contract I will be using a programming environment called Remix, created for working on Solidity. It can compile and run a smart contract on its own private blockchain. Also, it provides a comfortable interface for surface testing.


pragma solidity 0.5.10;

contract VotingSystem { mapping (address => bool) public voters; mapping (address => bool) public voted;

uint256 public totalVoterRegistered;
uint256 public totalVoted;
uint256 public endOfVoting;

uint16 constant votingPeriod = 9000;

bool public isVotingClosed;

address public owner;

constructor () public {
    owner = msg.sender;
    endOfVoting = now + votingPeriod;
}

modifier onlyContractOwner() {
    require(owner == msg.sender, 'Not a contract owner');
    _;
}

modifier ifVoitingGoing() {
    require(!isVotingClosed, 'Voting is closed');
    _;
}

function registerVoter(address _voter) public onlyContractOwner() ifVoitingGoing() returns(bool success) {
    if (voters[_voter] == false) {
        voters[_voter] = true;
        totalVoterRegistered++;
    }
    return true;
}

function unregisterVoter(address _voter) public onlyContractOwner() ifVoitingGoing() returns(bool success) {
    if(voters[_voter] == true) {
        voters[_voter] = false;
        totalVoterRegistered--;
    }
    return true;
}

function registerVoters(address[] memory _voters) public onlyContractOwner() ifVoitingGoing() returns(bool success) {
    uint256 newRegisteredCount;
    for (uint256 i = 0; i < _voters.length; i++) {
        if (voters[_voters[i]] == false) {
            voters[_voters[i]] = true;
            newRegisteredCount++;
        }
    }
    totalVoterRegistered += newRegisteredCount;
    return true;
}

function voteFor() public ifVoitingGoing() returns(bool success) {
    require(voters[msg.sender] == true, 'Not a registered voter');

    if(voted[msg.sender] == false) {
        voted[msg.sender] = true;
        totalVoted++;
    }
    return true;
}

function voteAgainst() public ifVoitingGoing() returns(bool success) {
    require(voters[msg.sender] == true, 'Not a registered voter');

    if(voted[msg.sender] == true) {
        voted[msg.sender] = false;
        totalVoted--;
    }
    return true;
}

function endVoting() public ifVoitingGoing() returns(bool success) {
    require(now >= endOfVoting, 'End date has not come yet');
    isVotingClosed = true;

    return true;
}

function getVotingResult() public view returns(uint256 votingResult) {
    require(isVotingClosed, 'Voting is not ended yet');

    return (100/totalVoterRegistered) * totalVoted;
}

}


Starting Explanation of the Code


Now I will explain what is happening here without diving deep into the details. Almost every part of the contract deserves full article telling about it and in the next articles I will definitely explain every piece of code.

The first part of the contract is a global variable declaration. 

‘Mapping’ is a special type in solidity, basically, it is a data structure called Hashtable. It is a table that consists of pairs of ‘key - value’. Values in brackets mean that address value is a ‘key’ and boolean value is a ‘value’ after brackets visibility modifier and the name of hashtable are located. Getting value by its key can be done by the next line of code 


 HashtableName [address]

It contains a boolean value.

The next variables are counters of registered voters and users who already voted and also a variable that saves the value when voting should be ended.

‘votingPeriod’ is a value that shows how much time from the present moment should pass in seconds before the voting is ended. It is possible because in Solidity we can use the Unix timestamp system. Actually, the current timestamp is a number of seconds or milliseconds passed from 00:00:00 on 1 January 1970 to some specific date. In Solidity, we can use the variable ‘now’ for getting timestamp at the current moment. So with the help of this system, we can easily define the needed moment in the future when we need to stop the voting contract.

In our contract, it is done in the constructor function. We define ‘endOfVoting’ variable by calling ’now’ in the constructor which is actually the time of contract creation plus ‘votingPeriod’ variable which is period in seconds that we define by ourselves. As a result, we get an ’endOfVoting’ variable that shows a specific timestamp that is needed to be reached. Everything left we need to do is to check it inside of the ending function. 

I will explain the rest of the logic of the contract in the next articles.


Armen Arakelyan


Comments

Scroll to top