Mettre en place un projet blockchain Ethereum avec Hardhat

Qu’est ce que Hardhat?

Hardhat est un ensemble logiciciel pour vous aider à développer un projet blockchain, tout comme un Laragon ou MAMP va vous simuler un Internet local, Hardhat va vous simuler une blockchain locale, élément nécessaire pour faire marcher un smart contract.

Hardhat est à privilégier pour tout nouveau projet blockchain, car Truffle n’est plus maintenu, il est possible que beaucoup de projet legacy utilisent encore Truffle cependant.

Configuration de VSCode pour un projet blockchain

Installation du plugin Remix Light et Solidity

Le plugin Solidity permet le syntax highlighting et l’intégration avec le compilateur, Solidity est un langage compilé.

Remix Light permet de tester et débugger.

Structure du projet blockchain

Créez un répertoire my-solidity-project entrez dedans. La strucutre sera comme ci-dessous

my-solidity-project/
├── contracts/         # Your smart contracts go here
├── scripts/           # Deployment and interaction scripts
├── test/              # Test files for your contracts
├── hardhat.config.js  # Hardhat configuration
└── package.json       # Project dependencies

Nous allons avoir besoin de NPM pour développer un projet blockchain.

// initialisation d'une projet nodeJS avec le flag -y pour répondre oui à toutes les questions

npm init -y

Installations du framework Hardhat

npm install --save-dev hardhat @nomicfoundation/hardhat-ethers ethers dotenv @nomicfoundation/hardhat-toolbox


// initialisation du framework

npx hardhat  (et suivre les instructions  /!\ c'est NPX et non NPM)
 
// on va choisir create a javascript project (mais il faut savoir que Typescript est très populaire)

Création du premier contrat

Un contrat est simplement un fichier en langage Solidity

Codage d’un contrat en Solidity MyToken

Rappel vous devez avoir la structure suivante:
my-solidity-project/
├── contracts/         # Your smart contracts go here
├── scripts/           # Deployment and interaction scripts
├── test/              # Test files for your contracts
├── hardhat.config.js  # Hardhat configuration
└── package.json       # Project dependencies
// le fichier se trouve dans contracts/MyToken.sol

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
    constructor(
        address initialOwner
    ) ERC20("MyToken", "MTK") Ownable(initialOwner) {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

Le script ci-dessus fait appel à OpenZeppelin, on va installer ce dernier

npm install @openzeppelin/contracts

Création d’un script de déploiement

script/deploy.js

const hre = require("hardhat");

async function main() {
    const [deployer] = await ethers.getSigners();
    console.log("Deploying contracts with the account:", deployer.address);

    const MyToken = await ethers.getContractFactory("MyToken");
    const myToken = await MyToken.deploy(deployer.address);

    await myToken.waitForDeployment();
    console.log("MyToken deployed to:", await myToken.getAddress());
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

Création d’un fichier de test

// tests/myToken.js

const { expect } = require("chai");

describe("MyToken", function () {
  let myToken;
  const initialMessage = "Hello, Hardhat!";

  beforeEach(async function () {
    const MyToken = await ethers.getContractFactory("MyToken");
    myToken = await MyToken.deploy(initialMessage);
  });

  it("Should return the initial message", async function () {
    expect(await myToken.getMessage()).to.equal(initialMessage);
  });

  it("Should set a new message", async function () {
    const newMessage = "New message";
    await myToken.setMessage(newMessage);
    expect(await myToken.getMessage()).to.equal(newMessage);
  });
});

Compilation du contrat

// compilation des contracts
npx hardhat compile

// les fichiers compilés sont dans artifacts/contracts

// jouer les test
npx hardhat test


Si vous avez une erreur essayez la commande suivante:
npm cache clean --force

Démarrer la blockchain locale

Tout comme en Web2 on a un internet local avec un serveur web, nous allons lancer une blockchain locale. Ensuite on va pouvoir déployer notre smart contract.

// démarrer le noeud de blockchain local
npx hardhat node

// cette commande va afficher les 20 wallets créés par défaut

Déployer le contrat

// Déployer le contract dans le noeud local
npx hardhat run scripts/deploy.js --network localhost

Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
MyToken deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3

Cette étape est importante car vous allez voir l’adresse de votre smart contract

En résumé :

  • compiler le smart contract
  • Tester le smart contract
  • démarrer un noeud
  • déployer les smart contrat sur le noeud
  • interagir avec le smart contract

Et voilà !

Interagir avec un smart contract qu’on a déployé

Démarrez plusieurs terminaux pour avoir la vue sur tout les scripts du projet. Nous allons interagir avec le smart contract. Pas question encore de le faire avec un wallet du genre Metamask, il y a plusieurs façons d’interagir avec un smart contract.

Interaction avec une console Hardhat

//démarre une console Hardhat et la branche sur le réseau localhost

npx hardhat console --network localhost

Ensuite il y a une invite de commande. Vous allez mettre ce code dans l’invite de commande. Il n’y a pas de fichier javascript, on interagit en ligne de commande. Pour utiliser les exemples, il faut remplacer l’adresse du smart contract par celui que vous obtenez au lancement.

// Get the contract factory
const MyToken = await ethers.getContractFactory("MyToken");

// Connect to your deployed contract (replace with your actual contract address)
const myToken = await MyToken.attach("0x5FbDB2315678afecb367f032d93F642f64180aa3");

// Call read functions
const name = await myToken.name();
console.log("Token name:", name);

const totalSupply = await myToken.totalSupply();
console.log("Total supply:", totalSupply.toString());

// Call write functions (transactions)
const [owner, addr1] = await ethers.getSigners();
const mintTx = await myToken.mint(addr1.address, ethers.parseEther("100"));
await mintTx.wait();
console.log("Minted 100 tokens to:", addr1.address);

// Check balance
const balance = await myToken.balanceOf(addr1.address);
console.log("Balance:", ethers.formatEther(balance));

Je vous invite à jouer avec les lignes de commande pour afficher les contenus des variables par exemple.

Interaction avec un script nodeJS

//  interact.js

const hre = require("hardhat");

async function main() {
  // Replace with your deployed contract address
  const contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
  
  const MyToken = await ethers.getContractFactory("MyToken");
  const myToken = MyToken.attach(contractAddress);
  
  console.log("Token name:", await myToken.name());
  console.log("Token symbol:", await myToken.symbol());
  
  const [owner, addr1] = await ethers.getSigners();
  console.log("Owner address:", owner.address);
  
  // Get owner balance
  const ownerBalance = await myToken.balanceOf(owner.address);
  console.log("Owner balance:", ethers.formatEther(ownerBalance));
  
  // Mint tokens to addr1
  console.log("Minting 100 tokens to:", addr1.address);
  const mintTx = await myToken.mint(addr1.address, ethers.parseEther("100"));
  await mintTx.wait();
  
  // Get addr1 balance
  const addr1Balance = await myToken.balanceOf(addr1.address);
  console.log("Address 1 balance:", ethers.formatEther(addr1Balance));
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

Pour faire tourner le script vous devez l’invoquer avec Hardhat

npx hardhat run scripts/interact.js --network localhost

Quoi d’autres après?

Il serait intéressant de faire une application ReactJS pour interagir avec le smart contract.

Retour en haut