Comment créer une DApp sur Morph : Un guide complet

Comment créer une DApp sur Morph : Un guide complet

Les DApps fonctionnent sur une blockchain, offrant transparence, sécurité et décentralisation. Morph, avec ses fonctionnalités uniques et son environnement convivial pour les développeurs, est une excellente plateforme pour créer des DApps. Cet article technique vous guidera à travers le processus de développement d'une DApp sur Morph, de la configuration de votre environnement à la mise en ligne de votre application.

Introduction à Morph

Morph est la première solution zkEVM optimiste de couche 2 pour Ethereum, compatible à 100 % avec l'EVM. Développer sur Morph est comme développer sur Ethereum. Si vous avez de l'expérience dans le développement sur Ethereum, vous constaterez que votre code, vos outils et vos dépendances existants sont entièrement compatibles avec Morph.

Prérequis

Pour ce tutoriel, nous allons utiliser Hardhat avec TypeScript pour le Smart Contract.

Initialisation du projet

Ouvrez votre terminal et suivez les étapes suivantes :

  • Créez un dossier de projet. Commande exemple : mkdir morphme

  • Entrez dans le dossier que vous venez de créer : cd morphme

  • Pour initialiser le projet, exécutez la commande suivante : npx hardhat init

Cela va initialiser votre dépôt de contrat intelligent avec Hardhat. Vous verrez l'écran suivant :

Utilisez la flèche vers le bas pour sélectionner TypeScript et appuyez sur Entrée. Vous serez invité à répondre à quelques questions, répondez simplement "oui".

Attendez la fin de l'installation et ouvrez le dossier dans votre éditeur de code.

Structure du projet

Les projets Hardhat comportent 3 dossiers principaux auxquels il faut prêter attention :

  • Le dossier contracts qui contient vos contrats Solidity.

  • Le dossier test qui contient les tests de vos contrats.

  • Le dossier scripts qui contient des scripts personnalisés pour des tâches comme le déploiement de contrats. Créez ce dossier s'il n'existe pas.

En plus de ceux-ci, un fichier important est hardhat.config.ts, qui contient la configuration pour les clés privées et les réseaux blockchain.

Hardhat crée également des fichiers par défaut dans ces dossiers pour vous : Lock.sol dans le dossier contracts et Lock.ts dans le dossier test. Vous pouvez les supprimer puisque nous allons les remplacer par nos propres contrats.

Écriture de votre contrat

Nous allons lancer notre token sur le testnet et créer un "faucet" (distributeur) qui permettra à nos utilisateurs de demander une quantité fixe de tokens chaque jour. Pour cela, nous allons coder et lancer deux contrats intelligents.

  1. Un token conforme à la norme ERC20 de la bibliothèque OpenZeppelin. Nous appellerons ce token "iToken".

  2. Un contrat "faucet" qui permet à tout compte de demander quotidiennement une quantité fixe de tokens, appelé "iTokenFaucet".

iToken

Nous allons hériter du contrat ERC20 de la bibliothèque OpenZeppelin.

  • Installez OpenZeppelin avec la commande suivante : npm install @openzeppelin/contracts.

  • Créez le fichier iToken.sol dans le dossier contracts et collez le code suivant :

// contracts/GLDToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

contract IToken is ERC20, ERC20Permit {
    constructor() ERC20("I Token", "IT") ERC20Permit("I Token") {
        _mint(_msgSender(), 1_000_000_000 * 1e18);
    }
}
  • Ce code hérite de la bibliothèque ERC20 d'OpenZeppelin et crée un contrat qui générera 1 milliard de iTokens lors de son déploiement.

Ensuite, nous allons créer notre contrat "faucet" de tokens.

iTokenFaucet

C'est un contrat simple mais intéressant qui permet à tout compte de demander quotidiennement une quantité fixe de iTokens.

  • Créez le fichier iTokenFaucet.sol dans le dossier contracts et collez le code suivant :
// contracts/GLDToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

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

contract ITokenFaucet is Ownable {
    uint256 public dailyClaim = 1000 * 1e18;

    uint256 public claimInterval = 1 days;

    mapping(address => uint256) public lastClaimed;

    IERC20 public iToken;
    constructor(address _iAddress) Ownable(msg.sender) {
        iToken = IERC20(_iAddress);
    }

    error AlreadyClaimed();

    event Claimed(address _cliamer, uint256 _amount);

    function claim() external {
        if ((block.timestamp - lastClaimed[msg.sender]) < claimInterval) {
            revert AlreadyClaimed();
        }
        lastClaimed[msg.sender] = block.timestamp;
        SafeERC20.safeTransfer(iToken, msg.sender, dailyClaim);
        emit Claimed(msg.sender, dailyClaim);
    }

    function drain() external onlyOwner {
        SafeERC20.safeTransfer(iToken, owner(), iToken.balanceOf(address(this)));
    }
}
  • Ce contrat importe également des contrats de la bibliothèque OpenZeppelin pour s'assurer que nous utilisons un code sécurisé et audité.
  • C'est une bonne pratique d'utiliser des contrats intelligents déjà testés et éprouvés dès que possible.
  • En plus des imports, nous avons écrit notre contrat intelligent avec deux méthodes principales : claim et drain.
  • claim peut être appelé par n'importe qui pour demander sa dose quotidienne de iTokens (fixée à 1000, que vous pouvez changer).

  • drain ne peut être appelé que par le propriétaire du contrat grâce au modificateur onlyOwner.

Maintenant que nous avons les contrats prêts, l'étape suivante est d'écrire des tests pour eux.

Tests

Écrire des tests pour vos contrats est essentiel, car cela vous permet de vous assurer qu'ils fonctionnent comme prévu. Cela dépend de la précision et de l'exhaustivité de vos tests. En général, pour les contrats intelligents, l'objectif est d'atteindre une couverture de test de 100 %.

Nous allons écrire des tests pour le contrat iTokenFaucet.sol, car le contrat iToken.sol ne contient pas beaucoup de notre code, à part celui que nous avons importé d'OpenZeppelin, qui est déjà testé.

  • Créez le fichier iTokenFaucet.ts dans votre dossier test et collez le code suivant :
import {
    time,
    loadFixture,
  } from "@nomicfoundation/hardhat-toolbox/network-helpers";
  import { expect } from "chai";
  import { ethers } from "hardhat";

  export async function deployiTokenFaucet() {
    const [owner, otherAccount] = await ethers.getSigners();

    const iTokenContract = await ethers.getContractFactory("iToken");
    const iToken = await iTokenContract.deploy();

    const iTokenFaucet = await ethers.getContractFactory("iTokenFaucet");
    const faucet = await iTokenFaucet.deploy(iToken);

    await iToken.transfer(await faucet.getAddress(), BigInt(1e24));

    return { iToken, owner, otherAccount, faucet };
  }

  describe("iTokenFaucet", function () {
    describe("Deployment", function () {
      it("Should Deploy", async function () {
        await loadFixture(deployiTokenFaucet);
      });
    });

    describe("Claim iToken", function () {
      it("Should Claim iToken", async function () {
        const { faucet, otherAccount } = await loadFixture(deployiTokenFaucet);
        await expect(faucet.connect(otherAccount).claim())
          .emit(faucet, "Claimed")
          .withArgs(await otherAccount.getAddress(), await faucet.dailyClaim());

        await expect(
          faucet.connect(otherAccount).claim()
        ).revertedWithCustomError(faucet, "AlreadyClaimed");

      });
    });
  });
  • Ceci est un test minimal pour commencer.

  • Vous pouvez voir qu'il vérifie que : a. Le contrat peut être déployé. b. L'utilisateur peut demander des tokens.

Écrire des tests en Solidity est incontournable, car cela vous permet de déployer rapidement votre contrat et de vous assurer que le code peut être exécuté et que les méthodes nécessaires peuvent être appelées. N'hésitez pas à ajouter autant de cas de test que vous le souhaitez.

Configuration de Hardhat

  • Avant de passer à l'exécution des tests, revenons à notre fichier hardhat.config.ts pour nous assurer que toutes les configurations sont correctes.

  • Remplacez le contenu de ce fichier par le code suivant. Cette configuration est spécifique à l'actuel testnet Morph :

import * as dotenv from "dotenv";

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

dotenv.config();

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.26",
    settings: {
      viaIR: true,
      optimizer: {
        enabled: true,
        runs: 99999,
      },
      evmVersion: "london",
    },
  },
  networks: {
    morphTestnet: {
      url: "https://rpc-quicknode-holesky.morphl2.io",
      accounts: [process.env.PRIVATE_KEY!],
      gasPrice: 20000000000, // 2 gwei in wei
    },
  },
  etherscan: {
    apiKey: {
      morphTestnet: "anything",
    },
    customChains: [
      {
        network: "morphTestnet",
        chainId: 2810,
        urls: {
          apiURL: "https://explorer-api-holesky.morphl2.io/api? ",
          browserURL: "https://explorer-holesky.morphl2.io/",
        },
      },
    ],
  },
};

export default config;
  • Vous pouvez voir qu'il y a une importation de la bibliothèque dotenv en haut, que nous devons installer.

  • Installez-la avec la commande suivante : npm install dotenv.

  • Une fois que c'est fait, créez un fichier .env et remplacez-le par le contenu suivant.

      PRIVATE_KEY=YouPrivateKeyHere
      ITOKEN=AddressOfItokenOnceYouDeploy
      ITOKEN_FAUCET=AddressOfItokenFaucetOnceYouDeploy
    
    • Gardez à l'esprit que le contenu de ce fichier est censé rester privé, alors assurez-vous qu'il ne soit pas envoyé sur votre GitHub.

    • Vérifiez que votre fichier .gitignore contient bien le fichier .env.

      Lancer les tests

      • Après avoir inclus vos tests, exécutez la commande suivante pour les lancer :npx hardhat test.

      • Vous devriez voir que tous les tests sont passés avec succès, super !

Déployer le contrat

Enfin, la partie amusante : déployons nos contrats intelligents sur le réseau ultra-rapide MorphL2.

  • Nous devons écrire des scripts de déploiement que nous pourrons exécuter pour déployer les contrats. Rappelez-vous, nous devons déployer deux contrats.

Déployer iToken

  • Créez un fichier dans le dossier scripts et nommez-le deploy_itoken.ts. N'hésitez pas à choisir un autre nom si vous le souhaitez.

  • Collez le code suivant dans ce fichier.

import { ethers } from "hardhat";

async function main() {
  const shadow = await ethers.deployContract("IToken");

  await shadow.waitForDeployment();

  const { ...tx } = shadow.deploymentTransaction()?.toJSON();
  tx.data = await shadow.getAddress();

  console.log(`deployed to ${JSON.stringify(tx, null, 2)}`);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
  • Lorsque vous exécutez ce script, il va déployer le contrat iTokens.

  • Voici la commande pour exécuter le script :
    npx hardhat run ./scripts/deploy_itoken.ts.Vous devriez voir le résultat suivant :

  • Cependant, ce contrat n'a pas encore été déployé sur le réseau Morph. Pour ce faire, nous devons ajouter l'argument --network et spécifier le réseau sur lequel nous souhaitons déployer.

  • Exécutez cette commande pour déployer sur le testnet Morph Holesky :
    npx hardhat run ./scripts/deploy_itoken.ts --network morphTestnet.

  • Le testnet morphTestnet ici est pris à partir de la configuration dans hardhat.config.ts.

Voici l'adresse que nous avons obtenue après le déploiement : 0x5086D4873B48041D276E40b7bd5644E6C3c0D247. La vôtre sera différente. Vous pouvez la vérifier ici : Détails de l'adresse Morph Holesky pour 0x5086D4873B48041D276E40b7bd5644E6C3c0D247.
N'oubliez pas de la définir dans votre fichier .env. Exemple :
ITOKEN=0x5086D4873B48041D276E40b7bd5644E6C3c0D247.

Vérifier le contrat iToken

Lorsque vous vérifiez un contrat, il obtient une coche dans l'explorateur, ce qui augmente la confiance des utilisateurs dans le contrat. Cela permet également d'afficher le code en Solidity lisible.

  • Exécutez cette commande pour installer le package de vérification Hardhat :
    npm install --save-dev @nomicfoundation/hardhat-verify

  • Ensuite, exécutez cette commande pour vérifier le contrat que vous venez de déployer :
    npx hardhat verify [ITOKEN] --network morphTestnet.
    N'oubliez pas de remplacer [ITOKEN] par l'adresse que vous avez obtenue lors du déploiement du contrat iToken.

Déployer iTokenFaucet

  • Créez un fichier dans le dossier scripts et nommez-le deploy_faucet.ts. N'hésitez pas à lui donner un autre nom si vous le souhaitez.

  • Collez le code suivant dans ce fichier.

import { ethers } from "hardhat";

async function main() {
  const shadow = await ethers.deployContract("ITokenFaucet", [
    process.env.ITOKEN!,
  ]);

  await shadow.waitForDeployment();

  const { ...tx } = shadow.deploymentTransaction()?.toJSON();
  tx.data = await shadow.getAddress();

  console.log(`deployed to ${JSON.stringify(tx, null, 2)}`);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
  • Lorsque vous exécutez ce script, il va déployer le contrat iTokenFaucet.

  • Exécutez cette commande pour déployer sur le testnet Morph Holesky :
    npx hardhat run ./scripts/deploy_faucet.ts --network morphTestnet.

Voici l'adresse que nous avons obtenue après le déploiement : 0xF2E381ee43cdC0CD99f107eBb9820ca27DA0A1BE. La vôtre sera différente. Vous pouvez la vérifier ici : Détails de l'adresse Holesky pour 0xF2E381ee43cdC0CD99f107eBb9820ca27DA0A1BE.
N'oubliez pas de la définir dans votre fichier .env. Exemple :
ITOKEN_FAUCET=0xF2E381ee43cdC0CD99f107eBb9820ca27DA0A1BE.

Vérifier le contrat iTokenFaucet

  • Ensuite, exécutez cette commande pour vérifier le contrat que vous venez de déployer :
    npx hardhat verify [ITOKEN_FAUCET] [ITOKEN] --network morphTestnet.
    N'oubliez pas de remplacer [ITOKEN] par l'adresse obtenue lors du déploiement du contrat iToken.

  • Cela nécessite à la fois iTokenFaucet et iToken, car le contrat iTokenFaucet prend l'adresse du contrat iToken en paramètre lors du déploiement.

Vous pouvez maintenant transférer des tokens au contrat iTokenFaucet et le tester sur le testnet Morph Holesky.

  • Visitez l'adresse du contrat iToken, cliquez sur l'icône MetaMask et ajoutez-le à votre MetaMask.

  • Allez ensuite dans vos tokens MetaMask et vous le verrez là.

  • Transférez quelques tokens de votre compte vers iTokenFaucet.

  • Vérifiez sur iTokenFaucet que les tokens ont bien été transférés.

Frontend

Le tutoriel jusqu'à présent s'est concentré sur l'écriture et le déploiement du contrat intelligent, ce qui est honnêtement la partie compliquée. Si vous êtes déjà développeur frontend, il devrait être facile d'écrire une interface simple pour utiliser ce contrat intelligent.

Bibliothèques et Frameworks à Utiliser

  • React/Next pour le framework. La plupart des bibliothèques frontend pour l'écosystème Ethereum sont écrites en React, donc c'est toujours un meilleur choix.

  • Rainbowkit pour la connexion du portefeuille. Rainbowkit

  • Wagmi est un kit d'outils de haut niveau pour construire des applications frontend Ethereum. Il fonctionne bien avec Rainbowkit. Wagmi

  • Viem est un kit d'outils de bas niveau pour construire des applications frontend Ethereum. Il est utilisé par Wagmi. Viem.

Notez que si vous ne trouvez pas le réseau Morph dans ces bibliothèques, vous pouvez en créer un personnalisé avec Viem comme ceci :

import { defineChain } from 'viem'

export const morph = defineChain({
  id: 2810,
  name: 'Morph Holesky',
  nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://rpc-quicknode-holesky.morphl2.io'] },
  },
  blockExplorers: {
    default: { name: 'Blockscout', url: 'https://explorer-holesky.morphl2.io' },
  },
})

Conclusion sur le Frontend

Avec ces bibliothèques, vous devriez être capable de construire un frontend qui interagit avec n'importe quel contrat intelligent Ethereum. Lancez-vous un défi et construisez-en un pour le faucet. Commentez avec un lien vers votre application.

Conclusion

Construire sur Morph est fluide et sécurisé. Ce guide vous offre un aperçu complet pour vous aider à développer et déployer efficacement des applications décentralisées sur la blockchain Morph. Visitez le lien du repo attaché pour plus de détails : GitHub Repo