Solidity tutorial: Smart contracts explained

Today we’ll learn more about smart contracts. With my Solidity tutorial, we’ll develop a simple token using Solidity with the help of a Truffle framework and deploy it to Ganache/testrpc. Why do we need to create a simple token as a smart contract? ICOs are increasingly gaining in popularity, so this will be an ideal place for learning more about the technology behind them. They will be excellent to showcase most of the tools in the Ethereum/smart contract stack.

 

Hello, again! Glad you made to our Solidity tutorial. I am not sure if you know but there is a previous tutorial on Ethereum and how to set up your own Ethereum private network. If you missed that, click the link: Ethereum tutorial.

Smart contracts explained in a nutshell

Before we start our Solidity tutorial and dive into developing a smart contract, we first have to learn what they are. Well, smart contracts are just programs that are executed and run on the blockchain. That’s it! A smart contract defines the conditions to which all parties using the contract agree. So if the required conditions are met, certain actions are executed. It’s just that simple.

 

As in every good guide, we will start our Solidity tutorial with setting up with the environment and download everything we need. So grab your favorite soda and some snacks, it’s time to set up the dev env!

 

Solidity Tutorial: Environment and Truffle intro

SIDE NOTE [I’m developing everything on the MacOS so all of the terminal commands will be for this system.]

 

First things first, we need NodeJS on our machine.

 

brew install node

 

Phew, that was complicated. Next, we need to have Truffle and testrpc installed. Truffle is a framework for writing and testing our smart contracts, it saves a lot of time and is very helpful. Testrpc simulates a local Ethereum node for quick development and test the deployment of our smart contract code. Instead of setting up geth, creating a private node and deploying it there, we can just use Testrpc.

 

npm install -g ethereumjs-testrpc

npm install -g truffle

 

As we have that installed, it’s time to create a project directory, let’s call it espeo-smart-contract-tutorial and initialize the project.

 

mkdir espeo-smart-contract-tutorial && cd espeo-smart-contract-tutorial

truffle init

 

After initialization we should have a file structure like this:

 

.

├── contracts

│   ├── ConvertLib.sol

│   ├── MetaCoin.sol

│   └── Migrations.sol

├── migrations

│   ├── 1_initial_migration.js

│   └── 2_deploy_contracts.js

├── test

│   ├── TestMetacoin.sol

│   └── metacoin.js

└── truffle.js

 

Smart contracts explained: main directories and files:

  • contracts/: Directory for Solidity contracts
  • migrations/: Directory for scriptable deployment files
  • test/: Directory for test files of your application and contracts
  • truffle.js: Truffle configuration file

 

Great, we have our project initialized with some sample files inside. We could delete some of them and create our own for our token, but we will use them to learn Truffle commands. Let’s start!

 

As is the case with many programming languages, we first need to compile our project.

 

$ truffle compile

Compiling ./contracts/ConvertLib.sol…

Compiling ./contracts/MetaCoin.sol…

Compiling ./contracts/Migrations.sol…

Writing artifacts to ./build/contracts

 

In its first use, Truffle will compile all the files in the contracts/ directory. Any subsequent run it will compile only these files that were changed. If you want to compile everything from scratch, just add –all flag to the end of the command.

 

You may have noticed that artifacts were written to the ./build/contracts directory. Truffle will use these files to deploy contracts to the network, you shouldn’t edit them as any manual change here will be lost next time the compiler is run!

 

With our contracts compiled, it’s time for the next step in our Solidity tuorial. Let’s run tests. With Truffle init, all sample contracts come with test files. We will learn later how to write our own tests for smart contracts. Running tests is easy, in terminal:

 

$truffle test

 

TestMetacoin

√    testInitialBalanceUsingDeployedContract (62ms)

√    testInitialBalanceWithNewMetaCoin (82ms)

 

 Contract: MetaCoin

√    should put 10000 MetaCoin in the first account (48ms)

√    should call a function that depends on a linked library (78ms)

√    should send coin correctly (177ms)

 

 5 passing (890ms)

 

Done, all tested and we can see the results of those tests.

 

We have our contracts compiled and tested, now it’s time to migrate (deploy the contracts) to the network. Migration won’t work if we do not have a live or local network specified. We will deploy our MetaCoin to the test network so we need to have testrpc running.

 

Open a second terminal window and run our testrpc. Testrpc will simulate Ethereum node on our local machine. To run it, you need to type:

$ testrpc -u 0

 

Switch to our main window and run Truffle migrate. Configuration for Truffle (to know to which network performs a migration) can be found in trufffle.js

$ truffle migrate

Using network ‘development’.

 

Running migration: 1_initial_migration.js

 Deploying Migrations…

 … 0x5ba32780e5ce7de88e03787a79296697f1eb7dfa3fa06880223730fa0d371928

 Migrations: 0xcf63a785a9b11201b4d29a71830af2fefc52e680

Saving successful migration to network…

 … 0xf6e57b392b9cb6437b541684cdadfe9c0a1a1267acabd64758d64005e1437c0c

Saving artifacts…

Running migration: 2_deploy_contracts.js

 Deploying ConvertLib…

 … 0xfc099f048c063bc9d86723043219ff4c78c533cb05d4355dc874905c2184707a

 ConvertLib: 0x4dc736cffe4790c3e37629dd7fb81daa07ed1608

 Linking ConvertLib to MetaCoin

 Deploying MetaCoin…

 … 0x925e5f4853f78a0083ab40871fd4c20a2c4d0a988c95972eac8666721a4266b9

 MetaCoin: 0x42b320a6c86ff16afca7346c8612ed64ece8ecb3

Saving successful migration to network…

 … 0x68eafc1814bcdeaffa8a30306ec31f3a7077b6eb305873d236e01093e2a21d8a

Saving artifacts…

 

You can see that 2 files were executed to run our migrations.

1_initial_migration.js and 2_deploy_contracts.js

We will get back to these files in a minute.

 

Truffle requires you to have a Migrations contract in order to use the Migrations feature. Such a contract was created when we initialized our project with “Truffle init”. Its file name is ./contracts/Migrations.sol

 

To deploy this contract using the migration feature we need to create 1_initial_migrations.js file.

But wait! We already have that file! That’s right, Truffle init also created an initial_migration file to deploy the Migration contract and that’s what this file is for, just to enable the Migration feature.

 

The second file is used for deploying our contracts. You can have many migrations files, just create another one with number prefix e.g. 3_test_migrations.js

 

We won’t dive much into explaining what each field in 2_deploy_contracts.js mean, here you can find the full Truffle documentation.

First, we tell Truffle which contracts we want to interact with. For that we use the artifacts.require() method. In it we just type the contract file name.

 

For migration to work each migration needs to have “module.exports”. The function exported by the migration needs to take a “deployer” as the first argument to the function. Deployer is an interface for deployment tasks inside Truffle.

 

To deploy a contract we just later state that deployer deploys MetaCoin which equals to :

 

deployer.deploy(MetaCoin);

Simple ICO creation

 

Delete two files from the contracts directory: ConvertLib.sol MetaCoin.sol. Delete everything from the tests directory and delete the whole build directory. Now we have a clear project and can create our simple ICO.

 

To help us with smart contracts creation we need to install open-zeppelin. Open zeppelin creates secure smart contract templates for ICO and we will use it in our Solidity tutorial.

 

$ npm install zeppelin-solidity

 

This adds the zeppelin-solidity folder to node_modules where you will find all smart contract templates.

 

The first step is to create a token contract

 

$ touch contracts/EspeoToken.sol

 

And add this code inside the file:

 

 

That’s it, a simple token contract. OpenZeppelin smart contract templates handle token creation and management mechanics and we can just focus on developing our unique functionality. Here we reference MintableToken. A mintable token is a token type where the supply is controlled by the owner. If you want to have a look at the code for it, follow this link: node_modules/zeppelin-solidity/contracts/token/MintableToken.sol .

 

The following step is to create a Crowdsale contract.

 

OpenZeppelin offers a template for a Crowdsale contract, and we are going to workfrom it. Our code looks like this.

 

 

A crowdsale requires a few parameters for its constructor and before we deploy a contract we must move parameters to it i.e. startTime and endTime timestamps, the rate of token per ether rate; and the wallet address of the contract owner(s).

Javascripts tests

 

We have our code, but we need to test it. It would be disastrous to deploy the code before making sure it does what it’s supposed to do. Tests can be written in solidity or Javascript. We will focus on Javascripts as it can be neatly integrated with web3.js and gives you more flexibility.

 

Create two tests files in the test directory.

 

$ touch test/espeo_token.js

 

Our first test code for Espeo Token looks like this:

 

 

In tests we are using the async/await approach instead of callbacks. You will find later that wrapping your test code in promises will save you much time and the code looks a lot cleaner. If you don’t know anything about async/await, visit this page.

 

The first thing needed in the test is to import the contract we want to test, hence const EspeoToken = artifacts.require(‘EspeoToken’);

 

contract() function is similar to the describe() function in Mocha, the only difference is that Truffle wraps it with some additional features. For example, making sure the contracts are deployed before running the tests.

 

beforeEach() function is run, as you guessed it, before each test. Here we usually put the initialization code that we need to execute before each and every test. In the case of our Solidity tutorial, it will create a fresh EspeoToken instance before each test.

 

Inside each it() block we have separate test cases.

 

If you are familiar with Javascript, the test written above will be straightforward to you. Basically we check if EspeoToken is populated with the right values.

 

The test code for a Crowdsale will be similar to this one but will need to cover more cases.

 

Using Truffle command test executes all the tests in your Truffle project. Which means it:

  1. Compiles your contracts
  2. Runs migrations to deploy the contracts to the network
  3. Runs tests against the contracts deployed on the network

 

Truffle test can be run on testrpc, testnet or the main net. Make sure that you use the proper network whilst running your tests, you don’t want to use the main net and waste all of your precious Ether on GAS.

 

There’s also a neat trick if we want to optimize our contract. In Truffle.js you can add

 

solc: {
 optimizer: {
   enabled: true,
   runs: 200
 }
}

 

This will optimize the compiled bytecode and the GAS usage of the contract execution and creation.

Deployment with Truffle 4.0

Before we deploy our Crowdsale we need to update the 2_deploy_contracts.js.

 

 

You may notice that we aren’t deploying EspeoToken. That’s because EspeoTokenCrowdsale will deploy EspeoToken at its creation so we do not need add it to the deploy contracts. Crowdsale has a method called createTokenContract() which returns the EspeoToken. Having the EspeoToken deployed again during migration is redundant and GAS price would be higher.

 

EspeoTokenCrowdsale also needs a few parameters for its constructor and we need to provide them.

 

Now we’re going to deploy it, difference is we’re going to use Truffle develop instead of using testrpc. You will see why in a minute.

 

Go to the project root category and run truffle develop.

 

$ truffle develop

Truffle Develop started at http://localhost:9545/

 

Accounts:

(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57

(1) 0xf17f52151ebef6c7334fad080c5704d77216b732

(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef

(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544

(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2

(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e

(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5

(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5

(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc

(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de

 

Private Keys:

(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3

(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f

(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1

(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c

(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418

(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63

(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8

(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7

(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4

(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5

 

Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat

 

truffle(develop)>

 

That’s right, Truffle has now integrated dev node based on Ganache. We do not need testrpc, we can just do everything inside using Truffle!

 

To deploy to our dev node, just type deploy.

 

truffle(develop)> deploy

Using network ‘develop’.

 

Running migration: 1_initial_migration.js

 Replacing Migrations…

 … 0x6fa60b1082ee7bcc22cf4f0a661a03816b123d714a641151ca49561ed47ae021

 Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0

Saving successful migration to network…

 … 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956

Saving artifacts…

Running migration: 2_deploy_contracts.js

 Deploying EspeoTokenCrowdsale…

 … 0x53ca863b13b2e6f948dd7f143bfb02ff3d5fbdfa022b21b69eda0c329f2bb1e6

 EspeoTokenCrowdsale: 0x345ca3e014aaf5dca488057592ee47305d9b3e10

Saving successful migration to network…

 … 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0

Saving artifacts…

 

Great! We have our contracts tested and deployed on the development network, but that’s only half of the story. In the next chapter we will focus on showing you how we can deploy our contracts to the testnetwork (ropsten) and how we can automate a few steps.

 

Manual Deployment (MEW and Metamask)

 

We need a way to interact with the Ethereum network and the most popular way is to use MetaMask. MetaMask is a Chrome Extension that allows you to interact with the Ethereum network without having to run a node on your system. You can simply install it by visiting metamask.io.

 

Create an account and switch to ropsten network.

solidity tutorial

solidity tutorial

Once you’ve switched to ropsten network we will need to fill our account with some Ether. Don’t worry, you won’t need to spend any money. You’re only using ether for testnetwork. There are many faucets where you can provide your account address and test ether will be sent to you.

 

Use this faucet: http://faucet.ropsten.be:3001/

Provide it with your account address from MetaMask by clicking three dots:

smart contracts explained

 

I already have 3 ether on this account from using a faucet. We will need it later.

 

To manually deploy our contract to the ropsten network we will use the myetherwallet.com/#contracts website.

smart contracts explained

 

Click “Deploy Contract”

smart contracts explained

To deploy a contract, you need to provide a byte code of the contract. We will deploy EspeoToken. Open build/contracts/EspeoToken.json. In that file, if you scroll down, you will find the bytecode section. Copy everything that’s between  “” and paste it into myetherwallet.

solidity tutorial

 

Sign the transaction and then click deploy transaction. A new MetaMask window will pop up and you will need to confirm the transaction. You will also need to put in a GAS Limit as it’s stated in the MEW website that it’s not filled in automatically. In our case it would be 983570 (check the MEW screenshot)

solidity tutorial

You can track the transaction progress on etherscan.io (the link will be available once the transaction is confirmed by the myetherwallet).

smart contracts explained

 

Great, we have our Token contract deployed on Ropsten! Now let’s try to interact with it. Go to the myetherwallet.com/#contracts and then to the “Interact with contract” tab. It should already be selected.

 

You need to have a smart contract address and an ABI. Smart contract addresses can be taken from etherscan.io from the previous transaction when we first deployed the contract.

 

ABI can be found in the build/contracts/EspeoToken.json file. There’s a section called abi, you need to take everything from the abi and paste it in the MEW.

solidity tutorial

 

Now we can interact with our contract, and use all the functions available.

smart contract explained

 

You’ll find that there are many more functions than we’ve created in the EspeoToken contract. That’s because it also takes functions from the Mintable Token.

 

All of that is great, but when try to deploy the EspeoTokenCrowdsale contract we will get an error message. It will say that we need to provide constructor parameters. Fortunately, there is a way to deploy such a contract with MEW and be able to change some parameters on the fly without the need to hardcode it. We need to create abFactory contract which will deploy our crowdsale contract.

 

Factory smart contract

Factory smart contract is very simple.

 

 

It’s a simple contract with one function that uses the same parameters which we’ll later pass to the EspeoTokenCorwdsale constructor. That’s it. We can compile it and deploy it using MEW as we did with the EspeoToken. The difference is that, to deploy crowdsale we do so using a function from the Factory contract.

 

You should be comfortable deploying it with MEW by yourself now. I’ll just skip this step and get straight to interacting with the contract.

smart contracts explained

 

Our deployed factory contract can now deploy another contract. We just need to fill these fields in and everything will be taken care of.

Automated deployment (Infura)

You are now familiar with manual deployment. However, I know the spirit of automating everything lies deep within you. You won’t have (or want to waste) time. With Truffle, you can migrate all contracts to testnetwork or mainnet just using Truffle migrate. I will now show you how you can do that using Truffle and infura.io.

 

Infura is a cluster of hosted Ethereum nodes that you can use for development/deployment without the need of setting up the node by yourself. To see how to set up your own node, visit part 1 of this Ethereum tutorial.

 

Go to infura.io and signup. After signing up you will be provided with your own key. For security reasons, Infura does not manage your private keys, which means Infura cannot sign transactions on your behalf. Truffle can sign transactions through the use of its HDWalletProvider. This provider can handle the signing of transactions as well as the connection to the Ethereum network.

 

First you will need to install it:

$ npm install truffle-hdwallet-provider

 

The next step is to edit your truffle.js file to use HDWalletProvider and provide all the necessary configuration required for deploying to Ropsten.

 

const HDWalletProvider = require(“truffle-hdwallet-provider”);

 

You also need to provide your infura API key which you got after signing up. You can add it to the code like this:

 

const infura_apikey = “abcdefGHijkawwedacKA1“; // it’s random string as I won’t put my key here publicly.

 

One thing that you will need is a mnemonic for your Ethereum account from which the deployment will be done. A mnemonics is a 12 seed word from which you can access your eth account. You can check what mnemonic you have by accessing MetaMask->Settings->Reveal Seed Words

Add them to the truffle.js

const mnemonic = “one two three four five six seven eight nine ten eleven twelve”;

 

And lastly we have our Ropsten configuration which looks like this.

 

ropsten: {

     provider: new HDWalletProvider(mnemonic, “https://ropsten.infura.io/”+infura_apikey),

     network_id: 3,

     gas: 4612388

   }

 

The full truffle.js is below.

 

 

But this isn’t the only change that we need to do. Deploying to infura is asynchronous. Since our 2_deploy_contracts.js is written in a synchronous way, we need to add promises to it (async/await). To save you the trouble I’ve updated the file with the proper code.

 

 

I also added a promisify function which takes a synchronous function and wraps it in promises. Using promises also changes the way we define our blocks, so now we use async and await. That’s why module.exports changed a little. If you want to understand more about how these changes work, please go to the tutorial for async/await that was linked earlier.

 

You can specify to which network a migration is required in a simple way. Just run:

$ truffle migrate –network ropsten

 

Using network ‘ropsten’.

 

Running migration: 1_initial_migration.js

 Replacing Migrations…

 … 0xe6d8479c9190a6d5e84af42c542beb908835163428632e3c344da34e2ab35cee

 Migrations: 0x734ed4ea42d9a80db38653ceca03c1fcc437bae6

Saving successful migration to network…

 … 0xc66608fff6d787a418f3d1f661f89ef982e93af5acc82507534d558b0e389074

Saving artifacts…

Running migration: 2_deploy_contracts.js

Saving successful migration to network…

… 0x2c7a9449aca2c27e0df0006846ccec51661fe2acb19c5037e2b372026e3a32fa

 Deploying EspeoTokenCrowdsale…

 … 0x24a4e068ce9274fd0db7c4dd6619bc248b7616aca756e830e0d7802ba9bf916a

Saving artifacts…

 EspeoTokenCrowdsale: 0x03760c45b3a644c20cd1200bb39090d9782fc6c7

 

It will take longer to deploy to testnetwork than for the local node. After a while you will see this:

Saving artifacts…

EspeoTokenCrowdsale: 0x03760c45b3a644c20cd1200bb39090d9782fc6c7

This is a hash of our transaction. You can copy that transaction hash and go to the http://ropsten.etherscan.io and monitor the transaction.

 

Contract verification (etherscan.io)

We’re almost done with our deployment of the contract. Wait, what? We just deployed it, how can we not be done?! Good practice tells us that when we deploy something to the network, testnetwork or mainnet, people would like to see if the contract is verified. What does it mean that a contract is verified? Well, it means that the code which we deployed is the same that the users want to use. They can later check the source code of the smart contract and verify that our code does what we say it does.

 

Verifying a smart contract is a simple process. Let’s go to the ropsten.etherscan.io and look for our smart contract. The deployed smart contract address can be taken from the transaction. In this case, the address is “0x03760c45b3a644c20cd1200bb39090d9782fc6c7”

smart contracts explained

When on EspeoTokenCrowdsale contract page, go to the “Contract Code”

solidity tutorial

Here you will see the Bytecode of the contract code. Click “Verify and Publish”

solidity tutorial

Here you need to fill in all of the information regarding your smart contract. We will go through the process together.

Contract Name: EspeoTokenCrowdsale

Compiler : V.0.4.18

Optimization: Yes

Solidity Contract Code:

This one is not that simple, as we will need a flattened code of our contract. This requires that all the code in our contract needs to be copied here, which means all of the Openzeppelin template code.

 

Luckily we have a tool for that. That tool uses Python3 so make sure you have it installed. Later, just type these commands.

 

$ virtualenv -p python3 .venv

$ . .venv/bin/activate

$ pip install solidity-flattener

$ solidity_flattener –solc-paths=”zeppelin-solidity=${PWD}/node_modules/zeppelin-solidity” contracts/EspeoTokenCrowdsale.sol > flat.sol

$ pbcopy < flat.sol

 

And that’s all. You can exit Python’s virtualenv by typing exit. You can now paste the flattened smart contract code in the Solidity Contract Code section.

 

Now we’re left only with the

Constructor Arguments ABI-encoded (For contracts that accept constructor parameters):

 

Our contract accepts constructor parameters. We even provided it with some during the migration. Go to the MEW, interact with our contract and copy all of the 4 parameters

startTime, endTime, rate and wallet.

 

We’ll need to write a short script which will transform our parameters for ABI encoded parameters. As always, our script will be small and compact.

 

Install ethereumjs-abi.

$ npm install ethereumjs-abi

Create file for our script

$ touch abi_encoded_parameters.js

Our script will look like that:

 

 

We need to provide 4 parameters in proper types, our time is just uint256, rate has the same type, and the wallet address has an address type. Later we’ll provide correct parameters that we took from MEW from our contract. We encode those parameters and log the result into the terminal.

 

Run this script:

$ node abi_encoded_parameters.js

 

Copy the result and paste it into the field on the etherscan.io. Click on Verify and Publish and wait. After a while you, should see this on the screen:

smart contracts explained

 

Everyone with the contract address can go to the etherscan.io and check if the contract code is verified. You can check mine on https://ropsten.etherscan.io/address/0x03760c45b3a644c20cd1200bb39090d9782fc6c7#code

 

Congrats! Our Solidity tutorial is complete, and smart contracts explained. You now have a fully published and verified a contract on the Ropsten! You have fundamental knowledge of the Ethereum and smart contract development. You’ve learnt more, written more code in Solidity, and written your own application on Ethereum. Well done you! If you’d rather save yourself the hassle and have other people do it for you, just let us know 😉 Use the box below to write to us.