11.6 Exemple d'application Web 2.0/Web 3.0 de chaîne de blocs Ethereum
Objectifs d'apprentissage
À la fin de cette section, vous serez capable de :
- Construire une application hybride Web 3.0 de chaîne de blocs Ethereum
- Créer l'application React et installer les dépendances
- Créer le contrat intelligent
- Créer les composants frontaux React
- Ajouter Web3 à l'application React
- Configurer l'application React pour communiquer avec le contrat intelligent
Jusqu'à présent, ce chapitre a exploré comment développer une application web Todo, ainsi qu'une application mobile Todo, en utilisant Bootstrap, Django, React (React), React Native (React Native) et Node (Node). Dans cette dernière section, vous apprendrez à créer une application Todo simple en utilisant React avec le Web 3.0 alimenté par des contrats intelligents (smart contract) Ethereum sur la chaîne de blocs.
Création d'une application Todo Web 3.0 de chaîne de blocs Ethereum
Comme vous l'avez appris, les applications Todo peuvent être créées à l'aide de différents outils. Dans cette section, vous explorerez la chaîne de blocs Ethereum (Ethereum blockchain), qui crée un réseau pair-à-pair sécurisé grâce à l'utilisation d'un contrat intelligent, qui est un accord numérique sécurisé permettant aux utilisateurs de transiger directement entre eux via la chaîne de blocs. Vous utiliserez React pour créer une application Todo Web 3.0 de chaîne de blocs Ethereum.
Lien vers l'apprentissage
Ganache est un environnement personnel de chaîne de blocs Ethereum qui fournit aux développeurs les moyens d'utiliser une chaîne de blocs privée pour le développement et les tests. Ganache peut émuler la chaîne de blocs Ethereum, et parce qu'il s'agit d'une chaîne de blocs privée, il permet aux développeurs de contrôler les processus de développement et de test.
Prérequis
Pour construire l'application Todo Web 3.0 (Web 3.0) de chaîne de blocs Ethereum, vous devriez utiliser React v17.0.2, Bootstrap v4.5.0, Node v14.17.5, Web 3.js v1.2.2, Truffle v5.0.2 et Solidity v0.8.11. De plus, Ganache est utilisé comme chaîne de blocs personnelle pour le développement. Pour commencer, faites ce qui suit :
- Téléchargez et installez Ganache. Lancez Ganache et choisissez l'option de démarrage rapide Ethereum comme illustré à la Figure 11.46.
Figure 11.46 Ceci est l'option de démarrage rapide Ethereum disponible après l'installation de Ganache. (source : Ganache, sous licence MIT)
- L'étape suivante consiste à installer le plug-in Chrome MetaMask. Configurez le compte MetaMask et connectez-vous.
Création de l'application React
Précédemment dans ce chapitre, vous avez créé des applications React. Pour cette application, vous devez créer une nouvelle application React.
Pour créer la nouvelle application React, exécutez la commande suivante :
$ npx create-react-app ethreact
Installer Bootstrap, Web3 et d'autres dépendances
Pour utiliser Bootstrap et Web3 dans une application React, les paquets correspondants doivent être installés. Pour ce faire, dans le répertoire ethreact/, exécutez les commandes suivantes :
$ npm install bootstrap@4.6.0 reactstrap@8.9.0 --legacy-peer-deps
$ npm install react-bootstrap
$ npm install web3@1.2.2
Ensuite, importez le fichier CSS de Bootstrap dans l'application React. Ouvrez ethreact/src/index.js et ajoutez l'importation Bootstrap suivante.
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Lien vers l'apprentissage
Truffle fournit une suite d'outils qui peuvent être utilisés pour développer des contrats intelligents. Truffle offre un développement de bout en bout qui inclut la capacité de développer, tester et implémenter des contrats intelligents, tout en utilisant Truffle pour gérer le flux de travail.
Création du contrat intelligent
Pour développer le contrat intelligent Ethereum, vous utiliserez le cadriciel Truffle (Truffle Framework), qui est une suite d'outils populaires utilisée pour développer des contrats intelligents. Implémentez le cadriciel Truffle en utilisant Solidity (Solidity), qui est un langage de haut niveau, orienté objet, axé sur l'implémentation de contrats intelligents. Pour utiliser le cadriciel Truffle, dans le répertoire ethreact/, exécutez la commande d'installation suivante :
$ npm install -g [email protected]
Pour configurer l'application React afin d'utiliser Truffle, dans le répertoire ethreact/, exécutez la commande suivante, ce qui peut prendre plusieurs minutes.
$ truffle init
Lorsque l'initialisation est terminée, le répertoire contracts/ et le fichier Migrations.sol seront générés. De plus, le fichier truffle-config.js sera généré, comme mis en évidence à la Figure 11.47.
Pour créer le contrat intelligent (smart contract), dans le répertoire ethreact/contracts/, créez le fichier TodoList.sol et ajoutez le code suivant.
pragma solidity ^0.5.0;
contract TodoList {
uint public taskCount = 0;
struct Task {
uint id;
string content;
bool completed;
}
mapping(uint => Task) public tasks;
event TaskCreated(
uint id,
string content,
bool completed
);
event TaskCompleted(
uint id,
bool completed
);
constructor () public {
createTask("Check out dappuniversity.com");
}
function createTask(string memory _content) public {
taskCount ++;
tasks[taskCount] = Task(taskCount, _content, false);
emit TaskCreated(taskCount, _content, false);
}
function toggleCompleted(uint _id) public {
Task memory _task = tasks[_id];
_task.completed = !_task.completed;
tasks[_id] = _task;
emit TaskCompleted(_id, _task.completed);
}
}
Ensuite, compilez le contrat intelligent. Dans le répertoire ethreact/, exécutez la commande suivante :
$ truffle compile
Cette commande devrait fournir un statut confirmant que le contrat intelligent a été compilé avec succès, comme le montre le code suivant :
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscription.clang
Figure 11.48 montre comment ce processus générera quelques fichiers, y compris deux fichiers JSON dans le répertoire build/contracts/ et un fichier de migration dans le répertoire migrations/.
Le fichier TodoList.json dans le répertoire build/contracts/ est le fichier ABI (Abstract Binary Interface) du contrat intelligent. Ce fichier contient ce qui suit :
- bytecode compilé à partir du code du contrat intelligent Solidity qui peut s'exécuter sur la machine virtuelle Ethereum (EVM)
- une représentation JSON du contrat intelligent.
Ensuite, configurez l'application React pour qu'elle se connecte au réseau de chaîne de blocs Ganache. Pour ce faire, ouvrez le fichier ethreact/truffle-config.js et décommentez les deux sections affichées. Sous « networks », activez l'hôte et le port de connexion au réseau de chaîne de blocs Ganache. Assurez-vous que l'hôte et le port sont synchronisés avec les paramètres suivants dans Ganache.
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
Ensuite, sous « compilers », activez l'optimiseur solc.
// Configure your compilers
compilers: {
solc: {
// version: "0.5.1", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: true,
runs: 200
},
// evmVersion: "byzantium"
// }
}
},
Ensuite, créez un script de migration pour déployer le contrat intelligent sur le réseau de chaîne de blocs Ganache. Dans le répertoire ethreact/migrations/, créez le fichier 2_deploy_contracts.js et ajoutez le code suivant.
var TodoList = artifacts.require("./TodoList.sol");
module.exports = function(deployer) {
deployer.deploy(TodoList);
};
L'étape suivante consiste à migrer le contrat. Dans le répertoire ethreact/, exécutez cette commande.
$ truffle migrate
Figure 11.49 montre comment le contrat sera migré et fournit les détails de la transaction. Vous devriez noter l'adresse du contrat dans la sortie car elle sera ajoutée au fichier config.js plus tard.
Lien vers l'apprentissage
Solidity est un langage de haut niveau, orienté objet, utilisé pour implémenter des contrats intelligents. Influencé par JavaScript, C++ et Python, Solidity est axé sur la machine virtuelle Ethereum. Les contrats intelligents implémentés par Solidity sont utilisés à des fins telles que les enchères aveugles, le vote et le financement participatif. Visitez cette page sur Solidity pour en savoir plus.
Création des composants frontaux React
Le composant TodoList rend l'interface utilisateur pour l'application Todo. Dans le répertoire ethreact/src/, créez le répertoire components/. Dans le répertoire components/, créez le fichier TodoList.js, puis créez le composant TodoList.
import React, { Component } from 'react'
class TodoList extends Component {
render() {
return (
<div id="content">
<form onSubmit={(event) => {
event.preventDefault()
this.props.createTask(this.task.value)
}}>
<input
id="newTask"
ref={(input) => {
this.task = input
}}
type="text"
className="form-control"
placeholder="Ajouter une tâche..."
required />
<input type="submit" hidden={true} />
</form>
<ul id="taskList" className="list-unstyled">
{ this.props.tasks.map((task, key) => {
return(
<div className="taskTemplate" className="checkbox" key={key}>
<label>
<input
type="checkbox"
name={task.id}
defaultChecked={task.completed}
ref={(input) => {
this.checkbox = input
}}
onClick={(event) => {
this.props.toggleCompleted(this.checkbox.name) }}/>
<span className="content">{task.content}</span>
</label>
</div>
)
})}
</ul>
<ul id="completedTaskList" className="list-unstyled">
</ul>
</div>
);
}
}
export default TodoList;
Mettez à jour le fichier ethreact/src/App.js pour importer et rendre le composant TodoList.
render() {
return (
<div>
<nav className="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
<a className="navbar-brand col-sm-3 col-md-2 mr-0" href="#">ToDo</a>
<ul className="navbar-nav px-3">
<li className="nav-item text-nowrap d-none d-sm-none d-sm-block">
<small><a className="nav-link" href="#"><span id="account"></span></a></small>
</li>
</ul>
</nav>
<div className="container-fluid">
<div className="row">
<main role="main" className="col-lg-12 d-flex justify-content-center">
{ this.state.loading
? <div id="loader" className="text-center"><p className="text-center">Chargement...</p></div>
: <TodoList
tasks={this.state.tasks}
createTask={this.createTask}
toggleCompleted={this.toggleCompleted} />
}
</main>
</div>
</div>
</div>
);
}
Ajout de Web3 à l'application React
L'étape suivante consiste à ajouter Web3 et à le configurer pour qu'il se connecte à Ganache. Pour ce faire, ouvrez ethreact/src/App.js, importez le paquet Web3 et ajoutez le code présenté ici. Dans ce code, une connexion web3 est instanciée en fournissant l'URL de Ganache (http://localhost:8545). Cela permet à l'application React de se connecter à la chaîne de blocs. Les informations du compte de la chaîne de blocs sont ensuite accédées et ajoutées à l'objet d'état de l'application React. Dans le répertoire ethreact/src/, créez le fichier getWeb3.js et ajoutez le code présenté. Ce code crée un objet Web3 via différentes approches de connexion selon l'approche utilisée (par exemple, type de navigateur DApp, utilisation de localhost).
import Web3 from "web3";
const getWeb3 = () =>
new Promise((resolve, reject) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
window.addEventListener("load", async () => {
// Navigateurs dapp modernes...
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
// Request account access if needed
await window.ethereum.enable();
// Accounts now exposed
resolve(web3);
} catch (error) {
reject(error);
}
}
// Anciens navigateurs dapp...
else if (window.web3) {
// Utiliser le fournisseur de Mist/MetaMask.
//const web3 = window.web3; // ORIG
const web3 = window.web3.currentProvider.enable()
console.log("Web3 injecté détecté.");
resolve(web3);
}
// Fallback to localhost; use dev console port by default...
else {
const provider = new Web3.providers.HttpProvider(
"http://127.0.0.1:8545"
);
const web3 = new Web3(provider);
console.log("Aucune instance web3 injectée, utilisation de web3 local.");
resolve(web3);
}
});
});
export default getWeb3;
Configuration de l'application React (React) pour communiquer avec le contrat intelligent
Pour rendre les tâches du contrat intelligent disponibles pour l'application React, créez un fichier de configuration, ainsi que l'adresse du contrat et l'ABI. Pour ce faire, dans le répertoire ethreact/src/, créez le fichier config.js. Ensuite, créez deux variables : TODO_LIST_ADDRESS et TODO_LIST_ABI. Récupérez l'adresse du contrat qui a été fournie lors du déploiement du contrat intelligent sur la chaîne de blocs et assignez-la à TODO_LIST_ADDRESS. Ouvrez le fichier ethreact/build/contracts/TodoList.json et copiez uniquement la partie ABI et assignez-la à TODO_LIST_ABI.
export const TODO_LIST_ADDRESS = '0x9A93A9951c1cAcF0Cecc320Fa6aD4e05d55a2d02'
export const TODO_LIST_ABI = [
{
"inputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bool",
"name": "completed",
"type": "bool"
}
],
"name": "TaskCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "content",
"type": "string"
},
{
"indexed": false,
"internalType": "bool",
"name": "completed",
"type": "bool"
}
],
"name": "TaskCreated",
"type": "event"
},
{
"constant": true,
"inputs": [],
"name": "taskCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "tasks",
"outputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "string",
"name": "content",
"type": "string"
},
{
"internalType": "bool",
"name": "completed",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "string",
"name": "_content",
"type": "string"
}
],
"name": "createTask",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "toggleCompleted",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
Ensuite, mettez à jour ethreact/src/App.js. Importez getWeb3.js et ajoutez le code suivant à la méthode de cycle de vie componentDidMount(). Cela connectera au réseau de chaîne de blocs et chargera le contrat avant que les composants React ne soient rendus dans le navigateur.
componentDidMount = async () => {
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Utiliser web3 pour obtenir les comptes de l'utilisateur.
const accounts = await web3.eth.getAccounts();
// Obtenir l'instance du contrat.
const networkId = await web3.eth.net.getId();
let deployedNetwork = TodoListABI.networks[networkId];
const todoListInstance = new web3.eth.Contract(
TODO_LIST_ABI,
deployedNetwork && deployedNetwork.address
);
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ web3, accounts, todoListContract: todoListInstance }, this.runExample);
} catch (error) {
// Catch any errors for any of the above operations.
alert(
'Échec du chargement de web3, des comptes ou du contrat. Vérifiez la console pour plus de détails.',
);
console.error(error);
}
};
Lancez l'application React en exécutant la commande suivante :
$npm start
Lancez un navigateur avec le plug-in MetaMask installé et naviguez vers http://localhost:3000. Créez une tâche.