Ethereum Development Crash Course Part Four:

Connor Wiseman
Nov 9, 2018 · 10 min read

Welcome back!

Now we have deployed a smart contract locally and interacted with the logic through some different instances, its time to move on to frameworks and test scripts. To start to gain more a collective understanding of workflow in a development environment, to do this we will be using tools such as truffles to better understand the importance of eliminating security vulnerabilities in Solidity smart contracts. I say importance of eliminating because as you should know by now… Once a smart contract is deployed to the blockchain is stored there perpetually and can not be erased given the immutability of the blockchain. Quite alot of smart contracts will hold a significant amounts of funds aswell during a crowdsale, or any type of event that tends to hold funds from participants or communities in general. (i.e The DAO, Parity Multisig)

A secuirty vulnerability is a peice or line of code that compromises the state of the contract and/or the funds being held within that contract. Whereby a hacker could change the state of the contract and effect data integrity, drain the contract of it’s funds or even take control of the whole contract itself. These are all catastrophic events that can cause an application to become inactive and un-usable within a matter of minutes or seconds.

See the DAO hack: https://www.abitgreedy.com/dao/#dao-hack

And the Parity MultiSig hack: https://motherboard.vice.com/en_us/article/ywbqmg/parity-multi-signature-wallet-vulnerability-300-million-hard-fork

Both of the hacks above accounted millions in losses! 🤯 from security bugs in their code; The recursive calling bug in the DAO smart contract allowed a hacker to keep calling a function and drain the balance of a contract. please see below for more details

https://ethereum.stackexchange.com/questions/6176/what-is-a-recursive-calling-vulnerability

To get ready for the next step you will need to install truffle:

https://github.com/trufflesuite/truffle

npm install  -g truffle

Conducting installation of truffles will allow a user/developer to get analyst of their or anyone’s smart contract and allow for compliation, migration and testing of a set of smart contracts. it’s quite handy!

To initialise a truffle pack all you have to do is create a directory in your terminal and run

truffle init

Once you have run the command you should see something similar too

Now in your new directory you have 3 new folders; 1: contracts, 2: migrations, 3: test, and 2 new files truffle-config.js and truffle.js.

Folders ------------------------------------------------------------Contracts - Stores your smart contracts.Migrations - Are storage for migration/deployment scripts.Test - Is storage for you're testing scripts.truffle-config.js and truffle.js - Allow for configuration of networks, default accounts and gas limits etc.. --------------------------------------------------------------------

What you need to do for the next few steps is first copy and paste the smart contract below into a text editor and save the file in the contracts folder of you’re truffle directory.

pragma solidity ^0.4.24;import "./SafeMath.sol";contract erc20TokenInterface {function name() public view returns (string);
 function symbol() public view returns (string);
 function totalSupply() public view returns (uint);
 function decimals() public view returns (uint);
 function getBalance(address _owner) public view returns (uint);
 function transfer(address _to, uint _amount) public returns (bool success);
 function transferFrom(address _owner, address _to, uint _amount) public returns (bool success);
 function approve(address _spender, uint _amount) public returns (uint, bool success);
 event Transfer(address indexed _from, address indexed _to, uint amount);
 event Approval(address indexed _spender, address indexed _to, uint amount);}contract ERC20Token is erc20TokenInterface {
      
    using SafeMath for uint256;event Transfer(address indexed _from, address indexed _to, uint amount);
 event Approval(address indexed _spender, address indexed _to, uint amount);uint constant private MAX_UINT256 = 2**256 - 1;
   uint _totalSupply = 21000000;
   uint _decimals = 10;
   string _name;
   string _symbol;
   address public owner;mapping (address => uint) public balances;
   mapping (address => mapping (address => uint)) public allowances;constructor () public {
    _totalSupply = 21000000;
    _decimals = 8;
    _name = "A Very High Token";
    _symbol = "HIGH";
    owner = msg.sender;
    balances[owner] =  _totalSupply;
    emit Transfer(address(0), msg.sender, _totalSupply);
   }function name() public view returns (string) {
    return _name;
   }
 function symbol() public view returns (string) {
  return _symbol;
 }
 function totalSupply() public view returns (uint) {
  return _totalSupply;
 }
 function decimals() public view returns (uint) {
  return _decimals;
 }
 function getBalance(address _owner) public view returns (uint) {
  return balances[_owner];
 }function transfer(address _to, uint _amount) public returns (bool success) {
     require (balances[msg.sender] >= _amount);
     balances[msg.sender] = balances[msg.sender].sub(_amount);
     balances[_to] = balances[_to].add(_amount);
     require (balances[_to] >= _amount);
     emit Transfer(msg.sender, _to, _amount);
     return success;
     
 }
 
 function transferFrom(address _owner, address _to, uint _amount) public returns (bool success) {
     require (allowances[_owner][msg.sender] >= _amount);
     require (balances[_owner] > _amount);
     allowances[_owner][msg.sender] = allowances[_owner].  [msg.sender].sub(_amount);
     balances[_owner] = balances[_owner].sub(_amount); 
     balances[_to] = balances[_to].add(_amount);
     emit Transfer(_owner, _to, _amount);
     return success;
 }
 
    function approve(address _spender, uint _amount) public returns (uint, bool success) {
        allowances[_spender][msg.sender] = allowances[_spender][msg.sender].add(_amount);
      return (_amount, success);
 }}

The above is a token contract that i created a little while ago. This is an ERC20 compliant token and can be used in the Ethereum eco-system for a range of different use-cases. One of them being a currency like the DAI and another being rewards token like BAT.

PLEASE NOTE: THE CONTRACT ABOVE IMPORTS SafeMath.sol when adding this contract to your contracts folder, please add the safe maths contract aswell from open zeppelin to the contracts folder.

Once you have that done you can run truffle compile:

truffle compile 
If compiled correctly you will have a 4th file in your directory called ‘build’ that contain your JSON files.

Next comes the migrations files that allows us too migrate contracts onto the blockchain… In your text editor open a blank page and enter the following piece of code.

NOTE: Save the file as '2_deploy_contracts.js'var tokenContract = artifacts.require("Token.sol");module.exports = function(deployer) {
 deployer.deploy(tokenContract);
};

Once you have written your deployment script please save it and open

“truffle.js” so we can begin configuration.

Enter the following and save - module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 9545,
      network_id: "*" // Match any network id
    }
  }
};NOTE: You may need to change your port. we will see in a sec! 

Now you have your configuration file and your deployment script ready to get your smart contract on the blockchain. Lets spin up an instance of the Ethereum blockchain by using the following command in a new terminal.

truffle develop

You should have a screen with 10 key pairs on there and mnemonic seed phrase similar to the one below, please also check that the localhost and port is the same as the one in your “truffle.js” file.

Now lets get the contract deployed to the blockchain so we check that everything is good so far… Go back to the orginal terminal where we initialised the truffle package and use the command.

truffle migrate

If everything is done correctly you should end up with the contracts compiling along with the transaction logs from the blockchain.

A successful migration ^^^

Nice work guys! You’re contract is on the blockchain. To interact with the smart contract we need is the contract address which is in the case above “0xeec918” and the ABI (Application Binary Interface) to get the ABI what you can is open up a new terminal that is connected to project directory and start nodejs

simply use - node

Once you have started node we will need to read the token contract JSON file from the “build” folder. To do that use the following script in terminal where you started up node.

var Mcontract = JSON.parse(fs.readFileSync('./build/contracts/ERC20Token.json', 'utf8')); console.log(JSON.stringify(Mcontract.abi));

This will print your abi in the terminal for you :)

Back in the truffle develop you can now set the variables needed to interact with your smart contract.

truffle(develop)> var contractAddress = '0xeec918d74c746167564401103096d45bbd494b74'truffle(develop)> var abi = [{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_spender","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"uint256"},{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]truffle(develop)> var contract = new web3.eth.contract(abi, contractAddress)"which should allow you to interact with the contract by..."truffle(develop)> contract.methods.name().call((err, result) => { console.log(result) })"To get the name of the contract. If that is not working please use something like..."truffle(develop)> ERC20Token.at("0xeec918d74c746167564401103096d45bbd494b74").name.call();
21 Million very high tokens………

WEHEYYYYYY! You are now really starting to work magic with the Blockchain! 🆒⛓

Testing.. 🛂

The next step is probably one of the most important pieces of development in the Ethereum eco-system, this is because each smart contract must be fully tested and audited before being deployed on to the main Ethereum blockchain. Testing allows you test(“What it says on the tin”) the functions in your smart contract to make sure that it is behaving correctly and the data structures are also responding to the function calls and changing state when needed.

To get started what we will need to do is create a new file in your text editor and call it ‘tokenContractTest.js’ and save. Now time to start writing the script, first we will check that the variables set in the constructor function are saved and can be seen. Some of the functions in the test script below will also test for transfers between 2 accounts and check the balance of the accounts once the transfer has finished to make sure that the value has sustained its durability. Please copy and paste the code below into your test file.

const shouldFail = require('../helpers/shouldFail');
const expectEvent = require('../helpers/expectEvent');const token = artifacts.require('ERC20Token.sol');const BigNumber = web3.BigNumber;require('chai')
  .use(require('chai-bignumber')(BigNumber))
  .should();const name = "A Very High Token";
const symbol = "HIGH";
const decimals = 8;contract('ERC20', function ([owner, recipient, anotherAccount]) {
  beforeEach(async function () {
    this.token = await token.new();
  });describe('total supply', function () {
    it('returns the total amount of tokens', async function () {
      (await this.token.totalSupply()).should.be.bignumber.equal(21000000);
    });
  });describe('how many decimals', function () {
    it('should have the same amount of decimals as provided in the constructor of the contract', async function () {
      (await this.token.decimals()).should.be.bignumber.equal(decimals);
    });
  });describe('name of token', function () {
    it('should be the same name as specified in the constructor of the contract', async function () {
      (await this.token.name()).should.be.equal(name);
    });
  });describe('symbol', function () {
    it('should have the same symbol as specified in the contract constructor', async function () {
      (await this.token.symbol()).should.be.equal(symbol);
    });
  });describe('balanceOf', function () {
    describe('when the requested account has no tokens', function () {
      it('returns zero', async function () {
        (await this.token.getBalance(anotherAccount)).should.be.bignumber.equal(0);
      });
    });describe('when the requested account has some tokens', function () {
      it('returns the total amount of tokens', async function () {
        (await this.token.getBalance(owner)).should.be.bignumber.equal(21000000);
      });
    });
  });describe('transfer', function () {
    describe('when the recipient is not the zero address', function () {
      const to = recipient;describe('when the sender does not have enough balance', function () {
        const amount = 210000001;it('reverts', async function () {
          await shouldFail.reverting(this.token.transfer(to, amount, { from: owner }));
        });
      });describe('when the sender has enough balance', function () {
        const amount = 21000000;it('transfers the requested amount', async function () {
          await this.token.transfer(to, amount, { from: owner });(await this.token.getBalance(owner)).should.be.bignumber.equal(0);(await this.token.getBalance(to)).should.be.bignumber.equal(amount);
        });
      });
    });
  });  
});

You may have noticed some code at the top of the test script that we haven’t spoke about which is:

const shouldFail = require('../helpers/shouldFail');
const expectEvent = require('../helpers/expectEvent');

What these are is two scripts that help with certain tasks in the test script we’ve just saved. For the tests to pass what you will need to do is create a new folder in your project directory called “helpers” then in your text editor create 2 new blank scripts.

please see: https://github.com/OpenZeppelin/openzeppelin-solidity/tree/master/test/helpers — for the code, copy and paste, then save the files.

When you’ve done that go to the terminal where you created your project directory and use the command:

truffle test 

You’re output should be 8 test that PASS! 👏

your output should replicate the above.

If that is correct and you have 8 test that pass…. Bloody Well Done! Theres more magic happening by the minute! Or should we say “Block” 🙊

Hopefully you’re starting to see the “picture” or getting the ‘jist’ of how development in the Ethereum eco-system is expected to be conducted and what kinds of measures are taken to ensure the security of a smart contract that is getting deployed onto the main-net.

In this post we have covered some of the fundamental requirements for developing solidity smart contracts like compilation, migration to the blockchain and making sure that the contract is working as expected. ie testing; If you noticed aswell we started using the JavaScript programming language to write test scripts for our contracts. Tests can be written in solidity but mostly they’re in JS because they can get complex and JS has more flexibility for workflow with a large set of smart contracts.

We also started using a little bit more of WEB3.JS with interacting with the smart contract we deployed in the truffle develop terminal. And we even pulled the abi from the build script in nodeJS, you should also be aware of the folders that you are given upon initialization of a truffle project and how to configure the project so that deployment and interaction is successful.

Thanks for reading! And hope to see you at the next one… 😘

Please clap and leave a comment “good” or “bad” feedback is feedback and will always be appriciated!

✌️

PS: in the next part we will start to explore some simple front-end development with react.

bitfwd

We bring you workshops, open-source projects and blog to take you where the bit is going

Connor Wiseman

Written by

Blockchain architect — interested in decentralised solutions that remove the currently centralised middlemen of many industries.

bitfwd

bitfwd

We bring you workshops, open-source projects and blog to take you where the bit is going