Developing a ToDo list dApp in Ethereum
Pick up your groceries, on the chain.
What we will develop: A command-line ToDo list app. Making the frontend gets confusing and we will deal with that later!
Why: This is an introduction to Blockchain, Ethereum and dApps, and I treat toDo list apps as the “Hello World” of the dev world.
Before we start with how to work with Blockchain applications, let’s see the architecture if we developed this app as a centralized service. You have the backend server, running some code that fetches data from database, pushes data to database and serves you the frontend code. The frontend code is usually HTML + CSS + JavaScript, which is rendered by your browser to serve you the website.
Now a decentralized System works similarly, except you use a framework to contact a Blockchain network instead of a Server. Keeping this in mind, let’s get started! A Blockchain is essentially a Peer-to-Peer system, Ethereum included. There are many networks out there, but we will stick to Ethereum. Ehtereums run Smart Contracts, which are written in Solidity. If you have done any amount of Object-Oriented Programming before, Solidity will be easy to get on. For this tutorial you will need Web3.js, Truffle and Ganache. A quick introduction to all of this: Web3.js is used to communicate with your Blockchain, Truffle is used to interface with your solidity code, push it to the chain, test your smart contracts et al. and Ganache is used to run a local Blockchain to deploy your code to, since deploying to the Ethereum Virtual Network costs money (Ether) in the form of Gas.
Before we jump into anything further, let’s launch a local Blockchain!
If you have Ganache installed in your system (Download from https://www.trufflesuite.com/ganache), then start it.
Now that you have Ganache fired up (There could be a bit of setting up required depending on future upgrades), click on New Workspace. Name your workspace as you want, and click on “Next”.
Now there should be 10 accounts with 100.00 eth balance (I have only shown 2 here). The Address shown is the public address of the account, you can use this to send/recieve Ethereum. Go ahead and download MetaMask extension for your browser, I will show you how. TXcount is the count of transactions that account has. A few more things, in the screenshot above, can you see RPC server? Note the port. This is the port where your local virutal Ethereum network is running, we will need this. Now go to Metamask and login. On the top, you will see “Main Ethereum Network”, now that’s a problem. If we are working on a local Blockchain, we cannot work on main ethereum network that is running out there, isn’t it? So click on that button, and click on Custom RPC. Name the network with your portnumber, and in URL, enter ‘HTTP://127.0.0.1:<port>’, replace port with the port we noted earlier, for me it would be ‘HTTP://127.0.0.1:7545’. Now we need to import an account.
Click on your profile image, and click on “import account” (Ignore the fact I am on Ropsten, I will dicuss that in a future blog. Now go back to Ganache and click on the little key at the end for any account. Copy the private key and paste it in metamask and click “ok”.
A quick recap of what all we have done:
- Installed and launched Ganache
- Launched a local Blockchain on a localhost port
- Changed Metamask to work on our local Blockchain
- And imported our private accounts
So let’s develop the Smart Contracts!
contract Todo {
uint public count = 0;
First we declare the contract todo list and add our first member, the count. Since we cannot count all the tasks in the chain, we use a counter function.
struct Task {
uint id;
string content;
bool completed;
}
The Task contract will have the ID, Content and the Boolean for status of Task. Let’s add a mapping here:
mapping(uint => Task) public tasks;
Now we need to add a Task function which we can call:
function createTask(string memory _content) public {
count = count + 1;
tasks[count] = Task(taskCount, _content, false);
emit TaskCreated(taskCount, _content, false);
}
The parameter is the content, once we call the function with the content, it will call the function, and create a task by using the Task contract and add it to the tasks mapping. I will come to the emit TaskCreated in the next section.
Now that we can create tasks, we need to make sure we can check them off too. So let’s create two events:
event TaskCreated(
uint id,
string content,
bool completed
);event TaskCompleted(
uint id,
bool completed
);
Events are these inheritable members of a Contract. Whenever you emit an event, you store the arguments passed in logs. These logs are stored on blockchain and are accessible using address of the contract till the contract is present on the blockchain. Pretty simple, right?
Let’s create a function to check off a task!
function checkTask(uint _id) public {
Task memory _task = tasks[_id];
_task.completed = !_task.completed;
tasks[_id] = _task;
emit TaskCompleted(_id, _task.completed);
}
In this function, we ask for the ID of the Task in the parameter, then we store the task using the ID in a variable called _task, then we access the completed boolean member of the task instance, and flip it using the NOT function (‘!’), then put it back in the tasks[id]. Finally we emit it to the chain.
Now, let’s put everything on the chain. If you missed anything, here’s the code!
We need to add a file to help us migrate it now. Go to ./migrations and make a new file ‘2_deploy_contracts.js’, add the following code to it:
var Todo = artifacts.require(“./Todo.sol”);
module.exports = function(deployer)
{ deployer.deploy(Todo);};
Now let’s migrate it to the chain folks!
truffle migrate
(Quick note: Make sure the port in your truffle config and the port of your Ganache are the same)
Now you are all good to test it using truffle.
truffle console
todo = await Todo.deployed()
todo.createTask(“Give me 50 claps!”)
task = await todo.tasks(1)
You should now have a task at your hand, go ahead and complete it!
Once you are done giving me 50 claps (And I can see through the screen, I am staring at your soul), go to console again
task.checkTask(1)
And now it’s checked off! Thanks for joining me on this blog, be sure to follow, tons of high quality material coming through!
See ya.