To-do List Blockchain dApp avec NextJS + Solidity + Web3.js - Tutoriel pas à pas
Tags: blockchain, solidity, nextjs, web3js
Published: 2024-06-26 15:32:16

### Introduction

Dans ce tutoriel, nous allons créer une application décentralisée (dApp) de liste de tâches en utilisant plusieurs technologies clés : NextJS pour le front-end, Solidity pour les smart contracts, Web3.js pour l'interaction avec la blockchain et Alchemy pour la connexion à Ethereum. Nous utiliserons également Sepolia, un réseau de test Ethereum, pour déployer et tester notre application sans utiliser de véritables ethers (ETH).

### Technologies utilisées

1. **dApp (Application Décentralisée)** : Une dApp fonctionne sur un réseau décentralisé, comme la blockchain. Contrairement aux applications traditionnelles, les dApps n'ont pas de point central de contrôle et utilisent des smart contracts pour gérer la logique applicative de manière sécurisée et transparente.

2. **Front-end** : Le front-end est la partie visible de l'application avec laquelle les utilisateurs interagissent directement. Il inclut les interfaces utilisateur (UI) et est généralement construit avec des technologies comme HTML, CSS et JavaScript. Dans ce projet, nous utilisons **Next.js** pour le front-end.

3. **Backend** : Le backend est la partie de l'application qui gère la logique, les calculs, et les interactions avec la base de données. Dans une dApp, une partie de la logique backend est gérée par des smart contracts sur la blockchain. Nous utiliserons **Hardhat** pour développer et tester notre backend en Solidity.

4. **JavaScript** : JavaScript est un langage de programmation utilisé pour développer à la fois le front-end et certaines parties du backend des applications web. Dans ce projet, nous utiliserons JavaScript pour créer et gérer notre front-end avec Next.js, ainsi que pour interagir avec la blockchain via Web3.js.

5. **Web3.js** : Web3.js est une bibliothèque JavaScript qui permet d'interagir avec la blockchain Ethereum. Elle permet aux applications web d'envoyer des transactions, de lire des données et d'interagir avec des smart contracts.

6. **Hardhat** : Hardhat est un environnement de développement Ethereum pour compiler, déployer, tester et déboguer vos smart contracts. Il simplifie le processus de développement des smart contracts en fournissant des outils puissants.

7. **Alchemy** : Alchemy est une plateforme de développement blockchain qui fournit des outils et une infrastructure pour interagir avec la blockchain Ethereum. Elle offre des APIs améliorées et une infrastructure de nœud supérieure pour faciliter le développement et le déploiement de dApps.

8. **Sepolia** : Sepolia est un réseau de test (testnet) Ethereum utilisé pour déployer et tester des smart contracts sans utiliser de véritables ethers (ETH). Les testnets comme Sepolia permettent aux développeurs de tester leurs applications dans un environnement simulé.

### Vue d'ensemble des étapes

1. **Développement du Smart Contract** :
    - Définir un smart contract pour gérer les éléments de la liste de tâches.
    - Compiler et déployer le contrat.

2. **Frontend Next.js** :
    - Configurer un projet Next.js.
    - Connecter le frontend au réseau Ethereum en utilisant Web3.js.
    - Implémenter la fonctionnalité pour créer, lire et gérer les éléments de la liste de tâches.

3. **Déploiement du Frontend en Local** :
    - Exécuter l'application localement pour tester l'intégration avec le smart contract.

### 1. Développement du Smart Contract

#### Configuration du Projet Backend

Pour commencer, nous devons créer un projet Hardhat. Hardhat est un environnement de développement Ethereum pour compiler, déployer, tester et déboguer vos smart contracts. Ouvrez votre terminal, créez ou accédez à un nouveau répertoire vide et exécutez la commande suivante :

```sh
npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers @openzeppelin/contracts dotenv
```
> **Explication** : Cette commande installe plusieurs packages essentiels pour développer et tester des smart contracts avec Hardhat, y compris `ethers` pour interagir avec Ethereum, `hardhat` pour le développement local, et `dotenv` pour gérer les variables d'environnement.

Ensuite, initialisez un nouvel environnement de développement avec la commande Hardhat :

```sh
npx hardhat
```
> **Explication** : Cette commande initialise un nouveau projet Hardhat dans le répertoire courant. Suivez les instructions pour créer un projet de base.

Après avoir exécuté cette commande, sélectionnez l'option "Create a basic sample project" et pour les autres options, appuyez sur "yes". Vous devriez voir les fichiers et dossiers suivants créés dans votre répertoire racine :

- **hardhat.config.js** : Contient la configuration de Hardhat.
- **scripts** : Contient un script nommé sample-script.js qui déploiera votre smart contract lorsqu'il sera exécuté.
- **test** : Contient un exemple de script de test.
- **contracts** : Contient un exemple de smart contract Solidity.

#### Obtenir une clé API Ethereum avec Alchemy

Alchemy est une plateforme de développement blockchain. Pour créer une API, suivez les étapes suivantes :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1uo81ijxls0ragqpbf1z.png)

1. Inscrivez-vous sur [Alchemy](https://www.alchemy.com/).
2. Allez sur le Dashboard.
3. Sélectionnez le réseau "Sepolia".
4. Copiez la clé HTTP après avoir créé l'application sur Alchemy.

Créez un fichier `.env` dans la racine de votre projet et stockez cette clé HTTP comme suit :

```env
ALCHEMY_SEPOLIA_URL="VOTRE_CLE_HTTP_ALCHEMY"
```
> **Explication** : Le fichier `.env` stocke les variables d'environnement de manière sécurisée, comme l'URL de votre API Alchemy, pour ne pas les exposer directement dans votre code source.

#### Obtenir votre clé privée de compte depuis Metamask

Metamask est un portefeuille de cryptomonnaies qui permet d'interagir avec la blockchain Ethereum. Cette clé privée est nécessaire pour notre script de déploiement du smart contract afin de l'exécuter et de prendre des frais de gaz en ether depuis notre portefeuille.

1. Cliquez sur l'icône de profil.
2. Sélectionnez le compte que vous souhaitez exporter.
3. Cliquez sur "Account Details".
4. Cliquez sur "Export Private Key" et entrez votre mot de passe.
5. Copiez et collez cette clé privée dans votre fichier `.env`.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8fm4htowfx3g0r5ubtj.png)



```env
ACCOUNT_PRIVATE_KEY="VOTRE_CLE_PRIVEE"
```
> **Explication** : La clé privée de votre compte Metamask est nécessaire pour signer et envoyer des transactions sur le réseau Ethereum. Ne partagez jamais cette clé et gardez-la sécurisée.

#### Obtenir des tokens de test pour Sepolia

Pour tester vos smart contracts sur Sepolia, vous aurez besoin de tokens de test. Vous pouvez obtenir des tokens de test (ETH) à partir de faucets de testnet. Voici quelques faucets que vous pouvez utiliser :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9h2gn1twfpteqy3xy2zb.png)

- [Sepolia Faucet](https://sepoliafaucet.io/)

> **Explication** : Les faucets de testnet vous fournissent des ETH gratuits que vous pouvez utiliser pour payer les frais de gaz lors du déploiement et du test de vos smart contracts sur les réseaux de test comme Sepolia.

#### Mise à jour de hardhat.config.js

Mettez à jour la configuration dans hardhat.config.js comme suit :

```js
require("@nomiclabs/hardhat-waffle");
require('dotenv').config();

module.exports = {
  solidity: "0.8.4",
  networks: {
    sepolia: {
      url: process.env.ALCHEMY_SEPOLIA_URL,
      accounts: [process.env.ACCOUNT_PRIVATE_KEY]
    }
  }
};
```
> **Explication** : Cette configuration permet à Hardhat de se connecter au réseau Sepolia via Alchemy en utilisant l'URL de votre API et la clé privée de votre compte Metamask pour déployer et tester les smart contracts.

#### Création de la logique du Smart Contract

Créez un nouveau fichier dans le répertoire contracts nommé `TaskContract.sol`. Ajoutez le code suivant :

```solidity
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract TaskContract {

    event AddTask(address recipient, uint taskId);
    event DeleteTask(uint taskId, bool isDeleted);

    struct Task {
        uint id;
        address username;
        string taskText;
        bool isDeleted;
    }

    Task[] private tasks;
    mapping(uint256 => address) taskToOwner;

    function addTask(string memory taskText, bool isDeleted) external {
        uint taskId = tasks.length;
        tasks.push(Task(taskId, msg.sender, taskText, isDeleted));
        taskToOwner[taskId] = msg.sender;
        emit AddTask(msg.sender, taskId);
    }

    function getMyTasks() external view returns (Task[] memory) {
        Task[] memory temporary = new Task[](tasks.length);
        uint counter = 0;
        for (uint i = 0; i < tasks.length; i++) {
            if (taskToOwner[i] == msg.sender && tasks[i].isDeleted == false) {
                temporary[counter] = tasks[i];
                counter++;
            }
        }

        Task[] memory result = new Task[](counter);
        for (uint i = 0; i < counter; i++) {
            result[i] = temporary[i];
        }
        return result;
    }

    function deleteTask(uint taskId, bool isDeleted) external {
        if (taskToOwner[taskId] == msg.sender) {
            tasks[taskId].isDeleted = isDeleted;
            emit DeleteTask(taskId

, isDeleted);
        }
    }
}
```
> **Explication** : Ce smart contract gère une liste de tâches. Il permet d'ajouter, de récupérer et de supprimer des tâches. Les tâches sont associées à l'adresse de l'utilisateur qui les crée.

#### Tester les Smart Contracts

Pour tester le smart contract, créez et ouvrez `test/TaskContractTest.js` et mettez-le à jour avec le code suivant :

```js
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Task Contract", function () {
  let TaskContract;
  let taskContract;
  let owner;

  const NUM_TOTAL_TASKS = 5;
  let totalTasks;

  beforeEach(async function () {
    TaskContract = await ethers.getContractFactory("TaskContract");
    [owner] = await ethers.getSigners();
    taskContract = await TaskContract.deploy();

    totalTasks = [];
    for (let i = 0; i < NUM_TOTAL_TASKS; i++) {
      let task = {
        'taskText': 'Task number: ' + i,
        'isDeleted': false
      };
      await taskContract.addTask(task.taskText, task.isDeleted);
      totalTasks.push(task);
    }
  });

  describe("Add Task", function () {
    it("should emit AddTask event", async function () {
      let task = {
        'taskText': 'New Task',
        'isDeleted': false
      };
      await expect(await taskContract.addTask(task.taskText, task.isDeleted))
        .to.emit(taskContract, 'AddTask')
        .withArgs(owner.address, NUM_TOTAL_TASKS);
    });
  });

  describe("Get All Tasks", function () {
    it("should return the correct number of total tasks", async function () {
      const tasksFromChain = await taskContract.getMyTasks();
      expect(tasksFromChain.length).to.equal(NUM_TOTAL_TASKS);
    });
  });

  describe("Delete Task", function () {
    it("should emit delete task event", async function () {
      const TASK_ID = 0;
      const TASK_DELETED = true;

      await expect(taskContract.deleteTask(TASK_ID, TASK_DELETED))
        .to.emit(taskContract, 'DeleteTask')
        .withArgs(TASK_ID, TASK_DELETED);
    });
  });
});
```
> **Explication** : Ces tests vérifient que le smart contract fonctionne correctement en ajoutant, récupérant et supprimant des tâches. Les tests utilisent `chai` pour les assertions et `ethers` pour interagir avec le contrat.

Exécutez les tests unitaires avec la commande suivante :

```sh
npx hardhat test
```
> **Explication** : Cette commande exécute les tests définis dans le répertoire `test` pour vérifier que le smart contract fonctionne comme prévu.

#### Déployer le Smart Contract sur le réseau SEPOLIA

Pour déployer le contrat, créez un fichier `deploy.js` dans le dossier `scripts` et ajoutez le contenu suivant :

```js
const main = async () => {
  const contractFactory = await ethers.getContractFactory('TaskContract');
  const contract = await contractFactory.deploy();
  await contract.deployed();

  console.log("Contract deployed to:", contract.address);
};

const runMain = async () => {
  try {
    await main();
    process.exit(0);
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};

runMain();
```
> **Explication** : Ce script déploie le smart contract sur le réseau Sepolia en utilisant Hardhat. Il affiche l'adresse du contrat déployé une fois le déploiement terminé.

Exécutez le script avec la commande suivante :

```sh
npx hardhat run scripts/deploy.js --network sepolia
```
> **Explication** : Cette commande exécute le script de déploiement sur le réseau Sepolia, utilisant les informations de configuration fournies dans `hardhat.config.js`.

### 2. Frontend Next.js

#### Initialiser le projet Next.js

```sh
npx create-next-app todo-dapp-frontend
cd todo-dapp-frontend
```
> **Explication** : Cette commande crée un nouveau projet Next.js et accède au répertoire du projet.

#### Installer les dépendances nécessaires

Installez Web3.js et les autres dépendances requises pour le frontend :

```sh
npm install web3 axios @emotion/react @emotion/styled @mui/icons-material @mui/material react-toastify
```
> **Explication** : Cette commande installe les bibliothèques nécessaires pour construire l'interface utilisateur, gérer les notifications, et interagir avec la blockchain.

#### Configuration du Frontend

##### Création de la structure de l'application

1. **Dossier src et pages** : Dans le dossier `src`, créez un dossier `pages` avec un fichier `index.js`.

Voici le contenu du fichier `pages/index.js` :

```js
"use client";
import { React, useState, useEffect } from 'react';
import { Container, Box, Typography, TextField, Button, AppBar, Toolbar, IconButton } from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import TaskTable from '../components/Task';
import Web3 from 'web3';
import { TaskContractAddress } from '../config';
import TaskAbi from '../utils/TaskContract.json';

export default function Home() {
  const [tasks, setTasks] = useState([]);
  const [input, setInput] = useState('');
  const [currentAccount, setCurrentAccount] = useState('');
  const [correctNetwork, setCorrectNetwork] = useState(false);

  // Fonction pour récupérer toutes les tâches
  const getAllTasks = async () => {
    try {
      const { ethereum } = window;

      if (ethereum) {
        const web3 = new Web3(ethereum);
        const TaskContract = new web3.eth.Contract(TaskAbi.abi, TaskContractAddress);

        let allTasks = await TaskContract.methods.getMyTasks().call();
        allTasks = allTasks.map(task => ({
          id: task.id.toString(),
          taskText: task.taskText,
          wallet: task.wallet,
          taskDate: new Date(task.taskDate * 1000).toLocaleDateString(),
          taskTime: new Date(task.taskDate * 1000).toLocaleTimeString(),
          isDeleted: task.isDeleted
        }));
        setTasks(allTasks);
      } else {
        console.log("Ethereum object doesn't exist");
      }
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    getAllTasks();
  }, []);

  // Fonction pour connecter le portefeuille Metamask
  const connectWallet = async () => {
    try {
      const { ethereum } = window;

      if (!ethereum) {
        toast.error('Metamask not detected');
        return;
      }
      let chainId = await ethereum.request({ method: 'eth_chainId' });
      console.log('Connected to chain:' + chainId);

      const sepoliaChainId = '0xaa36a7';

      if (chainId !== sepoliaChainId) {
        alert('You are not connected to the Sepolia Testnet!');
        return;
      } else {
        setCorrectNetwork(true);
      }

      const accounts = await ethereum.request({ method: 'eth_requestAccounts' });

      console.log('Found account', accounts[0]);
      setCurrentAccount(accounts[0]);
      toast.success('Wallet connected');
    } catch (error) {
      console.log('Error connecting to metamask', error);
    }
  };

  // Fonction pour ajouter une tâche
  const addTask = async (e) => {
    e.preventDefault();

    const task = {
      'id': tasks.length + 1,
      'taskText': input,
      'isDeleted': false
    };

    try {
      const { ethereum } = window;

      if (ethereum) {
        const web3 = new Web3(ethereum);
        const TaskContract = new web3.eth.Contract(TaskAbi.abi, TaskContractAddress);

        await TaskContract.methods.addTask(task.taskText, task.isDeleted).send({ from: currentAccount });
        setTasks([...tasks, task]);
        setInput('');
        toast.success('Task added');
      } else {
        console.log("Ethereum object doesn't exist!");
      }
    } catch (error) {
      console.log("Error submitting new Task", error);
      toast.error('Error adding task');
    }
  };

  // Fonction pour supprimer une tâche
  const deleteTask = async (taskId) => {
    try {
      const { ethereum } = window;
  
      if (ethereum) {
        const web3 = new Web3(ethereum);
        const TaskContract = new web3.eth.Contract(TaskAbi.abi, TaskContractAddress);
  
        await TaskContract.methods.deleteTask(taskId, true).send({ from: currentAccount });
        
        const updatedTasks = tasks.map(task => 
          task.id === taskId.toString() ? { ...task, isDeleted: true } : task
        );
        
        setTasks(updatedTasks);
        toast.success('Task deleted');
      } else {
        console.log("Ethereum object doesn't exist");
      }
    } catch (error) {
      console.log(error);
      toast.error('Error deleting task');
    }
  };
  

  return (
    <div>
      <ToastContainer />
      <AppBar position="static">
        <Toolbar>
          <IconButton edge="start" color="inherit" aria-label="

menu">
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" style={{ flexGrow: 1 }}>
            TodoList DApp
          </Typography>
          {currentAccount === '' ? (
            <Button color="inherit" onClick={connectWallet}>Connect Wallet</Button>
          ) : (
            <Typography variant="h6">{currentAccount}</Typography>
          )}
        </Toolbar>
      </AppBar>
      <Container>
        {currentAccount === '' ? (
          <Box display="flex" justifyContent="center" alignItems="center" height="100vh">
            <Button variant="contained" color="primary" size="large" onClick={connectWallet}>
              Connect Wallet
            </Button>
          </Box>
        ) : correctNetwork ? (
          <Box mt={4}>
            <Typography variant="h4" align="center" gutterBottom> TodoList DApp </Typography>
            <Box component="form" onSubmit={addTask} display="flex" justifyContent="center" mb={2}>
              <TextField 
                id="outlined-basic" 
                label="New Task" 
                variant="outlined" 
                value={input}
                onChange={e => setInput(e.target.value)}
                style={{ marginRight: 8 }}
              />
              <Button variant="contained" color="primary" type="submit">Add Task</Button>
            </Box>
            <TaskTable tasks={tasks} onDelete={deleteTask} />
          </Box>
        ) : (
          <Box display="flex" flexDirection="column" alignItems="center" mt={4}>
            <Typography variant="h6" color="error">Please connect to the Sepolia Testnet</Typography>
            <Typography variant="subtitle1">and reload the page</Typography>
          </Box>
        )}
      </Container>
    </div>
  );
}
```
> **Explication** : Ce composant React représente la page principale de notre dApp. Il permet de connecter le portefeuille Metamask, de récupérer et d'afficher les tâches depuis la blockchain, et de gérer l'ajout et la suppression de tâches. `useEffect` est utilisé pour récupérer les tâches au chargement de la page.

2. **Dossier components** : Créez un dossier `components` dans `src` et ajoutez le fichier `Task.js`.

Voici le contenu du fichier `Task.js` :

```js
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import './Task.css';

const TaskTable = ({ tasks, onDelete }) => {
    return (
        <TableContainer component={Paper} className="task-table">
            <Table>
                <TableHead>
                    <TableRow>
                        <TableCell>ID</TableCell>
                        <TableCell>Task</TableCell>
                        <TableCell>Action</TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {tasks.map((task) => (
                        <TableRow key={task.id}>
                            <TableCell>{task.id.toString()}</TableCell>
                            <TableCell>{task.taskText}</TableCell>
                            <TableCell>
                                <DeleteIcon fontSize="large" style={{ opacity: 0.7, cursor: 'pointer' }} onClick={() => onDelete(task.id)} />
                            </TableCell>
                        </TableRow>
                    ))}
                </TableBody>
            </Table>
        </TableContainer>
    );
};

export default TaskTable;
```
> **Explication** : Ce composant représente le tableau des tâches. Il affiche chaque tâche dans une ligne de tableau et inclut un bouton de suppression pour chaque tâche. Le bouton appelle la fonction `onDelete` passée en tant que prop lorsqu'il est cliqué.

3. **Fichier CSS** : Ajoutez un fichier `Task.css` dans `components`.

Voici le contenu du fichier `Task.css` :

```css
/* Task.css */

.task-table {
    margin-top: 25px;
}

.task-table th {
    background-color: #f5f5f5;
    font-weight: bold;
}

.task-table td, .task-table th {
    padding: 12px 15px;
}

.todo__list {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 20px;
    border-bottom: 1px solid #ddd;
    background-color: #ffffff;
    transition: background-color 0.3s ease;
    border-radius: 4px;
    margin-bottom: 10px;
}

.todo__list:last-child {
    border-bottom: none;
}

.todo__list:hover {
    background-color: #f1f1f1;
}

.MuiSvgIcon-root {
    cursor: pointer;
    transition: opacity 0.3s, transform 0.3s;
    opacity: 0.7;
}

.MuiSvgIcon-root:hover {
    opacity: 1;
    transform: scale(1.1);
    color: #ee0808;
}
```
> **Explication** : Ce fichier CSS stylise le tableau des tâches et le bouton de suppression. Il définit les marges, les couleurs de fond, et les transitions pour améliorer l'apparence visuelle de la liste de tâches.

4. **Dossier utils** : Créez un dossier `utils` dans `src` et ajoutez le fichier `TaskContract.json` récupéré au niveau du backend dans le dossier `artifacts/contracts/TaskContract`.

Voici le contenu du fichier `TaskContract.json` :

```json
{
    "_format": "hh-sol-artifact-1",
    "contractName": "TaskContract",
    "sourceName": "contracts/TaskContract.sol",
    "abi": [
      {
        "anonymous": false,
        "inputs": [
          {
            "indexed": false,
            "internalType": "address",
            "name": "recipient",
            "type": "address"
          },
          {
            "indexed": false,
            "internalType": "uint256",
            "name": "taskId",
            "type": "uint256"
          }
        ],
        "name": "AddTask",
        "type": "event"
      },
      {
        "anonymous": false,
        "inputs": [
          {
            "indexed": false,
            "internalType": "uint256",
            "name": "taskId",
            "type": "uint256"
          },
          {
            "indexed": false,
            "internalType": "bool",
            "name": "isDeleted",
            "type": "bool"
          }
        ],
        "name": "DeleteTask",
        "type": "event"
      },
      {
        "inputs": [
          {
            "internalType": "string",
            "name": "taskText",
            "type": "string"
          },
          {
            "internalType": "bool",
            "name": "isDeleted",
            "type": "bool"
          }
        ],
        "name": "addTask",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "inputs": [
          {
            "internalType": "uint256",
            "name": "taskId",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "isDeleted",
            "type": "bool"
          }
        ],
        "name": "deleteTask",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "inputs": [],
        "name": "getMyTasks",
        "outputs": [
          {
            "components": [
              {
                "internalType": "uint256",
                "name": "id",
                "type": "uint256"
              },
              {
                "internalType": "address",
                "name": "username",
                "type": "address"
              },
              {
                "internalType": "string",
                "name": "taskText",
                "type": "string"
              },
              {
                "internalType": "bool",
                "name": "isDeleted",
                "type": "bool"
              }
            ],
            "internalType": "struct TaskContract.Task[]",
            "name": "",
            "type": "tuple[]"
          }
        ],
        "stateMutability": "view",
        "type": "function"
      }
    ],
    "bytecode": "0x608060405234801561001057600080fd5b50610e62806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806320df4581146100465780636e13f81814610062578063aaba290714610080575b600080fd5b610060600480360381019061005b91906108fc565b61009c565b005b61006a610229565b6040516100779190610b34565b60405180910390f35b61009a60048036038101906100959190610950565b61067f565b005b600080805490509050600060405180608001604052808381526020013373ffffffffffffffffffffffffffffffffffffffff168152602001858152602001841515815250908060018154018082558091505060019003906000526020600020906004020160009091909190915060008201518160000155602082

01518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040820151816002019080519060200190610176929190610787565b5060608201518160030160006101000a81548160ff0219169083151502179055505050336001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f1f54e1ba1832d428fbd7e7792beaf62b1fc5a382c207ffd614209c1413e94fda338260405161021c929190610b0b565b60405180910390a1505050565b60606000808054905067ffffffffffffffff811115610271577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156102aa57816020015b61029761080d565b81526020019060019003908161028f5790505b5090506000805b600080549050811015610553573373ffffffffffffffffffffffffffffffffffffffff166001600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614801561038857506000151560008281548110610365577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020906004020160030160009054906101000a900460ff161515145b1561054057600081815481106103c7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000209060040201604051806080016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160028201805461045090610cb4565b80601f016020809104026020016040519081016040528092919081815260200182805461047c90610cb4565b80156104c95780601f1061049e576101008083540402835291602001916104c9565b820191906000526020600020905b8154815290600101906020018083116104ac57829003601f168201915b505050505081526020016003820160009054906101000a900460ff161515151581525050838381518110610526577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250818061053c90610d17565b9250505b808061054b90610d17565b9150506102b1565b5060008167ffffffffffffffff811115610596577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156105cf57816020015b6105bc61080d565b8152602001906001900390816105b45790505b50905060005b8281101561067557838181518110610616577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151828281518110610657577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250808061066d90610d17565b9150506105d5565b5080935050505090565b3373ffffffffffffffffffffffffffffffffffffffff166001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610783578060008381548110610721577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020906004020160030160006101000a81548160ff0219169083151502179055507ff88a35c3d2016c409a46570b994a17b408dbc83c14a03f521512d50b85386d06828260405161077a929190610b56565b60405180910390a15b5050565b82805461079390610cb4565b90600052602060002090601f0160209004810192826107b557600085556107fc565b82601f106107ce57805160ff19168380011785556107fc565b828001600101855582156107fc579182015b828111156107fb5782518255916020019190600101906107e0565b5b509050610809919061084d565b5090565b604051806080016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081526020016000151581525090565b5b8082111561086657600081600090555060010161084e565b5090565b600061087d61087884610ba4565b610b7f565b90508281526020810184848401111561089557600080fd5b6108a0848285610c72565b509392505050565b6000813590506108b781610dfe565b92915050565b600082601f8301126108ce57600080fd5b81356108de84826020860161086a565b91505092915050565b6000813590506108f681610e15565b92915050565b6000806040838503121561090f57600080fd5b600083013567ffffffffffffffff81111561092957600080fd5b610935858286016108bd565b9250506020610946858286016108a8565b9150509250929050565b6000806040838503121561096357600080fd5b6000610971858286016108e7565b9250506020610982858286016108a8565b9150509250929050565b60006109988383610a8a565b905092915050565b6109a981610c2a565b82525050565b6109b881610c2a565b82525050565b60006109c982610be5565b6109d38185610c08565b9350836020820285016109e585610bd5565b8060005b85811015610a215784840389528151610a02858261098c565b9450610a0d83610bfb565b925060208a019950506001810190506109e9565b50829750879550505050505092915050565b610a3c81610c3c565b82525050565b610a4b81610c3c565b82525050565b6000610a5c82610bf0565b610a668185610c19565b9350610a76818560208601610c81565b610a7f81610ded565b840191505092915050565b6000608083016000830151610aa26000860182610aed565b506020830151610ab560208601826109a0565b5060408301518482036040860152610acd8282610a51565b9150506060830151610ae26060860182610a33565b508091505092915050565b610af681610c68565b82525050565b610b0581610c68565b82525050565b6000604082019050610b2060008301856109af565b610b2d6020830184610afc565b9392505050565b60006020820190508181036000830152610b4e81846109be565b905092915050565b6000604082019050610b6b6000830185610afc565b610b786020830184610a42565b9392505050565b6000610b89610b9a565b9050610b958282610ce6565b919050565b6000604051905090565b600067ffffffffffffffff821115610bbf57610bbe610dbe565b5b610bc882610ded565b9050602081019050919050565b600081905060208201905

0919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b6000610c3582610c48565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015610c9f578082015181840152602081019050610c84565b83811115610cae576000848401525b50505050565b60006002820490506001821680610ccc57607f821691505b60208210811415610ce057610cdf610d8f565b5b50919050565b610cef82610ded565b810181811067ffffffffffffffff82111715610d0e57610d0d610dbe565b5b80604052505050565b6000610d2282610c68565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610d5557610d54610d60565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b610e0781610c3c565b8114610e1257600080fd5b50565b610e1e81610c68565b8114610e2957600080fd5b5056fea26469706673582212209cf2120d1c2331a546dc67e1b144e55ded28e1e2a9bbcd5277ea9cf6eaec679464736f6c63430008040033",
    "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806320df4581146100465780636e13f81814610062578063aaba290714610080575b600080fd5b610060600480360381019061005b91906108fc565b61009c565b005b61006a610229565b6040516100779190610b34565b60405180910390f35b61009a60048036038101906100959190610950565b61067f565b005b600080805490509050600060405180608001604052808381526020013373ffffffffffffffffffffffffffffffffffffffff16815260200185815260200184151581525090806001815401808255809150506001900390600052602060002090600402016000909190919091506000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040820151816002019080519060200190610176929190610787565b5060608201518160030160006101000a81548160ff0219169083151502179055505050336001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f1f54e1ba1832d428fbd7e7792beaf62b1fc5a382c207ffd614209c1413e94fda338260405161021c929190610b0b565b60405180910390a1505050565b60606000808054905067ffffffffffffffff811115610271577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156102aa57816020015b61029761080d565b81526020019060019003908161028f5790505b5090506000805b600080549050811015610553573373ffffffffffffffffffffffffffffffffffffffff166001600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614801561038857506000151560008281548110610365577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020906004020160030160009054906101000a900460ff161515145b1561054057600081815481106103c7577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060005260206000209060040201604051806080016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160028201805461045090610cb4565b80601f016020809104026020016040519081016040528092919081815260200182805461047c90610cb4565b80156104c95780601f1061049e576101008083540402835291602001916104c9565b820191906000526020600020905b8154815290600101906020018083116104ac57829003601f168201915b505050505081526020016003820160009054906101000a900460ff161515151581525050838381518110610526577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250818061053c90610d17565b9250505b808061054b90610d17565b9150506102b1565b5060008167ffffffffffffffff811115610596577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156105cf57816020015b6105bc61080d565b8152602001906001900390816105b45790505b50905060005b8281101561067557838181518110610616577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010151828281518110610657577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250808061066d90610d17565b9150506105d5565b5080935050505090565b3373ffffffffffffffffffffffffffffffffffffffff166001600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610783578060008381548110610721577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906000526020600020906004020160030160006101000a81548160ff0219169083151502179055507ff88a35c3d2016c409a46570b994a17b408dbc83c14a03f521512d50b85386d06828260405161077a929190610b56565b60405180910390a15b5050565b82805461079390610cb4565b90600052602060002090601f0160209004810192826107b557600085556107fc565b82601f106107ce57805160ff19168380011785556107fc565b828001600101855582156107fc579182015b828111156107fb5782518255916020019190600101906107e0565b5b509050610809919061084d565b5090565b604051806080016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081526020016000151581525090565b5b8082111561086657600081600090555060010161084e565b5090565b600061087d61087884610ba4565b610b7f565b905082815260208101

84848401111561089557600080fd5b6108a0848285610c72565b509392505050565b6000813590506108b781610dfe565b92915050565b600082601f8301126108ce57600080fd5b81356108de84826020860161086a565b91505092915050565b6000813590506108f681610e15565b92915050565b6000806040838503121561090f57600080fd5b600083013567ffffffffffffffff81111561092957600080fd5b610935858286016108bd565b9250506020610946858286016108a8565b9150509250929050565b6000806040838503121561096357600080fd5b6000610971858286016108e7565b9250506020610982858286016108a8565b9150509250929050565b60006109988383610a8a565b905092915050565b6109a981610c2a565b82525050565b6109b881610c2a565b82525050565b60006109c982610be5565b6109d38185610c08565b9350836020820285016109e585610bd5565b8060005b85811015610a215784840389528151610a02858261098c565b9450610a0d83610bfb565b925060208a019950506001810190506109e9565b50829750879550505050505092915050565b610a3c81610c3c565b82525050565b610a4b81610c3c565b82525050565b6000610a5c82610bf0565b610a668185610c19565b9350610a76818560208601610c81565b610a7f81610ded565b840191505092915050565b6000608083016000830151610aa26000860182610aed565b506020830151610ab560208601826109a0565b5060408301518482036040860152610acd8282610a51565b9150506060830151610ae26060860182610a33565b508091505092915050565b610af681610c68565b82525050565b610b0581610c68565b82525050565b6000604082019050610b2060008301856109af565b610b2d6020830184610afc565b9392505050565b60006020820190508181036000830152610b4e81846109be565b905092915050565b6000604082019050610b6b6000830185610afc565b610b786020830184610a42565b9392505050565b6000610b89610b9a565b9050610b958282610ce6565b919050565b6000604051905090565b600067ffffffffffffffff821115610bbf57610bbe610dbe565b5b610bc882610ded565b9050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b6000610c3582610c48565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015610c9f578082015181840152602081019050610c84565b83811115610cae576000848401525b50505050565b60006002820490506001821680610ccc57607f821691505b60208210811415610ce057610cdf610d8f565b5b50919050565b610cef82610ded565b810181811067ffffffffffffffff82111715610d0e57610d0d610dbe565b5b80604052505050565b6000610d2282610c68565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610d5557610d54610d60565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b610e0781610c3c565b8114610e1257600080fd5b50565b610e1e81610c68565b8114610e2957600080fd5b5056fea26469706673582212209cf2120d1c2331a546dc67e1b144e55ded28e1e2a9bbcd5277ea9cf6eaec679464736f6c63430008040033",
    "linkReferences": {},
    "deployedLinkReferences": {}
  }
```
> **Explication** : Ce fichier JSON contient l'ABI (Application Binary Interface) et le bytecode compilé du smart contract. L'ABI est utilisée par Web3.js pour interagir avec le smart contract déployé.

Ensuite, créez un fichier `config.js` à la racine du dossier `client` et collez l'adresse du contrat déployé :

```js
export const TaskContractAddress = "ADRESSE_DU_CONTRAT_DEPLOYE";
```
> **Explication** : Ce fichier JavaScript exporte l'adresse du smart contract déployé. Cette adresse sera utilisée par le front-end pour interagir avec le smart contract sur la blockchain.

### Déploiement du frontend en local

Pour exécuter le projet en local, suivez ces étapes :

1. Ouvrez votre terminal et accédez au répertoire racine de votre projet frontend.
2. Assurez-vous que toutes les dépendances sont installées en exécutant `npm install`.
3. Lancez l'application avec `npm run dev`.

Accédez à votre navigateur et ouvrez `http://localhost:3000` pour voir votre application en action.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dd663b1az04kz03ds80y.png)



### Conclusion

Ce tutoriel vous a guidé à travers le processus de création d'une dApp de liste de tâches avec Next.js, Solidity et Web3.js. En suivant ces étapes, vous pouvez maintenant développer et déployer vos propres applications décentralisées. Pour plus de tutoriels et de ressources, restez connectés et continuez à explorer les possibilités infinies offertes par la blockchain.

[Voir le projet sur GitHub](https://github.com/starlabman/TodoList_DApp_using_Nextjs_Solidity_Web3js.git)
[Regarder le tutoriel sur YouTube](https://www.youtube.com/watch?v=MYjdFSyl_7E)

### Références des outils utilisés

- **Next.js** : [Site officiel](https://nextjs.org/)
- **Web3.js** : [Site officiel](https://web3js.readthedocs.io/)
- **Hardhat** : [Site officiel](https://hardhat.org/)
- **Alchemy** : [Site officiel](https://www.alchemy.com/)
- **Metamask** : [Site officiel](https://metamask.io/)

### Présentation de l'auteur

Je m'appelle **AGBETISIASSI KODJO LABORE**, développeur blockchain passionné par la création de solutions innovantes et sécurisées. Avec une expérience approfondie dans le développement de dApps, je suis dévoué à partager mes connaissances et à aider la communauté à explorer le monde fascinant de la blockchain.

Pour me soutenir, voici mes wallets crypto : 
EVM : 0xf249F24182CdE7bAd264B60Ed38727Fd3674FE6A
SOL : Fq9sgX7UHqEEwpVMu7UKjpstQGcf1JD3kPnUTYRbEdcZ


Pour plus d'informations et pour voir d'autres projets, vous pouvez me suivre sur :

- **LinkedIn** : [AGBETISIASSI KODJO LABORE](https://www.linkedin.com/in/starlabman)
- **GitHub** : [Github Profile](https://github.com/starlabman)
- **Twitter** : [Twitter Profile](https://twitter.com/0xWeb3Devrel)