CommonLounge Archive

Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 3

November 15, 2017

In  Part 1, we built a simple voting dapp and got it working on our local machine. In Part 2, we moved our app to use truffle framework and deployed it to the public Ropsten testnet and interacted with it through the truffle console and through a webpage. In this tutorial, we will add few more features to our voting dapp in order to learn a few key concepts. Here is what you will learn in this tutorial:

  1. Learn to use new data types like struct to organize and store data on the blockchain.
  2. Learn the concept of tokens and its usage.
  3. Learn to make payments using Ether, the currency of the Ethereum blockchain platform.

You can find all the code in chapter3 directory in this repository: [https://github.com/maheshmurthy/ethereumvotingdapp](https://github.com/maheshmurthy/ethereumvotingdapp)

As you may know, in a general election, every citizen gets to cast one vote for their favorite candidate. However there are elections like electing a board of directors of a company where you are a shareholder, you get to vote based on the number of shares you own in that company. So, the more shares you own, the more votes you get.

Let’s enhance our voting dapp to support this type of election. We will add functionality for anyone to purchase shares in the company. They can then use those shares to vote for the candidates. We will also add a feature to lookup voter information. In the Ethereum blockchain world, these shares are more commonly referred to as tokens. We will refer to these shares as tokens in the rest of this tutorial.

If you want to skip all the explanation and want to just see the contract file, you can find it here: [https://github.com/maheshmurthy/ethereumvotingdapp/blob/master/chapter3/contracts/Voting.sol](https://github.com/maheshmurthy/ethereumvotingdapp/blob/master/chapter3/contracts/Voting.sol).

Updating the Contract

The first step is to declare the variables we need to store all the information we are interested in. Below are the contract variables with explanation.

// We use the struct datatype to store the voter information.
  struct voter {
    address voterAddress; // The address of the voter
    uint tokensBought;    // The total no. of tokens this voter owns
    uint[] tokensUsedPerCandidate; // Array to keep track of votes per candidate.
    /* We have an array called candidateList initialized below.
     Every time this voter votes with her tokens, the value at that
     index is incremented. Example, if candidateList array declared
     below has ["Rama", "Nick", "Jose"] and this
     voter votes 10 tokens to Nick, the tokensUsedPerCandidate[1] 
     will be incremented by 10.
     */
  }
/* mapping is equivalent to an associate array or hash.
 The key of the mapping is candidate name stored as type bytes32 
 and value is an unsigned integer which used to store the vote 
 count
 */
mapping (bytes32 => uint) public votesReceived;
mapping (address => voter) public voterInfo;
/* Solidity doesn't let you return an array of strings yet. We will 
 use an array of bytes32 instead to store the list of candidates
 */
bytes32[] public candidateList;
uint public totalTokens; // Total no. of tokens available for this election
uint public balanceTokens; // Total no. of tokens still available for purchase
uint public tokenPrice; // Price per token

In Part 1 and Part 2, we initialized the list of candidates contesting in a constructor. Remember that the constructor is invoked just once when the contract is deployed on the blockchain. Here, we also have to initialize the contract with total number of tokens available for sale and the cost of each token. So, we update our contract constructor like below:

/* When the contract is deployed on the blockchain, we will 
 initialize the total number of tokens for sale, cost per token and
 all the candidates
 */
  function Voting(uint tokens, uint pricePerToken, bytes32[] candidateNames) public {
    candidateList = candidateNames;
    totalTokens = tokens;
    balanceTokens = tokens;
    tokenPrice = pricePerToken;
  }

In truffle, you deploy your code on to the blockchain using migrations. You can take a peek at a migration file here. An example deploy call in truffle migration file looks like this:

deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
// 1000 is the total number of tokens for sale and the price of each token is set to 0.1 ether.
// We will revisit this section again later in this tutorial.

Buying tokens

Now that we have initialized the tokens and set the price, let’s see how someone could purchase these tokens by paying ether. Here is the function to buy tokens.

/* This function is used to purchase the tokens. Note the keyword 
 'payable' below. By just adding that one keyword to a function, 
 your contract can now accept Ether from anyone who calls this 
 function. Accepting money can not get any easier than this!
 */
function buy() payable public returns (uint) {
    uint tokensToBuy = msg.value / tokenPrice;
    if (tokensToBuy > balanceTokens) throw;
    voterInfo[msg.sender].voterAddress = msg.sender;
    voterInfo[msg.sender].tokensBought += tokensToBuy;
    balanceTokens -= tokensToBuy;
    return tokensToBuy;
}

An example purchase call looks like this:

truffle(development)> Voting.deployed().then(function(contract) {contract.buy({value: web3.toWei('1', 'ether'), from: web3.eth.accounts[1]})})

The value: web3.toWei(‘1’, ‘ether’) argument is accessed in the buy() function using msg.value and msg.sender gives us the account address of web3.eth.accounts[1]. Assuming the value of each token to be 0.1 Ether, the web3.eth.accounts[1] will receive 1 Ether/0.1 Ether = 10 tokens.

Let’s take a break from looking at the code for a moment and visualize the interaction between accounts (voters) and the contract.

As you can see in the contract file on github, the rest of the new methods in the contract are mostly getters and should be easy to follow along.

The index.html file has some new updates:

  1. To vote for a candidate, you now have to specify the no. of tokens you want to vote with.
  2. There is a new section where you can purchase tokens.
  3. You can now look up voter information — how many tokens they own and no. of votes they have cast to each candidate.
  4. The candidates are not hardcoded anymore. We fetch the candidates from the blockchain and populate it.

The app.js file has the updates to support all the UI functionality above.

Update the deployment file 2deploycontracts.js to pass in total tokens and token price along with candidate names.

var Voting = artifacts.require("./Voting.sol");
module.exports = function(deployer) {
  deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
};

Deploying

To summarize, the four files we have updated in this tutorial are Voting.sol, index.html, app.js and 2_deploy_contracts.js. Once you have updated your truffle repository with these files, we can deploy the contract to the blockchain. The deploy process is exactly the same as the previous tutorial.

You just have to compile and migrate using truffle command.

maheshmurthy|~/dev/ethereum_voting_dapp/chapter3$ truffle migrate
Using network 'development'.
Compiling Migrations.sol...
Compiling Voting.sol...
Writing artifacts to ./build/contracts
Running migration: 1_initial_migration.js
Deploying Migrations...
Migrations: 0xc9249947010675b8a3b1defb12334148f7f59010
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying Voting...
Voting: 0x795d6d1f7cf467f27e48181da5f1ebd5bbd0a8df
Saving successful migration to network...
Saving artifacts...

If you are able to successfully deploy the contract and start your web server, your page will look like below:

As you can see in the screenshot above, you will be able to purchase tokens, vote for candidates using the tokens and lookup voter information by their address. If you are able to get all these features working, congratulations!

I hope this series of tutorials has given you an idea of what Ethereum is, its capabilities, and how to build decentralized applications.

You now know just enough Ethereum to be dangerous :)


© 2016-2022. All rights reserved.