ToDo List Ethereum Dapp (Step1) | Writing The Smart Contract – Part I

This tutorial is part of the series ToDo List Ethereum Dapp. It is the Step 1. Tutorials already published:

Initialize the project

First, open a terminal, create a new folder step1 and bootstrap a Truffle project:

mkdir step1
cd step1
truffle init

Create a new smart contract ToDo.sol with this command:

truffle create contract ToDo

Our project is setup. Now we need to start coding our smart contract. First Let’s have a look at the skeleton code created by the truffle create contract command.

First look at our smart contract code

Open contracts/ToDo.sol. You should see something like this:

// Note: since this tutorial Solidity had a few changes, so
// you will see something slightly different. I will tell you
// when this happen. This tutorial is still valid, no worries :)
pragma solidity 0.4.4^; //You might see a different version of Solidity.
contract ToDo {
  function ToDo() {     //You might see `constructor()` for recent versions of Solidity.
  }
}

The first line sets the Solidity version for the compiler:

pragma solidity 0.4.4^;

Then the contract statement defines our smart contract.

Finally the function ToDo() (or constructor()) is the constructor function, which is executed only once when the smart contract is first deployed.

Let’s get rid of the constructor (function ToDo()).

Alright, now you understand the very basic elements of our smart contract. The most important thing in a smart contract is its data. We are going to define the basic data structures of our smart contract.

Create a struct and an array for tasks

Since our smart contract allows us to manage tasks, we need a way to represent a task in Solidity. Fortunately, Solidity has a construct to represent data: struct. We are going to use this. struct constructs are similar to objects in other programming languages because they can have fields. However, they differ in that they cannot have methods.

Enough theory, let’s get down to business!. Inside contract ToDo{}, add this:

struct Task {
  uint id;
  uint date;
  string content;
  string author;
  bool done;
};

Here we define a Task struct, with its different fields. Each field has a name and a type, like all variables in Solidity. For example, uint id means it is a field of type uint (integer) and has a name id. Notice that we represent date as integers.

We need a container to hold all our task instances. Solidity has arrays, like other programming languages. Let’s use this. Just below the Task `struct, add this:

Task[] task;

Cool. We have defined our basic data structures. How are we going to populate them?

Create a new task

Let’s create a function that can create new tasks. It will be able to:

  • Create a new Task struct instances
  • Add this new struct instance to the tasks array

Add this in your smart contract:

function createTask(string _content, string _author) public {
  tasks.push(Task(tasks.length, now, _content, _author, false));
}

What’s going on in this function?

First we define the function signature with its argument name and type;

function createTask(string _content, string _author) 

Then we specify the visibility of the function with the public keyword. In Solidity function visibility determines whether this function can be called from outside the smart contract or not. By default, functions have a public visibility and can be called from outside. Even if it’s already the default, this is a good practice to be explicit about this.

Then we create a new Task instance with:

Task(tasks.length, now, _content, _author, false))

And we add it to our tasks array with:

tasks.push(...);

Now we can create new tasks. Fantastic! But how are going to access these tasks? For this we need to create another function.

Read tasks

Let’s create a function to return a task by its id. Below createTask() add this:

function getTask(uint id) public constant
  returns(
    uint,
    uint,
    string,
    string,
    bool
  ) {
    return(
      id,
      tasks[id].date,
      tasks[id].content,
      tasks[id].author,
      tasks[id].done,
    );
  }
}

This function takes the id of the task to be returned as an argument.

Next to the public visibility specifier, we also specified that its a constant function, meaning that it does not modify data. This information will be used by web3 to just call the function instead of sending a transaction to the Ethereum Blockchain (technically it will trigger eth_call instead of eth_sendTransaction).

Then, we specify the types of the returned values:

 returns(
    uint,
    uint,
    string,
    string,
    bool
  )

NOTE: to specify the returned types you need to use the returns keyword WITH a final s. Don’t be confused with the return keyword WITHOUT a final s. This keyword is used INSIDE a function body to actually return values;

Finally, we return the values of our task. tasks[id] is how we access the correct entry in the tasks array, and the dot notation (.date, .content, …) is how we access a field of a specific struct instance:

    return(
      id,
      tasks[id].date,
      tasks[id].content,
      tasks[id].author,
      tasks[id].done,
    );
  }

To return all the tasks, you might be tempted to create this function:

function getTasks() public constant returns(Task[]) {
  return tasks;
}

But as of Solidity 0.4.24 this will not compile as Solidity cannot return an array of struct. So we will not add this function and we will leave it for the next step to read all tasks.

We have finished to write the code of the smart contract. But that’s not finished yet. We still need to deploy the smart contract and verify than it’s working.

Deploy and check that the smart contract is working

Go back to your terminal and launch a local ethereum blockchain with:

truffle develop

Then, inside the truffle develop console deploy our smart contract with:

truffle(develop)> migrate

Then let’s grab an instance of the deployed contract:

truffle(develop)> var inst;
truffle(develop)> ToDo.deployed.then((i) => inst = i)

Then let’s create a task by executing the createTask() function of the smart contract:

truffle(develop)> inst.createTask("My task content", "Julien")

Finally let’s execute the getTask() function of the smart contract to make sure we can access the task:

truffle(develop)> inst.getTask(0)

You should see an output similar to this:

truffle(develop)>
[ BigNumber { s: 1, e: 0, c: [ 0 ] },
  BigNumber { s: 1, e: 9, c: [ 1515334152 ] },
'My task content',
'Julien',
false ]

We can see the fields we pass to createTask() before. That’s the correct task, wonderful! Don’t be scared by the BigNumber thing. That is what is returned for the first 2 fields of the task (id, and date). To convert these fields to normal numbers, just execute toNumber() on them.

The End

Let’s briefly recap what we did during this tutorial. We created a basic smart contract that can:

  • represent a task
  • create new task
  • read a specific task

You learned about:

  • Solidity pragma and contract keywords
  • Arrays
  • Struct
  • Function
  • Function visibility
  • Constant keyword

We still don’t have a way to know about all the tasks that were created, and using an array to store Tasks can pose some problems. In the next tutorial we will solve these problems and finish our smart contract!

Leave a Reply

Your email address will not be published. Required fields are marked *