Create your account

Already have an account? Login here

Note: By joining, you will receive periodic emails from Coursetro. You can unsubscribe from these emails.

Create account

Solidity Inheritance and Deploying an Ethereum Smart Contract

By Gary simon - Nov 01, 2017

The following tutorial is a part of our 100% free course: Developing Ethereum Smart Contracts for Beginners

Up until now so far in this course, we've only worked with a single contract. Inheritance allows us to define a base contract, from which other contracts can use. This allows you to reuse base contracts in future contracts without having to rewrite code.

When contract A inherits from contract B, only contract A is actually deployed to the blockchain. All code from contract B is copied into contract A.

Let's give inheritance a try in our smart contract project we've been working on.

If you prefer watching a video instead..

Be sure to Subscribe to the Official Coursetro Youtube Channel for more videos.

Our Current Contract

Just for purposes of reference, our current Solidity contract looks like this:

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;
    }
    
}

Feel free to copy and paste this into the Remix IDE if you haven't been following along through the previous lessons.

Creating a Base Contract

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 { line, we're 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 {

// Other code removed for brevity

If you followed along with this course, you'll notice that the code in the Owned contract is familiar. We're setting the owner address to the creator of the contract, and a modifier.

Also, note that we added is Owned onto the contract Courses line. That's how you make a contract inherit from a base contract.

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

// Other code removed for brevity

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

// Other code removed for brevity

If you create this contract and try to set an instructor as we've been doing in this previous lessons, it will only work if you set it with the address that was used to deploy the contract.

This works because our Courses contracted inherits from the Owned contract.

This, in a nutshell, is how inheritance works in Solidity. You can even pass in arguments from inherited contracts, but that's a topic we will touch on in a different tutorial in the future. For now, we're just sticking to the basics.

Changing from Strings to Bytes

Our 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.

Here is the full contract with all of those changes made:

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;
    }
    
}

Continuing our Project

We're nearly at the end of the course, but we're going to spend the rest of this lesson by setting up a lite-server and reworking the Web3 UI to work with this new smart contract.

At this point, our contract is written and ready to go. We won't be adding anymore to it in this course. 

We will be installing the MetaMask chrome plugin, which will allow us to connect to the Ropsten test network to more accurately simulate the experience of the dApp on the live Ethereum blockchain. Because of this, we have to install a lite-server in order for MetaMask to inject an instance of the Web3 API. If we don't, MetaMask will not work by just loading our index.html file into the browser straight from the hard drive.

Visit your console in the project folder we've 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 we've been working on, in your browser at a localhost address:

> npm run dev

Installing MetaMask

Going forward, we 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 our 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're 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

The current state of our Web3 UI project only works with a different version of our contract. We've since 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.

Click Create to deploy the contract. Visit the Compile tab and copy the ABI from the Details button.

Visit our project in your code editor and paste the new API code into the following line:

var CoursetroContract = web3.eth.contract(PASTE ABI HERE);

Then, in the Remix IDE, copy the address associated with the deployed contract.

Paste the new address into the following code here:

var CoursetroContract = ...

var Coursetro = CoursetroContract.at('PASTE ADDRESS HERE');

We need to modify the actual HTML to accomodate for our first and last name fields, along with a few other things. Change the actual HTML above our Javascript to the following:

    <div class="container">

        <h1>Coursetro Instructor</h1>
        <span id="countIns"></span>

        <h2 id="instructor"></h2>
        <span id="insTrans"></span>
        <hr>

        <img id="loader" src="https://loading.io/spinners/double-ring/lg.double-ring-spinner.gif">

        <label for="fName" class="col-lg-2 control-label">First Name</label>
        <input id="fName" type="text">

        <label for="lName" class="col-lg-2 control-label">Last Name</label>
        <input id="lName" type="text">

        <label for="age" class="col-lg-2 control-label">Instructor Age</label>
        <input id="age" type="text">

        <button id="button">Update Instructor</button>

    </div>

The next line in our Javascript underneath the contract address is where we define a variable for the event. We need to make a slight change;

// Change this:
var instructorEvent = Coursetro.Instructor();

// To this:
var instructorEvent = Coursetro.instructorInfo({},'latest');

The former line worked fine in the testrpc environment, but I found that I had to pass in an empty object in the first argument, and a 'latest' string in the second, in order for it to work on the Ropsten network.

This is simply informing the event that we only want the latest event when an instructor has been added.

We also need to change the .watch() function associated with that event to:

instructorEvent.watch(function (err, result) {
    if (!err) {
        if (result.blockHash != $("#instrans").html()) 
            $("#loader").hide();
            
        $("#insTrans").html('Block hash: ' +result.blockHash);
        $("#instructor").html(web3.toAscii(result.args.fName) + ' ' + web3.toAscii(result.args.lName) + ' (' + result.args.age + ' years old)');
    } else {
        $("#loader").hide();
    }
});

First, we're checking if the current *.blockHash* is not equal to the blockHash defined in the #instrans ID. If it's not, then and only then will we hide the loading graphic.

Next, we're using a new funciton called .toAscii, this is because the names are now bytes types, which does not return the actual string value. .toAscii reverts it back.

Underneath this code, let's add a new section that will give us a count on our instructors:

Coursetro.countInstructors((err, res) => {
    if (res)
        $("#countIns").html(res.c + ' Instructors'); 
});

Then, let's update the click event to work with the new function in the smart contract:

$("#button").click(function() {
    $("#loader").show();
    Coursetro.setInstructor(web3.eth.defaultAccount, $("#age").val(), $("#fName").val(),$("#lName").val(), (err, res) => {
        if (err) 
            $("#loader").hide();
});

And that's it!

Conclusion

In the next and final lesson that's a part of this course, we're going to interact with this contract on the Ropsten Test Network.


Share this post




Say something about this awesome post!