Building a Decentralized Todo List DApp in React and Solidity
Tags: react, solidity, javascript, programming
Published: 2024-02-17 07:00:03

Blockchain technology and Ethereum's innovation with Turing-complete smart contracts provide the ability to develop serverless applications with backend code running on a decentralized network. 

This removes reliance on centralized servers and builds censorship resistance into the core of our apps.


![Web3 Vs Web2: The Untold Lies of Blockchain Technology](https://res.cloudinary.com/practicaldev/image/fetch/s--2iWwUcQg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.learnhub.africa/wp-content/uploads/2024/02/Web3-Vs-Web2-The-Untold-Lies-of-Blockchain-Technology-1024x535.png)


Learn why we feel are sham find out in this guide: [Web3 Vs Web2: The Untold Lies of Blockchain Technology](https://blog.learnhub.africa/2024/02/08/web3-vs-web2-the-untold-lies-of-blockchain-technology/)

In this comprehensive guide, we will demonstrate these strengths by architecting the backend smart contract for a blockchain-powered Todo List DApp.

Our tech stack includes:

- Solidity - For implementing self-executing logic on Ethereum
- Hardhat - Local Ethereum development and testing framework
- React - For building a sleek frontend UI
    

By the end, you will gain practical skills in crafting complex smart contracts ready for real-world usage.

## Development Environment Setup

The Hardhat framework sets up an integrated local environment for rapidly building Ethereum-based decentralized applications. Hardhat includes utilities for compiling, deploying, testing, and debugging Solidity smart contracts - great for boosting developer productivity.

First install Hardhat:

    npm install --save-dev hardhat 

Then initialize a sample project with:

    npx hardhat

Choose the `Create a sample project` option when prompted to generate a starter kit including a configurable `hardhat.config.js` file and folders for contracts and tests.


![Boost Your Solidity Development Game with VS Code The Ultimate Setup Guide](https://res.cloudinary.com/practicaldev/image/fetch/s--PWpkUhXG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.learnhub.africa/wp-content/uploads/2024/02/Boost-Your-Solidity-Development-Game-with-VS-Code-The-Ultimate-Setup-Guide-1024x535.png)


[Boost Your Blockchain Development Game with VS Code The Ultimate Setup Guide](https://blog.learnhub.africa/2024/02/03/boost-your-blockchain-development-game-with-vs-code-the-ultimate-setup-guide/)

We need additional plugins for enhanced capabilities around Ethers wallet integration and advanced contract testing using the Waffle library:


    npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai

Ethers.js assists with wallet management used later for deploying contracts while Waffle handles spinning up a testing blockchain network that mimics the Ethereum mainnet.
Finally, connect your Alchemy or Infura API key in `hardhat.config.js` to deploy to public test networks:


    module.exports = {
      solidity: "0.8.4",
      networks: {
        rinkeby: {
          url: `${process.env.ALCHEMY_API_URL}`,  
          accounts: [`0x${process.env.ACCOUNT_PRIVATE_KEY}`]
        },
      }
    }


## Smart Contract Design

With our Hardhat-powered development environment set up, let's start coding the smart contract backend!

Inside `contracts/TodoList.sol`, first structure a Todo data model containing essential fields via a Solidity struct:


    struct Todo {
      uint id;
      string text;
      bool completed; 
    }

Two critical aspects of any functional Todo list include:

1. Persisting added Todo items
2. Tracking completion status
    |

Hence our data model stores a unique `id`, a `text` description of the actual todo task, and a boolean flag `completed` denoting whether it's been marked done.

We manage storage via a list declared as:

    Todo[] public todos;

With the data foundation in place, we specify key application logic around managing todos in the form of Solidity functions:

**createTodo** - Insert new Todo into list by pushing to `todos` array
**toggleCompleted** - Flip the `completed` flag to true/false
**getTodos** - Fetch and return the `todos` array

Modular design best practices recommend emitting events in response to state changes. This allows detached frontends and analytics engines to conveniently listen for logs instead of directly observing contract storage which consumes higher gas fees.


    event TodoCreated(uint indexed id, string text);  
    
    function createTodo(string calldata _text) external {
      todos.push(Todo(_nextTodoId++, _text, false)); 
      emit TodoCreated(_nextTodoId, _text);
    }

Here when a new todo gets created, we emit a `TodoCreated` event containing the auto-incremented `id` and `text` details.


## Thoroughly Testing the Contract

With core functionality coded, it is prudent software engineering practice to comprehensively test smart contracts before relying on their correctness.

Waffle provides a testing environment by running a temporary Ethereum node optimized for rapid iteration. Under `test/TodoList.spec.js` we leverage Waffle's integration with Mocha/Chai for familiar syntax:


    describe('TodoList', () => {
      let todoList
      let owner
    
      beforeEach(async () => {
        // Deploy a new contract instance before each test
    
        owner = new ethers.Wallets.createRandom()  
        const TodoList = await ethers.getContractFactory('TodoList') 
        todoList = await TodoList.deploy() 
      })
    
      it('creates new todo', async () => {
    
        await todoList.connect(owner).createTodo('Get milk')
    
        const todos = await todoList.getTodos()
        assert.equal(todos.length, 1)
    
      })
    
    })

We test critical functionality like creating todos and retrieving them for validation against expected behavior per specifications. These end-to-end integration style tests capture real usage scenarios.

Combined with unit tests and code review, our comprehensive test suite guarantees the TodoList contract works correctly before launch.


## Deploying to Public Testnet

Once satisfied with functionality on the local emulated blockchain, we script a pipeline for standing up a live version on the public Rinkeby test network.

Configure Alchemy/Infura endpoints under Hardhat to connect to Rinkeby. Then simply import helpers and deploy in `scripts/deploy.js`:


    async function main() {
    
      const TodoList = await ethers.getContractFactory('TodoList')
    
      const todoList = await TodoList.deploy()
    
      await todoList.deployed()
    
      console.log('TodoList deployed to: ', todoList.address)
    
    }
    
    main()

Run via `npx hardhat run scripts/deploy.js --network rinkeby`.
The console prints the deployed contract address on success. Share this address with the DApp frontend to enable Web3 connectivity.

With an active instance now running on public infrastructure outside our proprietary control, the Todo list inherits blockchain's censorship resistance and persistent availability guarantees through decentralization.

## Conclusion

In this guide, we built a full-fledged backend for a decentralized Todo list DApp showcasing concepts like:

- Spinning up a Hardhat-powered dev environment
- Structuring data models with Solidity
- Developing core create, read, update contract functions
- Writing comprehensive integration test suites with Waffle
- Scripting deployment pipelines for publishing on Ethereum's public testnets
    

Composing the backend in this manner enables us to realize the Web3 vision of crafting resilient software immune from centralized failure points.

Equipped with these learnings, integrating any frontend such as React via web3 libraries like Ethers.js can now connect users to this serverless data layer living permanently on the blockchain.

This is the first section, in the next section we are going to dive into deployment and testing our contract. 

If you like our work and want to help us continue dropping content like this, buy us a [cup of coffee](https://www.buymeacoffee.com/scofields1s).

If you find this post exciting, find more exciting posts on [Learnhub Blog](https://blog.learnhub.africa/); we write everything tech from [Cloud computing](https://blog.learnhub.africa/category/cloud-computing/) to [Frontend Dev](https://blog.learnhub.africa/category/frontend/), [Cybersecurity](https://blog.learnhub.africa/category/security/), [AI](https://blog.learnhub.africa/category/data-science/), and [Blockchain](https://blog.learnhub.africa/category/blockchain/).

## Resource
- [Getting Started with Foundry for Beginners in 2024](https://blog.learnhub.africa/2023/12/19/getting-started-with-foundry-for-beginners-in-2024/)
- [What are Smart Contracts?](https://blog.learnhub.africa/2023/09/25/what-are-smart-contracts/)
- [Create a Raffle Draw Smart Contract Using Foundry 2024 (Part 1)](https://blog.learnhub.africa/2023/12/27/create-a-raffle-draw-smart-contract-using-foundry-2024-part-1/)