paint-brush
Cómo crear una aplicación de transacciones de Ethereum con React y Solidity: Parte 2por@daltonic
15,553 lecturas
15,553 lecturas

Cómo crear una aplicación de transacciones de Ethereum con React y Solidity: Parte 2

por Darlington Gospel 2022/01/17
Read on Terminal Reader
Read this story w/o Javascript

Demasiado Largo; Para Leer

Siguiendo la primera parte de este tutorial, construiremos el lado frontal de este proyecto. Vea [demostración] en vivo y Git Repo [aquí] Recuerde, la demostración en línea utiliza la red de prueba de ropsten. Cree una nueva carpeta llamada "dalto" y cree dos carpetas más llamadas **cliente** y **smart_contract**. El cliente y el contrato inteligente vivirán en la misma carpeta, mientras que la aplicación de reacción está en el cliente. El código se utilizará para configurar el contrato inteligente.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coins Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Cómo crear una aplicación de transacciones de Ethereum con React y Solidity: Parte 2
Darlington Gospel  HackerNoon profile picture


Lo que construirá: vea una demostración en vivo y Git Repo aquí . Recuerde, la demostración en línea utiliza la red de prueba de ropsten.

Aplicación de transacciones Dalto Ethereum

Introducción

Siguiendo la primera parte de este tutorial, construiremos el lado frontal de este proyecto. Si no has visto la PARTE UNO , te recomiendo que lo hagas para entender esta parte dos.

Si estás listo, aplastemos esta aplicación...

Configuración del proyecto

Asegúrese de que ya tiene NodeJs instalado en su máquina, si no lo tiene, siga el enlace a continuación para hacerlo.


Vaya a su directorio de proyectos y cree una nueva carpeta llamada "dalto". Puedes nombrarlo como quieras, pero en aras de la uniformidad, te sugiero que me sigas con los nombres.


Dentro de este directorio dalto , cree dos carpetas más llamadas client y smart_contract , nuestro código ethereum vivirá en la carpeta smart_contract, mientras que la aplicación reaccionar vivirá en el directorio del cliente. Por último, abra este proyecto en su editor de código, prefiero VS Code . Si hizo todo eso correctamente, la estructura de su proyecto debería verse así.


Estructura del proyecto

Estructura del proyecto Los códigos deben estructurarse de la siguiente manera.


Estructura del clienteEstructura de contrato inteligente

La configuración del contrato inteligente

Vaya a la terminal, mueva (cd) al directorio smart_contract y ejecute el siguiente comando.


 npm init -y


Esto creará un archivo npm en la raíz de la carpeta smart_contract . Para especificar los paquetes que se usarán para construir el contrato inteligente, ejecutaremos el fragmento de código a continuación.


 yarn add @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle chai ethereum-waffle ethers hardhat --dev # or npm install -D @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle chai ethereum-waffle ethers hardhat


Tenga en cuenta que estos paquetes se enumeran solo en el entorno de desarrollo. Una vez finalizada la instalación, tendrá un resultado similar al mío.


Paquete de contrato inteligente.json

Ahora necesita ejecutar el código a continuación para configurar el casco en la carpeta smart_contract actual.


 yarn hardhat # or npm hardhat


Se le harán algunas preguntas, debe seleccionar las siguientes opciones.

  • Cree un proyecto de muestra básico cuando se le pregunte qué quiere hacer.
  • Especifique el directorio actual cuando se le solicite la carpeta raíz, esta opción se completa previamente en el terminal para usted.
  • Ingrese 'y' cuando se le pregunte si desea agregar un .gitIgnore y presione enter en su teclado.


Una vez que especifique las opciones anteriores correctamente, hardhat generará automáticamente la estructura del proyecto para usted.


Creación de proyectos de cascos

Procesamiento del contrato inteligente A continuación, diríjase al directorio smart_contract >> contratos y cambie el nombre del archivo Greeter.sol a Transactions.sol . Luego, pegue los códigos a continuación, guárdelo y muévase conmigo.


 // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Transactions { address private owner; uint256 transactionCounts; mapping (address => uint) balanceOf; event Transfer(address indexed sender, address indexed receiver, uint256 amount, string remark, uint256 timestamp); struct TransferStruct { address sender; address receiver; uint256 amount; string remark; uint256 timestamp; } TransferStruct[] transactions; constructor() { owner = msg.sender; balanceOf[tx.origin] = msg.sender.balance; } function getOwner() public view returns (address) { return owner; } function sendMoney(address payable receiver, uint256 amount, string memory remark) public returns(bool success) { if (balanceOf[owner] < amount) return false; balanceOf[owner] -= amount; balanceOf[receiver] += amount; transactionCounts += 1; transactions.push( TransferStruct( owner, receiver, amount, remark, block.timestamp ) ); emit Transfer(msg.sender, receiver, amount, remark, block.timestamp); return true; } function getBalance(address addr) public view returns(uint) { return balanceOf[addr]; } function getAllTransactions() public view returns(TransferStruct[] memory) { return transactions; } function getTransactionsCount() public view returns(uint256) { return transactionCounts; } }


Configurar el encabezado del script de implementación en el directorio smart_contract >> scripts y cambiar el nombre del archivo sample-script.js a deployment.js . Luego, reemplace los códigos a continuación en él. El fragmento de código a continuación especifica dónde vivirá nuestro contrato inteligente en la web.


 const hre = require('hardhat') const main = async () => { const Transactions = await hre.ethers.getContractFactory('Transactions') const transactions = await Transactions.deploy() await transactions.deployed() console.log('Transactions deployed to:', transactions.address) } const runMain = async () => { try { await main() process.exit(0) } catch (error) { console.error(error) process.exit(1) } } runMain()


Fantástico trabajo, en este momento ya debería tener su red de prueba Rinkeby financiada y lista para usar, si no la tiene, vuelva a la PARTE UNO de este tutorial, encontrará las instrucciones allí.


Ahora toca saber de alquimia

Implementación en Alchemy

Desarrollo e implementación de Alchemy Blockchain


Actualmente, nuestro contrato inteligente solo puede ejecutarse en nuestra computadora y los extraños no pueden conectarse a él. Para que sea accesible para todos sin costo alguno, usaremos la alquimia para eso.

Continúe registrándose con ellos, o INICIAR SESIÓN si ya tiene una cuenta.


Página de autenticación


Una vez que haya iniciado sesión, verá la página del panel que le da acceso para crear una nueva aplicación de cadena de bloques.


Tablero de alquimia


Creación de una aplicación de Alchemy Haga clic en el botón CREAR APLICACIÓN y complete los detalles que desea como se ve en la imagen a continuación, asegúrese de especificar la red de prueba de Rinkeby .


Crear ventana emergente de nueva aplicación


Después de haber creado la aplicación, haga clic en el nombre de la aplicación o vea el botón de detalles para ver la información de la aplicación.


Aplicación creada


Haga clic en el botón VER CLAVE y copie la URL HTTP como se ve en la imagen a continuación.


Detalles de Http de la aplicación creada


Fantástico, ahora sigue los pasos que se muestran en las imágenes a continuación para obtener tu cuenta de Rinkeby. Tenga en cuenta que no estamos utilizando la dirección de cuenta habitual, sino la clave privada de esa cuenta.


Paso unoSegundo pasoPaso tres

Paso cuatro


Impresionante, ahora regrese al código VS >> smart_contract >> hardhat.config.js y reemplace su contenido con los códigos a continuación. Utilice su propia URL en lugar de la existente en el archivo.


 require('@nomiclabs/hardhat-waffle') module.exports = { solidity: '0.8.0', networks: { rinkeby: { url: '<YOUR_ALCHEMY_APP_URL_GOES_HERE>', accounts: [ '<YOUR_RINKEBY_ACCOUNT_PRIVATE_KEY_GOES_HERE>', ], }, }, }


Si ha hecho todo eso correctamente, solo tenemos que hacer una cosa más antes de pasar a la parte frontal de este proyecto. Implementemos este contrato inteligente en Alchemy, ejecute el código a continuación, asegúrese de que su terminal esté en el directorio smart_contract .


 yarn hardhat run scripts/deploy.js --network rinkeby or npx hardhat run scripts/deploy.js --network rinkeby


Después de que el contrato inteligente se implemente con éxito en Alchemy, tendrá la dirección del contrato inteligente que puede ver resaltada en la imagen a continuación.


Contrato implementado


Copie y guarde esa dirección, luego se usará en el directorio del cliente >> utils >> archivo constants.js .


Felicitaciones, acaba de completar la implementación del contrato inteligente, ahora usémoslo en nuestra aplicación frontend.

La configuración de la interfaz

Usando Vite React en la interfaz


Abra la terminal, cd en el directorio del cliente y realice las siguientes instrucciones. Para la interfaz, usaremos Vite para crear nuestra aplicación de reacción, Vite es un conjunto de herramientas increíble que simplifica el proceso de creación de su aplicación de interfaz.


Para esta compilación, también usaremos Yarn como nuestro administrador de paquetes principal, es mucho más agradable para instalar paquetes npm. Tenga en cuenta que todos los comandos de hilo también se pueden hacer fácilmente con npm. Solo necesitas hacer un pequeño ajuste. Ahora instalemos Vite si no lo has hecho.


 yarn create vite # or npm init vite@latest

Se le pedirá que ingrese el nombre de su proyecto, solo use " ./ ". Esto le indicará a Vite que descargue los códigos en el directorio actual (cliente) . A continuación, se le pedirá el nombre del proyecto, simplemente ingrese " dalto " y luego seleccione reaccionar de la lista de marcos disponibles. Consulte la imagen a continuación para obtener orientación.


Guía de instalación de Vite

Después de realizar las ejecuciones anteriores en el terminal, ejecute el siguiente comando para instalar los módulos npm que se utilizarán en nuestro proyecto.


 yarn install # or npm install

Instalación de dependencias del proyecto

Una vez que el proceso se realiza en la terminal, nuevamente debe instalar los siguientes paquetes de los que depende nuestra aplicación.


 yarn add @heroicons/react ethers @faker-js/faker identicon.js react-hooks-global-state # or npm install @heroicons/react ethers @faker-js/faker identicon.js react-hooks-global-state


Si ha instalado esos paquetes, es increíble, procedamos a instalar el Tailwind CSS del que también depende nuestra aplicación.

Instalación de Tailwind CSS

CSS viento de cola

Use los comandos a continuación para hacer eso.


 yarn add tailwindcss postcss autoprefixer --dev yarn tailwindcss init # or npm install -D tailwindcss postcss autoprefixer npx tailwindcss init


Debe tener dos archivos en la raíz de la carpeta del cliente . tailwind.config.js y postcss.config.js , pero si no lo hace, puede crearlos usted mismo.


A continuación, reemplace el contenido de los dos archivos con los siguientes códigos.


 # postcss.config.js const tailwindcss = require('tailwindcss') module.exports = { plugins: [tailwindcss('./tailwind.config.js'), require('autoprefixer')], } # tailwind.config.js module.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: {}, }, plugins: [], }


Ahora, reemplace el contenido del archivo index.css en el directorio del cliente >> src con los códigos a continuación.


 @tailwind base; @tailwind components; @tailwind utilities;


Muy bien, probemos la aplicación para ver si todo funciona bien ejecutando el siguiente código.


 # Running the application yarn dev # or npm run dev

Si hiciste todo bien, deberías tener el mismo resultado que el mío.


aplicación en ejecución

Trabajo épico hasta ahora, comencemos a codificar. Procederemos codificando los componentes.

Codificación de los componentes

Tenemos cuatro componentes y comenzaremos con el componente Encabezado. Antes de hacer eso, vaya al directorio del cliente >> src y cree una carpeta llamada componentes. Aquí es donde residirán todos nuestros componentes.


Componente de encabezado

El componente de encabezado

Cree un componente llamado Header.jsx . Este componente contiene el botón de envío que se utiliza para iniciar el modal addTransactionCard para ingresar nuevas transacciones. Vea el bloque de código a continuación.


 import ethLogo from '../assets/ethlogo.png' import { setGlobalState } from '../store' const Header = () => { return ( <header className="flex flex-row items-center justify-between drop-shadow-md py-2 px-5 bg-white"> <div className="flex flex-row justify-center items-center cursor-pointer"> <img className="w-6 h-6 object-contain cursor-pointer" src={ethLogo} alt="Etherium Logo" /> <span>Dalto</span> </div> <nav className="flex flex-row justify-center items-center list-none"> <li className="cursor-pointer mr-3 hover:text-blue-500">Pricing</li> <li className="cursor-pointer mr-3 hover:text-blue-500">Docs</li> <li className="cursor-pointer mr-3"> <button onClick={() => setGlobalState('modal', 'scale-100')} className="text-white bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring" > Send </button> </li> </nav> </header> ) } export default Header


Increíble, vamos a crear el componente AddTransactionCard .


Componente AddTransactionCard

Enviar modal de transacción

Todavía en el directorio de componentes, cree otro componente llamado AddTransactionCard.jsx , luego pegue los códigos a continuación y guárdelo. Usaremos este componente modal para crear nuevas transacciones. Un usuario puede iniciarlo cada vez que se hace clic en el botón Enviar en el componente Encabezado.


 import { useGlobalState, setGlobalState } from '../store' import { useState } from 'react' import { sendMoney } from '../shared/Transaction' const AddTransactionCard = () => { const [modal] = useGlobalState('modal') const [connectedAccount] = useGlobalState('connectedAccount') const [address, setAddress] = useState('') const [amount, setAmount] = useState('') const [remark, setRemark] = useState('') const [loading, setLoading] = useState(false) const handleSubmit = () => { if (!address || !amount || !remark) return setLoading(true) sendMoney({ connectedAccount, address, amount, remark }) .then(() => { setGlobalState('transaction', { address, amount, remark }) setLoading(false) setGlobalState('modal', '') resetForm() }) .catch((error) => { setLoading(false) console.log(error) }) } const resetForm = () => { setAddress('') setAmount('') setRemark('') } return ( <div className={`fixed top-0 left-0 w-screen h-screen flex items-center justify-center bg-black bg-opacity-50 transform scale-0 transition-transform duration-300 ${modal}`} > <div className="bg-white rounded-xl w-1/3 h-7/12 p-6"> <div className="flex flex-col"> <div className="flex flex-row justify-between items-center"> <p className="font-semibold text-gray-800">Add a step</p> <button onClick={() => setGlobalState('modal', '')} className="border-0 bg-transparent focus:outline-none" > <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" ></path> </svg> </button> </div> <div className="flex flex-row justify-between items-center bg-gray-100 rounded-xl p-3 mt-5"> <input className="bg-transparent focus:outline-none w-full" type="text" name="address" placeholder="Address To" onChange={(e) => setAddress(e.target.value)} value={address} /> </div> <div className="flex flex-row justify-between items-center bg-gray-100 rounded-xl p-3 mt-5"> <input className="bg-transparent focus:outline-none w-full" type="number" step={0.0001} name="amount" placeholder="Amount (Eth)" onChange={(e) => setAmount(e.target.value)} value={amount} /> </div> <div className="flex flex-row justify-between items-center bg-gray-100 rounded-xl p-3 mt-5"> <input className="bg-transparent focus:outline-none w-full" type="text" name="remark" placeholder="Remark" onChange={(e) => setRemark(e.target.value)} value={remark} /> </div> <div className="flex flex-row justify-between items-centerrounded-xl mt-5"> {!loading ? ( <button type="submit" onClick={handleSubmit} className="flex flex-row justify-center items-center w-full text-white text-lg bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring" > Send Money </button> ) : ( <button className="flex flex-row justify-center items-center w-full text-white text-lg bg-blue-300 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent focus:outline-none focus:ring" disabled > <svg xmlns="http://www.w3.org/2000/svg" width="30px" height="30px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" > <path d="M10 50A40 40 0 0 0 90 50A40 42 0 0 1 10 50" fill="white" stroke="none" > <animateTransform attributeName="transform" type="rotate" dur="1s" repeatCount="indefinite" keyTimes="0;1" values="0 50 51;360 50 51" ></animateTransform> </path> </svg> Sending... </button> )} </div> </div> </div> </div> ) } export default AddTransactionCard


Bien, vamos a crear el resto de los componentes.


Componente héroe

El componente héroe

Cree otro componente con el nombre Hero.jsx en la carpeta de componentes. Este componente contiene las descripciones de lo que hace esta aplicación. No tiene una funcionalidad especial, pero ayuda a la belleza del diseño de nuestra aplicación. Pegue los códigos a continuación en él y guárdelo.


 import { LightningBoltIcon, ScaleIcon } from '@heroicons/react/outline' const Hero = () => { const features = [ { name: 'No hidden fees', description: 'Sending money is free of charge, you have no need for a middle man or annoying taxes.', icon: ScaleIcon, }, { name: 'Transfers are instant', description: 'You do not have to wait for days anymore, you can get you money in seconds within any country in the world', icon: LightningBoltIcon, }, ] return ( <div className="py-12 bg-white"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="lg:text-center"> <p className="mt-2 text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl"> A better way to send money </p> <p className="mt-4 max-w-2xl text-xl text-gray-500 lg:mx-auto"> Explore the crypto world. Buy and sell cryptocurrencies easily on Dalto. </p> </div> <div className="mt-10"> <dl className="space-y-10 md:space-y-0 md:grid md:grid-cols-2 md:gap-x-8 md:gap-y-10"> {features.map((feature) => ( <div key={feature.name} className="relative"> <dt> <div className="drop-shadow-xl absolute flex items-center justify-center h-12 w-12 rounded-md bg-blue-500 text-white"> <feature.icon className="h-6 w-6" aria-hidden="true" /> </div> <p className="ml-16 text-lg leading-6 font-medium text-gray-900"> {feature.name} </p> </dt> <dd className="mt-2 ml-16 text-base text-gray-500"> {feature.description} </dd> </div> ))} </dl> </div> </div> </div> ) } export default Hero


Por último, creemos el componente Tabular.


Componente tabular

El componente tabular

Cree un componente con el nombre Tabular.jsx en la carpeta de componentes y pegue los códigos a continuación. Este componente es responsable de renderizar todas las transacciones registradas en nuestra red blockchain. Observe el código a continuación.


 import { useEffect, useState } from 'react' import ethLogo from '../assets/ethlogo.png' import Identicon from 'identicon.js' import faker from '@faker-js/faker' import { getAllTransactions } from '../shared/Transaction' import { useGlobalState } from '../store' const Tabuler = () => { const [transactionsStore] = useGlobalState('transactions') const [transactionCount] = useGlobalState('transactionCount') const [transactions, setTransaction] = useState([]) const [start, setStart] = useState(0) const [end, setEnd] = useState(6) const makeImage = (address) => { const data = new Identicon(address, 400).toString() return `data:image/png;base64,${data}` } const loadMoreTransactions = () => { setTransaction((prevState) => [ ...prevState, ...transactionsStore.slice(start, end), ]) setStart(end) setEnd(end * 2) } const shortenAddress = (address) => `${address.slice(0, 5)}...${address.slice(address.length - 4)}` useEffect(() => { getAllTransactions().then((data) => { setTransaction([...data.slice(start, end)]) setStart(end) setEnd(end * 2) }) }, []) return ( <> <section className="antialiased rounded-xl text-gray-600 p-5"> <div className="flex flex-col justify-center h-full"> <div className="max-w-full mx-auto px-4 sm:px-6 lg:px-8 bg-white shadow-2xl rounded-xl"> <header className="px-5 py-4"> <h2 className="font-semibold text-gray-800 text-center"> Total Transactions({transactionCount}) </h2> </header> <div className="p-3"> <div className="overflow-x-auto"> <table className="table-auto w-full"> <thead className="text-xs font-semibold uppercase text-gray-400 bg-gray-50"> <tr> <th className="p-2 whitespace-nowrap"> <div className="font-semibold text-left">Name</div> </th> <th className="p-2 whitespace-nowrap"> <div className="font-semibold text-left">Sender</div> </th> <th className="p-2 whitespace-nowrap"> <div className="font-semibold text-left">Receiver</div> </th> <th className="p-2 whitespace-nowrap"> <div className="font-semibold text-left">Amount</div> </th> <th className="p-2 whitespace-nowrap"> <div className="font-semibold text-left">Timestamp</div> </th> <th className="p-2 whitespace-nowrap"> <div className="font-semibold text-center">Remark</div> </th> </tr> </thead> <tbody className="text-sm divide-y divide-gray-100"> {transactions.map((tx, index) => ( <tr key={index + 1}> <td className="p-2 whitespace-nowrap"> <div className="flex items-center"> <div className="w-10 h-10 flex-shrink-0 mr-2 sm:mr-3"> <img className="rounded-full" src={makeImage(tx.sender)} width="40" height="40" alt="Alex Shatov" /> </div> <div className="font-medium text-gray-800"> {faker.name.findName()} </div> </div> </td> <td className="p-2 whitespace-nowrap"> <div className="text-left"> <a href={`https://ropsten.etherscan.io/address/${tx.sender}`} target="_blank" rel="noreferrer" className="hover:text-blue-500" > {shortenAddress(tx.sender)} </a> </div> </td> <td className="p-2 whitespace-nowrap"> <div className="text-left"> <a href={`https://ropsten.etherscan.io/address/${tx.receiver}`} target="_blank" rel="noreferrer" className="hover:text-blue-500" > {shortenAddress(tx.receiver)} </a> </div> </td> <td className="p-2 whitespace-nowrap"> <div className="flex flex-row justify-center items-center text-left font-medium"> <img className="w-3 h-3 object-contain cursor-pointer mr-1" src={ethLogo} alt="Etherium Logo" /> <span className="text-green-500">{tx.amount}</span> </div> </td> <td className="p-2 whitespace-nowrap"> <div className="text-sm text-center"> {tx.timestamp} </div> </td> <td className="p-2 whitespace-nowrap"> <div className="text-sm text-center">{tx.remark}</div> </td> </tr> ))} </tbody> </table> </div> </div> </div> </div> </section> <div className="text-center mt-5 mb-10"> <button onClick={loadMoreTransactions} className="text-white bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring" > Load more </button> </div> </> ) } export default Tabuler


Todos estos componentes están unificados por un único almacén de datos mediante el paquete npm react-hooks-global-state . Ahora reunamos los componentes anteriores en el componente de la aplicación .

El componente de la aplicación

Los códigos a continuación unen todos los componentes y funcionan juntos.


 import { useEffect } from 'react' import AddTransactionCard from './components/AddTransactionCard' import Header from './components/Header' import Hero from './components/Hero' import Tabuler from './components/Tabuler' import { isWallectConnected, checkIfTransactionExist, connectWallet, } from './shared/Transaction' import { useGlobalState } from './store' const App = () => { const [connectedAccount] = useGlobalState('connectedAccount') useEffect(() => { isWallectConnected() checkIfTransactionExist() }, []) return ( <div className="flex flex-col min-h-screen"> <Header /> <Hero /> {!connectedAccount ? ( <div className="text-center mb-10"> <button onClick={connectWallet} className="text-white bg-blue-500 py-2 px-5 rounded-xl drop-shadow-xl border border-transparent hover:bg-transparent hover:text-blue-500 hover:border hover:border-blue-500 focus:outline-none focus:ring" > Connect Wallet </button> </div> ) : ( <> <Tabuler /> <AddTransactionCard /> </> )} </div> ) } export default App


Genial, el código anterior une todos nuestros componentes, pero ¿qué pasa con la administración del estado? ¿Cómo se acopla? Veamos la configuración de la tienda react-hooks-global-state .

El almacén de datos

Vaya al directorio cliente >> src y cree una carpeta llamada store. Dentro de esta carpeta de la tienda, cree un archivo llamado index.jsx y pegue los códigos a continuación.

 import { createGlobalState } from 'react-hooks-global-state' const { setGlobalState, useGlobalState } = createGlobalState({ modal: '', connectedAccount: '', transactions: [], transaction: { address: '', amount: '', remark: '', }, transactionCount: localStorage.getItem('transactionCount'), }) export { useGlobalState, setGlobalState }

Genial, este sencillo paquete de gestión de estado elimina todas las complejidades de Redux o la API de contexto. Aquí es donde almacenamos todas nuestras transacciones y realizamos un seguimiento de la cuenta conectada.

Si has llegado hasta aquí, te mereces una taza de café, trabajemos en la siguiente parte.

Las utilidades de la aplicación

Dirígete a la carpeta del cliente >> directorio src y crea una nueva carpeta llamada utils . Ahora, dentro de esta carpeta utils, cree dos archivos llamados constants.js y Transactions.json . El archivo JSON contiene la interfaz binaria de la aplicación ( ABI ) que fue generada por hardhat y el archivo js lo preparará para las exportaciones.


El ABI es generado por hardhat después de la compilación, describe nuestro contrato inteligente y lo prepara de una manera que puede ser entendido por ethers.js .


En el directorio smart_contract vaya a >> artefactos >> contratos >> Transactions.sol >> Transactions.json . Copiará los códigos completos en este archivo y los pegará en client >> src >> utils >> Transactions.json .


A continuación, pegue el código siguiente en el archivo constants.js.


 import abi from './Transactions.json' export const contractAbi = abi.abi export const contractAddress = '<YOUR_DEPLOYED_SMART_CONTRACT_ADDRESS_GOES_HERE>'

Impresionante, sé que esto ha sido intenso, pero tranquilos, ya casi estamos terminando.

Los recursos del contrato inteligente

Este archivo nos proporciona todos los métodos disponibles en el archivo Transactions.sol . Estos métodos nos ayudarán a comunicarnos con la aplicación blockchain utilizando la biblioteca ethers.js y la URL que copiamos de Alchemy.


Cree una carpeta llamada shared dentro del directorio del cliente >> src. Cree un archivo llamado Transaction.jsx y pegue los códigos a continuación en él.


 import { ethers } from 'ethers' import { setGlobalState } from '../store' import { contractAbi, contractAddress } from '../utils/constants' const { ethereum } = window const getEtheriumContract = () => { const provider = new ethers.providers.Web3Provider(ethereum) const signer = provider.getSigner() const transactionContract = new ethers.Contract( contractAddress, contractAbi, signer ) return transactionContract } const isWallectConnected = async () => { try { if (!ethereum) return alert('Please install Metamask') const accounts = await ethereum.request({ method: 'eth_accounts' }) if (accounts.length) { setGlobalState('connectedAccount', accounts[0]) } else { console.log('No accounts found.') } } catch (error) { console.log(error) throw new Error('No ethereum object.') } } const checkIfTransactionExist = async () => { try { const transactionContract = getEtheriumContract() const transactionCount = await transactionContract.getTransactionsCount() window.localStorage.setItem('transactionCount', transactionCount) } catch (error) { console.log(error) throw new Error('No ethereum object.') } } const connectWallet = async () => { try { if (!ethereum) return alert('Please install Metamask') const accounts = await ethereum.request({ method: 'eth_requestAccounts' }) setGlobalState('connectedAccount', accounts[0]) } catch (error) { console.log(error) throw new Error('No ethereum object.') } } const sendMoney = async ({ connectedAccount, address, amount, remark }) => { try { if (!ethereum) return alert('Please install Metamask') const transactionContract = getEtheriumContract() const parsedAmount = ethers.utils.parseEther(amount) await ethereum.request({ method: 'eth_sendTransaction', params: [ { from: connectedAccount, to: address, gas: '0x5208', value: parsedAmount._hex, }, ], }) const transactionHash = await transactionContract.sendMoney( address, parsedAmount, remark ) console.log(`Loading - ${transactionHash.hash}`) await transactionHash.wait() console.log(`Success - ${transactionHash.hash}`) const transactionCount = await transactionContract.getTransactionsCount() setGlobalState('transactionCount', transactionCount.toNumber()) window.location.reload() } catch (error) { console.log(error) throw new Error('No ethereum object.') } } const getAllTransactions = async () => { try { if (!ethereum) return alert('Please install Metamask') const transactionContract = getEtheriumContract() const availableTransactions = await transactionContract.getAllTransactions() const structuredTransactions = availableTransactions.map((tx) => ({ receiver: tx.receiver, sender: tx.sender, timestamp: new Date(tx.timestamp.toNumber() * 1000).toLocaleString(), remark: tx.remark, amount: parseInt(tx.amount._hex) / 10 ** 18, })).reverse() setGlobalState('transactions', structuredTransactions) return structuredTransactions } catch (error) { console.log(error) throw new Error('No ethereum object.') } } export { getEtheriumContract, isWallectConnected, checkIfTransactionExist, connectWallet, sendMoney, getAllTransactions, }


Si está confundido acerca de lo que hacen las funciones anteriores, consulte la PARTE UNO de este tutorial aquí.


Descargue y coloque las siguientes imágenes en el directorio del cliente >> src >> assets y listo.

https://raw.githubusercontent.com/Daltonic/dalto/main/client/src/assets/ethLogo.png

https://github.com/Daltonic/dalto/blob/main/client/src/assets/logo.png?raw=true


Genial, acabas de aplastar toda la aplicación, es hora de probarla, ejecuta el código a continuación.


 yarn dev # or npm run dev

Conclusión

Felicitaciones por completar una aplicación descentralizada completa con react y solidity.

Crear una aplicación web 3.0 puede ser un desafío, ya que exige muchas habilidades y componentes, pero no es imposible.


Con suerte, el conocimiento que obtuvo de este tutorial le ha ayudado de alguna manera. Deje un aplauso o haga clic en el botón Me gusta para mostrar un poco de amor.


Gracias por codificar, nos vemos en el próximo tutorial ...

Sobre el Autor

Gospel Darlington inició su viaje como ingeniero de software en 2016. A lo largo de los años, ha desarrollado habilidades completas en pilas de JavaScript como React, ReactNative, VueJs y más.


Actualmente trabaja de forma independiente, crea aplicaciones para clientes y escribe tutoriales técnicos para enseñar a otros cómo hacer lo que él hace.


Gospel Darlington está abierto y disponible para escuchar de usted. Puede comunicarse con él en LinkedIn , Facebook , Github o en su sitio web .


También publicado en: https://dev.to/daltonic/building-an-ethereum-transaction-app-with-react-and-solidity-part-two-2pg2