Lo que construirá: vea una en vivo y Git Repo . Recuerde, la demostración en línea utiliza la red de prueba de ropsten. demostración aquí Introducción Siguiendo la primera parte de este tutorial, construiremos el lado frontal de este proyecto. Si no has visto la , te recomiendo que lo hagas para entender esta parte dos. PARTE UNO Si estás listo, aplastemos esta aplicación... Configuración del proyecto Asegúrese de que ya tiene instalado en su máquina, si no lo tiene, siga el enlace a continuación para hacerlo. NodeJs 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 , cree dos carpetas más llamadas y , 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 . Si hizo todo eso correctamente, la estructura de su proyecto debería verse así. dalto client smart_contract VS Code Los códigos deben estructurarse de la siguiente manera. Estructura del proyecto La configuración del contrato inteligente Vaya a la terminal, al directorio y ejecute el siguiente comando. mueva (cd) smart_contract npm init -y Esto creará un archivo en la raíz de la carpeta . Para especificar los paquetes que se usarán para construir el contrato inteligente, ejecutaremos el fragmento de código a continuación. npm smart_contract 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. Ahora necesita ejecutar el código a continuación para configurar el en la carpeta actual. casco smart_contract 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 cuando se le pregunte si desea agregar un y presione enter en su teclado. 'y' .gitIgnore Una vez que especifique las opciones anteriores correctamente, hardhat generará automáticamente la estructura del proyecto para usted. A continuación, diríjase al directorio >> y cambie el nombre del archivo a . Luego, pegue los códigos a continuación, guárdelo y muévase conmigo. Procesamiento del contrato inteligente smart_contract contratos Greeter.sol Transactions.sol // 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; } } en el directorio >> y cambiar el nombre del archivo a . 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. Configurar el encabezado del script de implementación smart_contract scripts sample-script.js deployment.js 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 de este tutorial, encontrará las instrucciones allí. PARTE UNO Ahora toca saber de … alquimia Implementación en Alchemy 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 si ya tiene una cuenta. INICIAR SESIÓ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. Haga clic en el y complete los detalles que desea como se ve en la imagen a continuación, asegúrese de especificar la . Creación de una aplicación de Alchemy botón CREAR APLICACIÓN red de prueba de Rinkeby Después de haber creado la aplicación, haga clic en el o vea el botón de detalles para ver la información de la aplicación. nombre de la aplicación Haga clic en el y copie la como se ve en la imagen a continuación. botón VER CLAVE URL HTTP 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. Impresionante, ahora regrese al >> >> y reemplace su contenido con los códigos a continuación. Utilice su propia en lugar de la existente en el archivo. código VS smart_contract hardhat.config.js URL 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 que puede ver resaltada en la imagen a continuación. dirección del contrato inteligente Copie y guarde esa dirección, luego se usará en el directorio del >> >> archivo . cliente utils 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 Abra la terminal, en el directorio del y realice las siguientes instrucciones. Para la interfaz, usaremos 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. cd cliente Vite 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 . A continuación, se le pedirá el nombre del proyecto, simplemente ingrese " " y luego seleccione de la lista de marcos disponibles. Consulte la imagen a continuación para obtener orientación. ./ (cliente) dalto reaccionar Después de realizar las ejecuciones anteriores en el terminal, ejecute el siguiente comando para instalar los que se utilizarán en nuestro proyecto. módulos npm 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 del que también depende nuestra aplicación. Tailwind CSS Instalación de Tailwind CSS 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 . pero si no lo hace, puede crearlos usted mismo. cliente tailwind.config.js y postcss.config.js , 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 en el directorio del >> con los códigos a continuación. index.css cliente src @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. 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 >> y cree una carpeta llamada componentes. Aquí es donde residirán todos nuestros componentes. cliente src Componente de encabezado Cree un componente llamado . Este componente contiene el que se utiliza para iniciar el modal para ingresar nuevas transacciones. Vea el bloque de código a continuación. Header.jsx botón de envío addTransactionCard 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 Todavía en el directorio de componentes, cree otro componente llamado , 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 en el componente Encabezado. AddTransactionCard.jsx botón Enviar 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 Cree otro componente con el nombre 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. Hero.jsx 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 Cree un componente con el nombre 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. Tabular.jsx 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 . Ahora reunamos los componentes anteriores en el componente de la . react-hooks-global-state 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 >> y cree una carpeta llamada store. Dentro de esta carpeta de la tienda, cree un archivo llamado y pegue los códigos a continuación. cliente src index.jsx 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 >> directorio y crea una nueva carpeta llamada . Ahora, dentro de esta carpeta utils, cree dos archivos llamados y . El archivo contiene la interfaz binaria de la aplicación ( ) que fue generada por hardhat y el archivo lo preparará para las exportaciones. cliente src utils constants.js Transactions.json JSON ABI js 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 >> >> >> >> . Copiará los códigos completos en este archivo y los pegará en >> >> >> . smart_contract vaya a artefactos contratos Transactions.sol Transactions.json 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 . Estos métodos nos ayudarán a comunicarnos con la aplicación blockchain utilizando la biblioteca y la URL que copiamos de Alchemy. Transactions.sol ethers.js Cree una carpeta llamada dentro del directorio del >> Cree un archivo llamado y pegue los códigos a continuación en él. shared cliente src. Transaction.jsx 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 de este tutorial aquí. PARTE UNO Descargue y coloque las siguientes imágenes en el directorio del >> >> y listo. cliente src assets 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 , , o en su . LinkedIn Facebook Github sitio web También publicado en: https://dev.to/daltonic/building-an-ethereum-transaction-app-with-react-and-solidity-part-two-2pg2