Create & Deploy Node.js app based on Ethereum BlockChain

Here I will describe you how you will create a simple node.js app which will have user interface and interaction with smart contracts using web3.js API further advancing your smart contract structure to use Events, Modifiers, Struct, Mapping, Inheritance and at the end about its deployment on lite-server, following are the tools/apis you will use in this subject.

  • Remix IDE (for creating smart contracts)
  • Ganache (to set-up private blockchain and run tests)
  • web3.js API (provides interface to interact with smart contracts)
  • Node.js
  • Lite-server
  • Let me explain the complete flow:

Setup the project

So after downloading all these tools, lets setup the project by running following commands on console:

mkdir instructor-eth

cd instructor-eth

Next, run the npm init command to create a package.json file, which will store project dependencies:

npm init

Then install web3.js which will register its entry in package.json

npm install ethereum/web3.js --save

Run Ganache

Run the Ganache tool to setup private blockchain with 10 test accounts provided and it will start listening on this port http://localhost:8545 for transactions

Create Smart Contract

Open Remix IDE and create smart contract, here is the sample code:


pragma solidity ^0.4.18;

contract Instructor {
    
   string fName;
   uint age;
   
   function setInstructor(string _fName, uint _age) public {
       fName = _fName;
       age = _age;
   }
   
   function getInstructor() public constant returns (string, uint) {
       return (fName, age);
   }
    
}

Deploy Smart Contract

Switch over to the Remix IDE, click on the Run tab, and then change the Environment dropdown from Javascript VM to Web3 Provider.

Hit “OK” and then specify the Ganache localhost address (by default, it is http://localhost:8545)

Hit “Create”, you will need the address of this contract shortly, so leave this window open.

Create User Interface

Now you will create user interface to play with, open up your preferred code editor with the project folder you created. Here, you will notice a node_modules folder, which includes web3 that you installed via npm earlier.

Let’s create an index.html in the project folder.
It will consist of a simple UI, having form with 2 input fields for a name and age.

To get started, paste the following code into the empty index.html file:

Create CSS file

As you can see, you are referencing a main.css file, so create that file and paste in the following rulesets real quickly:

Configure Web3.js

I – Setup Default Address

Now It’s time to interact with smart contracts using web3.js, just replace the tags with this piece of code, It will connect to your Ganache client to do transactions with the default address mentioned below, using first address of provided 10 accounts:


if (typeof web3 !== 'undefined') {
        web3 = new Web3(web3.currentProvider);
    } else {
        // set the provider you want from Web3.providers
        web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
    }
web3.eth.defaultAccount = web3.eth.accounts[0];        

II- Setup Smart Contract Interface

Next, you need to use the web3.eth.contract() method to initialize (or create) the contract on an address. It accepts one parameter, which is referred to as the ABI (Application Binary Interface).
This ABI allows you to call functions and receive data from your smart contract.

If you switch back to the Remix IDE, click on the Compile tab and click Details. Scroll down until you see the Interface – ABI section and click the copy icon as shown below:

Then going back to index.html and paste it where mentioned:


    
        if (typeof web3 !== 'undefined')
	…..
 
	web3.eth.defaultAccount = web3.eth.accounts[0];
	var myContract= web3.eth.contract(PASTE ABI HERE!);
   

III- Setup Smart Contract Address

After having interface object to interact, the last thing to do is to define the actual contract address, to do this Goto Remix IDE -> Run tab, create the contract and click on the copy icon next to the contract that you just created on the right column.
Back to index.html and update it with the address:


        if (typeof web3 !== 'undefined')
	…..
 
	web3.eth.defaultAccount = web3.eth.accounts[0];
	var myContract= web3.eth.contract(PASTE ABI HERE!);
	var contract = myContract.at('PASTE CONTRACT ADDRESS HERE');
        console.log(contract);

Now, let’s open index.html to see if its connected to your smart contract or not.
CTRL-SHIFT-I (i) will show the console. You will see something similar to the following:

Interacting with Smart Contract
Smart contract has been connected, now let’s use jQuery to make function calls based on your form, update the index.html:



        contract.getInstructor(function(error, result){
            if(!error)
                {
                    $("#instructor").html(result[0]+' ('+result[1]+' years old)');
                    console.log(result);
                }
            else
                console.error(error);
        });

        $("#button").click(function() {
            contract.setInstructor($("#name").val(), $("#age").val());
        });

Awesome, save and refresh it then give it a go!, now UI will look like this:

But here after clicking on “Update Instructor” values set successfully but not reflected on the UI instantly, for which you will need to refresh the page and then see the results

Events & Modifiers

To get rid of manually refreshing the UI, Solidity introduces the concept Events, here you will add it in your smart contract and also listen for the events in the UI script tags, the other thing you are going to add is Modifiers which is just like, to whom you want to give permission to your contract interface, after adding Event & Modifier, your smart contract will look like this:

After updating the contract, you must need to re-Create the contract from Remix IDE then update its ABI and address in index.html file.
Now you are going to make some changes on the UI part. First, no longer need to call contract.getInstructor(), so you are going to remove that.

Then, you are going to create a variable to reference your event and adding the watch() method on instructorEvent with a callback. Beneath the above line of code, paste this:


        var instructorEvent = contract.Instructor();
        instructorEvent.watch(function(error, result){
            if (!error)
                {
                    $("#loader").show();
                    $("#instructor").html(result.args.name + ' (' + result.args.age + ' years old)');
                } else {
                    $("#loader").hide();
                    console.log(error);
                }
        });

After doing all this stuff refresh the index.html file on browser, try to update values, you will see UI will be refreshed instantly:

Mapping using Struct

Let’s start with the new contract named Courses.sol, first you need to create struct of Instructor in it which will store its name, first name and last name, just like model class in java referred from Hashmap, further details can be seen on Solidity site, here is the complete contract, just copy/paste it at your end:


pragma solidity ^0.4.18;

contract Courses {
    
    struct Instructor {
        uint age;
        string fName;
        string lName;
    }
    
    mapping (address => Instructor) instructors;
    address[] public instructorAccts;
    
    function setInstructor(address _address, uint _age, string _fName, string _lName) public {
        var instructor = instructors[_address];
        
        instructor.age = _age;
        instructor.fName = _fName;
        instructor.lName = _lName;
        
        instructorAccts.push(_address) -1;
    }
    
    function getInstructors() view public returns(address[]) {
        return instructorAccts;
    }
    
    function getInstructor(address _address) view public returns (uint, string, string) {
        return (instructors[_address].age, instructors[_address].fName, instructors[_address].lName);
    }
    
    function countInstructors() view public returns (uint) {
        return instructorAccts.length;
    }
    
}

Inheritance

A common pattern in smart contracts when it concerns inheritance is to define an owner address and a modifier that gives only the smart contract owner address the ability to access certain functions.

Above the contract Courses , you are going to create a new base contract for that purpose:


pragma solidity ^0.4.18;

contract Owned {
    address owner;
    
    function Owned() public {
        owner = msg.sender;
    }
    
   modifier onlyOwner {
       require(msg.sender == owner);
       _;
   }
}

contract Courses is Owned {

You can assure that this works by adding the onlyOwner modifier to the setInstructor() function in the derived contract:


function setInstructor(address _address, uint _age, bytes16 _fName, bytes16 _lName) onlyOwner public {

Strings to Bytes

In the above contract, you will notice your smart contract consists of two strings first name and last name. Strings are costworthy on the Ethereum blockchain, and when possible, you should actually use type of bytes.
Modify the smart contract so that each reference of first and last name, is no longer a type of string, but bytes16 instead as mentioned in above setInstructor() method

Deploying on Lite-Server

Your smart contract is ready to deploy, before deploying it, you need to install lite-server & MetaMask chrome plugin, which will allow you to connect to the Ropsten test network to more accurately simulate the experience of the dApp on the live Ethereum blockchain, So at this point you will turn off Ganache client to use Ropsten test network instead. Because of this, you have to install a lite-server in order for MetaMask to inject an instance of the Web3 API. If you do not, MetaMask will not work by just loading your index.html file into the browser straight from the hard drive.

Visit your console in the project folder you have been working in, and use npm to install the lite-server package:

npm install lite-server --save-dev

Note: If you have problems running this command as I did, make sure you are running your console as administrator.

Next, open up your code editor and inside of the package.json file, add this under scripts:


"scripts": {
"dev": "lite-server"
},

Now, you can run the following command to start the lite-server, which will automatically load the index.html file you have been working on, in your browser at a localhost address:

npm run dev

Installing MetaMask

Going forward, you will use MetaMask, which is a chrome extension that brings Ethereum to your browser. It provides you with a wallet, and the ability to connect to different test networks, as well as the main Ethereum blockchain.

It provides you with a way to interact with decentralized apps by providing you with a way to manage multiple accounts on the live network and test network. It also allows you to sign/approve transactions that are initiated by your Web3 project.

Install the plugin and follow this guide to getting started with setting up the plugin for the first time. You want to get to the point at which you are logged in to the Ropsten test network. If you need to, you can click Buy, which will provide you with free test Ether for use in your project.

Deploying the Contract to the Ropsten Test Network

Since you have updated the contract, so, let’s go back to the Remix IDE and redeploy this contract.

Click on Run and change the Environment to Injected Web3.

This will use MetaMask’s injected Web3 instance, which will deploy the contract on the Ropsten test network. After moving back to index.html, again you need to update contract Address, ABI to reflect the changes and also updating the UI part a little bit:

As you are now using Ropsten test network on MetaMask instead using your own private-net on Ganache, therefore need to do some changes mentioned below:

After deployment lets run it on lite-server, now you see the results:

After pressing submit it will take some time depends upon the Gas price, higher for quick processing of transaction.
here is the Full Solidity contract which you have deployed, just make sure at your end:


pragma solidity ^0.4.18;

contract Owned {
    address owner;    
    function Owned() public {
        owner = msg.sender;
    }    
   modifier onlyOwner {
       require(msg.sender == owner);
       _;
   }
}
contract Courses is Owned {
     struct Instructor {
        uint age;
        bytes16 fName;
        bytes16 lName;
    }    
    mapping (address => Instructor) instructors;
    address[] public instructorAccts;    
    event instructorInfo(
       bytes16 fName,
       bytes16 lName,
       uint age
    );    
    function setInstructor(address _address, uint _age, bytes16 _fName, bytes16 _lName) onlyOwner public {
        var instructor = instructors[_address];
        
        instructor.age = _age;
        instructor.fName = _fName;
        instructor.lName = _lName;
        
        instructorAccts.push(_address) -1;
        instructorInfo(_fName, _lName, _age);
    }    
    function getInstructors() view public returns(address[]) {
        return instructorAccts;
    }    
    function getInstructor(address _address) view public returns (uint, bytes16, bytes16) {
        return (instructors[_address].age, instructors[_address].fName, instructors[_address].lName);
    }    
    function countInstructors() view public returns (uint) {
        return instructorAccts.length;
    }
    
}


Get In Touch

Share your ideas. We help bring them to reality.
Show Buttons
Hide Buttons