Part 5: Making a DApp

If you have read every part of this tutorial series, you already know how to make a decentralized application on Ethereum, and in this tutorial, I’ll just guide you to use that knowledge together.

On Ethereum, a DApp is a web application that will interact with smart contracts deployed on the blockchain. You can do it using python or other programming languages, but these will not be covered in this tutorial. We will focus only on JavaScript.

We saw how to make a smart contract, in the first part, and how to deploy it in the second. And in this tutorial, I assumed that you have a JavaScript background, it doesn’t matter how advanced you are, or which frameworks you use, we will use vanilla JavaScript, and a bit of JQuery to make our life easier.

One thing that we will need, is, a tool that let us interact with the deployed smart contract, for that, we have a great API named Web3.js.

We have seen Web3.js, both on the Truffle console in part 2, and when we performed a test on our contract in part 3.

Let’s start

Create a new folder for the project, and run the truffle init command.

Next, create a folder named “src” where we will store our web application files. Inside the folder “src”, create an “index.html” file. Paste the following code inside:

Text Box

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Wrestling DApp</title>
  </head>
  <body>
    <h1 class="text-center">Wrestling DApp</h1>
    <hr/>


    <!-- ... -->


    <!-- JQuery will help us extract data from json files -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <!-- Web3.js will help us interact with the deployed smart contract -->
    <script src="JShelpers/web3.min.js"></script>
    <!-- Truffle contract  will our life easier when interacting with smart contracts -->
    <script src="JShelpers/truffle-contract.js"></script>
    <!-- app.js is where we will write our JS logic -->
    <script src="app.js"></script>
  </body>
</html>
Create a folder named “JShelpers”, and create the following three files inside:

Text Box

touch jquery.min.js 
touch truffle-contract.js 
touch web3.min.js

You can find their content in the source code for this tutorial on Github.

Now, back to the “src” folder, create a new file named “app.js”. “app.js” will hold our JS logic, we will use a bit of JQuery with vanilla JavaScript to keep it simple, but of course in a real DApp, you can use the frameworks you like, for example React, Angular, Vue etc.

Now, open “app.js”, and add the following code:

Text Box

var web3Provider = null;
var WrestlingContract;
const nullAddress = "0x0000000000000000000000000000000000000000";

function init() {
  // We init web3 so we have access to the blockchain
  initWeb3();
}

function initWeb3() {
  if (typeof web3 !== 'undefined' && typeof web3.currentProvider !== 'undefined') {
    web3Provider = web3.currentProvider;
    web3 = new Web3(web3Provider);
  } else {    
    console.error('No web3 provider found. Please install Metamask on your browser.');
    alert('No web3 provider found. Please install Metamask on your browser.');
  }
  
  // we init The Wrestling contract infos so we can interact with it
  initWrestlingContract();
}

We start by creating some necessary variables, and initializing our Web3 provider variable. We will expect the users to have a web3 provider running. Most users at the moment use Chrome or Firefox, with an extension called “Metamask” to interact with an Ethereum blockchain, so we are expecting Metamask to inject an instance of web3 in the page, if not, we ask the users to install it.

Now, let’s implement the necessary functions to interact with our contract, we will start by initializing a reference to the deployed smart contract, creating the function ‘initWrestlingContract ()’:

Text Box

function initWrestlingContract () {
  $.getJSON('Wrestling.json', function(data) {
    // Get the necessary contract artifact file and instantiate it with truffle-contract
    WrestlingContract = TruffleContract(data);

    // Set the provider for our contract
    WrestlingContract.setProvider(web3Provider);

    // listen to the events emitted by our smart contract
    getEvents ();

    // We'll retrieve the Wrestlers addresses set in our contract using Web3.js
    getFirstWrestlerAddress();
    getSecondWrestlerAddress();
  });
}
Then we will create the body of the other functions that will retrieve the informations for us:

Text Box

function getEvents () {
  WrestlingContract.deployed().then(function(instance) {
  var events = instance.allEvents(function(error, log){
    if (!error)
      $("#eventsList").prepend('<li>' + log.event + '</li>'); // Using JQuery, we will add new events to a list in our index.html
  });
  }).catch(function(err) {
    console.log(err.message);
  });
}

function getFirstWrestlerAddress() {
  WrestlingContract.deployed().then(function(instance) {
    return instance.wrestler1.call();
  }).then(function(result) {
    $("#wrestler1").text(result); // Using JQuery again, we will modify the html tag with id wrestler1 with the returned text from our call on the instance of the wrestling contract we deployed
  }).catch(function(err) {
    console.log(err.message);
  });
}

function getSecondWrestlerAddress() {
  WrestlingContract.deployed().then(function(instance) {
    return instance.wrestler2.call();
  }).then(function(result) {
    if(result != nullAddress) {
      $("#wrestler2").text(result);
      $("#registerToFight").remove(); // By clicking on the button with the ID registerToFight, a user can register as second wrestler, so we need to remove the button if a second wrestler is set 
    } else {
      $("#wrestler2").text("Undecided, you can register to wrestle in this event!");
    }   
  }).catch(function(err) {
    console.log(err.message);
  });
}
The ‘init()’ that launches the execution of all these functions will of course not be executed automatically, so we need to trigger it:

Text Box

// When the page loads, this will call the init() function
$(function() {
  $(window).load(function() {
    init();
  });
});
Now we will need to complete our html page, modify it so it will look like this:

Text Box

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Wrestling DApp</title>
  </head>
  <body>
    <h1 class="text-center">Wrestling DApp</h1>
    <hr/>

    <div style="text-align: center;">
      <h3>Today's wrestling event</h3>
      <h3><span id="wrestler1"></span> <span style="color: red">VERSUS</span> <span id="wrestler2"></span></h3>

      <button id="registerToFight" onclick="registerAsSecondWrestler()">REGISTER TO FIGHT</button>
    </div>

    <div>
      <ul id="eventsList">
        <!-- Events will appear here from app.js -->
      </ul>
    </div>


    <!-- JQuery will help us extract data from json files -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <!-- Web3.js will help us interact with the deployed smart contract -->
    <script src="JShelpers/web3.min.js"></script>
    <!-- Truffle contract  will our life easier when interacting with smart contracts -->
    <script src="JShelpers/truffle-contract.js"></script>
    <!-- app.js is where we will write our JS logic -->
    <script src="app.js"></script>
  </body>
</html>

Back to our “app.js” script, we need to add ‘registerAsSecondWrestler’, the function that will let a user register as a second wrestler :

Text Box

function registerAsSecondWrestler () {
  web3.eth.getAccounts(function(error, accounts) {
  if (error) {
    console.log(error);
  } else {
    if(accounts.length <= 0) {
      alert("No account is unlocked, please authorize an account on Metamask.")
    } else {
      WrestlingContract.deployed().then(function(instance) {
        return instance.registerAsAnOpponent({from: accounts[0]});
      }).then(function(result) {
        console.log('Registered as an opponent')
        getSecondWrestlerAddress();
      }).catch(function(err) {
        console.log(err.message);
      });
    }
  }
  });
}

That’s it for our web app! We just need to configure a few things and we are set to go.

Installations

While an html document could be opened directly on your browser, the Metamask extension wouldn’t be able to interact with it due to your browser security measure, so we will use a little local http server to serve our files. For that, we will use lite-server:

npm init -y

npm install lite-server --save-dev

Create file a config file for lite-server named ‘bs-config.json’ in your project root folder, and paste the following inside:

Text Box

{
  "server": {
    "baseDir": ["./src", "./build/contracts"]
  }
}

This instructs lite-server to take files from the folder “src”, where our web app is, and “./build/contracts” where the json files that describe the smart contracts deployed by truffle.

Next, add this line:

"dev": "lite-server",

To ‘package.json’ inside the “scripts” node like the following:

Text Box

...
  "scripts": {
    "dev": "lite-server",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...
Then run the following command inside your console, it should open a page on your browser at “http://localhost:3000/”:
npm run dev

Now, search for and install Metamask on your browser.

The smart contract

Don’t forget to deploy a smart contract to your test network. You can find the Wrestling contract in part 1 of this tutorial, and use one of the methods shown in the second part of this tutorial series.

For this part, I’ll use Ganache, the UI version, but you can use ganache-cli to simulate the ethereum blockchain.

To deploy the smart contract, use truffle migration command:

truffle migrate --network development

Don’t forget to check that your “truffle-config.js” file is set correctly. And that you added the migration script necessary to deploy it.

Configuring Metamask

After installing Metamask, click on its icon, then click on the top left of the pop-up, you’ll see a list of different networks, choose the “http://127.0.0.1:7545” one. If there is no such option, click on the “Custom RPC” option, and add that url, so Metamask can connect with Ganache.

Now click on the “restore from seed phrase” option shown in the pop up of Metamask, add copy-past the 12 words of the mnemonic on ganache, and write a password you like.

This process will unlock the first account, the one with which we deployed the contract, but for a good simulation, we will use the second account that Ganache generated, so we will have to add it manually to Metamask, click on the user icon on the top right of Metamask, and choose “import account”, paste the private key that you can copy from the ganache-cli, or click on the key icon on Ganache if you are using the GUI version.

Testing the DApp

Now that the smart contract is deployed on our test network, that we have our web app set up, and that Metamask is configured, we can test the DApp.

Start by going to http://localhost:3000/, the link where lite-server is serving our web app, you’ll see the interface of the web app:

The amazing and cutting-edge UI of our DApp

Making sure that the Account 2 is still selected on Metamask, press the “Register to fight” button, and normally a pop up from Metamask will appear, asking you to confirm the transaction (You can see it also by clicking on the icon of Metamask if it doesn’t pop up).

Upon clicking on the submit button, the address of the second wrestler should be replaced by the address of the account that triggered the call (If it doesn’t automatically, refresh the page. If it seems that the transaction fails, check that you followed this tutorial correctly, or that Metamask doesn’t bug, because it did for me when I was writing this tutorial. Most tools around Ethereum are still under development, and we can only thank the developers behind them for the huge effort they put on them).

That’s really what a DApp on Ethereum is, there is nothing more to it. For the ones who want to interact with a smart contract in the backend of their DApp, you can of course use Web3.js on NodeJS by installing it with NPM, and using Geth, or infura.io as the provider. Here is a good tutorial that will walk you through that process.

Here is the link for the source code for this tutorial:

Here are an alternative tutorial if you had a hard time following this one. And an other one over here.

Going forward

Now, you have all the cards in hands to develop your Ethereum contracts and DApps, read other tutorials on the points that you didn’t understand well, read the documentations of the tools we saw in this project, and of course, practice, a good exercise for you will be to complete the web app of this tutorial, by adding the others functions of the smart contract.

You could join the developer community over Reddit, good tidbits are posted there regularly. You can read weekly news of what’s going on in the Ethereum world on the WeekInEthereum website. The ethereum forums are interesting too, and there are pretty active chats on the gitter of Ethereum.

This tutorial series ends here, but I’m already pen and paper, preparing another tutorial. Don’t hesitate to follow me so you’ll be notified when it’s out!

You can also find me on twitter @dev_zl.

Comments