Maîtrisez le Développement Web3 : Créer des DApps avec Solidity et React
Maîtrisez le Développement Web3 : Créer des DApps avec Solidity et React

Développement et Déploiement de Votre Premier Smart Contract

Bienvenue dans cette leçon fondamentale de votre parcours Web3 ! Après avoir posé les bases de la blockchain et de ses concepts, nous allons plonger au cœur de la programmation décentralisée en apprenant à développer et déployer notre tout premier Smart Contract. Les Smart Contracts sont les briques essentielles des DApps (Applications Décentralisées), agissant comme des accords numériques auto-exécutables stockés sur une blockchain.

Dans cette leçon, nous allons :

  • Comprendre ce qu'est un Smart Contract et son importance.
  • Mettre en place un environnement de développement local.
  • Écrire un Smart Contract simple en Solidity.
  • Compiler, tester et déployer ce contrat sur un réseau blockchain de test.

1. Comprendre les Smart Contracts

1.1 Qu'est-ce qu'un Smart Contract ?

Un Smart Contract est un programme informatique auto-exécutable et immuable stocké sur une blockchain. Imaginez-le comme un contrat traditionnel, mais dont les termes et conditions sont inscrits dans du code. Une fois déployé, il ne peut être modifié et son exécution est automatiquement déclenchée lorsque les conditions prédéfinies sont remplies.

Les caractéristiques clés sont :

  • Immuabilité : Une fois déployé, le code du contrat ne peut pas être modifié. Cela garantit la confiance et la prévisibilité.
  • Transparence : Le code est public et vérifiable par quiconque sur la blockchain.
  • Décentralisation : Il n'y a pas d'autorité centrale contrôlant le contrat. Il s'exécute sur tous les nœuds du réseau.
  • Auto-exécution : Une fois les conditions remplies, le contrat s'exécute automatiquement sans intervention humaine.

1.2 À quoi servent les Smart Contracts ?

Les Smart Contracts sont le fondement de la plupart des applications Web3 et des innovations de la blockchain, y compris :

  • Cryptomonnaies et jetons (Tokens) : Création et gestion de jetons (ERC-20, ERC-721/NFTs).
  • Finance Décentralisée (DeFi) : Prêts, emprunts, échanges automatisés, pools de liquidité.
  • Organisation Autonome Décentralisée (DAO) : Gestion de la gouvernance et du vote.
  • Jeux (GameFi) : Propriété d'actifs en jeu, logiques de jeu.
  • Logistique et Supply Chain : Traçabilité automatisée.

2. L'Écosystème de Développement

Pour développer des Smart Contracts, nous avons besoin d'un ensemble d'outils. Nous nous concentrerons sur l'écosystème Hardhat, qui est un environnement de développement puissant et flexible pour Ethereum.

2.1 Prérequis Techniques

Avant de commencer, assurez-vous d'avoir installé :

  • Node.js et npm (ou Yarn) : Ces outils sont essentiels pour gérer les dépendances de notre projet. Vous pouvez les télécharger depuis nodejs.org.
  • Un éditeur de code : Visual Studio Code est fortement recommandé pour son support étendu de Solidity (via des extensions comme Solidity de Juan Blanco).

2.2 Hardhat : Votre Boîte à Outils

Hardhat est un environnement de développement pour la compilation, le déploiement, le test et le débogage de votre logiciel Ethereum. Il fournit une infrastructure complète pour les Smart Contracts en Solidity.

Ses avantages incluent :

  • Réseau Hardhat local : Un réseau Ethereum local intégré pour des tests rapides.
  • Plugins : Un système de plugins riche pour étendre les fonctionnalités.
  • Débogage facile : Support pour les messages d'erreur détaillés et les traces de pile.

3. Initialisation du Projet avec Hardhat

Créons notre premier projet Hardhat.

3.1 Création du Dossier Projet

Ouvrez votre terminal et suivez ces étapes :

# Créez un nouveau dossier pour votre projet
mkdir mon-premier-contrat-web3
cd mon-premier-contrat-web3

# Initialisez un projet Node.js
npm init -y

# Installez Hardhat
npm install --save-dev hardhat

3.2 Initialisation de Hardhat dans le Projet

Une fois Hardhat installé, vous pouvez l'initialiser :

npx hardhat

Vous serez invité à choisir une option. Sélectionnez Create a JavaScript project.

√ What do you want to do? · Create a JavaScript project
√ Hardhat project root: · /chemin/vers/mon-premier-contrat-web3
√ Do you want to add a .gitignore? (Y/n) · Y
√ Do you want to install this project's dependencies with npm? (Y/n) · Y

Hardhat va créer une structure de projet de base avec les dossiers suivants :

  • contracts/: Où vos fichiers Solidity (.sol) seront stockés.
  • scripts/: Pour vos scripts de déploiement et d'interaction.
  • test/: Pour vos fichiers de test JavaScript.
  • hardhat.config.js: Le fichier de configuration de Hardhat.

4. Écriture de Votre Premier Smart Contract (Solidity)

Nous allons créer un Smart Contract simple appelé SimpleStorage. Ce contrat permettra de stocker un nombre et de le récupérer.

4.1 Introduction à Solidity

Solidity est un langage de programmation orienté objet, de haut niveau, utilisé pour implémenter des Smart Contracts sur diverses blockchains compatibles avec la Machine Virtuelle Ethereum (EVM).

Un contrat Solidity typique contient :

  • pragma solidity: Indique la version du compilateur Solidity.
  • contract NomDuContrat { ... }: La définition du contrat.
  • variables d'état: Des variables stockées en permanence sur la blockchain.
  • fonctions: Des blocs de code qui peuvent interagir avec les variables d'état ou effectuer d'autres logiques.

4.2 Le Contrat SimpleStorage.sol

Créez un nouveau fichier SimpleStorage.sol dans le dossier contracts/ et ajoutez-y le code suivant :

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; // Indique la version du compilateur Solidity

contract SimpleStorage {
    // Ceci est une variable d'état. Sa valeur est stockée en permanence sur la blockchain.
    uint256 public myNumber; // 'public' génère automatiquement une fonction getter pour cette variable.

    // Cette fonction permet de définir la valeur de 'myNumber'.
    // 'setNumber' est un nom descriptif pour notre fonction.
    // 'newNumber' est l'argument que la fonction prend.
    // 'public' signifie que n'importe qui peut appeler cette fonction.
    function setNumber(uint256 newNumber) public {
        myNumber = newNumber; // Met à jour la variable d'état 'myNumber'.
    }

    // Cette fonction permet de récupérer la valeur de 'myNumber'.
    // 'view' signifie que la fonction ne modifie pas l'état de la blockchain.
    // 'returns (uint256)' indique que la fonction retourne un entier non signé de 256 bits.
    function getNumber() public view returns (uint256) {
        return myNumber; // Retourne la valeur actuelle de 'myNumber'.
    }
}

Explication du Code :

  • SPDX-License-Identifier: MIT: Obligatoire depuis Solidity 0.6.8, indique la licence du code.
  • pragma solidity ^0.8.24;: Spécifie que ce contrat doit être compilé avec une version de Solidity supérieure ou égale à 0.8.24, et inférieure à 0.9.0.
  • contract SimpleStorage { ... }: Définit notre Smart Contract nommé SimpleStorage.
  • uint256 public myNumber;: Déclare une variable d'état nommée myNumber de type uint256 (entier non signé de 256 bits, le type le plus courant pour les nombres en Solidity). Le mot-clé public crée automatiquement une fonction getter pour myNumber, nous permettant de lire sa valeur depuis l'extérieur du contrat.
  • function setNumber(uint256 newNumber) public { ... }: Définit une fonction setNumber qui prend un argument newNumber et met à jour la variable myNumber avec cette nouvelle valeur. Puisqu'elle modifie l'état de la blockchain, appeler cette fonction coûtera des frais de gaz.
  • function getNumber() public view returns (uint256) { ... }: Définit une fonction getNumber qui renvoie la valeur actuelle de myNumber. Le mot-clé view indique que cette fonction ne modifie pas l'état de la blockchain. Par conséquent, appeler une fonction view ne coûte pas de gaz.

5. Compilation du Smart Contract

Avant de pouvoir déployer notre contrat, il doit être compilé en bytecode, que la Machine Virtuelle Ethereum (EVM) peut comprendre. Hardhat s'occupe de cela pour nous.

5.1 Commande de Compilation

Dans votre terminal, exécutez la commande suivante :

npx hardhat compile

Hardhat va parcourir votre dossier contracts/, compiler tous les fichiers Solidity et générer les artefacts (bytecode, ABI) dans le dossier artifacts/.

Qu'est-ce que l'ABI ?

L'ABI (Application Binary Interface) est une interface qui définit comment interagir avec le Smart Contract. Elle spécifie les fonctions du contrat et leurs paramètres, permettant aux applications externes (comme votre DApp React) de communiquer avec lui.

6. Test du Smart Contract

Il est crucial de tester vos Smart Contracts avant de les déployer sur un réseau réel. Les bugs dans les contrats peuvent avoir des conséquences irréversibles (perte de fonds, vulnérabilités).

Hardhat intègre un environnement de test puissant basé sur Mocha et Chai.

6.1 Écriture d'un Test Simple

Ouvrez le fichier test/Lock.js (si Hardhat l'a créé) ou créez un nouveau fichier test/simple-storage.js. Supprimez le contenu existant et ajoutez ceci :

const { expect } = require("chai"); // Importe la bibliothèque d'assertions Chai
const { ethers } = require("hardhat"); // Importe la bibliothèque ethers.js de Hardhat

describe("SimpleStorage", function () {
  let SimpleStorage; // Variable pour stocker la fabrique du contrat
  let simpleStorage; // Variable pour stocker l'instance du contrat déployé

  // Avant chaque test, nous déployons une nouvelle instance du contrat
  beforeEach(async function () {
    // Obtenir la fabrique du contrat "SimpleStorage"
    SimpleStorage = await ethers.getContractFactory("SimpleStorage");
    // Déployer une nouvelle instance du contrat
    simpleStorage = await SimpleStorage.deploy();
    // Attendre que le déploiement soit terminé
    await simpleStorage.waitForDeployment();
  });

  it("Devrait stocker la nouvelle valeur et la récupérer", async function () {
    const initialValue = await simpleStorage.getNumber();
    expect(initialValue).to.equal(0); // Par défaut, uint256 est initialisé à 0

    const newValue = 42;
    // Appeler la fonction setNumber pour changer la valeur
    const tx = await simpleStorage.setNumber(newValue);
    await tx.wait(); // Attendre que la transaction soit minée

    // Récupérer la nouvelle valeur et vérifier qu'elle est correcte
    const storedValue = await simpleStorage.getNumber();
    expect(storedValue).to.equal(newValue);
  });

  it("Devrait permettre la modification répétée de la valeur", async function () {
    await simpleStorage.setNumber(10);
    expect(await simpleStorage.getNumber()).to.equal(10);

    await simpleStorage.setNumber(20);
    expect(await simpleStorage.getNumber()).to.equal(20);
  });
});

Explication du Code de Test :

  • describe("SimpleStorage", function() { ... }): Définit une suite de tests pour notre contrat SimpleStorage.
  • beforeEach(async function() { ... }): Un hook Mocha qui est exécuté avant chaque test. C'est ici que nous déployons une nouvelle instance du contrat pour assurer que chaque test commence avec un état propre.
    • ethers.getContractFactory("SimpleStorage"): Récupère l'abstraction du contrat SimpleStorage, qui est comme une "usine" pour créer des instances de ce contrat.
    • SimpleStorage.deploy(): Déploie une nouvelle instance du contrat sur le réseau Hardhat local (simulé).
    • await simpleStorage.waitForDeployment(): Attend que le contrat soit effectivement déployé.
  • it("Devrait stocker la nouvelle valeur et la récupérer", async function() { ... }): Définit un cas de test individuel.
    • await simpleStorage.getNumber(): Appelle la fonction getNumber du contrat déployé.
    • expect(...).to.equal(...): Utilise Chai pour faire des assertions sur les résultats.
    • await simpleStorage.setNumber(newValue): Appelle la fonction setNumber du contrat.
    • await tx.wait(): Attendre la confirmation de la transaction sur la blockchain (importante pour les fonctions qui modifient l'état).

6.2 Exécution des Tests

Dans votre terminal, exécutez la commande :

npx hardhat test

Hardhat lancera un réseau Ethereum local temporaire, déploiera votre contrat, exécutera les tests, puis arrêtera le réseau. Vous devriez voir un résultat indiquant que les tests ont réussi.

7. Déploiement du Smart Contract

Maintenant que notre contrat est écrit et testé, nous pouvons le déployer sur un réseau blockchain. Nous allons commencer par le déployer sur un réseau de test public, comme Sepolia ou Goerli, qui simule le Mainnet Ethereum.

7.1 Préparation au Déploiement

Pour déployer sur un réseau de test, vous avez besoin de :

  1. Fonds sur le réseau de test (Ether de test) : Vous pouvez en obtenir gratuitement via des "faucets" (robinets) en ligne, par exemple faucet.sepolia.dev pour Sepolia.
  2. Un compte Ethereum (clé privée) : L'adresse Ethereum associée à cette clé privée sera l'expéditeur de la transaction de déploiement et paiera les frais de gaz.
  3. Un nœud Ethereum (ou un service RPC) : Pour interagir avec le réseau, nous utiliserons un fournisseur de services comme Infura ou Alchemy. Ils vous donnent une URL RPC pour se connecter à leur nœud.

Obtenir une clé privée :

  • Si vous utilisez MetaMask, vous pouvez exporter la clé privée d'un compte (attention : ne partagez jamais votre clé privée en production !).
  • Pour les projets de développement, il est courant d'utiliser une variable d'environnement pour stocker la clé privée de manière sécurisée.

Obtenir une URL RPC :

  • Rendez-vous sur Infura ou Alchemy.
  • Créez un compte gratuit.
  • Créez un nouveau projet et sélectionnez le réseau Sepolia (ou Goerli).
  • Copiez l'URL HTTPS du point de terminaison RPC.

7.2 Configuration de Hardhat pour le Déploiement

Nous devons mettre à jour le fichier hardhat.config.js pour inclure les détails de notre réseau de test.

require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config(); // Pour charger les variables d'environnement

const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.24",
  networks: {
    sepolia: {
      url: SEPOLIA_RPC_URL || "", // Votre URL RPC Sepolia
      accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [], // Votre clé privée
      chainId: 11155111, // ID de chaîne pour Sepolia
    },
    // Vous pouvez ajouter d'autres réseaux ici si nécessaire
  },
};

Sécuriser votre clé privée et URL RPC :

  • Créez un fichier .env à la racine de votre projet.

  • Ajoutez vos variables d'environnement dedans :

    SEPOLIA_RPC_URL="https://sepolia.infura.io/v3/VOTRE_ID_INFURA"
    PRIVATE_KEY="VOTRE_CLE_PRIVEE_ICI"
    
  • Très important : Ajoutez .env à votre fichier .gitignore pour ne jamais le pousser sur GitHub !

    # .gitignore
    node_modules/
    .env
    artifacts/
    cache/
    

7.3 Écriture du Script de Déploiement

Hardhat utilise des scripts pour le déploiement. Un script de déploiement est un fichier JavaScript qui utilise ethers.js pour interagir avec la blockchain.

Ouvrez le fichier scripts/deploy.js (si Hardhat l'a créé) ou créez-en un nouveau. Remplacez le contenu par :

const hre = require("hardhat"); // Hardhat Runtime Environment

async function main() {
  // Récupérer la fabrique du contrat "SimpleStorage"
  const SimpleStorage = await hre.ethers.getContractFactory("SimpleStorage");

  console.log("Déploiement du contrat SimpleStorage...");

  // Déployer le contrat
  const simpleStorage = await SimpleStorage.deploy();

  // Attendre que le contrat soit déployé (transaction confirmée)
  await simpleStorage.waitForDeployment();

  // Afficher l'adresse du contrat déployé
  console.log(`Contrat SimpleStorage déployé à l'adresse : ${simpleStorage.target}`);
}

// Nous recommandons que ce modèle soit suivi pour gérer les erreurs.
// C'est un pattern courant pour les scripts Hardhat.
main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Explication du Script :

  • hre.ethers.getContractFactory("SimpleStorage"): Similaire au test, cela récupère l'objet ContractFactory pour notre contrat.
  • SimpleStorage.deploy(): Lance la transaction de déploiement du contrat.
  • await simpleStorage.waitForDeployment(): Attend que la transaction de déploiement soit confirmée sur la blockchain.
  • simpleStorage.target: Contient l'adresse à laquelle le contrat a été déployé.

7.4 Exécution du Déploiement

Assurez-vous que votre fichier .env est correctement configuré avec votre URL RPC et votre clé privée, et que vous avez des ETH de test sur le compte associé à votre clé privée sur le réseau Sepolia.

Dans votre terminal, exécutez la commande :

npx hardhat run scripts/deploy.js --network sepolia

Si tout se passe bien, vous devriez voir un message indiquant l'adresse à laquelle votre contrat a été déployé sur le réseau Sepolia. Vous pouvez ensuite copier cette adresse et la consulter sur un explorateur de blockchain comme Sepolia Etherscan.

Félicitations ! Vous venez de déployer votre premier Smart Contract sur un réseau de test public !

Conclusion

Vous avez franchi une étape majeure dans votre parcours Web3 ! Dans cette leçon, vous avez appris à :

  • Définir et comprendre le rôle fondamental des Smart Contracts dans le paysage Web3.
  • Mettre en place un environnement de développement Hardhat pour Solidity.
  • Écrire un Smart Contract simple en Solidity pour stocker et récupérer une valeur.
  • Compiler votre contrat en bytecode et ABI.
  • Tester votre contrat pour garantir sa fiabilité.
  • Déployer votre Smart Contract sur un réseau de test public comme Sepolia.

Ce contrat SimpleStorage n'est que la pointe de l'iceberg. Les concepts que vous avez appris ici – la structure du projet, l'écriture Solidity, le test et le déploiement – sont les piliers pour construire des DApps beaucoup plus complexes.

Dans les prochaines leçons, nous explorerons comment interagir avec ce Smart Contract depuis une application front-end (par exemple, en utilisant React et Ethers.js), comment créer des contrats plus sophistiqués (comme des jetons ERC-20), et les meilleures pratiques de sécurité pour le développement de Smart Contracts.


Ressources Supplémentaires