Getting started with Ethereum development

The Ethereum development ecosystem has really taken off lately. The tools for developing DApps have improved a great deal, and there are now plenty of learning resources to choose from. So, if you want to join in on the fun, there’s no better time than now!

We’ll be publishing regular blog posts about blockchain development, with a focus on practical, hands-on stuff. We want to share our knowledge, and encourage you to comment and give us feedback so that we can learn from you as well.

Today, we’ll take a look at the tools you can use to get started with Ethereum development and show you how to set them up. We’ll write a simple smart contract, deploy it to a local blockchain and interact with it. No prior experience of developing smart contracts is needed to follow along. Some previous programming knowledge is welcome, as well as basic familiarity with the Ethereum blockchain.

Don’t Truffle my feathers 🦉

Truffle is the most popular development framework for Ethereum right now. It aims to make developing smart contracts easier by providing you with tools for everything from compiling and deploying smart contracts to debugging and interacting with them.

To install Truffle, you need to have the npm package manager installed on your system. I recommend installing Truffle locally for each project. That way, the version of Truffle that your project depends on is specified in your package.json file and upgrading your version of Truffle for one project won’t mess up your other ones.

Let’s make a directory and initialise a new npm package.

$ mkdir my-project

$ cd my-project

$ npm init -y

This will create a package.json file that will specify which npm packages your project relies on. Let’s go ahead and install Truffle. We’ll specify exactly which version we want, so that if you revisit this tutorial at a later date, everything should work the same. In practice, it’s best to use the newest version.

$ npm install truffle@4.1.5

This will put our Truffle installation inside our package’s node_modules directory, as well as add it to package.json . Because Truffle wants an empty directory to initialise a project, we’ll make a new directory for it.

$ mkdir my-truffle-project

$ cd my-truffle-project

$ npx truffle init

The npx command is used to run executables from our node_modules/.bin directory. That way, we always use our local Truffle installation for development. Running truffle init creates our Truffle project skeleton. It creates directories for our contracts, tests and migrations. It also creates a file called truffle.js , which serves as the configuration for our project.

Our very own blockchain ⛓

Before we can start developing smart contracts, we need some way to test them locally without deploying them to the main network or one of the test networks. Ganache is an application that runs an Ethereum blockchain locally on your computer, which happens to be just what we need. It has a neat graphical user interface that gives us an overview of accounts, their balances and all the transactions that happened on our blockchain. It unlocks a couple of accounts for us to use and preloads them with 100 ETH.

Let’s go ahead and tell Truffle where to find our local blockchain. By default, Ganache listens on port 7545, but you can make sure by checking the top part of Ganache’s GUI.

Open up truffle.js and add a network for development.

module.exports = {

networks: {

development: {

host: '127.0.0.1',

port: 7545,

network_id: '*',

}

}

};

Each Ethereum blockchain has a network ID which sets it apart from other blockchains. For instance, the main network’s ID is 1, whereas the Kovan test network has an ID of 42. In this configuration, we use a wildcard to indicate that we don’t care what ID our network has.

Making a billboard 🖼

Now that we have Truffle installed and Ganache up and running, we can try our hand at making a simple smart contract and deploying it to Ganache.

Here’s an idea: let’s make a smart contract that will function as a billboard. It will have a message that is visible to anyone. And if you want, you can replace that message with your own — for a price. To post a message to the billboard, you have to send some ether along with the message. However, for your message to be displayed on the billboard, you have to send more ether than the current message’s buyer did.

What happens with all the ether that’s held on the contract? It goes to our favorite charity, of course! We will enable the charity organisation of our choice to withdraw the ether on the contract whenever they please.

To begin writing a contract, we use truffle create contract .

$ npx truffle create contract Billboard

This will create a file called Billboard.sol in our contracts directory and prefill it with a stub contract.

pragma solidity ^0.4.4; contract Billboard {

function Billboard() {

// constructor

}

}

Alright, let’s get busy! Go to the contracts directory and open Billboard.sol .

The first line in the contract defines which version of the Solidity compiler should be used to compile it. 0.4.4 means any version between 0.4.4 and 0.5.0 . However, if we’re writing contracts that do not act as libraries, it’s good practice to specify exactly which version of the Solidity compiler should be used. Let’s see which version we’re using right now.

$ npx truffle version

Truffle v4.1.5 (core: 4.1.5)

Solidity v0.4.21 (solc-js)

We can use pragma solidity 0.4.21 to make sure that whenever our contract is compiled, the same version of the Solidity compiler is used.

Let’s define some state variables. State variables are values which are permanently stored in contract storage. They persist across multiple function calls and act as our contract’s long-term memory.

These are the things our contract will have to remember.

The text that’s displayed on the billboard

How much ether was sent along with that text

The address of our charity

We define our state variables at the beginning of the contract.

contract Billboard {

address public charity;

string public text = 'Your ad goes here';

uint256 public currentTextValue;

...

First we define the type of our value, and then its visibility. public means that other contracts and web clients can see the variable and its value.

Now we can define the constructor. The constructor is a function that’s called when we deploy our contract. We’ll pass the address of our charity to the contract via its constructor.

function Billboard(address _charity) public {

charity = _charity;

}

We take the address that’s passed to the constructor and put it in our contract’s storage, simple enough.

What we need now is a way for people to publish their own message to our billboard. We’ll create a function for that and call it setText .

This function takes the text to be set as its sole argument. We declare it as public so that anyone can set the text. We also declare it as payable , allowing people and other contracts to send ether when calling the function.

By using the require statement, we declare that a certain condition must be true, otherwise the execution stops, the transaction is reverted and all the changes it tried to make so far are rolled back. We require that the amount of ether sent with the function call be greater than what the current message is worth.

Next, we just set the text and currentTextValue state variables to match the new text and how much the caller paid for it, respectively. msg is a special variable that holds information about the function call, such as who initiated it and how much ether they transferred.

People can now pay to have their message displayed on our billboard. Let’s add a function that our charity can call to withdraw ether from the contract.

function withdraw() public {

require(msg.sender == charity);

charity.transfer(address(this).balance);

}

Very simple stuff. We require the caller of this function to be our charity. Then we just transfer all the ether from our contract to it.

Great, we now have a working smart contract! Here’s the final product:

pragma solidity 0.4.21; contract Billboard {

address public charity;

string public text = 'Your ad goes here';

uint256 public currentTextValue; function Billboard(address _charity) public {

charity = _charity;

} function setText(string _text) public payable {

require(msg.value > currentTextValue);

text = _text;

currentTextValue = msg.value;

} function withdraw() public {

require(msg.sender == charity);

charity.transfer(address(this).balance);

}

}

We can compile the contract with truffle compile .

$ npx truffle compile

Compiling ./contracts/Billboard.sol...

Compiling ./contracts/Migrations.sol...

Writing artifacts to ./build/contracts

For each contract that it compiles, the compiler generates a JSON file called an artifact. Artifacts contain information about the contract’s functions, its code, the address where it was deployed, etc. We’ll use these artifacts to deploy our contract and to interact with it.

The migration script 🦆

One thing left to do before we deploy our contract is to give Truffle the instructions on how to deploy it. Let’s create a new migration.

$ npx truffle create migration billboard

This will create a file in our migrations directory. The file’s name will look something like 1522398980_billboard.js . Truffle uses the current timestamp to gkenerate the filename.

This is what we will put into our migration:

var Billboard = artifacts.require('Billboard') module.exports = function(deployer) {

let charityAddress = web3.eth.accounts[1]

deployer.deploy(Billboard, charityAddress)

};

We import our contract’s artifact as it has all the information we need to deploy it.

Ganache provides you with twenty unlocked accounts for testing purposes. You can access them from your tests and migrations by using web3.eth.accounts . When doing deployments, the first account, web3.eth.accounts[0] , is used by default. We define the second account, web3.eth.accounts[1] , to be our charity’s address.

The values that we pass to the `deploy` function will be passed on to the contract’s constructor. If we wanted to, we could use the same contract to deploy billboards for several charities by adjusting the migration script for each one.

Make sure that Ganache is running and then do truffle migrate .

$ npx truffle migrate

Using network 'development'. Running migration: 1_initial_migration.js

Deploying Migrations...

... 0xebd5a0a747e959e14a77c74e2750865809528f7f1dac420b5eef750ee4e94b00

Migrations: 0xeec918d74c746167564401103096d45bbd494b74

Saving successful migration to network...

... 0x60f9e7ee0b52c4e115c89824213f42cd5cd4e4a891213ef2ba89150f0fb55129

Saving artifacts...

Running migration: 1522398980_billboard.js

Deploying Billboard...

... 0xdd1974bc72a4920c23df9e7c6780179ccc66cb1655238b89a5d9e985fa675a1f

Billboard: 0xecfcab0a285d3380e488a39b4bb21e777f8a4eac

Saving successful migration to network...

... 0x40cc9de68f7dc90a946caea716431a405865fe44dc020d1066785457bd96813d

Saving artifacts...

Interacting with our smart contract 🎹

Our contract should now be deployed to our local blockchain. We’ll use the Truffle console to interact with it.

$ npx truffle console

truffle(development)>

Let’s get the instance of our deployed contract and put it in a variable.

truffle(development)> Billboard.deployed().then(instance => billboard = instance)

Billboard.deployed() returns a promise that evaluates to a contract instance. We use `then` to bind the instance to the variable billboard . Truffle creates accessor functions for all our public state variables. These functions also return promises, but the Truffle console will wait for promises to be resolved if they are the result of a command.

Let’s see what the current message on the billboard is.

truffle(development)> billboard.text()

'Your ad goes here'

Cool! How much is the current message worth? Let’s find out.

truffle(development)> billboard.currentTextValue()

BigNumber { s: 1, e: 0, c: [ 0 ] }

The BigNumber library is used to represent numbers that might potentially be too big for JavaScript’s normal numeric types. We can use their toString method to display them in a readable format. The special variable _ holds the result of the previous command.

truffle(development)> _.toString()

'0'

The current message is worth zero ether. Let’s buy some ad space. We’ll use web3.eth.accounts[2] as the buyer’s address. Whenever we call a function on a contract instance, we can pass along an object with some extra options. We’ll specify which account is doing the function call and how much ether they are passing along.

truffle(development)> billboard.setText('I like truffles', { from: web3.eth.accounts[2], value: web3.toWei(10, 'ether')})

The value field has to be specified in wei (1 ether is 10¹⁸ wei), which is why we used web3.toWei to convert ten ether to wei. The text on the billboard should now be updated.

truffle(development)> billboard.text()

'I like truffles'

Let’s check the balance of web3.eth.accounts[2] to see if they actually paid any ether. When we get the balance of an account, the amount is returned in wei, so we use the web3.fromWei function to convert the balance from wei to ether.

truffle(development)> web3.eth.getBalance(web3.eth.accounts[2])

BigNumber { s: 1, e: 19, c: [ 899946, 4000000000000 ] }

truffle(development)> web3.fromWei(_).toNumber()

89.994604

Cool, we see that the account has paid ten ether for the billboard, along with

a small amount of ether being used for gas.

We can inspect the balance of our contract in the same way.

truffle(development)> web3.eth.getBalance(billboard.address)

BigNumber { s: 1, e: 19, c: [ 100000 ] }

truffle(development)> web3.fromWei(_).toNumber()

10

If we want to buy an ad now, we have to transfer more than 10 ether to the contract or the transaction won’t go through.

truffle(development)> billboard.setText('Jazz for your soul', { from: web3.eth.accounts[3], value: web3.toWei(9, 'ether') })

Error: VM Exception while processing transaction: revert

The from account should only have been charged for gas and the text on the billboard should remain unchanged.

truffle(development)> web3.eth.getBalance(web3.eth.accounts[3])

BigNumber { s: 1, e: 19, c: [ 999976, 34300000000000 ] }

truffle(development)> web3.fromWei(_).toNumber()

99.9976343

truffle(development)> billboard.text()

'I like truffles'

Finally, our charity should be able to transfer the balance on the contract to its own account. When writing our migration, we defined web3.eth.accounts[1] to be the charity’s address.

truffle(development)> billboard.withdraw({ from: web3.eth.accounts[1] })

truffle(development)> web3.eth.getBalance(web3.eth.accounts[1])

BigNumber { s: 1, e: 20, c: [ 1099970, 16200000000000 ] }

truffle(development)> web3.fromWei(_).toNumber()

109.9970162

Awesome, we see that they successfully withdrew their funds. The contract’s balance should be zero.

truffle(development)> web3.eth.getBalance(billboard.address)

BigNumber { s: 1, e: 0, c: [ 0 ] }

truffle(development)> web3.fromWei(_).toNumber()

0

What’s next? 🌈

In this tutorial, we set up Truffle, wrote a simple smart contract and interacted with it. This serves as a good starting point for continuing our learning. You can download the repo with the code on our github page.

There’s still a lot left to do, such as writing tests and making a web interface from which we can interact with our contracts, so stay tuned!