Foreword

Recently I’ve heard from several fullstack dev colleagues that although Smart contracts and DAPPs (Distributed Apps) sound real exciting they are clueless on how to get started.

This actually surprised me as developers with good FED (Front End Development) skills actually have an advantageous starting point, so I decided to write this short post as a short guide on how to make the leap from WebApp to DApp development.

This post assumes, that you are fluent in JavaScript and the modern developments ecosystem/practices, familiar with the blockchain basics, and are comfortable working with a command-line interface.

The entire project can be found and cloned here.

The Contracts Language: Solidity

Solidity: In a nutshell, it is the primary programming language for writing smart contracts and distributed applications (DAPPS) that (when compiled) run on the Ethereum Virtual Machine (EVM). Interestingly enough, its syntax is based on ECMAScript, the same specification JavaScript is based on, so FEDs should be able to pick it up pretty fast.

Still, Solidity does differ from JS by having static types, special keywords, function modifiers, events, contract inheritance and other language features, so a bit of a learning curve is required, for not a steep one though.

There are many free resources online for learning Solidity, for example this youtube series might serve as a good starting point. Again, if you’re a JavaScript developer you should learn the ropes very fast.

The Dev Ecosystem: Truffle

Knowing the language is one thing, but of no lesser importance is having a working dev ecosystem for compiling, testing, deploying, tinkering with and interacting with the deployed smart contracts.

I find the Truffle suite to be the most convenient development framework, especially if you come from front-end background in which case you’d feel pretty comfy right away.

The suite is built around three main components:

Ganache – a local in-memory Ethereum blockchain for deploying contracts, running tests and commands and exploring the blockchain, and 10 pre-configured accounts holding 10 Ether each. It also exposes a CLI which could be used for test automation. Simply download the installable file and you’re ready to go.

Truffle – the main framework for developing smart contracts and DAPPs for Ethereum. This is a true piece of art, abstracting away a lot of the headaches pertinent to the development, testing and deployment of smart contracts, just to name a few:

  • Scaffolding of an entire new project, contract, test etc. using its simple CLI
  • Compiling the contracts (CLI> truffle compile)
  • Easy contract deployment a.k.a. Migrations, similar to Laravel, Django, Nodejs’ Sequelize etc; (CLI> truffle migrate)
  • A testing framework which can run directly against Ganache. It is based on Mocha and Chai so FEDs have near zero learning curve here (CLI> truffle test)
  • A console for interacting/tinkering with your contracts (CLI> truffle console)
  • A simple transactions debugger for stepping and printing values
  • Ability to run external scripts to interact with contracts

To install Truffle simply run > npm install truffle -g

Drizzle – the icing on the cake. This is the perfect companion for the front-end piece of a DAPP, which includes state store integration (e.g. Redux, Saga) which keeps accounts, balances, contracts and transactions data synchronized with the store at all times (by actually subscribing to on-chain events).

It also provides a couple of convenience functions (wrapping web3.Contract methods) for reading data from the blockchain and executing transactions while keeping the store in sync, and even a few React common components.

Although the components are React oriented, the state store integration is applicable for any other frontend framework you might want to use (i.e. React, Angular, Vue.js).

Kicking the Tires

Let’s conclude this post with a concrete example. We’ll write, compile, test and deploy the simplest possible smart contract – one that can only receive transfers, which isn’t really useful but will keep us focused on the essential basics to get you rolling.

Preparation

We’ll now install all prerequisites, use the CLI to create a new project structure, and configure truffle to work against our local Ganache Ethereum network.

> npm install truffle -g

  • Create a project folder and cd into it:

> mkdir pay-me

> cd pay-me

  • Initialize a new Truffle project:

> truffle init

  • Open the project in your preferred IDE
  • If you’re a Windows user: delete the file named truffle.js (to avoid ambiguity with the globally installed truffle command)
  • Make sure Ganache is up and running
  • Open the file truffle-config.js and replace its contents with the following:
module.exports = {
    networks: {
        development: {
            host: "127.0.0.1",
            port: 7545, // default Ganache port
            network_id: "*" // Match any network id
        }
    }
};

Create a Smart Contract

Time for the real stuff. We’ll scaffold a new contract file and write its code.

  • Run the command:

> truffle create contract PayMe

  • Open the file contracts/PayMe.sol in your IDE
  • Replace the file’s contents with the following:
pragma solidity ^0.4.22;

contract PayMe {

    event FundingEvent(address indexed from, uint256 value);

    constructor() public {
    }

    // fallback method to accept transfers
    function () public payable {
        FundingEvent(msg.sender, msg.value);
    }
}

Create a Migration

A migration file is required in order and deploy our contract. Migration files are prefixed by a number (e.g. 1541149214_pay_me.js) to ensure a sequential deployment order. When we’ll soon create a migration expect a similar filename to be generated under the migrations folder.

We will now create one for our PayMe contract.

  • Run the following command:

> truffle create migration PayMe

  • Open the file migrations/{some_number}_pay_me.js
  • Replace its contents with the following:
const PayMe = artifacts.require('PayMe');

module.exports = function(deployer, network, accounts) {
    deployer.deploy(PayMe).then((instance) => {
        console.log(`PayMe has been deployed. It's address is: ${instance.address}`)
    });
};

Write Unit Tests

We are going to write two simple tests, the first one validates that our contract is able to receive fund transfers, the second will validate that the FundingEvent event is raised and contains a from and value fields.

  • Create a test file for the contract by running:

> truffle create test PayMe

  • Open the file test/pay_me.js in your IDE
  • Replace its contents with the following:
const PayMe = artifacts.require('PayMe');
const sendAmount = web3.toWei(0.001, "ether");

contract('PayMe', accounts => {

    it("should receive 0.01 ether", () => {
        return PayMe.deployed().then(instance => {
            return instance.send(sendAmount).then(result => {
                return web3.eth.getBalance(instance.address);
            })
        }).then(balance => {
            assert.equal(balance.valueOf(), sendAmount, "contract balance doesn't equal 0.01 ether");
        });
    });

    it("should raise a FundingEvent", () => {
        return PayMe.deployed().then(instance => {
            return instance.send(sendAmount);
        }).then(result => {
            const {args, event} = result.logs[0];
            assert.equal(event, 'FundingEvent', "FundingEvent has not been fired");
            assert.ok(args.from, "event has 'from' field");
            assert.ok(args.value, "event has 'value' field");
        });
    });
});

Test our Contract

Money time – let’s see how everything plays together. We will run our unit tests, which will first deploy the contract to our local blockchain, then execute our tests and provide a report.

  • Run the following command:

> truffle test

If all went well, you should see a similar output:

Using network 'development'.

PayMe has been deployed. It's address is: 0xc0f3cbd4f206320f4cdfeb8593959555f803e7d8

  Contract: PayMe
    √ should receive 0.01 ether (375ms)
    √ should raise a FundingEvent (42ms)

  2 passing (470ms)

If you’ll now open the Ganache interface, you might notice the first account’s balance holding a bit less than 100.00 Ether, since during the first unit test we’ve transferred some 0.001 ether from this account to the PayMe contract.

Tinkering with the Contract

Sometimes it is handy to manually interact with a contract. This is where the Truffle console comes in handy. Since the console is not multiline friendly however, external files can be executed directly from the console. As a final step, let’s write a short script to check the contract’s deployed address and run it from the console.

  • At the root of the project, create a file named external.js
  • Paste the following contents into it:
const artifacts = require('./build/contracts/PayMe.json');
const contract = require('truffle-contract');
const PayMe = contract(artifacts);
PayMe.setProvider(web3.currentProvider);

module.exports = callback => {
    PayMe.deployed().then(instance => {
        console.log(`Contract address = ${instance.address}`);
        callback();
    });
};
  • Install the truffle-contract dependency (required by the script) by running the following commands:

> npm init -y

> npm install –save truffle-contract

  • Enter the console by running the following command:

> truffle console

  • You should now be in the console (the prompt will change to truffle(development)>)
  • In the console, let’s first ensure our contract is deployed by running:

> migrate –reset

  • Run the external script:

> exec ./external.js

  • You should now see a similar output:
Contract address = 0x22634fd051864b48752589ebabfabd924d6848ce

Congratulations!

You’re just created your first smart contract, deployed it to a local Ethereum blockchain, tested and interacted with it.

That’s it! Hope you found this post a good entry point, and welcome to the blockchain!

– Zacky