paint-brush
Comment rédiger un contrat intelligent Solidity et le déployer sur Ropstenpar@johnjvester
616 lectures
616 lectures

Comment rédiger un contrat intelligent Solidity et le déployer sur Ropsten

par John Vester35m2022/08/05
Read on Terminal Reader
Read this story w/o Javascript

Trop long; Pour lire

Les contrats intelligents permettent à deux parties de conclure un accord. Plongez dans les contrats intelligents pour montrer comment réutiliser un seul contrat encore et encore.

People Mentioned

Mention Thumbnail
Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Comment rédiger un contrat intelligent Solidity et le déployer sur Ropsten
John Vester HackerNoon profile picture


La " Passer de développeur full-stack à pionnier Web3 ” La publication a fourni un aperçu de haut niveau pour donner aux développeurs full-stack un aperçu du monde du développement Web3. Si vous n'avez pas eu l'occasion de consulter cet article, pensez à y jeter un coup d'œil, car il fournit également une bonne introduction à Web3.


Le résultat final de mon article original a démontré comment une association de propriétaires (HOA) pouvait utiliser la technologie Web3 pour héberger son scrutin électoral. Le problème avec la conception originale est que le contrat intelligent sous-jacent ne permettait qu'une seule réponse oui ou non. C'était par conception pour garder le contrat intelligent simple tout en introduisant d'autres concepts nécessaires pour créer un bulletin de vote HOA à l'aide des technologies Web3.


Le but de cette publication est d'approfondir les contrats intelligents pour créer une application qui non seulement capture les besoins et les fonctions réalistes d'un scrutin HOA, mais en conçoit une qui peut être réutilisée d'une élection à l'autre.

À propos des contrats intelligents

Avant de commencer, définissons un contrat intelligent :

« Un contrat intelligent est un programme qui s'exécute à une adresse sur Ethereum. Ils sont constitués de données et de fonctions qui peuvent s'exécuter lors de la réception d'une transaction. Voici un aperçu de ce qui constitue un contrat intelligent. »


la source ethereum.org


La machine à chewing-gum

Croyez-le ou non, un exemple simple de contrat intelligent peut être trouvé dans une simple machine à chewing-gum :


Les gens comprennent facilement le coût lié à l'achat avec la machine à chewing-gum. Normalement, il s'agit d'un trimestre (américain). Il est important de préciser ici que le client est anonyme, car le distributeur de chewing-gum ne nécessite pas de savoir qui est une personne avant de lui donner un chewing-gum salé.


Le consommateur anonyme place de l'argent dans le distributeur de chewing-gum et tourne le cadran pour accepter les termes du contrat. Cette étape est importante car la transaction est transparente et peer-to-peer : entre vous et la machine. La transaction est également sécurisée puisque vous devez fournir la devise attendue pour utiliser le distributeur de chewing-gum.


Une fois que la monnaie tombe à l'intérieur de la machine à gommes, les termes du contrat sont acceptés et une boule de gomme roule vers le bas de la machine, permettant au client de recevoir son achat. À ce stade, le contrat est entièrement exécuté.


Le client doit accepter ce qui est fourni, ce qui signifie qu'il ne peut pas retourner le chewing-gum ou inverser le cadran pour récupérer sa monnaie. De la même manière, les contrats intelligents sont généralement irréversibles et non modifiables.

Cas d'utilisation de contrats intelligents

Outre les exemples à motivation financière, certains scénarios dans lesquels des interactions anonymes, sans confiance, décentralisées et transparentes, irréversibles et non modifiables pourraient être mises en œuvre sont indiqués ci-dessous :

  • Essais cliniques - résultats de tests indépendants
  • Élections - suffrages exprimés participants
  • Identité - permet aux individus de déterminer avec qui ils partagent leur identité
  • Polices d'assurance - polices et conditions individuelles
  • Suivi des produits et des approvisionnements - suivi de l'état de la production et de l'approvisionnement
  • Immobilier et terrain - actes liés à l'immobilier et au terrain, qui peuvent être utilisés pour déterminer le propriétaire actuel à tout moment
  • Informations d'enregistrement - documents officiels et relevés de notes (comme le Adresse de Gettysburg )


Dans tous les cas, le contenu du contrat intelligent peut être rappelé et revu aussi souvent que possible, sans possibilité de changer ou de modifier les résultats. Chaque cas d'utilisation ci-dessus fournit le contrat intelligent comme système d'enregistrement des informations sous-jacentes.

Ce qu'un contrat intelligent n'est pas

À l'heure actuelle, les contrats intelligents ne sont pas des accords juridiquement contraignants, à l'exception de quelques exceptions. Cela signifie que si vous n'êtes pas satisfait du résultat de votre contrat intelligent, il n'est pas possible de porter votre problème devant un juge dans certains systèmes judiciaires.

Il existe quelques exceptions, comme dans l'État de l'Arizona, où les contrats intelligents sont considérés comme juridiquement contraignants. De plus, si vous êtes dans l'État de Californie et que votre licence de mariage est contenue dans un contrat intelligent, cet accord est également juridiquement contraignant. On s'attend à ce que davantage de gouvernements reconnaissent à l'avenir les contrats intelligents comme des accords juridiquement contraignants.

Cas d'utilisation : créer un bulletin de vote HOA réaliste

S'appuyant sur le simple contrat intelligent binaire (oui/non) de la publication "Moving From Full-Stack Developer To Web3 Pioneer", faisons un pas en avant et supposons que l'exigence suivante existe pour un scrutin HOA pour un quartier qui a un seul poste à pourvoir :

  • Sélectionnez le président de l'HOA


Idéalement, l'objectif serait qu'un seul contrat intelligent soit utilisé chaque fois qu'il y a une élection HOA. On s'attend à ce que les candidats au poste de président changent d'une élection à l'autre.

Maintenant, commençons à créer un contrat intelligent pour répondre à nos besoins.

Définir notre nouveau contrat intelligent

En utilisant Solidity, j'ai travaillé avec Paul McAviney , qui a conçu notre contrat intelligent pour le scrutin HOA comme indiqué ci-dessous :


 // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /********************************************************/ /* For learning purposes ONLY. Do not use in production */ /********************************************************/ // Download into project folder with `npm install @openzeppelin/contracts` import "@openzeppelin/contracts/access/Ownable.sol"; // Inherits the Ownable contract so we can use its functions and modifiers contract HOABallot is Ownable { // Custom type to describe a Presidential Candidate and hold votes struct Candidate { string name; uint256 votes; } // Array of Presidential Candidates Candidate[] public candidates; // Add a President Candidate - onlyOwner function addCandidate(string memory _name) public onlyOwner { require(bytes(_name).length > 0, "addCandidate Error: Please enter a name"); candidates.push(Candidate({name: _name, votes: 0})); } // Remove a Candidate - onlyOwner function removeCandidate(string memory _name) public onlyOwner { require(bytes(_name).length > 0, "removeCandidate Error: Please enter a name"); bool foundCandidate = false; uint256 index; bytes32 nameEncoded = keccak256(abi.encodePacked(_name)); // Set index number for specific candidate for (uint256 i = 0; i < candidates.length; i++) { if (keccak256(abi.encodePacked(candidates[i].name)) == nameEncoded) { index = i; foundCandidate = true; } } // Make sure a candidate was found require(foundCandidate, "removeCandidate Error: Candidate not found"); // shift candidate to be removed to the end of the array and the rest forward for (uint256 i = index; i < candidates.length - 1; i++) { candidates[i] = candidates[i + 1]; } // remove last item from array candidates.pop(); } // Reset the President Vote Counts - onlyOwner function resetVoteCount() public onlyOwner { for (uint256 p = 0; p < candidates.length; p++) { candidates[p].votes = 0; } } // Add a vote to a candidate by name function addVoteByName(string memory _name) public { require(bytes(_name).length > 0, "addVoteByName Error: Please enter a name"); // Encode name so only need to do once bytes32 nameEncoded = keccak256(abi.encodePacked(_name)); for (uint256 i = 0; i < candidates.length; i++) { // solidity can't compare strings directly, need to compare hash if (keccak256(abi.encodePacked(candidates[i].name)) == nameEncoded) { candidates[i].votes += 1; } } } // Returns all the Presidential Candidates and their vote counts function getCandidates() public view returns (Candidate[] memory) { return candidates; } function getWinner() public view returns (Candidate memory winner) { uint256 winningVoteCount = 0; for (uint256 i = 0; i < candidates.length; i++) { if (candidates[i].votes > winningVoteCount) { winningVoteCount = candidates[i].votes; winner = candidates[i]; } } return winner; } }


Voici quelques éléments clés liés à la conception du contrat intelligent :


  • Par défaut, il n'y a pas de candidats sur le bulletin de vote.
  • Les candidats peuvent être ajoutés (par le propriétaire du contrat intelligent uniquement) à l'aide de la fonction addCandidate().
  • De même, les candidats peuvent être supprimés (par le propriétaire du contrat intelligent uniquement) à l'aide de la fonction removeCandidate().
  • Voter tirera parti de la fonction getCandidates(), qui peut être utilisée dans le Dapp correspondant pour appeler la fonction addVoteByName().
  • La même méthode getCandidates() peut être appelée pour déterminer le nombre de votes actuel.
  • Le contrat Ownable d'OpenZeppelin permet la propriété du contrat, ainsi que la possibilité de transférer la propriété à une autre adresse.


Maintenant, préparons le contrat intelligent prêt à l'emploi.

Se préparer à utiliser le contrat intelligent

Afin de pouvoir utiliser notre contrat intelligent, nous allons créer un projet Truffle simple et déployer le contrat sur le testnet de Ropsten. Pour ce faire, nous aurons d'abord besoin de la version la plus récente de Truffle. Avec NPM installé , exécutez la commande :


 npm install -g truffle


L'installation de la dernière version nous donnera accès au Tableau de bord Truffe , ce qui rendra le déploiement de notre contrat intelligent tellement plus facile et considérablement plus sûr, car nous n'aurons pas à partager nos clés de portefeuille privées ou nos phrases mnémoniques. Nous y reviendrons un peu plus tard cependant.


Ensuite, créez un nouveau répertoire et initialisez un nouveau projet Truffle.


 mkdir hoa-ballot-contract && cd hoa-ballot-contract truffle init


Cela créera un projet de contrat intelligent barebones que nous pourrons remplir comme bon nous semble. Alors ouvrez le projet dans votre éditeur de code préféré, et allons-y !


Afin de tirer parti d'OpenZeppelin, la commande suivante doit également être exécutée dans le dossier du projet :


 npm install @openzeppelin/contracts


Ouvrez le fichier truffle-config.js et nous ajouterons le tableau de bord Truffle dans l'objet networks . Mis à part tous les passe-partout commentés, notre objet devrait maintenant ressembler à ceci :


 networks: { dashboard: { port: 24012, } }


Pour la prochaine étape, nous allons créer un nouveau fichier de contrat intelligent. Dans le dossier des contrats , créez un nouveau fichier et nommez-le HOABallot.sol . À partir de là, nous allons simplement coller le contrat intelligent ci-dessus.


La dernière chose que nous devons faire avant de pouvoir déployer ce contrat est de configurer le script de déploiement. En utilisant le contenu ci-dessous, nous devons créer un nouveau fichier dans le dossier migrations appelé 2_hoaballot_migration.js .


 const HOABallot = artifacts.require("HOABallot"); Module.exports = function (deployer) { deployer.deploy(HOABallot); }


Nous sommes maintenant prêts à déployer notre contrat sur le testnet de Ropsten. Dans une nouvelle fenêtre de terminal, saisissez la commande suivante pour démarrer le tableau de bord :


 truffle dashboard


Une fois lancé, notre navigateur devrait apparaître avec une interface nous demandant de connecter notre portefeuille. Si cela ne s'affiche pas, accédez à localhost:24012 .


Un simple clic sur le bouton METAMASK lancera MetaMask via le plug-in du navigateur. Si vous n'avez pas installé d'extension de navigateur de portefeuille, vous pouvez en obtenir une sur métamasque.io . Suivez les étapes pour créer un compte puis revenez au tableau de bord Truffle pour vous connecter :


Après avoir saisi un mot de passe valide et appuyé sur le bouton Déverrouiller , le Truffle Dashboard confirme le réseau à utiliser :


Après avoir cliqué sur le bouton CONFIRMER , le tableau de bord Truffle écoute maintenant les demandes :


Nous aurons besoin de Ropsten Eth pour effectuer le déploiement. Si vous n'en avez pas, vous pouvez en demander à ce robinet .


Il ne nous reste plus qu'à déployer le contrat. Dans votre fenêtre de terminal d'origine, assurez-vous d'être dans le dossier du projet et tapez la commande :


 truffle migrate --network dashboard


Truffle compilera automatiquement notre contrat intelligent, puis acheminera la demande via le tableau de bord. Chaque demande suivra le même flux indiqué ci-dessous.


Tout d'abord, le tableau de bord Truffle demande une confirmation pour traiter la demande :


En appuyant sur le bouton PROCESS , le plug-in MetaMask demandera également une confirmation :


Le bouton Confirmation permettra de retirer des fonds de ce portefeuille associé afin de traiter chaque demande.


Une fois le processus terminé, les informations suivantes apparaîtront dans la fenêtre du terminal utilisée pour émettre la commande truffle migrate :


 2_hoaballot_migration.js ======================== Deploying 'HOABallot' --------------------- > transaction hash: 0x5370b6f9ee1f69e92cc6289f9cb0880386f15bff389b54ab09a966c5d144f59esage. > Blocks: 0 Seconds: 32 > contract address: 0x2981d347e288E2A4040a3C17c7e5985422e3cAf2 > block number: 12479257 > block timestamp: 1656386400 > account: 0x7fC3EF335D16C0Fd4905d2C44f49b29BdC233C94 > balance: 41.088173901232893417 > gas used: 1639525 (0x190465) > gas price: 2.50000001 gwei > value sent: 0 ETH > total cost: 0.00409881251639525 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00409881251639525 ETH Summary ======= > Total deployments: 1 > Final cost: 0.00409881251639525 ETH


Maintenant, en utilisant la valeur de l' adresse du contrat , nous pouvons valider le contrat intelligent en utilisant l'URL suivante :

https://ropsten.etherscan.io/address/0x2981d347e288E2A4040a3C17c7e5985422e3cAf2


Nous pouvons maintenant basculer et commencer à construire le Dapp.

Création de la Dapp de vote HOA à l'aide de React

Je vais créer une application React appelée hoa-ballot-client à l'aide de la CLI React :


 npx create-react-app hoa-ballot-client


Ensuite, j'ai changé les répertoires dans le dossier nouvellement créé et j'ai exécuté ce qui suit pour installer les dépendances web3 et OpenZepplin dans l'application React :

 cd hoa-ballot-client npm install web3 npm install @openzeppelin/contracts —save


Sur la base du contenu du fichier de contrat intelligent HOABallot.sol , j'ai navigué vers le dossier build/contracts et ouvert le fichier HOBallot.json , puis utilisé les valeurs de la propriété "abi" pour la constante hoaBallot du fichier abi.js comme indiqué ci-dessous:


 export const hoaBallot = [ { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "candidates", "outputs": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_name", "type": "string" } ], "name": "addCandidate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_name", "type": "string" } ], "name": "removeCandidate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "resetVoteCount", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_name", "type": "string" } ], "name": "addVoteByName", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "getCandidates", "outputs": [ { "components": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "internalType": "struct HOABallot.Candidate[]", "name": "", "type": "tuple[]" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "getWinner", "outputs": [ { "components": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "internalType": "struct HOABallot.Candidate", "name": "winner", "type": "tuple" } ], "stateMutability": "view", "type": "function", "constant": true } ];


Ce fichier a été placé dans un dossier abi nouvellement créé dans le dossier src de l'application React.


Maintenant, nous devons mettre à jour le fichier React Apps.js. Commençons d'abord par le haut du fichier, qui doit être configuré comme indiqué ci-dessous :


 import React, { useState } from "react"; import { hoaBallot } from "./abi/abi"; import Web3 from "web3"; import "./App.css"; const web3 = new Web3(Web3.givenProvider); const contractAddress = "0x2981d347e288E2A4040a3C17c7e5985422e3cAf2"; const storageContract = new web3.eth.Contract(hoaBallot, contractAddress);


Le contractAddress peut être trouvé de plusieurs façons. Dans ce cas, j'ai utilisé les résultats de la commande CLI truffle — migrate. Une autre option consiste à utiliser le site Etherscan.


Maintenant, il ne reste plus qu'à créer un code React standard pour accomplir les choses suivantes :


  • Ajouter un candidat présidentiel HOA
  • Supprimer un candidat présidentiel HOA
  • Obtenir une liste des candidats présidentiels HOA
  • Votez pour un candidat présidentiel HOA
  • Déterminer le président de HOA


Dans ma publication "Moving From Full-Stack Developer To Web3 Pioneer", j'ai également ajouté le composant Nav, afin que l'adresse de l'électeur soit affichée pour une référence facile.


L'application React mise à jour apparaît maintenant comme suit :


 const web3 = new Web3(Web3.givenProvider); const contractAddress = "0x2981d347e288E2A4040a3C17c7e5985422e3cAf2"; const storageContract = new web3.eth.Contract(hoaBallot, contractAddress); const gasMultiplier = 1.5; const useStyles = makeStyles((theme) => ({ root: { "& > *": { margin: theme.spacing(1), }, }, })); const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { backgroundColor: theme.palette.common.black, color: theme.palette.common.white, fontSize: 14, fontWeight: 'bold' }, [`&.${tableCellClasses.body}`]: { fontSize: 14 }, })); function App() { const classes = useStyles(); const [newCandidateName, setNewCandidateName] = useState(""); const [account, setAccount] = useState(""); const [owner, setOwner] = useState(""); const [candidates, updateCandidates] = useState([]); const [winner, setWinner] = useState("unknown candidate"); const [waiting, setWaiting] = useState(false); const loadAccount = async(useSpinner) => { if (useSpinner) { setWaiting(true); } const web3 = new Web3(Web3.givenProvider || "http://localhost:8080"); const accounts = await web3.eth.getAccounts(); setAccount(accounts[0]); if (useSpinner) { setWaiting(false); } } const getOwner = async (useSpinner) => { if (useSpinner) { setWaiting(true); } const owner = await storageContract.methods.owner().call(); setOwner(owner); if (useSpinner) { setWaiting(false); } }; const getCandidates = async (useSpinner) => { if (useSpinner) { setWaiting(true); } const candidates = await storageContract.methods.getCandidates().call(); updateCandidates(candidates); await determineWinner(); if (useSpinner) { setWaiting(false); } }; const determineWinner = async () => { const winner = await storageContract.methods.getWinner().call(); if (winner && winner.name) { setWinner(winner.name); } else { setWinner("<unknown candidate>") } } const vote = async (candidate) => { setWaiting(true); const gas = (await storageContract.methods.addVoteByName(candidate).estimateGas({ data: candidate, from: account })) * gasMultiplier; let gasAsInt = gas.toFixed(0); await storageContract.methods.addVoteByName(candidate).send({ from: account, data: candidate, gasAsInt, }); await getCandidates(false); setWaiting(false); } const removeCandidate = async (candidate) => { setWaiting(true); const gas = (await storageContract.methods.removeCandidate(candidate).estimateGas({ data: candidate, from: account })) * gasMultiplier; let gasAsInt = gas.toFixed(0); await storageContract.methods.removeCandidate(candidate).send({ from: account, data: candidate, gasAsInt, }); await getCandidates(false); setWaiting(false); } const addCandidate = async () => { setWaiting(true); const gas = (await storageContract.methods.addCandidate(newCandidateName).estimateGas({ data: newCandidateName, from: account })) * gasMultiplier; let gasAsInt = gas.toFixed(0); await storageContract.methods.addCandidate(newCandidateName).send({ from: account, data: newCandidateName, gasAsInt, }); await getCandidates(false); setWaiting(false); } React.useEffect(() => { setWaiting(true); getOwner(false).then(r => { loadAccount(false).then(r => { getCandidates(false).then(r => { setWaiting(false); }); }); }); // eslint-disable-next-line react-hooks/exhaustive-deps },[]); return ( <div className={classes.root}> <Nav /> <div className="main"> <div className="card"> <Typography variant="h3"> HOABallot </Typography> {(owner && owner.length > 0) && ( <div className="paddingBelow"> <Typography variant="caption" > This ballot is owned by: {owner} </Typography> </div> )} {waiting && ( <div className="spinnerArea" > <CircularProgress /> <Typography gutterBottom> Processing Request ... please wait </Typography> </div> )} {(owner && owner.length > 0 && account && account.length > 0 && owner === account) && ( <div className="ownerActions generalPadding"> <Grid container spacing={3}> <Grid item xs={12}> <Typography variant="h6" gutterBottom> Ballot Owner Actions </Typography> </Grid> <Grid item xs={6} sm={6}> <TextField id="newCandidateName" value={newCandidateName} label="Candidate Name" variant="outlined" onChange={event => { const { value } = event.target; setNewCandidateName(value); }} /> </Grid> <Grid item xs={6} sm={6}> <Button id="addCandidateButton" className="button" variant="contained" color="primary" type="button" size="large" onClick={addCandidate}>Add New Candidate</Button> </Grid> </Grid> </div> )} <Typography variant="h5" gutterBottom className="generalPadding"> Candidates </Typography> {(!candidates || candidates.length === 0) && ( <div> <div className="paddingBelow"> <Typography variant="normal"> No candidates current exist. </Typography> </div> <div> <Typography variant="normal" gutterBottom> Ballot owner must use the <strong>ADD NEW CANDIDATE</strong> button to add candidates. </Typography> </div> </div> )} {(candidates && candidates.length > 0) && ( <div> <TableContainer component={Paper}> <Table sx={{ minWidth: 650 }} aria-label="customized table"> <TableHead> <TableRow> <StyledTableCell>Candidate Name</StyledTableCell> <StyledTableCell align="right">Votes</StyledTableCell> <StyledTableCell align="center">Actions</StyledTableCell> </TableRow> </TableHead> <TableBody> {candidates.map((row) => ( <TableRow key={row.name} sx={{ '&:last-child td, &:last-child th': { border: 0 } }} > <TableCell component="th" scope="row"> {row.name} </TableCell> <TableCell align="right">{row.votes}</TableCell> <TableCell align="center"> <Button color="success" variant="contained" onClick={() => { vote(row.name); }} > Vote </Button> &nbsp; {(owner && owner.length > 0 && account && account.length > 0 && owner === account) && <Button color="error" variant="contained" onClick={() => { removeCandidate(row.name); }} > Remove Candidate </Button> } </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> <div className="generalPadding"> <Typography variant="normal" gutterBottom> {winner} is winning the election. </Typography> </div> </div> )} </div> </div> </div> ); } export default App;


Pour démarrer la Dapp basée sur React, la CLI Yarn peut être utilisée :


 yarn start


Une fois compilée et validée, l'application apparaîtra à l'écran, comme indiqué ci-dessous :



Pendant la vidéo :


  • J'ai validé que j'étais le propriétaire du contrat, car la valeur "Votre adresse connectée" correspond exactement à la valeur "Ce vote appartient à" et la section Actions du propriétaire du vote est affichée.
  • En tant que propriétaire du contrat, j'ai pu voir et utiliser le bouton AJOUTER UN NOUVEAU CANDIDAT pour établir des candidats pour l'élection. J'ai utilisé les noms Dave Brown et Steve Smith pour cet exemple.
  • En tant que propriétaire du contrat, j'aurais également pu utiliser le bouton SUPPRIMER LE CANDIDAT.
  • Après avoir créé les deux candidats, j'ai voté pour l'un des deux candidats en utilisant le bouton VOTE sur la même ligne que le candidat souhaité. J'ai voté pour Dave Brown.
  • Le vainqueur actuel de l'élection est affiché sous le tableau des candidats. Dans ce cas, c'est Dave Brown.


Depuis le déploiement du contrat intelligent, n'importe qui peut consulter l'historique complet à l'URL suivante :


https://ropsten.etherscan.io/address/0x2981d347e288E2A4040a3C17c7e5985422e3cAf2


Conclusion

Depuis 2021, j'essaie de vivre selon l'énoncé de mission suivant, qui, selon moi, peut s'appliquer à tout professionnel de la technologie :


« Consacrez votre temps à fournir des caractéristiques/fonctionnalités qui étendent la valeur de votre propriété intellectuelle. Tirez parti des cadres, des produits et des services pour tout le reste.
J.Vester


Les contrats intelligents permettent à deux parties de conclure un accord où le résultat du contrat devient un enregistrement officiel gravé dans le marbre de la transaction. L'adoption d'un contrat intelligent adhère à mon énoncé de mission personnelle en ce sens que le cadre sous-jacent évite de réinventer la roue lorsque le besoin se fait sentir d'un tel contrat.


Dans le même temps, la conception du contrat intelligent elle-même va encore plus loin et répond à mon énoncé de mission à partir d'un facteur de réutilisation. Dans cet exemple, le même contrat intelligent HOA peut être utilisé, même si différents candidats se présentent aux élections en cours. Ici, nous tirons parti de la puissance du contrat intelligent pour éviter de créer un nouveau contrat intelligent à chaque fois qu'il y a une élection.


Lors de l'utilisation d'Etherscan pour rechercher la valeur de conversion de l'une des transactions à l'aide du convertisseur ETH en USD de Google, le coût par transaction était de 0,24 (USD) pour 0,0001348975 ETH. Ironiquement, c'était le prix d'un modeste chewing-gum sorti d'une machine à chewing-gum quand j'étais enfant.


Si vous souhaitez en savoir plus sur les contrats intelligents, l'équipe de ConsenSys a fourni d'excellentes ressources pour vous aider à prototyper vos idées afin de voir si l'adoption de contrats intelligents est un cas d'utilisation valable.


Si vous êtes intéressé par le code source de cet article, vous pouvez le trouver aux URL suivantes :


https://github.com/paul-mcaviney/smart-contract-deep-dive/blob/main/HOABallot.sol

https://gitlab.com/johnjvester/hoa-ballot-contract

https://gitlab.com/johnjvester/hoa-ballot-client


Passez une très bonne journée !