Iniziare a Sviluppare Smart Contract in Ethereum con Hardhat. Inizializzazione

29 dicembre 2021

Hardhat è un utilissimo tool che fornisce un ambiente di sviluppo e test completo per sviluppare progetti Smart Contract in Ethereum.

In questo modo è possibile simulare in locale (direttamente sul nostro pc) una rete Ethereum avendo a disposizione cryptovaluta ETH in quantità illimitata e senza dover accedere alle reti Ethereum pubbliche, avendo quindi tempi di deploy molto ridotti.

Hardhat dispone di un ricco ecosistema di plugin molto vasto, che permette di estenderne le funzionalità e mettendo a disposizione integrazioni con altri tool per lo sviluppo di progetti Web3.

Per utilizzare Hardhat occorre aver installato l'ambiente NodeJs. NodeJS è un ambiente di sviluppo ed esecuzione di codice Javascript. Per utilizzare Hardhat e sviluppare Smart Contract per Ethereum non è strettamente necessario conoscere Javascript e NodeJS, tuttavia è sicuramente molto utile. Lo sviluppo della parte Front End di un progetto Web3 inoltre richiede l'utilizzo di Javascript, quindi di fatto è praticamente obbligatorio.

Installazione di Hardhat e creazione in un nuovo progetto

Per prima cosa occorre creare una nuova cartella ed inizializzare un nuovo progetto NodeJS da linea di comando:

In Linux/MacOS:

mkdir test-hardhat
cd test-hardhat
npm init -y
npm install --save-dev hardhat

In Windows:

md test-hardhat
cd test-hardhat
npm init -y
npm install --save-dev hardhat

Se tutto è andato bene possiamo ora inizializzare un nuovo progetto Hardhat con il comando:

npx hardhat

Selezionare la voce per la creazione di un progetto di esempio eselezionare tutte le eventuali opzioni di difault. Al termine della creazione del progetto dovrebbero venire installate in automatico delle dipendenze aggiuntive. In caso di errori è possibile installarle manualmente con il comando:

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

Queste librerie permettono l'esecuzione di test per Smart Contract tramite Waffle e l'integrazione con Ethers.js.

A questo punto è possibile lanciare nuovamente il comando npx hardhat per verificare tutti i comandi disponibili:

npx hardhat

Hardhat version 2.8.0

Usage: hardhat [GLOBAL OPTIONS] <TASK> [TASK OPTIONS]

GLOBAL OPTIONS:

  --config              A Hardhat config file.
  --emoji               Use emoji in messages.
  --help                Shows this message, or a task's help if its name is provided
  --max-memory          The maximum amount of memory that Hardhat can use.
  --network             The network to connect to.
  --show-stack-traces   Show stack traces.
  --tsconfig            A TypeScript config file.
  --verbose             Enables Hardhat verbose logging
  --version             Shows hardhat's version.


AVAILABLE TASKS:

  accounts  Prints the list of accounts
  check     Check whatever you need
  clean     Clears the cache and deletes all artifacts
  compile   Compiles the entire project, building all artifacts
  console   Opens a hardhat console
  flatten   Flattens and prints contracts and their dependencies
  help      Prints this message
  node      Starts a JSON-RPC server on top of Hardhat Network
  run       Runs a user-defined script after compiling the project
  test      Runs mocha tests

To get help for a specific task run: npx hardhat help [task]

Per verificare che tutto sia stato configurato correttamente possiamo utilizzare il comando:

npx hardhat accounts

Se tutto va bene dovrebbe uscire una lista di indirizzi in formato esadecimale:

[...]
0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097
0xcd3B766CCDd6AE721141F452C550Ca635964ce71
0x2546BcD3c84621e976D8185a91A922aE77ECEc30
[...]

All'interno della cartella contracts vengono inseriti gli Smart Contract con estensione .sol (Solidity), in particolare dovrebbe essere presente il file Greeter.sol generato da Hardhat.

Greeter.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "hardhat/console.sol";

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        console.log("Deploying a Greeter with greeting:", _greeting);
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
        greeting = _greeting;
    }
}

Questo è il primo esempio di Smart Contract! Vediamo a cosa servono le varie linee.

//SPDX-License-Identifier: Unlicense

Questa linea indica semplicemente il tipo di licenza standard che vogliamo applicare al codice del nostro Smart Contract: in questo caso nessuna licenza. Inoltre rappresenta un esempio di commento. Come in Javascript e altri linguaggi, anche in Solidity è possibile inserire commenti a linea singola utilizzando //, oppure su linee multiple utilizzando /* per iniziare il commento e */ per concluderlo.

pragma solidity ^0.8.0;

Questa linea indica il range di versioni del compilatore Solidity che può essere utilizzato per questo Smart Contract.

import "hardhat/console.sol";

Questo import include la libreria di Hardhat che permette di scrivere output sulla shell (in modo equivalente al console.log() di Javascript).

contract Greeter {
   [...]
}

Questo definisce la classe del nostro Smart Contract!

string private greeting;

Questo definisce una variabile di stato (in questo caso di tipo string). Le variabili di stato sono delle variabili il cui valore viene memorizzato in modo permanente all'interno dello spazio dello Smart Contract sulla Blockchain. Le variabili di stato, se non inizializzate esplicitamente con un valore, vengono inizializzate automaticamente con il valore zero (o equivalente).

constructor(string memory _greeting) {
    console.log("Deploying a Greeter with greeting:", _greeting);
    greeting = _greeting;
}

Questo definisce il costruttore dello Smart Contract. Il costruttore è opzionale e può essere presente al massimo un costruttore all'interno dello Smart Contract. Il costruttore viene richiamato una volta durante la creazione dello Smart Contract.

In questo caso viene scritta a console la frase "Deploying a Greeter with greeting: " più il parametro _greeting che viene passato al costruttore in fase di inizializzazione. Inoltre, il parametro "_greeting" viene assegnato alla variabile di stato greeting.

Successivamente troviamo la funzione:

function greet() public view returns (string memory) {
    return greeting;
}

Questa funzione greet è pubblica, il che significa che fa parte dell'interfaccia dello Smart Contract epuò essere chiamata internamente o tramite messaggio. Esistono 4 differenti valori di visibilità per le funzioni:

  • external
  • public
  • internal
  • private

In questo caso, inoltre, si tratta di una funzione di tipo view, il che significa che non modifica lo stato (infatti ritorna semplicemente il valore della variabile di stato privata greetings)

Successivamente troviamo un'ulteriore funzione:

function setGreeting(string memory _greeting) public {
    console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
    greeting = _greeting;
}

Anche in questo caso si tratta di una funzione pubblica, quindi può essere richiamata tramite messaggio (quindi dall'esterno). In questo caso la funzione prende in input il parametro _greetings e lo assegna alla variabile di stato greetings, modificandone quindi il valore in Blockchain.

Bene, questo è tutto lo Smart Contract di esempio generato da Hardhat. Ora è il momento di compilarlo, possiamo farlo con il comando:

npx hardhat compile

Downloading compiler 0.8.4
Compiling 2 files with 0.8.4
Compilation finished successfully

La compilazione produce alcuni file all'interno della cartella artifacts. In particolare quello che ci interessa di più è il file artifacts/contracts/Greeter.sol/Greeter.json. Questo file in formato JSON contiene le informaioni necessarie per il deploy e l'interfacciamento delle applicazioni con il nostro Smart Contract. In particolare include il campo ABI (Application Binary Interface), che contiene le specifiche del nostro Smart Contract e l'interfaccia messa a disposizione per interagirvi.