Completiamo il Front End verso il nostro Smart Contract

04 gennaio 2022

L'ultimo passo per completare il nostro Front End è collegare e richiamare le funzioni dello Smart Contract. Per prima cosa, se abbiamo riavviato il nodo Hardhat, dobbiamo rifare il deploy dello Smart Contract.

npx hardhat run scripts/sample-script.js --network localhost

Greeter deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512

Prendiamo nota dell'indirizzo perchè ci servirà per collegarci.

Le operazioni da compiere sono sostanzialmente analoghe a quelle utilizzate nella lezione sul collegamento da linea di comando.

Per prima cosa modifichiamo leggermente la pagina web per aggiungere alcuni elementi che ci serviranno a visualizzare il messaggio dello Smart Contract e ad inviare un nuovo saluto.

index.html
<div id="smart-contract" style="visibility: hidden">
  <div class="card text-white bg-success mb-3" > <!-- style="" -->
    <div class="card-header">Lo Smart Contract dice:</div>
    <div class="card-body">
      <p class="card-text" id="contenuto"></p>
    </div>
  </div>

  <form>
    <div class="form-group">
      <label for="inputMessaggio">Inserisci un nuovo messaggio</label>
      <input type="text" class="form-control" id="inputMessaggio" aria-describedby="inputHelp" placeholder="Inserisci un messaggio da inviare in Blockchain">
      <small id="inputHelp" class="form-text text-muted">Il tuo saluto in Ethereum.</small>
    </div>
    <button type="button" class="btn btn-primary" onClick="inserisciMessaggio()">Invia!</button>
  </form>
</div>

Il primo blocco ci permetterà di visualizzare il messaggio memorizzato nello Smart Contract, mentre il form servirà a inviare un nuovo messaggio.

Modifichiamo il file saluti.js in modo da impostare alcune variabili accessibili a tutte le funzioni:

saluti.js
const greeterAddress = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512";
const greeterAbi = [
  [...]
]

const messaggiDiv = document.getElementById('messaggi')
const connectButton = document.getElementById('connectButton')
const smartContractDiv = document.getElementById('smart-contract')
const contenuto = document.getElementById('contenuto')

let accountCollegato = null
let provider = null
let signer = null
let greeterContract = null
let greeterContractWithSigner = null

Le prime due variabili sono gli identificativi dello Smart Contract: il suo indirizzo sulla Blockchain e la sua descrizione ABI presa dal file Greeter.json. Successivamente andiamoa memorizzarci alcuni elementi che dovremo andare a modificare in base allo stato del programma. Infine inizializziamo tutte le variabili necessarie alla gestione della Blockchain.

Inseriamo l'inizializzazione della Blockchain in una funzione dedicata:

saluti.js
function initContratto() {
  provider = new ethers.providers.Web3Provider(window.ethereum)
  signer = provider.getSigner()

  greeterContract = new ethers.Contract(greeterAddress, greeterAbi, provider)
  greeterContractWithSigner = greeterContract.connect(signer)
}

Questo è analogo a quello che abbiamo già fatto nel client da command line.

Aggiungiamo poi questa funzione per recuperare il messaggio dallo Smart Contract:

saluti.js
function recuperaMessaggio() {
  greeterContract.greet()
  .then( saluto => {
    console.log(saluto)
    smartContractDiv.style.visibility = 'visible'
    contenuto.innerHTML = saluto
  })
  .catch( error => console.log(error))
}

Possiamo iniziare a testare questa prima funzionalità.

Modifichiamo la logica di gestione in questo modo:

saluti.js
if (!window.ethereum) {
  console.log('Ethereum non trovato!')
  messaggiDiv.?innerHTML = '<p class="alert alert-danger">Ethereum non trovato! Installa Metamask!</p>'
} else {
  // listener per i cambiamenti di account
  ethereum.on('accountsChanged', gestisciAccount);

  // richiesta degli account collegati
  ethereum.request({ method: 'eth_accounts'})
    .then(
      accounts => {
        // nessun account trovato: visualizza interfaccia di login
        if (accounts.length < 1) {
          visualizzaLogin()
        } else {
          collegaAccount(accounts)
          initContratto()
          recuperaMessaggio()
        }
      }
    )
    .catch( error => {
      console.log(error)
    })
}

Se proviamo a caricare la pagina dovremmo riuscire a visualizzare il messaggio memorizzato all'interno dello Smart Contract!

Aggiungiamo la funzione per salvare un nuovo messaggio:

saluti.js
function inserisciMessaggio() {
  const messaggio = (document.getElementById('inputMessaggio')).value

  if (messaggio.length > 0) {
    greeterContractWithSigner.setGreeting(messaggio)
    .then(
      () => {
        messaggiDiv.innerHTML = '<p class="alert alert-success">Messaggio salvato!</p>'
        setTimeout(recuperaMessaggio, 1000)
      }
    ).catch(
      error => {
        console.log('Errore durante la chiamata a setGreeting():', error)
        messaggiDiv.innerHTML = '<p class="alert alert-danger">Errore!</p>'
      }
    )
  }
}

Il cuore di questa funzione è: greeterContractWithSigner.setGreeting(messaggio). Proviamo a ricaricare la pagina e ad inserire un nuovo messaggio. Se abbiamo utilizzato l'account che abbiamo creato inizialmente con Metamask, che quindi non ha nessun ETH, Metamask ci informerà che non possiamo procedere perchè non abbiamo credito sufficiente per pagare la transazione. Qua ci vengono in aiuto gli account che sono stati inizializzati da Hardhat. Copiamo la chiave privata di un account a caso a importiamola in Metamask. Selezioniamo poi questo account quando ci verrà chiesto da Metamask.

Se riproviamo a rimadare il messaggio utilizzando il nuovo account adesso dovremmo ricevere un messaggio di successo e dovremmo vedere il nuovo messaggio nell'interfaccia!