Writing Smart Contracts on Solidity for Blockchain

Narayan Shrestha
readytowork, Inc.
Published in
5 min readJun 19, 2023

Blockchain technology has gained significant attention in recent years due to its decentralized and transparent nature. At the core of many blockchain applications are smart contracts, which are self-executing contracts with predefined rules. In this article, we will explore how to write smart contracts using Solidity, a popular programming language for the Ethereum blockchain, and Remix, an online Solidity IDE. We will create a simple to-do app that displays a to-do list for each owner.

In this section, we will provide a detailed explanation of blockchain concepts, including decentralization, distributed ledger, consensus algorithms, and smart contracts. We will emphasize their importance in creating secure and transparent systems.

Here, we will introduce Solidity, the programming language used for writing smart contracts on the Ethereum blockchain. We will cover the basics of Solidity, such as variables, data types, functions, modifiers, events, error handling, and contract deployment.

To begin writing our smart contract, we will explore Remix, an online Solidity IDE. We will guide the readers through setting up Remix and creating a new contract.

And add the code snippet for the todo app as Todo.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Todo {
struct Task {
string content;
bool completed;
}

mapping(address => Task[]) public todoList;

function createTask(string memory _content) public {
Task memory newTask = Task(_content, false);
todoList[msg.sender].push(newTask);
}

function getTasks() public view returns (Task[] memory) {
return todoList[msg.sender];
}
}

Code explanation:
1. Todo the contract is created to manage the to-do list.

2. Task struct represents an individual task, with two properties: content (the content of the task) and completed (a flag indicating whether the task is completed or not).

3. todoList mapping is used to associate each owner's address with an array of tasks. Each owner will have their own to-do list.

4. createTask function allows an owner to create a new task by providing the task's content. It creates a new Task struct with the provided content and adds it to the owner's to-do list.

5. getTasks the function retrieves all the tasks associated with the calling owner's address. It returns an array of Task structs representing the to-do list for that owner.

Let's compile and deploy via remix

After the deployment is succeeded, we can see the deployed contract list

Now we can add manually by typing some todo work and submitting using createTask button.

After submission, you can see the transaction will be created on the terminal on the right side.
You can list the todo app by clicking getTasks button, you can see the list the user has created.

In the blockchain, every transaction has its owner, so currently we are using the default address so let's call it user1 for now.

To confirm the ownership, let's change the owner address and re-add the to-do task from the account dropdown as in the screenshot.

And create new to-do tasks, and fetch to-do tasks, and you will see only the task this address has created. This is handled for getTasks() function.

Let's add a new function to update the todo status to completed.

function updateTaskStatus(uint256 _taskIndex, bool _completed) public {
require(_taskIndex < todoList[msg.sender].length, "Invalid task index");
todoList[msg.sender][_taskIndex].completed = _completed;
}

This will update the status of the todo array.

Also let us create a function to edit the todo task which is yet to be completed so that we learn how to validate also
function updateTaskStatus(uint256 _taskIndex, bool _completed) public {

function updateTaskContent(uint256 _taskIndex, string memory _newContent) public {
require(_taskIndex < todoList[msg.sender].length, "Invalid task index");
require(!todoList[msg.sender][_taskIndex].completed, 'Opps, Completed task cannot be updated!!!');
todoList[msg.sender][_taskIndex].content = _newContent;
}

Here did all the operation. One operation is missing i.e., deletion.

Let's build that too. For that, we need to add a field to keep track that the item is deleted or not.

bool isDeleted;

And we need to change our getTask function accordingly, as the blockchain does not delete any node in real, so we need to filter accordingly. The updated function would be

function getTasks() public view returns (Task[] memory) { 
uint256 taskCount = todoList[msg.sender].length;
Task[] memory activeTasks = new Task[](taskCount);
uint256 activeTaskIndex = 0;
for (uint256 i = 0; i < taskCount; i++) {
if (!todoList[msg.sender][i].isDeleted) {
activeTasks[activeTaskIndex] = todoList[msg.sender][i];
activeTaskIndex++;
}
}
return activeTasks;
}

The final code output will look like

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Todo {
struct Task {
string content;
bool completed;
bool isDeleted;
}

mapping(address => Task[]) public todoList;

function createTask(string memory _content) public {
Task memory newTask = Task(_content, false, false);
todoList[msg.sender].push(newTask);
}

function getTasks() public view returns (Task[] memory) {
uint256 taskCount = todoList[msg.sender].length;
Task[] memory activeTasks = new Task[](taskCount);
uint256 activeTaskIndex = 0;

for (uint256 i = 0; i < taskCount; i++) {
if (!todoList[msg.sender][i].isDeleted) {
activeTasks[activeTaskIndex] = todoList[msg.sender][i];
activeTaskIndex++;
}
}

return activeTasks;
}

function updateTaskStatus(uint256 _taskIndex, bool _completed) public {
require(_taskIndex < todoList[msg.sender].length, "Invalid task index");
todoList[msg.sender][_taskIndex].completed = _completed;
}

function updateTaskContent(uint256 _taskIndex, string memory _newContent) public {
require(_taskIndex < todoList[msg.sender].length, "Invalid task index");
require(!todoList[msg.sender][_taskIndex].completed, "Opps, Completed task cannot be updated!!!");
todoList[msg.sender][_taskIndex].content = _newContent;
}

function deleteTask(uint256 _taskIndex) public {
require(_taskIndex < todoList[msg.sender].length, "Invalid task index");
todoList[msg.sender][_taskIndex].isDeleted = true;
}
}

You can build, deploy and test 🙏

Here, we created a simple crud operation contract on solidity.

Keep coding and learning

--

--