This tutorial is part of the series ToDo List Ethereum Dapp. It is the Step 1. Tutorials already published:
- Intro
- Step 1: Writing The ToDo Smart contracts- beginning (This tutorial)
- Step 2: Writing The ToDo Smart contracts- end
- Step 3: Writing The Nodejs Backend
- Step 4: Setup the frontend and read account data
- Step 5: Build a smart contract client with Truffle Contract
- Step 6: Refactor With Webpack, ES6 and truffle-solidity-loader
- Step 7: Read Contract data from Frontend
- Step 8: Create smart contract data from frontend
- Step 9: Toggle task done & keep frontend updated
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!
DappSolidity
9:29 you say you're not going to show how to do the migration file. Is there a video that you can show me where you explain how to do it?