Contrato inteligente de Hello World para principiantes: Fullstack
Si es nuevo en el desarrollo de la cadena de bloques y no sabe por dónde empezar o cómo desplegar e interactuar con contratos inteligentes, esta guía está hecha a su medida. Repasaremos la creación y el despliegue de un contrato inteligente simple en la red de prueba de Goerli usando MetaMaskopens in a new tab, Solidityopens in a new tab, Hardhatopens in a new tab, y Alchemyopens in a new tab.
Necesitará una cuenta de Alchemy para completar este tutorial. Regístrese para obtener una cuenta gratuitaopens in a new tab.
¡Si tiene preguntas en cualquier momento, no dude en ponerse en contacto con el Discord de Alchemyopens in a new tab!
Parte 1: Cree y despliegue su contrato inteligente usando Hardhat
Conectarse a la red de Ethereum
Hay muchas formas de hacer solicitudes a la cadena de Ethereum. Para simplificar, usaremos una cuenta gratuita en Alchemy, una plataforma de desarrollo de cadenas de bloques y una API que nos permite comunicarnos con la cadena Ethereum sin tener que ejecutar un nodo nosotros mismos. Alchemy también tiene herramientas de desarrollo para monitorización y análisis; las aprovecharemos en este tutorial para entender lo que ocurre entre bastidores en el despliegue de nuestro contrato inteligente.
Crear su aplicación y clave de API
Una vez que haya creado una cuenta de Alchemy, puede generar una clave de API creando una aplicación. Esto le permitirá hacer solicitudes a la red de prueba de Goerli. Si no está familiarizado con las redes de prueba, puede leer la guía de Alchemy para elegir una redopens in a new tab.
En el panel de Alchemy, encuentre el menú desplegable Apps en la barra de navegación y haga clic en Create App.
Asigne a su aplicación el nombre «Hello World» y escriba una breve descripción. Seleccione Staging como su entorno y Goerli como su red.
Nota: asegúrese de seleccionar Goerli, o este tutorial no funcionará.
Haga clic en Create app. Su aplicación aparecerá en la tabla de abajo.
Crear una cuenta de Ethereum
Necesita una cuenta de Ethereum para enviar y recibir transacciones. Usaremos MetaMask, una billetera virtual en el navegador que permite a los usuarios administrar la dirección de su cuenta de Ethereum.
Puede descargar y crear una cuenta de MetaMask gratis aquíopens in a new tab. Al crear una cuenta, o si ya tiene una, asegúrese de cambiar a la «red de prueba de Goerli» en la parte superior derecha (para que no estemos tratando con dinero real).
Paso 4: Añadir ether desde un Faucet
Para desplegar su contrato inteligente en la red de prueba, necesitará algo de ETH falso. Para obtener ETH en la red Goerli, vaya a un grifo de Goerli e ingrese la dirección de su cuenta de Goerli. Tenga en cuenta que los grifos de Goerli pueden ser un poco poco fiables últimamente; consulte la página de redes de prueba para obtener una lista de opciones para probar:
Nota: debido a la congestión de la red, esto podría tardar un rato. ``
Paso 5: Compruebe su saldo
Para volver a comprobar que el ETH está en su billetera, hagamos una solicitud de eth_getBalanceopens in a new tab utilizando la herramienta de composición de Alchemyopens in a new tab. Esto devolverá la cantidad de ETH a nuestra cartera. Para saber más, consulte el breve tutorial de Alchemy sobre cómo usar la herramienta de composiciónopens in a new tab.
Introduzca la dirección de su cuenta de MetaMask y haga clic en Send Request. Verá una respuesta parecida al fragmento de código que aparece a continuación.
1{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" }Nota: este resultado está en wei, no en ETH. El wei se utiliza como la denominación más pequeña de ether._
¡Fiu! Nuestro dinero de prueba está ahí sano y salvo.
Paso 6: Inicialice nuestro proyecto
Primero, tendremos que crear una carpeta para nuestro proyecto. Vaya a su línea de comandos e introduzca lo siguiente.
1mkdir hello-world2cd hello-worldAhora que estamos dentro de la carpeta de nuestro proyecto, usaremos npm init para inicializar el proyecto.
Si aún no tiene npm instalado, siga estas instrucciones para instalar Node.js y npmopens in a new tab.
A efectos de este tutorial, no importa cómo responda a las preguntas de inicialización. A continuación, se muestra cómo lo hicimos como referencia:
1package name: (hello-world)2version: (1.0.0)3description: contrato inteligente hello world4entry point: (index.js)5test command:6git repository:7keywords:8author:9license: (ISC)1011About to write to /Users/.../.../.../hello-world/package.json:1213{14 "name": "hello-world",15 "version": "1.0.0",16 "description": "contrato inteligente hello world",17 "main": "index.js",18 "scripts": {19 "test": "echo \"Error: no test specified\" && exit 1"20 },21 "author": "",22 "license": "ISC"23}Mostrar todoApruebe el package.json y ¡listo!
Paso 7: Descargue Hardhat
Hardhat es un entorno de desarrollo para compilar, implementar, probar y depurar su software de Ethereum. Ayuda a los desarrolladores cuando crean contratos inteligentes y dApps localmente antes de la implementación en la cadena real.
Dentro de nuestro proyecto hello-world, ejecute:
1npm install --save-dev hardhatConsulte esta página para obtener más detalles sobre las instrucciones de instalaciónopens in a new tab.
Paso 8: Cree el proyecto Hardhat
Dentro de nuestra carpeta de proyecto hello-world, ejecute:
1npx hardhatEntonces debería aparecer un mensaje de bienvenida y la opción de seleccionar lo que desea hacer. Seleccione «create an empty hardhat.config.js» (crear un hardhat.config.js vacío):
1888 888 888 888 8882888 888 888 888 8883888 888 888 888 88848888888888 8888b. 888d888 .d88888 88888b. 8888b. 8888885888 888 "88b 888P" d88" 888 888 "88b "88b 8886888 888 .d888888 888 888 888 888 888 .d888888 8887888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.8888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888910👷 Bienvenido a Hardhat v2.0.11 👷1112¿Qué quiere hacer?…13Crear un proyecto de ejemplo14❯ Crear un archivo hardhat.config.js vacío15SalirMostrar todoEsto generará un archivo hardhat.config.js en el proyecto. Lo utilizaremos más adelante en el tutorial para especificar la configuración de nuestro proyecto.
Paso 9: Añada las carpetas del proyecto
Para mantener el proyecto organizado, vamos a crear dos carpetas nuevas. En la línea de comandos, navegue hasta el directorio raíz de su proyecto hello-world y escriba:
1mkdir contracts2mkdir scriptscontracts/es donde guardaremos nuestro archivo de código del contrato inteligente «Hola, mundo».scripts/es donde guardaremos los scripts para desplegar e interactuar con nuestro contrato.
Paso 10: Escriba nuestro contrato
Puede que se esté preguntando cuándo vamos a escribir código. ¡Llegó la hora!
Abra el proyecto hello-world en su editor favorito. Los contratos inteligentes se escriben normalmente en Solidity, que es el lenguaje que usaremos para escribir nuestro contrato inteligente.
- Vaya a la carpeta
contractsy cree un nuevo archivo llamadoHelloWorld.sol - A continuación, se muestra un contrato inteligente de Hello World de ejemplo que utilizaremos para este tutorial. Copie el contenido siguiente en el archivo
HelloWorld.sol.
Nota: Asegúrese de leer los comentarios para entender qué hace este contrato.
1// Especifica la versión de Solidity, usando el versionado semántico.2// Más información: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity >=0.7.3;45// Define un contrato llamado `HelloWorld`.6// Un contrato es una colección de funciones y datos (su estado). Una vez desplegado, un contrato reside en una dirección específica en la cadena de bloques de Ethereum. Más información: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html7contract HelloWorld {89 //Se emite cuando se llama a la función de actualización10 //Los eventos de contratos inteligentes son una forma de que su contrato comunique que algo ha sucedido en la cadena de bloques a la interfaz de su aplicación, la cual puede estar 'escuchando' ciertos eventos y tomar medidas cuando suceden.11 event UpdatedMessages(string oldStr, string newStr);1213 // Declara una variable de estado `message` de tipo `string`.14 // Las variables de estado son variables cuyos valores se almacenan permanentemente en el almacenamiento del contrato. La palabra clave `public` hace que las variables sean accesibles desde fuera de un contrato y crea una función a la que otros contratos o clientes pueden llamar para acceder al valor.15 string public message;1617 // Similar a muchos lenguajes orientados a objetos basados en clases, un constructor es una función especial que solo se ejecuta en la creación del contrato.18 // Los constructores se utilizan para inicializar los datos del contrato. Más información:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors19 constructor(string memory initMessage) {2021 // Acepta un argumento de cadena `initMessage` y establece el valor en la variable de almacenamiento `message` del contrato).22 message = initMessage;23 }2425 // Una función pública que acepta un argumento de cadena y actualiza la variable de almacenamiento `message`.26 function update(string memory newMessage) public {27 string memory oldMsg = message;28 message = newMessage;29 emit UpdatedMessages(oldMsg, newMessage);30 }31}Mostrar todoEste es un contrato inteligente básico que almacena un mensaje en el momento de la creación. Se puede actualizar llamando a la función update.
Paso 11: Conecte MetaMask y Alchemy a su proyecto
Hemos creado una billetera de MetaMask, una cuenta de Alchemy y hemos escrito nuestro contrato inteligente, ahora es el momento de conectar los tres.
Cada transacción enviada desde su billetera requiere una firma que utilice su clave privada única. Para proporcionar a nuestro programa este permiso, podemos almacenar de forma segura nuestra clave privada en un archivo de entorno. También almacenaremos una clave de API para Alchemy aquí.
Para obtener más información sobre el envío de transacciones, consulte este tutorialopens in a new tab sobre el envío de transacciones mediante web3.
Primero, instale el paquete dotenv en su directorio de proyecto:
1npm install dotenv --saveLuego, cree un archivo .env en el directorio raíz del proyecto. Añada su clave privada de MetaMask y la URL de la API HTTP de Alchemy.
Su archivo de entorno debe tener el nombre .env; de lo contrario, no se reconocerá como un archivo de entorno.
No lo nombre process.env o .env-custom ni de ninguna otra manera.
- Siga estas instruccionesopens in a new tab para exportar su clave privada
- Vea a continuación cómo obtener la URL de la API de HTTP de Alchemy.
Su .env debería verse así:
1API_URL = "https://eth-goerli.alchemyapi.io/v2/su-clave-de-api"2PRIVATE_KEY = "su-clave-privada-de-metamask"Para conectar esto a nuestro código, haremos referencia a estas variables en nuestro archivo hardhat.config.js en el paso 13.
Paso 12: Instalar Ethers.js
Ethers.js es una biblioteca que facilita la interacción y la realización de solicitudes a Ethereum al encapsular los métodos JSON-RPC estándaropens in a new tab con métodos más sencillos para el usuario.
Hardhat nos permite integrar pluginsopens in a new tab para herramientas adicionales y funcionalidad extendida. Aprovecharemos el plugin de Ethersopens in a new tab para el despliegue del contrato.
En el directorio de su proyecto teclee:
npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0"Paso 13: Actualice hardhat.config.js
Hemos añadido varias dependencias y plugins hasta ahora, ahora necesitamos actualizar hardhat.config.js para que nuestro proyecto los conozca todos.
Actualice su hardhat.config.js para que se vea así:
1/**2 * @type import('hardhat/config').HardhatUserConfig3 */45require("dotenv").config()6require("@nomiclabs/hardhat-ethers")78const { API_URL, PRIVATE_KEY } = process.env910module.exports = {11 solidity: "0.7.3",12 defaultNetwork: "goerli",13 networks: {14 hardhat: {},15 goerli: {16 url: API_URL,17 accounts: [`0x${PRIVATE_KEY}`],18 },19 },20}Mostrar todoPaso 14: Compile nuestro contrato
Para asegurarnos de que todo funciona correctamente hasta ahora, compilemos nuestro contrato. La tarea compile es una de las tareas incorporadas de Hardhat.
Desde la línea de comandos ejecute:
npx hardhat compileEs posible que reciba una advertencia sobre SPDX license identifier not provided in source file, pero no necesita preocuparse por eso. ¡Esperemos que todo lo demás se vea bien! Si no es así, siempre puede enviar un mensaje en el discord de Alchemyopens in a new tab.
Paso 15: Escriba nuestro script de despliegue
Ahora que nuestro contrato está escrito y nuestro archivo de configuración está listo, es momento de escribir nuestro script de implementación del contrato.
Vaya a la carpeta scripts/ y cree un nuevo archivo llamado deploy.js, añadiendo el siguiente contenido:
1async function main() {2 const HelloWorld = await ethers.getContractFactory("HelloWorld")34 // Inicia el despliegue, devolviendo una promesa que se resuelve en un objeto de contrato5 const hello_world = await HelloWorld.deploy("Hello World!")6 console.log("Contrato desplegado en la dirección:", hello_world.address)7}89main()10 .then(() => process.exit(0))11 .catch((error) => {12 console.error(error)13 process.exit(1)14 })Mostrar todoHardhat hace un trabajo increíble explicando lo que hace cada una de estas líneas de código en su tutorial de Contratosopens in a new tab, hemos adoptado sus explicaciones aquí.
1const HelloWorld = await ethers.getContractFactory("HelloWorld")Una ContractFactory en ethers.js es una abstracción utilizada para desplegar nuevos contratos inteligentes, por lo que HelloWorld aquí es una factoríaopens in a new tab para instancias de nuestro contrato hello world. Al usar el plugin hardhat-ethers ContractFactory y las instancias de Contract, estas se conectan al primer firmante (propietario) por defecto.
1const hello_world = await HelloWorld.deploy()Llamar a deploy() en una ContractFactory iniciará el despliegue y devolverá una Promise que se resuelve en un objeto Contract. Este es el elemento que tiene un método para cada una de nuestras funciones de contrato inteligente.
Paso 16: Desplegar nuestro contrato
¡Ahora ya estamos listos para desplegar nuestro contrato inteligente! Vaya a la línea de comandos y ejecute:
npx hardhat run scripts/deploy.js --network goerliDebería mostrarse algo parecido a esto:
Contrato desplegado en la dirección: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570Por favor, guarde esta dirección. La usaremos más adelante en el tutorial.
Si vamos al explorador de bloques de Goerliopens in a new tab y buscamos la dirección de nuestro contrato, deberíamos poder ver que se ha desplegado con éxito. La transacción tendrá un aspecto parecido a este:
La dirección From debería coincidir con la dirección de su cuenta de MetaMask y la dirección To dirá Creación de Contrato. Si hacemos clic en la transacción, veremos la dirección de nuestro contrato en el campo To.
¡Enhorabuena! Acaba de desplegar un contrato inteligente en una red de prueba de Ethereum.
Para entender lo que está sucediendo internamente, navegue a la pestaña Explorador en nuestro panel de Alchemyopens in a new tab. Si tiene varias aplicaciones de Alchemy, asegúrese de filtrar por aplicación y seleccionar Hello World.
Aquí verá un puñado de métodos JSON-RPC que Hardhat/Ethers crearon internamente para nosotros cuando llamamos a la función .deploy(). Dos métodos importantes aquí son eth_sendRawTransactionopens in a new tab, que es la solicitud para escribir nuestro contrato en la cadena Goerli, y eth_getTransactionByHashopens in a new tab, que es una solicitud para leer información sobre nuestra transacción dado el hash. Para obtener más información sobre el envío de transacciones, consulte nuestro tutorial sobre el envío de transacciones con Web3.
Parte 2: Interactúe con su contrato inteligente
Ahora que hemos desplegado con éxito un contrato inteligente en la red Goerli, aprendamos a interactuar con él.
Cree un archivo interact.js
Este es el archivo en el que escribiremos nuestro script de interacción. Usaremos la biblioteca Ethers.js que instaló previamente en la Parte 1.
Dentro de la carpeta scripts/, cree un nuevo archivo llamado interact.js y añada el siguiente código:
1// interact.js23const API_KEY = process.env.API_KEY4const PRIVATE_KEY = process.env.PRIVATE_KEY5const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESSActualice su archivo .env
Usaremos nuevas variables de entorno, así que necesitamos definirlas en el archivo .env que creamos anteriormente.
Necesitaremos añadir una definición para nuestra API_KEY de Alchemy y el CONTRACT_ADDRESS donde se desplegó su contrato inteligente.
Su archivo .env debería tener un aspecto similar a este:
# .envAPI_URL = "https://eth-goerli.alchemyapi.io/v2/<su-clave-de-api>"API_KEY = "<su-clave-de-api>"PRIVATE_KEY = "<su-clave-privada-de-metamask>"CONTRACT_ADDRESS = "0x<la-dirección-de-su-contrato>"Obtenga la ABI de su contrato
La de nuestro contrato es la interfaz para interactuar con nuestro contrato inteligente. Hardhat genera automáticamente una ABI y la guarda en HelloWorld.json. Para usar la ABI, necesitaremos analizar el contenido añadiendo las siguientes líneas de código a nuestro archivo interact.js:
1// interact.js2const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json")Si quiere ver el ABI, puede imprimirlo en su consola:
1console.log(JSON.stringify(contract.abi))Para ver su ABI impresa en la consola, vaya a su terminal y ejecute:
npx hardhat run scripts/interact.jsCrear una instancia de su contrato
Para interactuar con nuestro contrato, necesitamos crear una instancia de contrato en nuestro código. Para hacerlo con Ethers.js, tendremos que trabajar con tres conceptos:
- Proveedor: un proveedor de nodos que le dé acceso de lectura y escritura a la cadena de bloques
- Firmante: representa una cuenta de Ethereum que puede firmar transacciones.
- Contrato: un objeto Ethers.js que representa un contrato específico desplegado en cadena
Utilizaremos el contrato ABI del paso anterior para crear nuestra instancia del contrato:
1// interact.js23// Proveedor4const alchemyProvider = new ethers.providers.AlchemyProvider(5 (network = "goerli"),6 API_KEY7)89// Firmante10const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider)1112// Contrato13const helloWorldContract = new ethers.Contract(14 CONTRACT_ADDRESS,15 contract.abi,16 signer17)Mostrar todoObtenga más información sobre proveedores, firmantes y contratos en la documentación de ethers.jsopens in a new tab.
Lea el mensaje de inicio
¿Recuerda cuando desplegamos nuestro contrato con initMessage = "Hello world!"? Ahora vamos a leer ese mensaje almacenado en nuestro contrato inteligente e imprimirlo en la consola.
En JavaScript, las funciones asíncronas se utilizan al interactuar con las redes. Para saber más sobre las funciones asíncronas, lea este artículo de Mediumopens in a new tab.
Utilice el siguiente código para llamar a la función message en nuestro contrato inteligente y leer el mensaje de inicio:
1// interact.js23// ...45async function main() {6 const message = await helloWorldContract.message()7 console.log("El mensaje es: " + message)8}9main()Mostrar todoDespués de ejecutar el archivo usando npx hardhat run scripts/interact.js en la terminal, debería ver esta respuesta:
1El mensaje es: Hello world!¡Enhorabuena! Acaba de leer con éxito los datos del contrato inteligente de la cadena de bloques de Ethereum, ¡bien hecho!
Actualice el mensaje
En lugar de solo leer el mensaje, ¡también podemos actualizar el mensaje guardado en nuestro contrato inteligente utilizando la función update! Genial, ¿verdad?
Para actualizar el mensaje, podemos llamar directamente a la función update en nuestro objeto Contract instanciado:
1// interact.js23// ...45async function main() {6 const message = await helloWorldContract.message()7 console.log("El mensaje es: " + message)89 console.log("Actualizando el mensaje...")10 const tx = await helloWorldContract.update("Este es el nuevo mensaje.")11 await tx.wait()12}13main()Mostrar todoTenga en cuenta que en la línea 11, hacemos una llamada a .wait() en el objeto de transacción devuelto. Esto garantiza que nuestro script espere a que la transacción se mine en la cadena de bloques antes de salir de la función. Si no se incluye la llamada .wait(), es posible que el script no vea el valor message actualizado en el contrato.
Lea el nuevo mensaje
Debería poder repetir el paso anterior para leer el valor message actualizado. ¡Tómese un momento y vea si puede hacer los cambios necesarios para imprimir ese nuevo valor!
Si necesita una pista, así es como debería verse su archivo interact.js en este momento:
1// interact.js23const API_KEY = process.env.API_KEY4const PRIVATE_KEY = process.env.PRIVATE_KEY5const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS67const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json")89// proveedor - Alchemy10const alchemyProvider = new ethers.providers.AlchemyProvider(11 (network = "goerli"),12 API_KEY13)1415// firmante - usted16const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider)1718// instancia del contrato19const helloWorldContract = new ethers.Contract(20 CONTRACT_ADDRESS,21 contract.abi,22 signer23)2425async function main() {26 const message = await helloWorldContract.message()27 console.log("El mensaje es: " + message)2829 console.log("Actualizando el mensaje...")30 const tx = await helloWorldContract.update("este es el nuevo mensaje")31 await tx.wait()3233 const newMessage = await helloWorldContract.message()34 console.log("El nuevo mensaje es: " + newMessage)35}3637main()Mostrar todo¡Ahora solo ejecute el script y debería poder ver el mensaje antiguo, el estado de la actualización y el nuevo mensaje impreso en su terminal!
npx hardhat run scripts/interact.js --network goerli
1El mensaje es: ¡Hola, mundo!2Actualizando el mensaje...3El nuevo mensaje es: Este es el nuevo mensaje.Mientras ejecuta ese script, puede notar que el paso Updating the message... tarda un tiempo en cargarse antes de que se cargue el nuevo mensaje. Eso se debe al proceso de minería; si tiene curiosidad sobre el seguimiento de las transacciones mientras se están minando, visite el mempool de Alchemyopens in a new tab para ver el estado de una transacción. Si la transacción es descartada, también es útil comprobar Goerli Etherscanopens in a new tab y buscar el hash de su transacción.
Parte 3: Publique su contrato inteligente en Etherscan
Ya ha hecho la parte más dura para dar vida a su contrato inteligente; ¡ahora es el momento de compartirlo con el mundo!
Al verificar su contrato inteligente en Etherscan, cualquiera puede ver su código fuente e interactuar con su contrato inteligente. ¡Empecemos!
Paso 1: Genere una clave de API en su cuenta de Etherscan
Se necesita una clave de API de Etherscan para verificar que es el propietario del contrato inteligente que está intentando publicar.
Si aún no tiene una cuenta de Etherscan, regístrese para obtener una cuentaopens in a new tab.
Una vez que haya iniciado sesión, busque su nombre de usuario en la barra de navegación, pase el cursor sobre él y seleccione el botón My profile.
En su página de perfil, debería ver una barra de navegación lateral. En la barra de navegación lateral, seleccione API Keys. A continuación, presione el botón «Add» para crear una nueva clave de API, nombre su aplicación hello-world y presione el botón Create New API Key.
Su nueva clave de API debería aparecer en la tabla de claves de API. Copie la clave de la API en su portapapeles.
A continuación, tenemos que añadir la clave de la API de Etherscan a nuestro archivo .env.
Después de añadirlo, su archivo .env debería tener este aspecto:
1API_URL = "https://eth-goerli.alchemyapi.io/v2/su-clave-de-api"2PUBLIC_KEY = "la-dirección-de-su-cuenta-pública"3PRIVATE_KEY = "la-dirección-de-su-cuenta-privada"4CONTRACT_ADDRESS = "la-dirección-de-su-contrato"5ETHERSCAN_API_KEY = "su-clave-de-etherscan"Contratos inteligentes desplegados con Hardhat
Instalar hardhat-etherscan
Publicar su contrato en Etherscan usando Hardhat es sencillo. Primero tendrá que instalar el plugin hardhat-etherscan para empezar. hardhat-etherscan verificará automáticamente el código fuente del contrato inteligente y la ABI en Etherscan. Para añadir esto, en el directorio hello-world ejecute:
1npm install --save-dev @nomiclabs/hardhat-etherscanUna vez instalado, incluya la siguiente declaración en la parte superior de su hardhat.config.js, y añada las opciones de configuración de Etherscan:
1// hardhat.config.js23require("dotenv").config()4require("@nomiclabs/hardhat-ethers")5require("@nomiclabs/hardhat-etherscan")67const { API_URL, PRIVATE_KEY, ETHERSCAN_API_KEY } = process.env89module.exports = {10 solidity: "0.7.3",11 defaultNetwork: "goerli",12 networks: {13 hardhat: {},14 goerli: {15 url: API_URL,16 accounts: [`0x${PRIVATE_KEY}`],17 },18 },19 etherscan: {20 // Su clave API para Etherscan21 // Obtenga una en https://etherscan.io/22 apiKey: ETHERSCAN_API_KEY,23 },24}Mostrar todoVerifique su contrato inteligente en Etherscan
Asegúrese de que todos los archivos estén guardados y de que todas las variables .env estén configuradas correctamente.
Ejecute la tarea verify, pasando la dirección del contrato y la red en la que está desplegado:
1npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS 'Hello World!'Asegúrese de que DEPLOYED_CONTRACT_ADDRESS es la dirección de su contrato inteligente desplegado en la red de prueba Goerli. Además, el argumento final ('Hello World!') debe ser el mismo valor de cadena utilizado durante el paso de despliegue en la parte 1.
Si todo va bien, aparecerá el siguiente mensaje en su terminal:
1Successfully submitted source code for contract2contracts/HelloWorld.sol:HelloWorld at 0xdeployed-contract-address3for verification on Etherscan. Waiting for verification result...456Contrato HelloWorld verificado correctamente en Etherscan.7https://goerli.etherscan.io/address/<dirección-del-contrato>#contracts¡Enhorabuena! ¡El código de su contrato inteligente está en Etherscan!
¡Eche un vistazo a su contrato inteligente en Etherscan!
Cuando navegue al enlace proporcionado en su terminal, ¡debería poder ver su código de contrato inteligente y ABI publicado en Etherscan!
¡Yuhuuuu! ¡Lo ha conseguido, campeón! ¡Ahora cualquiera puede llamar o escribir a su contrato inteligente! ¡Estamos deseando ver lo que construye a continuación!
Parte 4: Integración de su contrato inteligente con el frontend
Al final de este tutorial, sabrá cómo:
- Conectar una billetera MetaMask a su dapp
- Leer datos de su contrato inteligente usando la API de Alchemy Web3opens in a new tab
- Firmar transacciones de Ethereum usando MetaMask.
Para esta dapp, usaremos Reactopens in a new tab como nuestro marco de frontend; sin embargo, es importante tener en cuenta que no pasaremos demasiado tiempo desglosando sus fundamentos, ya que nos centraremos principalmente en llevar la funcionalidad Web3 a nuestro proyecto.
Como requisito previo, debe conocimientos de React a nivel principiante. De lo contrario, le recomendamos completar el tutorial oficial de Introducción a Reactopens in a new tab.
Clonar los archivos de inicio
Primero, ve al repositorio de GitHub hello-world-part-fouropens in a new tab para obtener los archivos de inicio de este proyecto y clona este repositorio en tu máquina local.
Abre el repositorio clonado localmente. Fíjate que contiene dos carpetas: starter-files y completed.
starter-files: trabajaremos en este directorio, conectaremos la IU a tu billetera de Ethereum y al contrato inteligente que publicamos en Etherscan en la Parte 3.completedcontiene el tutorial completo y solo debe usarse como referencia si te atascas.
A continuación, abre tu copia de starter-files en tu editor de código favorito y luego navega a la carpeta src.
Todo el código que escribiremos estará en la carpeta src. Editaremos el componente HelloWorld.js y los archivos JavaScript util/interact.js para dar a nuestro proyecto la funcionalidad de Web3.
Echa un vistazo a los archivos de inicio
Antes de empezar a programar, exploremos lo que se nos proporciona en los archivos de inicio.
Ponga en marcha su proyecto de React
Comencemos por ejecutar el proyecto React en nuestro navegador. La belleza de React es que, una vez que tenemos nuestro proyecto corriendo en el navegador, cualquier cambio que guardemos será actualizado en vivo en el navegador.
Para que el proyecto se ejecute, navega al directorio raíz de la carpeta starter-files y ejecuta npm install en tu terminal para instalar las dependencias del proyecto:
cd starter-filesnpm installUna vez que hayan terminado de instalarse, ejecute npm start en su terminal:
npm startAl hacerlo, se debería abrir http://localhost:3000/opens in a new tab en tu navegador, donde verás el frontend de nuestro proyecto. Debería constar de un campo (un lugar para actualizar el mensaje almacenado en tu contrato inteligente), un botón «Conectar billetera» y un botón «Actualizar».
Si intentas hacer clic en cualquiera de los botones, te darás cuenta de que no funcionan; esto se debe a que todavía tenemos que programar su funcionalidad.
El componente HelloWorld.js
Volvamos a la carpeta src en nuestro editor y abramos el archivo HelloWorld.js. Es muy importante que entendamos todo en este archivo, ya que es el componente principal en React en el que trabajaremos.
En la parte superior de este archivo, notarás que tenemos varias sentencias de importación que son necesarias para que nuestro proyecto se ejecute, incluyendo la biblioteca React, los hooks useEffect y useState, algunos elementos de ./util/interact.js (¡los describiremos con más detalle pronto!) y el logotipo de Alchemy.
1// HelloWorld.js23import React from "react"4import { useEffect, useState } from "react"5import {6 helloWorldContract,7 connectWallet,8 updateMessage,9 loadCurrentMessage,10 getCurrentWalletConnected,11} from "./util/interact.js"1213import alchemylogo from "./alchemylogo.svg"Mostrar todoA continuación, tenemos nuestras variables de estado que actualizaremos después de eventos específicos.
1// HelloWorld.js23//Variables de estado4const [walletAddress, setWallet] = useState("")5const [status, setStatus] = useState("")6const [message, setMessage] = useState("No hay conexión a la red.")7const [newMessage, setNewMessage] = useState("")Esto es lo que representa cada una de las variables:
walletAddress: una cadena que almacena la dirección del monedero del usuariostatus: una cadena que almacena un mensaje útil que guía al usuario sobre cómo interactuar con la dapp.message: una cadena que almacena el mensaje actual en el contrato inteligente.newMessage: una cadena que almacena el nuevo mensaje que se escribirá en el contrato inteligente.
Después de las variables de estado, verás cinco funciones no implementadas: useEffect, addSmartContractListener, addWalletListener, connectWalletPressed y onUpdatePressed. A continuación explicaremos lo que hacen:
1// HelloWorld.js23//se llama solo una vez4useEffect(async () => {5 //TODO: implementar6}, [])78function addSmartContractListener() {9 //TODO: implementar10}1112function addWalletListener() {13 //TODO: implementar14}1516const connectWalletPressed = async () => {17 //TODO: implementar18}1920const onUpdatePressed = async () => {21 //TODO: implementar22}Mostrar todouseEffectopens in a new tab: este es un hook de React que se llama después de que tu componente se renderiza. Debido a que se le pasa un prop de array vacío[](ver línea 4), solo se llamará en la primera renderización del componente. Aquí cargaremos el mensaje actual almacenado en nuestro contrato inteligente, llamaremos a nuestros oyentes de contrato inteligente y billetera, y actualizaremos nuestra IU para reflejar si ya hay una billetera conectada.addSmartContractListener: esta función configura un oyente que estará atento al eventoUpdatedMessagesde nuestro contrato HelloWorld y actualizará nuestra IU cuando el mensaje cambie en nuestro contrato inteligente.addWalletListener: esta función configura un oyente que detecta cambios en el estado de la billetera de MetaMask del usuario, como cuando el usuario desconecta su billetera o cambia de dirección.connectWalletPressed: esta función se llamará para conectar la billetera de MetaMask del usuario a nuestra dapp.onUpdatePressed: esta función se llamará cuando el usuario quiera actualizar el mensaje almacenado en el contrato inteligente.
Cerca del final de este archivo, tenemos la interfaz de usuario de nuestro componente.
1// HelloWorld.js23//la IU de nuestro componente4return (5 <div id="container">6 <img id="logo" src={alchemylogo}></img>7 <button id="walletButton" onClick={connectWalletPressed}>8 {walletAddress.length > 0 ? (9 "Conectado: " +10 String(walletAddress).substring(0, 6) +11 "..." +12 String(walletAddress).substring(38)13 ) : (14 <span>Conectar billetera</span>15 )}16 </button>1718 <h2 style={{ paddingTop: "50px" }}>Mensaje actual:</h2>19 <p>{message}</p>2021 <h2 style={{ paddingTop: "18px" }}>Nuevo mensaje:</h2>2223 <div>24 <input25 type="text"26 placeholder="Actualiza el mensaje en tu contrato inteligente."27 onChange={(e) => setNewMessage(e.target.value)}28 value={newMessage}29 />30 <p id="status">{status}</p>3132 <button id="publishButton" onClick={onUpdatePressed}>33 Actualizar34 </button>35</div>36 37</div>38)Mostrar todoSi examinas este código con atención, verás dónde usamos nuestras diversas variables de estado en nuestra IU:
- En las líneas 6-12, si la billetera del usuario está conectada (es decir,
walletAddress.length > 0), mostramos una versión truncada de lawalletAddressdel usuario en el botón con el ID «walletButton»; de lo contrario, simplemente dice «Conectar billetera». - En la línea 17, mostramos el mensaje actual almacenado en el contrato inteligente, que se captura en la cadena
message. - En las líneas 23-26, utilizamos un componente controladoopens in a new tab para actualizar nuestra variable de estado
newMessagecuando cambia la entrada en el campo de texto.
Además de nuestras variables de estado, también verás que las funciones connectWalletPressed y onUpdatePressed se llaman cuando se hace clic en los botones con los ID publishButton y walletButton respectivamente.
Por último, veamos dónde se añade este componente HelloWorld.js.
Si vas al archivo App.js, que es el componente principal en React que actúa como contenedor para todos los demás componentes, verás que nuestro componente HelloWorld.js se inyecta en la línea 7.
Por último, pero no por ello menos importante, echemos un vistazo a otro archivo que se te proporciona, el archivo interact.js.
El archivo interact.js
Como queremos seguir el paradigma M-V-Copens in a new tab, querremos un archivo separado que contenga todas nuestras funciones para gestionar la lógica, los datos y las reglas de nuestra dapp, y luego poder exportar esas funciones a nuestro frontend (nuestro componente HelloWorld.js).
👆🏽¡Este es el propósito exacto de nuestro archivo interact.js!
Navega a la carpeta util en tu directorio src, y notarás que hemos incluido un archivo llamado interact.js que contendrá todas nuestras funciones y variables de interacción con el contrato inteligente y la billetera.
1// interact.js23//export const helloWorldContract;45export const loadCurrentMessage = async () => {}67export const connectWallet = async () => {}89const getCurrentWalletConnected = async () => {}1011export const updateMessage = async (message) => {}Mostrar todoNotarás que en la parte superior del archivo hemos comentado el objeto helloWorldContract. Más adelante en este tutorial, descomentaremos este objeto e instanciaremos nuestro contrato inteligente en esta variable, que luego exportaremos a nuestro componente HelloWorld.js.
Las cuatro funciones no implementadas después de nuestro objeto helloWorldContract hacen lo siguiente:
loadCurrentMessage: esta función gestiona la lógica de cargar el mensaje actual almacenado en el contrato inteligente. Hará una llamada de lectura al contrato inteligente Hello World utilizando la API de Alchemy Web3opens in a new tab.connectWallet: esta función conectará el MetaMask del usuario a nuestra dapp.getCurrentWalletConnected: esta función comprobará si una cuenta de Ethereum ya está conectada a nuestra dapp al cargar la página y actualizará nuestra IU en consecuencia.updateMessage: esta función actualizará el mensaje almacenado en el contrato inteligente. Hará una llamada de escritura al contrato inteligente de Hello World, por lo que la billetera MetaMask del usuario tendrá que firmar una transacción de Ethereum para actualizar el mensaje.
Ahora que entendemos con qué estamos trabajando, ¡vamos a averiguar cómo leer de nuestro contrato inteligente!
Paso 3: Lee de tu contrato inteligente
Para leer de tu contrato inteligente, necesitarás configurar con éxito:
- Una conexión API a la cadena de Ethereum
- Una instancia cargada de tu contrato inteligente
- Una función para llamar a la función de tu contrato inteligente
- Un oyente para estar atento a las actualizaciones cuando cambien los datos que estás leyendo del contrato inteligente
Puede que parezcan muchos pasos, ¡pero no te preocupes! ¡Te guiaremos paso a paso sobre cómo hacer cada uno de ellos! :)
Establece una conexión API con la cadena de Ethereum
¿Recuerdas que en la Parte 2 de este tutorial, usamos nuestra clave de Alchemy Web3 para leer de nuestro contrato inteligenteopens in a new tab? También necesitarás una clave de Alchemy Web3 en tu dapp para leer de la cadena.
Si aún no lo tienes, primero instala Alchemy Web3opens in a new tab navegando al directorio raíz de tus starter-files y ejecutando lo siguiente en tu terminal:
1npm install @alch/alchemy-web3Alchemy Web3opens in a new tab es un envoltorio de Web3.jsopens in a new tab, que proporciona métodos de API mejorados y otros beneficios cruciales para facilitar su vida como desarrollador de web3. Se diseñó para requerir una configuración mínima, por lo que puede comenzar a usarla en su aplicación de inmediato.
Luego, instala el paquete dotenvopens in a new tab en tu directorio de proyecto, para que tengamos un lugar seguro donde almacenar nuestra clave de API después de obtenerla.
1npm install dotenv --savePara nuestra dapp, usaremos nuestra clave de API de Websockets en lugar de nuestra clave de API HTTP, ya que nos permitirá configurar un oyente que detecte cuándo cambia el mensaje almacenado en el contrato inteligente.
Una vez que tengas tu clave de API, crea un archivo .env en tu directorio raíz y añade tu URL de Alchemy Websockets. Después, tu archivo .env debería tener este aspecto:
1REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/<key>¡Ahora estamos listos para configurar nuestro punto de conexión de Alchemy Web3 en nuestra dapp! Volvamos a nuestro interact.js, que está anidado dentro de nuestra carpeta util y añadamos el siguiente código en la parte superior del archivo:
1// interact.js23require("dotenv").config()4const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY5const { createAlchemyWeb3 } = require("@alch/alchemy-web3")6const web3 = createAlchemyWeb3(alchemyKey)78//export const helloWorldContract;Arriba, primero importamos la clave de Alchemy desde nuestro archivo .env y luego pasamos nuestra alchemyKey a createAlchemyWeb3 para establecer nuestro punto de conexión de Alchemy Web3.
Con este punto de conexión listo, ¡es hora de cargar nuestro contrato inteligente!
Cargando tu contrato inteligente Hello World
Para cargar tu contrato inteligente Hello World, necesitarás su dirección de contrato y su ABI, los cuales se pueden encontrar en Etherscan si completaste la Parte 3 de este tutorial.
Cómo obtener el ABI de tu contrato desde Etherscan
Si te saltaste la Parte 3 de este tutorial, puedes usar el contrato HelloWorld con la dirección 0x6f3f635A9762B47954229Ea479b4541eAF402A6Aopens in a new tab. Su ABI se puede encontrar aquíopens in a new tab.
El ABI de un contrato es necesario para especificar qué función invocará un contrato, así como para garantizar que la función devuelva datos en el formato que esperas. Una vez que hayamos copiado el ABI de nuestro contrato, guardémoslo como un archivo JSON llamado contract-abi.json en tu directorio src.
Tu archivo contract-abi.json debe estar almacenado en tu carpeta src.
Armados con la dirección de nuestro contrato, el ABI y el punto de conexión de Alchemy Web3, podemos usar el método de contratoopens in a new tab para cargar una instancia de nuestro contrato inteligente. Importa el ABI de tu contrato en el archivo interact.js y añade la dirección de tu contrato.
1// interact.js23const contractABI = require("../contract-abi.json")4const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A"Ahora podemos finalmente descomentar nuestra variable helloWorldContract y cargar el contrato inteligente usando nuestro punto de conexión de AlchemyWeb3:
1// interact.js2export const helloWorldContract = new web3.eth.Contract(3 contractABI,4 contractAddress5)Para recapitular, las primeras 12 líneas de tu interact.js deberían tener este aspecto:
1// interact.js23require("dotenv").config()4const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY5const { createAlchemyWeb3 } = require("@alch/alchemy-web3")6const web3 = createAlchemyWeb3(alchemyKey)78const contractABI = require("../contract-abi.json")9const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A"1011export const helloWorldContract = new web3.eth.Contract(12 contractABI,13 contractAddress14)Mostrar todoAhora que tenemos nuestro contrato cargado, ¡podemos implementar nuestra función loadCurrentMessage!
Implementando loadCurrentMessage en tu archivo interact.js
Esta función es súper simple. Vamos a hacer una llamada asíncrona simple a web3 para leer de nuestro contrato. Nuestra función devolverá el mensaje almacenado en el contrato inteligente:
Actualiza loadCurrentMessage en tu archivo interact.js a lo siguiente:
1// interact.js23export const loadCurrentMessage = async () => {4 const message = await helloWorldContract.methods.message().call()5 return message6}Como queremos mostrar este contrato inteligente en nuestra IU, actualicemos la función useEffect en nuestro componente HelloWorld.js a lo siguiente:
1// HelloWorld.js23//llamado solo una vez4useEffect(async () => {5 const message = await loadCurrentMessage()6 setMessage(message)7}, [])Ten en cuenta que solo queremos que loadCurrentMessage se llame una vez durante la primera renderización del componente. Pronto implementaremos addSmartContractListener para actualizar automáticamente la IU después de que cambie el mensaje en el contrato inteligente.
Antes de profundizar en nuestro oyente, ¡veamos qué tenemos hasta ahora! Guarda tus archivos HelloWorld.js e interact.js, y luego ve a http://localhost:3000/opens in a new tab
Notarás que el mensaje actual ya no dice "Sin conexión a la red". En su lugar, refleja el mensaje almacenado en el contrato inteligente. ¡Genial!
Tu IU ahora debería reflejar el mensaje almacenado en el contrato inteligente
Ahora, hablando de ese oyente...
Implementa addSmartContractListener
Si recuerdas el archivo HelloWorld.sol que escribimos en la Parte 1 de esta serie de tutorialesopens in a new tab, recordarás que hay un evento de contrato inteligente llamado UpdatedMessages que se emite después de que se invoca la función update de nuestro contrato inteligente (ver líneas 9 y 27):
1// HelloWorld.sol23// Especifica la versión de Solidity, usando el control de versiones semántico.4// Aprende más: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma5pragma solidity ^0.7.3;67// Define un contrato llamado `HelloWorld`.8// Un contrato es una colección de funciones y datos (su estado). Una vez desplegado, un contrato reside en una dirección específica en la cadena de bloques de Ethereum. Aprende más: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 //Emitido cuando se llama a la función de actualización12 //Los eventos de contratos inteligentes son una forma para que su contrato comunique que algo sucedió en la cadena de bloques a su interfaz de aplicación, que puede estar 'escuchando' ciertos eventos y tomar medidas cuando suceden.13 event UpdatedMessages(string oldStr, string newStr);1415 // Declara una variable de estado `message` de tipo `string`.16 // Las variables de estado son variables cuyos valores se almacenan permanentemente en el almacenamiento del contrato. La palabra clave `public` hace que las variables sean accesibles desde fuera de un contrato y crea una función que otros contratos o clientes pueden llamar para acceder al valor.17 string public message;1819 // Al igual que muchos lenguajes orientados a objetos basados en clases, un constructor es una función especial que solo se ejecuta en la creación del contrato.20 // Los constructores se utilizan para inicializar los datos del contrato. Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) {2223 // Acepta un argumento de cadena `initMessage` y establece el valor en la variable de almacenamiento `message` del contrato).24 message = initMessage;25 }2627 // Una función pública que acepta un argumento de cadena y actualiza la variable de almacenamiento `message`.28 function update(string memory newMessage) public {29 string memory oldMsg = message;30 message = newMessage;31 emit UpdatedMessages(oldMsg, newMessage);32 }33}Mostrar todoLos eventos de contrato inteligente son una forma de que tu contrato comunique que algo ha sucedido (es decir, hubo un evento) en la cadena de bloques a tu aplicación de frontend, que puede estar 'escuchando' eventos específicos y tomar medidas cuando suceden.
La función addSmartContractListener va a escuchar específicamente el evento UpdatedMessages de nuestro contrato inteligente Hello World y actualizará nuestra IU para mostrar el nuevo mensaje.
Modifica addSmartContractListener a lo siguiente:
1// HelloWorld.js23function addSmartContractListener() {4 helloWorldContract.events.UpdatedMessages({}, (error, data) => {5 if (error) {6 setStatus("😥 " + error.message)7 } else {8 setMessage(data.returnValues[1])9 setNewMessage("")10 setStatus("🎉 ¡Tu mensaje ha sido actualizado!")11 }12 })13}Mostrar todoDesglosemos lo que sucede cuando el oyente detecta un evento:
- Si se produce un error cuando se emite el evento, se reflejará en la IU a través de nuestra variable de estado
status. - De lo contrario, usaremos el objeto
datadevuelto.data.returnValueses un array indexado en cero donde el primer elemento del array almacena el mensaje anterior y el segundo elemento almacena el actualizado. En conjunto, en un evento exitoso estableceremos nuestra cadenamessagecon el mensaje actualizado, borraremos la cadenanewMessagey actualizaremos nuestra variable de estadostatuspara reflejar que se ha publicado un nuevo mensaje en nuestro contrato inteligente.
Finalmente, llamemos a nuestro oyente en nuestra función useEffect para que se inicialice en la primera renderización del componente HelloWorld.js. En total, tu función useEffect debería tener este aspecto:
1// HelloWorld.js23useEffect(async () => {4 const message = await loadCurrentMessage()5 setMessage(message)6 addSmartContractListener()7}, [])Ahora que podemos leer de nuestro contrato inteligente, ¡sería genial descubrir cómo escribir en él también! Sin embargo, para escribir en nuestra dapp, primero debemos tener una billetera de Ethereum conectada a ella.
Entonces, a continuación, ¡abordaremos la configuración de nuestra billetera de Ethereum (MetaMask) y luego la conectaremos a nuestra dapp!
Paso 4: Configura tu billetera de Ethereum
Para escribir cualquier cosa en la cadena de Ethereum, los usuarios deben firmar transacciones usando las claves privadas de su billetera virtual. Para este tutorial, usaremos MetaMaskopens in a new tab, una billetera virtual en el navegador que se usa para gestionar la dirección de tu cuenta de Ethereum, ya que hace que la firma de esta transacción sea súper fácil para el usuario final.
Si quiere entender más sobre cómo funcionan las transacciones en Ethereum, consulte esta página de la Fundación Ethereum.
Descargar MetaMask
Puede descargar y crear una cuenta de MetaMask gratis aquíopens in a new tab. Cuando estés creando una cuenta, o si ya tienes una, asegúrate de cambiar a la «red de prueba de Goerli» en la parte superior derecha (para no estar manejando dinero real).
Añade ether desde un Faucet
Para firmar una transacción en la cadena de bloques de Ethereum, necesitaremos algo de ETH falso. Para obtener ETH, puedes ir a FaucETHopens in a new tab e introducir la dirección de tu cuenta de Goerli, hacer clic en «Request funds», luego seleccionar «Ethereum Testnet Goerli» en el menú desplegable y finalmente hacer clic en el botón «Request funds» de nuevo. Debería ver el Eth en su cuenta de MetaMask poco después.
Comprueba tu saldo
Para comprobar que nuestro saldo está ahí, hagamos una solicitud eth_getBalanceopens in a new tab utilizando la herramienta de composición de Alchemyopens in a new tab. Esto devolverá la cantidad de Eth en nuestra billetera. Después de introducir la dirección de su cuenta de Metamask y hacer clic en «Send Request», debería ver una respuesta como esta:
1{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}NOTA: Este resultado es en wei, no en eth. Wei se usa como la denominación más pequeña de Ether. La conversión de wei a eth es: 1 eth = 10¹⁸ wei. Entonces si convertimos 0xde0b6b3a7640000 a decimal, obtenemos 1*10¹⁸, que equivale a 1 eth.
¡Fiu! Nuestro dinero de prueba está ahí sin problemas. 🤑
Paso 5: Conecta MetaMask a tu IU
Ahora que nuestra billetera de MetaMask está configurada, vamos a conectar nuestra dapp a ella.
La función connectWallet
En nuestro archivo interact.js, implementemos la función connectWallet, que luego podremos llamar en nuestro componente HelloWorld.js.
Modifiquemos connectWallet a lo siguiente:
1// interact.js23export const connectWallet = async () => {4 if (window.ethereum) {5 try {6 const addressArray = await window.ethereum.request({7 method: "eth_requestAccounts",8 })9 const obj = {10 status: "👆🏽 Escribe un mensaje en el campo de texto de arriba.",11 address: addressArray[0],12 }13 return obj14 } catch (err) {15 return {16 address: "",17 status: "😥 " + err.message,18 }19 }20 } else {21 return {22 address: "",23 status: (24 <span>25 <p>26 {" "}27 🦊 <a target="_blank" href={`https://metamask.io/download`}>28 Debes instalar MetaMask, una billetera virtual de Ethereum, en tu29 navegador.30 </a>31 </p>32 </span>33 ),34 }35 }36}Mostrar todoEntonces, ¿qué hace exactamente este bloque de código gigante?
Bueno, primero, comprueba si window.ethereum está habilitado en tu navegador.
window.ethereum es una API global inyectada por MetaMask y otros proveedores de monederos que permite a los sitios web solicitar las cuentas de Ethereum de los usuarios. Si se aprueba, puede leer datos de las cadenas de bloques a las que el usuario está conectado y sugerir que el usuario firme mensajes y transacciones. ¡Consulte los documentos de MetaMaskopens in a new tab para obtener más información!
Si window.ethereum no está presente, significa que MetaMask no está instalado. Esto da como resultado la devolución de un objeto JSON, donde la address devuelta es una cadena vacía, y el objeto JSX status transmite que el usuario debe instalar MetaMask.
Ahora, si window.ethereum está presente, es cuando las cosas se ponen interesantes.
Usando un bucle try/catch, intentaremos conectarnos a MetaMask llamando a window.ethereum.request({ method: "eth_requestAccounts" });opens in a new tab. La invocación de esta función abrirá MetaMask en el navegador, donde se le solicitará al usuario conectar su billetera a su dapp.
- Si el usuario elige conectarse,
method: "eth_requestAccounts"devolverá un array que contiene todas las direcciones de cuenta del usuario que se conectaron a la dapp. En conjunto, nuestra funciónconnectWalletdevolverá un objeto JSON que contiene la primeraaddressde esta matriz (consulte la línea 9) y un mensaje destatusque solicita al usuario que escriba un mensaje en el smart contract. - Si el usuario rechaza la conexión, el objeto JSON contendrá una cadena vacía para la
addressdevuelta y un mensaje destatusque reflejará que el usuario ha rechazado la conexión.
Ahora que hemos escrito esta función connectWallet, el siguiente paso es llamarla en nuestro componente HelloWorld.js.
Añade la función connectWallet a tu componente de IU HelloWorld.js
Navega a la función connectWalletPressed en HelloWorld.js y actualízala a lo siguiente:
1// HelloWorld.js23const connectWalletPressed = async () => {4 const walletResponse = await connectWallet()5 setStatus(walletResponse.status)6 setWallet(walletResponse.address)7}¿Te das cuenta de cómo la mayor parte de nuestra funcionalidad se abstrae de nuestro componente HelloWorld.js desde el archivo interact.js? ¡Esto es así para cumplir con el paradigma M-V-C!
En connectWalletPressed, simplemente hacemos una llamada await a nuestra función connectWallet importada y, usando su respuesta, actualizamos nuestras variables status y walletAddress a través de sus state hooks.
Ahora, guardemos ambos archivos (HelloWorld.js e interact.js) y probemos nuestra IU hasta ahora.
Abre tu navegador en la página http://localhost:3000/opens in a new tab y presiona el botón «Conectar billetera» en la parte superior derecha de la página.
Si tiene MetaMask instalado, se le debería solicitar conectar su billetera a su dapp. Acepte la invitación para establecer la conexión.
¡Deberías ver que el botón de la billetera ahora refleja que tu dirección está conectada! ¡Síííí! 🔥
A continuación, intente refrescar la página... esto es extraño. Nuestro botón de billetera nos está solicitando conectar MetaMask, aunque ya está conectado...
Sin embargo, ¡no temas! Podemos solucionarlo fácilmente (¿lo pillas?). ¡implementando getCurrentWalletConnected, que comprobará si una dirección ya está conectada a nuestra dapp y actualizará nuestra IU en consecuencia!
La función getCurrentWalletConnected
Actualiza tu función getCurrentWalletConnected en el archivo interact.js a lo siguiente:
1// interact.js23export const getCurrentWalletConnected = async () => {4 if (window.ethereum) {5 try {6 const addressArray = await window.ethereum.request({7 method: "eth_accounts",8 })9 if (addressArray.length > 0) {10 return {11 address: addressArray[0],12 status: "👆🏽 Escribe un mensaje en el campo de texto de arriba.",13 }14 } else {15 return {16 address: "",17 status: "🦊 Conéctate a MetaMask usando el botón de la esquina superior derecha.",18 }19 }20 } catch (err) {21 return {22 address: "",23 status: "😥 " + err.message,24 }25 }26 } else {27 return {28 address: "",29 status: (30 <span>31 <p>32 {" "}33 🦊 <a target="_blank" href={`https://metamask.io/download`}>34 Debes instalar MetaMask, una billetera virtual de Ethereum, en tu35 navegador.36 </a>37 </p>38 </span>39 ),40 }41 }42}Mostrar todoEste código es muy similar a la función connectWallet que acabamos de escribir en el paso anterior.
La principal diferencia es que, en lugar de llamar al método eth_requestAccounts, que abre MetaMask para que el usuario conecte su monedero, aquí llamamos al método eth_accounts, que simplemente devuelve un array con las direcciones de MetaMask actualmente conectadas a nuestra dapp.
Para ver esta función en acción, llamémosla en nuestra función useEffect de nuestro componente HelloWorld.js:
1// HelloWorld.js23useEffect(async () => {4 const message = await loadCurrentMessage()5 setMessage(message)6 addSmartContractListener()78 const { address, status } = await getCurrentWalletConnected()9 setWallet(address)10 setStatus(status)11}, [])Mostrar todoObserve que utilizamos la respuesta de nuestra llamada a getCurrentWalletConnected para actualizar nuestras variables de estado walletAddress y status.
Ahora que has añadido este código, intentemos refrescar la ventana de nuestro navegador.
¡Geniaaaal! El botón debería decir que está conectado y mostrar una vista previa de la dirección de su billetera conectada, incluso después de actualizar la página.
Implementa addWalletListener
El último paso en la configuración de la billetera de dapp es implementar el oyente de billetera para que nuestra interfaz se actualice cuando el estado de la billetera cambie, por ejemplo, cuando el usuario se desconecte o cambie de cuenta.
En tu archivo HelloWorld.js, modifica tu función addWalletListener de la siguiente manera:
1// HelloWorld.js23function addWalletListener() {4 if (window.ethereum) {5 window.ethereum.on("accountsChanged", (accounts) => {6 if (accounts.length > 0) {7 setWallet(accounts[0])8 setStatus("👆🏽 Escribe un mensaje en el campo de texto de arriba.")9 } else {10 setWallet("")11 setStatus("🦊 Conéctate a MetaMask usando el botón de la esquina superior derecha.")12 }13 })14 } else {15 setStatus(16 <p>17 {" "}18 🦊 <a target="_blank" href={`https://metamask.io/download`}>19 Debes instalar MetaMask, una billetera virtual de Ethereum, en tu navegador.20 </a>21 </p>22 )23 }24}Mostrar todoApuesto a que a estas alturas ya no necesitas nuestra ayuda para entender lo que está pasando, pero para ser exhaustivos, vamos a desglosarlo rápidamente:
- Primero, nuestra función comprueba si
window.ethereumestá habilitado (es decir, si MetaMask está instalado).- Si no lo está, simplemente establecemos nuestra variable de estado
statusen una cadena JSX que pide al usuario que instale MetaMask. - Si está habilitado, configuramos el detector
window.ethereum.on("accountsChanged")en la línea 3 que escucha los cambios de estado en el monedero de MetaMask, que incluyen cuándo el usuario conecta una cuenta adicional a la dapp, cambia de cuenta o desconecta una cuenta. Si hay al menos una cuenta conectada, la variable de estadowalletAddressse actualiza como la primera cuenta del arrayaccountsdevuelto por el detector. De lo contrario,walletAddressse establece como una cadena vacía.
- Si no lo está, simplemente establecemos nuestra variable de estado
Por último, pero no por ello menos importante, debemos llamarla en nuestra función useEffect:
1// HelloWorld.js23useEffect(async () => {4 const message = await loadCurrentMessage()5 setMessage(message)6 addSmartContractListener()78 const { address, status } = await getCurrentWalletConnected()9 setWallet(address)10 setStatus(status)1112 addWalletListener()13}, [])Mostrar todo¡Y eso es todo! ¡Hemos completado con éxito la programación de toda la funcionalidad de nuestra billetera! ¡Ahora a nuestra última tarea: actualizar el mensaje almacenado en nuestro contrato inteligente!
Paso 6: Implementa la función updateMessage
¡Muy bien, amigos, hemos llegado a la recta final! En updateMessage de tu archivo interact.js, vamos a hacer lo siguiente:
- Asegurarnos de que el mensaje que deseamos publicar en nuestro contrato inteligente es válido
- Firmar nuestra transacción usando MetaMask
- Llamar a esta función desde nuestro componente de frontend
HelloWorld.js
Esto no llevará mucho tiempo; ¡terminemos esta dapp!
Manejo de errores de entrada
Naturalmente, tiene sentido tener algún tipo de manejo de errores de entrada al inicio de la función.
Querremos que nuestra función devuelva un valor de forma temprana si no hay ninguna extensión de MetaMask instalada, no hay ninguna billetera conectada (es decir, la address pasada es una cadena vacía), o el message es una cadena vacía. Añadamos el siguiente manejo de errores a updateMessage:
1// interact.js23export const updateMessage = async (address, message) => {4 if (!window.ethereum || address === null) {5 return {6 status:7 "💡 Conecta tu billetera de MetaMask para actualizar el mensaje en la cadena de bloques.",8 }9 }1011 if (message.trim() === "") {12 return {13 status: "❌ Tu mensaje no puede ser una cadena vacía.",14 }15 }16}Mostrar todoAhora que tiene un manejo de errores de entrada adecuado, ¡es hora de firmar la transacción a través de MetaMask!
Firmando nuestra transacción
Si ya te sientes cómodo con las transacciones tradicionales de web3 en Ethereum, el código que escribiremos a continuación te resultará muy familiar. Debajo de tu código de manejo de errores de entrada, añade lo siguiente a updateMessage:
1// interact.js23//configurar parámetros de transacción4const transactionParameters = {5 to: contractAddress, // Obligatorio excepto durante la publicación de contratos.6 from: address, // debe coincidir con la dirección activa del usuario.7 data: helloWorldContract.methods.update(message).encodeABI(),8}910//firmar la transacción11try {12 const txHash = await window.ethereum.request({13 method: "eth_sendTransaction",14 params: [transactionParameters],15 })16 return {17 status: (18 <span>19 ✅{" "}20 <a target="_blank" href={`https://goerli.etherscan.io/tx/${txHash}`}>21 ¡Consulta el estado de tu transacción en Etherscan!22 </a>23 <br />24 ℹ️ Una vez que la red verifique la transacción, el mensaje se actualizará automáticamente.25 </span>26 ),27 }28} catch (error) {29 return {30 status: "😥 " + error.message,31 }32}Mostrar todoDesglosemos lo que está sucediendo. Primero, configuramos nuestros parámetros de transacción, donde:
toespecifica la dirección del destinatario (nuestro smart contract)fromespecifica el firmante de la transacción, la variableaddressque pasamos a nuestra funcióndatacontiene la llamada al métodoupdatede nuestro contrato inteligente Hello World, recibiendo como entrada nuestra variable de cadenamessage
Luego, hacemos una llamada await, window.ethereum.request, donde le pedimos a MetaMask que firme la transacción. Fíjate, en las líneas 11 y 12, estamos especificando nuestro método eth, eth_sendTransaction, y pasando nuestros transactionParameters.
En este punto, MetaMask se abrirá en el navegador y solicitará al usuario firmar o rechazar la transacción.
- Si la transacción es exitosa, la función devolverá un objeto JSON donde la cadena JSX
statusle indica al usuario que consulte Etherscan para obtener más información sobre su transacción. - Si la transacción falla, la función devolverá un objeto JSON donde la cadena
statustransmite el mensaje de error.
En conjunto, nuestra función updateMessage debería tener este aspecto:
1// interact.js23export const updateMessage = async (address, message) => {4 //manejo de errores de entrada5 if (!window.ethereum || address === null) {6 return {7 status:8 "💡 Conecta tu billetera de MetaMask para actualizar el mensaje en la cadena de bloques.",9 }10 }1112 if (message.trim() === "") {13 return {14 status: "❌ Tu mensaje no puede ser una cadena vacía.",15 }16 }1718 //configurar parámetros de transacción19 const transactionParameters = {20 to: contractAddress, // Obligatorio excepto durante la publicación de contratos.21 from: address, // debe coincidir con la dirección activa del usuario.22 data: helloWorldContract.methods.update(message).encodeABI(),23 }2425 //firmar la transacción26 try {27 const txHash = await window.ethereum.request({28 method: "eth_sendTransaction",29 params: [transactionParameters],30 })31 return {32 status: (33 <span>34 ✅{" "}35 <a target="_blank" href={`https://goerli.etherscan.io/tx/${txHash}`}>36 ¡Consulta el estado de tu transacción en Etherscan!37 </a>38 <br />39 ℹ️ Una vez que la red verifique la transacción, el mensaje se40 actualizará automáticamente.41 </span>42 ),43 }44 } catch (error) {45 return {46 status: "😥 " + error.message,47 }48 }49}Mostrar todoPor último, pero no menos importante, necesitamos conectar nuestra función updateMessage a nuestro componente HelloWorld.js.
Conecta updateMessage al frontend de HelloWorld.js
Nuestra función onUpdatePressed debería hacer una llamada await a la función importada updateMessage y modificar la variable de estado status para reflejar si nuestra transacción tuvo éxito o falló:
1// HelloWorld.js23const onUpdatePressed = async () => {4 const { status } = await updateMessage(walletAddress, newMessage)5 setStatus(status)6}Es súper limpio y simple. Y adivina qué... ¡¡¡TU DAPP ESTÁ COMPLETA!!!
¡Adelante, prueba el botón Actualizar!
Crea tu propia dapp personalizada
¡Woooo, llegaste al final del tutorial! Para recapitular, aprendiste a:
- Conectar una billetera MetaMask a tu proyecto de dapp
- Leer datos de su contrato inteligente usando la API de Alchemy Web3opens in a new tab
- Firmar transacciones de Ethereum usando MetaMask.
¡Ahora estás totalmente equipado para aplicar las habilidades de este tutorial para construir tu propio proyecto de dapp personalizado! Como siempre, si tienes alguna pregunta, no dudes en contactarnos para obtener ayuda en el Discord de Alchemyopens in a new tab. 🧙♂️
Cuando finalice este tutorial, cuéntenos cómo fue su experiencia o comparta algún comentario etiquetándonos en Twitter @alchemyplatformopens in a new tab.
Última actualización de la página: 5 de diciembre de 2025





