Articolo originale: https://www.freecodecamp.org/news/full-stack-ethereum-development/

In questo articolo imparerai come creare dApp full stack con React, Ethers.js, Solidity e Hardhat.

Puoi trovare il codice per questo progetto qui . Il video corso per questo tutorial è qui.

Di recente mi sono unito a Edge & Node come Developer Relations Engineer e ho approfondito lo sviluppo di contratti intelligenti con Ethereum. Ho scelto quello che penso sia lo stack migliore per la creazione di dApp full stack con Solidity:

Però mi sono imbattuto in un problema mentre cercavo di capire tutto questo. Sebbene sia disponibile individualmente una documentazione abbastanza buona per ciascuno di questi strumenti, non c'è molto che ti aiuti a metterli tutti insieme e capire come funzionano tra loro.

Ci sono alcuni standard davvero buoni là fuori come scaffold-eth (che include anche Ethers, Hardhat e The Graph), ma potrebbero essere troppo da comprendere per le persone che hanno appena iniziato.

Volevo una guida end-to-end che mi mostrasse come creare app Ethereum full stack utilizzando le risorse, le librerie e gli strumenti più aggiornati.

Ecco cosa mi interessava:

  1. Come creare, distribuire e testare smart contract Ethereum su local, test e mainnet
  2. Come spostarsi tra ambienti/reti locali, di test e di produzione
  3. Come connettersi e interagire con i contratti utilizzando vari ambienti da un front-end come React, Vue, Svelte o Angular

Dopo aver passato un po' di tempo a capire tutto questo, sono finalmente riuscito a usare lo stack di cui mi sentivo davvero a mio agio. Quindi ho pensato che sarebbe stato bello scrivere come costruire e testare un'app Ethereum full stack usando questo stack.

Spero che questa guida sia utile non solo per altre persone là fuori che potrebbero essere interessate a questo stack, ma anche per me stesso come riferimento futuro. Questo è quel riferimento.

La tecnologia che useremo

Esaminiamo i pezzi principali che utilizzeremo e come si inseriscono nell'insieme.

1. Ambiente di sviluppo di Ethereum

Quando crei contratti intelligenti, avrai bisogno di un modo per distribuire i tuoi contratti, eseguire test ed eseguire il debug del codice Solidity senza dover gestire ambienti live.

Avrai anche bisogno di un modo per compilare il tuo codice Solidity in codice che può essere eseguito in un'applicazione lato client, nel nostro caso, un'app React. Impareremo di più su come questo funziona un più avanti.

Hardhat è un ambiente di sviluppo Ethereum e un framework progettato per lo sviluppo full stack, ed è il framework che userò per questo tutorial.

Altri strumenti simili nell'ecosistema sono Ganache e Truffle .

2. Libreria Web client di Ethereum

Nella nostra app React, avremo bisogno di un modo per interagire con gli smart contract che sono stati implementati. Avremo bisogno di un modo per leggere i dati e inviare nuove transazioni.

ethers.js mira ad essere una libreria completa e compatta per interagire con Ethereum Blockchain e il suo ecosistema da applicazioni JavaScript lato client come React, Vue, Angular o Svelte. È la libreria che useremo.

Un'altra opzione popolare nell'ecosistema è web3.js

3. Metamask

Metamask ti aiuta a gestire la gestione dell'account e a connettere l'utente corrente alla blockchain. MetaMask consente agli utenti di gestire i propri account e chiavi in ​​diversi modi isolandoli dal contesto del sito.

Una volta che un utente ha connesso il proprio portafoglio MetaMask, tu come sviluppatore puoi interagire con l'API Ethereum disponibile a livello globale (window.ethereum) che identifica gli utenti di browser compatibili con web3 (come gli utenti MetaMask). Ogni volta che richiedi una firma di transazione, MetaMask la richiederà all'utente in modo comprensibile.

4. React

React è una libreria JavaScript front-end per la creazione di applicazioni Web, interfacce utente e componenti dell'interfaccia utente. È gestito da Facebook e da molti sviluppatori e aziende individuali.

React e il suo ampio ecosistema di metaframework come Next.js, Gatsby, Redwood, Blitz.js e altri abilitano tutti i tipi di target di distribuzione inclusi SPA tradizionali, generatori di siti statici, rendering lato server e una combinazione di tutti e tre.

React continua apparentemente a dominare lo spazio front-end e penso che continuerà a farlo nel prossimo futuro e forse anche oltre.

5. The Graph

Per la maggior parte delle app basate su blockchain come Ethereum, è difficile e dispendioso in termini di tempo leggere i dati direttamente dalla chain. Quindi in passato vedevi persone e aziende costruire il proprio server di indicizzazione centralizzato e servire le richieste API da questi server. Ciò richiede molte risorse ingegneristiche e hardware e interrompe le proprietà di sicurezza richieste per la decentralizzazione.

The Graph è un protocollo di indicizzazione per interrogare i dati blockchain, che ti consente di creare applicazioni completamente decentralizzate. Risolve questo problema esponendo un ricco livello di query GraphQL che le app possono utilizzare.

In questa guida non creeremo un sottografo per la nostra app, ma lo faremo in un tutorial futuro.

Cosa costruiremo

In questo tutorial creeremo, implementeremo e ci collegheremo a un paio di contratti intelligenti di base:

  1. Un contratto per la creazione e l'aggiornamento di un messaggio sulla blockchain di Ethereum
  2. Un contratto per il conio di token, che consente al proprietario del contratto di inviare token ad altri e di leggere i saldi dei token e consente ai proprietari dei nuovi token di inviarli anche ad altri.

Realizzeremo anche un front-end React che consentirà a un utente di:

  1. Leggere il saluto dal contratto distribuito sulla blockchain
  2. Aggiornare il saluto
  3. Inviare i token appena coniati dal loro indirizzo a un altro indirizzo
  4. Una volta che qualcuno ha ricevuto i token, consentire loro di inviare i propri token anche a qualcun altro
  5. Leggere il saldo del token dal contratto distribuito sulla blockchain

Prerequisiti

  1. Node.js installato sul tuo computer locale
  2. Estensione MetaMask Chrome installata nel tuo browser

Non è necessario possedere alcun Ethereum per questa guida poiché utilizzeremo Ether falso/test su una rete di test per l'intero tutorial.

Come iniziare con create-react-app

Per iniziare, creeremo una nuova applicazione React:

npx create-react-app react-dapp

Quindi, passa alla nuova directory e installa ethers.js e  hardhat utilizzando NPM o Yarn :

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

Come installare e configurare un ambiente di sviluppo Ethereum

Quindi, inizializza un nuovo ambiente di sviluppo Ethereum con Hardhat:

npx hardhat

? What do you want to do? Create a sample project
? Hardhat project root: <Choose default path>

Ora dovresti vedere i seguenti file e cartelle creati per te nella tua directory principale:

  • hardhat.config.js – L'intera configurazione di Hardhat (ovvero la configurazione, i plug-in e le attività personalizzate) è contenuta in questo file.
  • scripts – Una cartella contenente uno script denominato sample-script.js che distribuirà il tuo smart contract una volta eseguito
  • test – Una cartella contenente uno script di test di esempio
  • contracts : una cartella contenente uno smart contract di Ethereum di esempio

A causa di un problema di configurazione di MetaMask , dobbiamo aggiornare l'ID della catena sulla nostra configurazione di HardHat in modo che sia 1337 . Abbiamo anche bisogno di aggiornare la posizione della cartella artifacts per i nostri contratti compilati in modo che siano nella directory src della nostra app React.

Per effettuare questi aggiornamenti, apri hardhat.config.js e aggiorna il file module.exports in modo che assomigli a questo:

module.exports = {
  solidity: "0.8.3",
  paths: {
    artifacts: './src/artifacts',
  },
  networks: {
    hardhat: {
      chainId: 1337
    }
  }
};

Il nostro smart contract

Quindi, diamo un'occhiata al contratto di esempio che abbiamo in contract/Greeter.sol :

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

import "hardhat/console.sol";


contract Greeter {
  string 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 è un contratto intelligente molto semplice. Quando viene distribuito, imposta una variabile Greeting ed espone una funzione (greet) che può essere chiamata per restituire il saluto.

Espone inoltre una funzione che consente a un utente di aggiornare il saluto (setGreeting). Una volta distribuiti sulla blockchain di Ethereum, questi metodi saranno disponibili per l'interazione di un utente.

Apportiamo una piccola modifica allo smart contract. Poiché impostiamo la versione di solidity del nostro compilatore su 0.8.3 in hardhat.config.js, assicuriamoci anche di aggiornare il nostro contratto per utilizzare la stessa versione di solidity:

// contracts/Greeter.sol
pragma solidity ^0.8.3;

Come leggere e scrivere sulla blockchain di Ethereum

Esistono due modi per interagire con uno smart contract: lettura o scrittura delle transazioni. Nel nostro contratto, greet può essere considerato transazione in lettura e setGreeting può essere considerato transazione in scrittura.

Quando si scrive o si inizializza una transazione, è necessario pagare affinché la transazione venga scritta sulla blockchain. Per farlo funzionare, devi pagare il gas che è la commissione o il prezzo richiesto per condurre con successo una transazione ed eseguire un contratto sulla blockchain di Ethereum.

Finché stai solo leggendo dalla blockchain e non modifichi o aggiorni nulla, non è necessario effettuare una transazione e non ci saranno gas o costi per farlo. La funzione che chiami viene poi svolta solo dal nodo a cui sei connesso, quindi non devi pagare alcun gas e la lettura è gratuita.

Dalla nostra app React, interagiremo con lo smart contract utilizzando una combinazione della libreria  ethers.js, indirizzo del contratto e ABI che verrà creato dal contratto da Hardhat.

Che cos'è un ABI? ABI sta per interfaccia binaria dell'applicazione. Puoi pensarla come l'interfaccia tra la tua applicazione lato client e la blockchain di Ethereum in cui viene distribuito lo smart contract con cui interagirai.

Gli ABI sono in genere compilati da smart contract di Solidity con un framework di sviluppo come Hardhat. Spesso puoi trovare gli ABI per uno smart contract anche su Etherscan

Come compilare l'ABI

Ora che abbiamo esaminato lo smart contract di base e sappiamo cosa sono gli ABI, compiliamo un ABI per il nostro progetto.

Per farlo, vai alla riga di comando ed esegui il seguente comando:

npx hardhat compile

Ora dovresti vedere una nuova cartella denominata artifacts nella directory src . Il file artifacts/contracts/Greeter.json contiene l'ABI come una delle proprietà. Quando dobbiamo usare l'ABI, possiamo importarlo dal nostro file JavaScript:

import Greeter from './artifacts/contracts/Greeter.sol/Greeter.json'

Possiamo quindi fare riferimento all'ABI in questo modo:

console.log("Greeter ABI: ", Greeter.abi)
Nota che Ethers.js abilita anche ABI leggibili dall'uomo , ma non ne parleremo durante questo tutorial.

Come distribuire e utilizzare una rete locale / Blockchain

Quindi, distribuiamo il nostro contratto intelligente su una blockchain locale in modo da poterlo testare.

Per eseguire la distribuzione nella rete locale, devi prima avviare il nodo di test locale. Per fare ciò, apri la CLI ed esegui il seguente comando:

npx hardhat node

Quando eseguiamo questo comando, dovresti vedere un elenco di indirizzi e chiavi private.

Indirizzi di nodi hardhat

Si tratta di 20 account di prova e indirizzi creati per noi che possiamo utilizzare per implementare e testare i nostri contratti intelligenti. Ogni account è anche caricato con 10.000 falsi Ether. Tra poco impareremo come importare l'account di prova in MetaMask in modo da poterlo utilizzare.

Successivamente, dobbiamo distribuire il contratto alla rete di test. Per prima cosa aggiorna il nome di scripts/sample-script.js in scripts/deploy.js .

Ora possiamo eseguire lo script di distribuzione e dare un flag alla CLI in modo da distribuire sulla nostra rete locale:

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

Una volta eseguito questo script, lo smart contract dovrebbe essere distribuito sulla rete di test locale e dovremmo essere quindi in grado di iniziare a interagire con esso.

Quando il contratto è stato distribuito, utilizzava il primo account creato quando abbiamo avviato la rete locale.

Se guardi l'output della CLI, dovresti essere in grado di vedere qualcosa del genere:

Greeter deployed to: 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0

Questo indirizzo è quello che useremo nella nostra applicazione client per parlare con lo smart contract. Mantieni questo indirizzo disponibile poiché dovremo usarlo quando ci connettiamo ad esso dall'applicazione client.

Per inviare transazioni allo smart contract, dovremo connettere il nostro portafoglio MetaMask utilizzando uno degli account creati quando abbiamo eseguito npx hardhat node. Nell'elenco dei contratti che la CLI ha stampato, dovresti vedere sia un numero di conto che una chiave privata :

➜  react-defi-stack git:(main) npx hardhat node
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

Accounts
========
Account #0: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

...

Possiamo importare questo account in MetaMask per iniziare a utilizzare alcuni dei falsi Eth disponibili lì. Per fare ciò, prima apri MetaMask e aggiorna la rete in modo che sia Localhost 8545:

MetaMask Localhost

Successivamente, in MetaMask, fai clic su Import Account dal menu degli account:

Importa conto

Copia, quindi incolla una delle chiavi private stampate nella CLI e fai clic su Import. Una volta importato l'account, dovresti vedere l'Eth nell'account:

Conto importato

Ora che abbiamo distribuito il nostro contratto intelligente e configurato il nostro account, possiamo iniziare a interagire con esso dall'app React.

Come collegare il client React

In questo tutorial non ci preoccuperemo di creare una bella interfaccia utente con CSS e tutto il resto: invece ci concentreremo al 100% sulle funzionalità di base per renderti operativo velocemente. Da lì poi, puoi prenderlo e farlo sembrare bello, se lo desideri.

Detto questo, esaminiamo i due obiettivi che desideriamo dalla nostra applicazione React:

  1. Recupera il valore corrente di greeting dal contratto intelligente
  2. Consenti a un utente di aggiornare il valore di greeting

Quindi, come lo realizziamo? Ecco le cose che dobbiamo fare perché ciò avvenga:

  1. Creare un campo di input e uno stato locale per gestire il valore dell'input (per aggiornare il greeting)
  2. Consentire all'applicazione di connettersi all'account MetaMask dell'utente per firmare le transazioni
  3. Creare le funzioni per leggere e scrivere sullo smart contract

Per fare ciò, apri src/App.js e aggiornalo con il seguente codice, impostando il valore di greeterAddress all'indirizzo del tuo smart contract:

import './App.css';
import { useState } from 'react';
import { ethers } from 'ethers'
import Greeter from './artifacts/contracts/Greeter.sol/Greeter.json'

// Aggiorna con l'indirizzo del contratto stampato dalla CLI quando è stato distribuito 
const greeterAddress = "indirizzo-del-tuo-contratto"

function App() {
  // memorizza il saluto nella stato locale
  const [greeting, setGreetingValue] = useState()

  // richiede l'accesso all'account MetaMask dell'utente
  async function requestAccount() {
    await window.ethereum.request({ method: 'eth_requestAccounts' });
  }

  // chiama lo smart contract, legge il valore attuale del saluto 
  async function fetchGreeting() {
    if (typeof window.ethereum !== 'undefined') {
      const provider = new ethers.providers.Web3Provider(window.ethereum)
      const contract = new ethers.Contract(greeterAddress, Greeter.abi, provider)
      try {
        const data = await contract.greet()
        console.log('data: ', data)
      } catch (err) {
        console.log("Error: ", err)
      }
    }    
  }

  // chiama lo smart contract, invia un aggiornamento
  async function setGreeting() {
    if (!greeting) return
    if (typeof window.ethereum !== 'undefined') {
      await requestAccount()
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner()
      const contract = new ethers.Contract(greeterAddress, Greeter.abi, signer)
      const transaction = await contract.setGreeting(greeting)
      await transaction.wait()
      fetchGreeting()
    }
  }

  return (
    <div className="App">
      <header className="App-header">
        <button onClick={fetchGreeting}>Fetch Greeting</button>
        <button onClick={setGreeting}>Set Greeting</button>
        <input onChange={e => setGreetingValue(e.target.value)} placeholder="Set greeting" />
      </header>
    </div>
  );
}

export default App;

Per testarlo, avvia il server React:

npm start

Quando l'app viene caricata, dovresti essere in grado di recuperare il saluto corrente e stamparlo sulla console. Dovresti anche essere in grado di aggiornare il saluto firmando il contratto con il tuo portafoglio MetaMask e spendendo il falso Ether.

Impostazione e ottenere il valore di saluto

Come distribuire e utilizzare una rete di test dal vivo

Esistono diverse reti di test di Ethereum come Ropsten, Rinkeby o Kovan a cui possiamo anche distribuire per avere una versione pubblicamente accessibile del nostro contratto disponibile senza doverla distribuire sulla mainnet.

In questo tutorial verrà distribuito nella rete di test Ropsten .

Per iniziare, aggiorna prima il tuo portafoglio MetaMask per connetterti alla rete Ropsten.

Rete Ropsten

Quindi, invia a te stesso un Ether di prova da utilizzare durante il resto di questo tutorial visitando questo faucet di prova .

Possiamo accedere a Ropsten (o a qualsiasi altra rete di test) iscrivendoci a un servizio come Infura o Alchemy (sto usando Infura per questo tutorial).

Dopo aver creato l'app in Infura o Alchemy, ti verrà assegnato un endpoint simile a questo:

https://ropsten.infura.io/v3/your-project-id

Assicurati di impostare ALLOWLIST ETHEREUM ADDRESSES nella configurazione dell'app Infura o Alchemy per includere l'indirizzo del portafoglio dell'account da cui eseguirai la distribuzione.

Per eseguire il deployment nella rete di test, è necessario aggiornare la nostra configurazione di Hardhat con alcune informazioni di rete aggiuntive. Una delle cose che dobbiamo impostare è la chiave privata del portafoglio da cui eseguiremo il deployment.

Per ottenere la chiave privata, puoi esportarla da MetaMask.

Esporta chiave privata
Suggerirei di non codificare questo valore nella tua app, ma invece di impostarlo come una variabile di ambiente.

Quindi, aggiungi una proprietà networks con la seguente configurazione:

module.exports = {
  defaultNetwork: "hardhat",
  paths: {
    artifacts: './src/artifacts',
  },
  networks: {
    hardhat: {},
    ropsten: {
      url: "https://ropsten.infura.io/v3/your-project-id",
      accounts: [`0x${your-private-key}`]
    }
  },
  solidity: "0.7.3",
};

Per eseguire la distribuzione, avviare il seguente script:

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

Una volta distribuito il contratto, dovresti essere in grado di iniziare a interagire con esso. Ora dovresti essere in grado di visualizzare il contratto live su Etherscan Ropsten Testnet Explorer

Come coniare i gettoni

Uno dei casi d'uso più comuni degli smart contract è la creazione di token. Diamo un'occhiata a come possiamo farlo. Dal momento che sappiamo un po' di più su come funziona tutto questo, andremo un po' più veloci.

Nella directory principale dei contracts, crea un nuovo file denominato Token.sol .

Quindi, aggiorna Token.sol con il seguente contratto intelligente:

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

import "hardhat/console.sol";

contract Token {
  string public name = "Nader Dabit Token";
  string public symbol = "NDT";
  uint public totalSupply = 1000000;
  mapping(address => uint) balances;

  constructor() {
    balances[msg.sender] = totalSupply;
  }

  function transfer(address to, uint amount) external {
    require(balances[msg.sender] >= amount, "Gettoni non sufficienti");
    balances[msg.sender] -= amount;
    balances[to] += amount;
  }

  function balanceOf(address account) external view returns (uint) {
    return balances[account];
  }
}
Tieni presente che questo contratto token è solo a scopo dimostrativo e non è conforme a ERC20 . Tratteremo i token ERC20 in seguito.

Questo contratto creerà un nuovo token chiamato "Nader Dabit Token" e imposterà la fornitura a 1000000.

Quindi, compila questo contratto:

npx hardhat compile

Ora, aggiorna lo script di distribuzione su scripts/deploy.js per includere questo nuovo contratto Token:

const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();

  console.log(
    "Distribuzione di contratti con l'account:",
    deployer.address
  );
  
  const Greeter = await hre.ethers.getContractFactory("Greeter");
  const greeter = await Greeter.deploy("Hello, World!");

  const Token = await hre.ethers.getContractFactory("Token");
  const token = await Token.deploy();
  
  await greeter.deployed();
  await token.deployed();

  console.log("Greeter distribuito a:", greeter.address);
  console.log("Token distribuito a:", token.address);
}

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

Ora possiamo distribuire questo nuovo contratto sulla rete locale o Ropsten:

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

Una volta distribuito il contratto, puoi iniziare a inviare questi token ad altri indirizzi.

Per fare ciò, aggiorniamo il codice client di cui avremo bisogno per farlo funzionare:

import './App.css';
import { useState } from 'react';
import { ethers } from 'ethers'
import Greeter from './artifacts/contracts/Greeter.sol/Greeter.json'
import Token from './artifacts/contracts/Token.sol/Token.json'

const greeterAddress = "il-tuo-indirizzo-di-contratto"
const tokenAddress = "il-tuo-indirizzo-di-contratto"

function App() {
  const [greeting, setGreetingValue] = useState()
  const [userAccount, setUserAccount] = useState()
  const [amount, setAmount] = useState()

  async function requestAccount() {
    await window.ethereum.request({ method: 'eth_requestAccounts' });
  }

  async function fetchGreeting() {
    if (typeof window.ethereum !== 'undefined') {
      const provider = new ethers.providers.Web3Provider(window.ethereum)
      console.log({ provider })
      const contract = new ethers.Contract(greeterAddress, Greeter.abi, provider)
      try {
        const data = await contract.greet()
        console.log('data: ', data)
      } catch (err) {
        console.log("Error: ", err)
      }
    }    
  }

  async function getBalance() {
    if (typeof window.ethereum !== 'undefined') {
      const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' })
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const contract = new ethers.Contract(tokenAddress, Token.abi, provider)
      const balance = await contract.balanceOf(account);
      console.log("Balance: ", balance.toString());
    }
  }

  async function setGreeting() {
    if (!greeting) return
    if (typeof window.ethereum !== 'undefined') {
      await requestAccount()
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      console.log({ provider })
      const signer = provider.getSigner()
      const contract = new ethers.Contract(greeterAddress, Greeter.abi, signer)
      const transaction = await contract.setGreeting(greeting)
      await transaction.wait()
      fetchGreeting()
    }
  }

  async function sendCoins() {
    if (typeof window.ethereum !== 'undefined') {
      await requestAccount()
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(tokenAddress, Token.abi, signer);
      const transation = await contract.transfer(userAccount, amount);
      await transation.wait();
      console.log(`${amount} Coins successfully sent to ${userAccount}`);
    }
  }

  return (
    <div className="App">
      <header className="App-header">
        <button onClick={fetchGreeting}>Fetch Greeting</button>
        <button onClick={setGreeting}>Set Greeting</button>
        <input onChange={e => setGreetingValue(e.target.value)} placeholder="Set greeting" />

        <br />
        <button onClick={getBalance}>Get Balance</button>
        <button onClick={sendCoins}>Send Coins</button>
        <input onChange={e => setUserAccount(e.target.value)} placeholder="Account ID" />
        <input onChange={e => setAmount(e.target.value)} placeholder="Amount" />
      </header>
    </div>
  );
}

export default App;

Quindi, esegui l'app:

npm start

Dovremmo essere in grado di fare clic su Get Balance e vedere che abbiamo 1.000.000 di monete nel nostro account stampato sulla console.

Dovresti anche essere in grado di visualizzarli in MetaMask facendo clic su Add Token:

Aggiungi token

Quindi fai clic su Custom Token e inserisci l'indirizzo del contratto del token e poi Add Token . Ora i token dovrebbero essere disponibili nel tuo portafoglio:

NDT

Quindi, proviamo a inviare quelle monete a un altro indirizzo.

Per fare ciò, copia l'indirizzo di un altro account e invialo a quell'indirizzo utilizzando l'interfaccia utente di React aggiornata. Quando controlli l'importo del token, dovrebbe essere uguale all'importo originale meno l'importo che hai inviato all'indirizzo.

Come costruire un token ERC20

Lo standard dei token ERC20 definisce un insieme di regole che si applicano a tutti i token ERC20 che consentono loro di interagire facilmente tra loro. ERC20 rende davvero facile per qualcuno coniare i propri token che avranno interoperabilità con altri sulla blockchain di Ethereum.

Diamo un'occhiata a come possiamo costruire il nostro token utilizzando lo standard ERC20.

Innanzitutto, installa la libreria di smart contract ERC20  OpenZepplin in cui importeremo il token di base:

npm install @openzeppelin/contracts

Successivamente, creeremo il nostro token estendendo (o ereditando) il contratto ERC20:

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

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

contract NDToken is ERC20 {
    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        _mint(msg.sender, 100000 * (10 ** 18));
    }
}

Il costruttore consente di impostare il nome e il simbolo del token e la funzione _mint consente di coniare i token e di impostare l'importo.

Per impostazione predefinita, ERC20 imposta il numero di decimali a 18, quindi nella nostra funzione _mint moltiplichiamo 100.000 per 10 alla potenza 18 per coniare un totale di 100.000 gettoni, ciascuno con 18 cifre decimali (in modo simile a come 1 Eth è composto da 10 a 18 wei .

Per distribuire, dobbiamo passare i valori del costruttore (name e symbol), quindi potremmo fare qualcosa del genere nel nostro script di distribuzione:

const NDToken = await hre.ethers.getContractFactory("NDToken");
const ndToken = await NDToken.deploy("Nader Dabit Token", "NDT");

Estendendo il token ERC20 originale, il tuo token erediterà tutte le seguenti funzioni e funzionalità:

function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)

Una volta implementato, puoi utilizzare una qualsiasi di queste funzioni per interagire con il nuovo contratto intelligente. Per un altro esempio di token ERC20, dai un'occhiata a Solidity by example qui: https://solidity-by-example.org/app/erc20/ .

Conclusione

Ok, abbiamo trattato molto in questo articolo. Ma per me questo è una specie di pane quotidiano / essenziale per iniziare con questo stack.

È un po' quello che volevo avere, non solo come qualcuno che sta imparando tutte queste cose, ma anche in futuro, se mai avessi bisogno di fare riferimento a qualcosa di cui potrei aver bisogno. Spero che tu abbia imparato molto.

Se desideri supportare più portafogli oltre a MetaMask, dai un'occhiata a Web3Modal che semplifica l'implementazione del supporto per più provider nella tua app con una configurazione abbastanza semplice e personalizzabile.

Nei miei futuri tutorial e guide, mi immergerò nello sviluppo di contratti intelligenti più complessi e anche su come distribuirli come sottografi per esporre un'API GraphQL su di essi e implementare cose come l'impaginazione e la ricerca full-text.

Tratterò anche di come utilizzare tecnologie come IPFS e database Web3 per archiviare i dati in modo decentralizzato.

Se hai domande o suggerimenti per futuri tutorial, fammi sapere.