# Web3: Creando tu primer App Descentralizada

By [D3Portillo](https://paragraph.com/@d3portillo) · 2022-09-15

---

El hype por las Aplicaciones Descentralizadas(DApps) no para. Esto genera que muchos desarrolladores tengan la necesidad de experimentar este maravilloso mundo llamado _Web3_.

Todo sobre la Web3 suena maravilloso hasta que, buscas un tutorial, y el resultado es completa desesperación, una alarma a 30 minutos de sonar y mucho café con _Korn_ a todo volumen.

Puedes tomar el texto anterior como un relato personal. El ecosistema Web3 es muy cambiante e involucra mucha adaptación. Despiertas un lunes por la mañana y descubres que se han lanzado docenas librerías, conceptos nuevos que estudiar, Tokens, The Merge`(1)`, y personas tirando hate en Twitter porque **Solana** no sube a $40 USD.

En resumen, Web3 puede generar muchísimo FOMO`(2)` sin importar la experiencia que tengas como desarrollador, tu background profesional, y mucho menos seniority.

Dando finiquito a la introducción anterior. A continuación podrás leer una guía detallada y elaborada con cariño para todos los interesados en adentrarse a este mundo. Tú puedes, no estás sólo en esto 🤗.

¿Qué demonios es Web3?
----------------------

![Lain del Anime "Serial Experiments Lain" intentando conectarse a “The Wired". Imágen de https://sabukaru.online/articles/serial-experiments-lain-coding-for-divinity](https://storage.googleapis.com/papyrus_images/9b8699b3a05477703de0af070b8250d13a5e8d2d1813c4d6bf704e8464b4bbe1.png)

Lain del Anime "Serial Experiments Lain" intentando conectarse a “The Wired". Imágen de https://sabukaru.online/articles/serial-experiments-lain-coding-for-divinity

Al inicio de los tiempos _dios_ creó la Web 1.0, sitios estáticos, contenido estático, y mucho texto con hipervínculos a más contenido estático.

La Web 2.0 es la Web que todos conocemos y consumimos. Esa popular y llena de memes “Internet”. Contenido dinámico y aplicaciones para consumir servicios, productos o interactuar con tus amigos de Facebook y Discord.

**Web 3.0** es un concepto de descentralización de estos servicios, productos y aplicaciones. Un lugar dónde no existen intermediarios, y mucho menos empresas que se alimenten de tu información.

Ethereum Network
----------------

Ethereum`(3)` es una red de computadores o _“nodos”_ distribuidos globalmente\*.\*

Cada nodo en esta red comparte una réplica o “estado” de la información disponible en la red. Este _“estado”_ es definido por un cómputo único llamado **_“Ethereum Virtual Machine”_** `(4)`**_._**

En Ethereum, cada nodo es partícipe en un consenso para cada evento que intente _modificar_ el “estado” de la EVM. Ya que esto requiere poder de cómputo, a los nodos participantes se les aporta ETH(Ether) como incentivo.

> Podemos imaginar “Ethereum” como una gigantesca “Máquina de estados finitos” (Finite State Machine ó FSM) `(5)`.

Con la EVM podemos manipular/condicionar el estado de la red usando _“Contratos Inteligentes” (Smart Contracts)_.

> **IMPORTANTE**: Para la fecha de lanzamiento de esta guía, Ethereum migró de [Proof of Work](https://ethereum.org/en/developers/docs/consensus-mechanisms/pow/) a [Proof of Stake](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/), [https://vitalik.ca/general/2017/12/31/pos\_faq.html](https://vitalik.ca/general/2017/12/31/pos_faq.html)

Smart Contracts y Sistemas Distribuidos
---------------------------------------

Los _“Smart Contracts”_ son programas/herramientas para acceder a la EVM, con ellos podemos leer, actualizar y escribir información a la red Ethereum.

En pocas palabras los desarrolladores tienen la posibilidad de crear aplicaciones _“Semi-Turing Complete”_ usando lenguajes como Vyper y Solidity.

Solidity y Vyper son lenguajes de alto nivel para desarrollar Smart Contracts en la EVM. Usamos estos lenguajes porque la EVM sólo comprende _“EVM Bytecode”_ `(6)`_._

![Ejemplo de cómputo distribuido en una red global, en esta red, cada nodo comparte información entre sí y en tiempo real. Los sistemas distribuidos se caracterizan por la alta disponibilidad de información, ya que la malfunción de uno de estos nodos no afectará en la distribución de información de dicha red. Si quieres saber más del tema, recomiendo leer "Falacias de los Sistemas Distribuidos", https://architecturenotes.co/fallacies-of-distributed-systems ](https://storage.googleapis.com/papyrus_images/6e0aa813e6fe02ff02384d783fe228f53b8798afe0a944bac7cf3e1e06e5fbb8.png)

Ejemplo de cómputo distribuido en una red global, en esta red, cada nodo comparte información entre sí y en tiempo real. Los sistemas distribuidos se caracterizan por la alta disponibilidad de información, ya que la malfunción de uno de estos nodos no afectará en la distribución de información de dicha red. Si quieres saber más del tema, recomiendo leer "Falacias de los Sistemas Distribuidos", https://architecturenotes.co/fallacies-of-distributed-systems

Talk is cheap. Show me the code
-------------------------------

Antes de iniciar a tirar código debes considerar la siguiente lista de elementos necesarios para esta guía:

1.  Firefox o Chrome e instalar la extensión de [Metamask](https://metamask.io/download/)
    
2.  Se recomienda crear una cuenta en Metamask sólamente para pruebas
    
3.  Visual Studio Code o un Editor de texto
    
4.  Si usas Windows tener WSL (_Windows Subsystem for Linux_) configurado
    
5.  NodeJS (Versión >= 16. Puedes usar [_nvm_](https://github.com/nvm-sh/nvm) para una instalación sencilla)
    
6.  Crear una cuenta en [Alchemy](https://auth.alchemyapi.io). Lo usaremos para lanzar nuestro Smart Contract en Goerli Testnet.
    

Si usas Visual Studio Code puedes instalar estos plugins:

*   [Solidity Visual Developer](https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor)
    
*   [Solidity + Hardhat](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity)
    

Stack de Desarrollo
-------------------

*   **NextJs:** Un framework de React muy popular que se vende como _“El Framework de React para producción”_. Personalmente es mi favorito del Ecosistema React y me agrada que sea de los más usados en Web3.
    
*   **Wagmi:** Colección de _React hooks_ con lo requerido para trabajar con Ethereum. Peticiones, conectividad, interacción con Smart Contracts, firmas — TODO `(7)`.
    
*   **RainbowKit:** Conectividad sencilla para React Devs. Un proyecto de los creadores de Rainbow Wallet.
    
*   **TailwindCSS:** Un framework de utilidad que expone una set de configuración consistente la cúal agiliza el desarrollo de componentes personalizados.
    
*   **Alchemy:** RPC Provider`(8)`. Plataforma que nos hace la vida sencilla para la arquitectura de DApps. Sus clientes incluyen, OpenSea, Chainlink y Meta. **NOTA:** Existen 2 plataformas similares e igual de populares que Alchemy, hablamos de _Moralis_ e _Infura_ `(9)`.
    
*   **Hardhat:** Entorno de desarrollo para Ethereum. Smart Contracts, Testing, Depuración y Tooling para Solidity.
    
*   Por último, pero no menos importante, **Typescript**.
    

Cuéntame, ¿ Qué vamos a crear ?
-------------------------------

Sí, ya sé que tu café se está enfriando, rellenalo que ahora entramos al objetivo de este documento; crear un pequeño proyecto, que lo extiendas y juegues con él mientras nos movemos en el Stack más popular para crear DApps. Y que por cierto, luego puedes incluir en tu portafolio ☺️.

La idea final es desarrollar un **“Libro de Notas”**.

Proyecto _“sencillo”_ de codear para la Web2, pero que aportará mucho jugar con él en un enfoque Web3. _¿ Por qué ?_ , tanto desarrollar la  interfaz, creación e integración del Smart Contract con Solidity requieren una atención/investigación muy similar, y así cualquier desarrollador puede aprovechar este documento 💛.

Al terminar aprenderemos cómo consumir información de Goerli, pintar esta información en un frontend y crear un Smart Contract que gestione este contenido :)

Crear este _“GuestBook en Ethereum”_ estará dividido en 5 etapas, y una etapa completamente opcional. Estas son:

1.  **Genesis:** RainbowKit y NextJS
    
2.  **Hardhat:** Solidity Hello World
    
3.  **Goerli Testnet:** Distribuyendo nuestro Smart Contract
    
4.  **Solidity Cardio:** Eventos, Funciones y Variables de estado
    
5.  **Wagmi React:** Interacción con el Frontend y finalización
    
6.  Opcional, **Plus Ultra:** Lanzando nuestra DApp en Vercel
    

Iniciamos,

Genesis: RainbowKit y NextJS
----------------------------

Primero necesitamos un proyecto **_NextJs_**, agregar **_RainbowKit_** y **_Wagmi_** como dependencias a este proyecto. El equipo de RainbowKit ya nos expone un comando para crear el boilerplate e incluir estas dependencias. Ejecutamos:

    npm init @rainbow-me/rainbowkit@latest -y kort
    

Puedes cambiar el argumento `”kort”` con el texto que gustes, este será el nombre de nuestro proyecto.

Ya creado nuestro proyecto, nos ubicamos en el directorio creado. Si dejaste como nombre de proyecto `“kort”`, haz `cd kort` y ejecutas `npm run dev`.

Hacer `npm run dev` lanza un servidor de desarrollo en NextJs, este refrescará el contenido servido cada vez que hagamos cambios en el árbol de archivos de nuestro espacio de trabajo.

Si visitamos nuestro local en [http://localhost:3000](http://localhost:3000) veremos este Frontend:

![La imágen muestra la página inicial de NextJS y RainbowKit en modo desarrollo. Se visualiza un widget de conexión a distintas redes  enlaces a documentación de RainbowKit, Wagmi y NextJs.](https://storage.googleapis.com/papyrus_images/74067761524fbba1ef4f810e0ac172d862af99a537dee1d2e1dad54d4827d6f2.png)

La imágen muestra la página inicial de NextJS y RainbowKit en modo desarrollo. Se visualiza un widget de conexión a distintas redes enlaces a documentación de RainbowKit, Wagmi y NextJs.

Podemos conectarnos con una Wallet en este frontend…, pero sólamente a redes Mainnet`(10)`, nosotros queremos, por pruebas, conectarnos a una Testnet, **_Goerli_**.

Si visualizas el contenido en `pages/_app.tsx` y te ubicas en la línea #15 verás esto:

    15  ...(process.env.NEXT_PUBLIC_ENABLE_TESTNETS === 'true'
    

La línea #15 evalúa que el valor de la “Variable de Entorno `(11)`” `NEXT_PUBLIC_ENABLE_TESTNETS` tiene como contenido `“true”`, esta bandera define si permitimos _Testnets_ en nuestro proyecto.

Para habilitarlas vamos a crear un archivo que tenga las variables de entorno para usar en nuestro proyecto. Ejecutamos:

    echo "NEXT_PUBLIC_ENABLE_TESTNETS=true" > .env
    

Se creará un archivo `.env` con el contenido `NEXT_PUBLIC_ENABLE_TESTNETS=true`

Para cargar las definiciones del archivo `.env` a nuestro proyecto, cerramos el proceso dónde hicimos `npm run dev` al comienzo de la guía, _matando el proceso_ con `CTRL + C`, luego ejecutamos `npm run dev` por una vez más. Hacemos esto porque las definiciones en el archivo `.env` se cargan en el arranque del servidor de desarrollo.

Y listo, ahora podemos conectarnos a Goerli Testnet con RainbowKit.

![La imágen muestra un ejemplo de cuenta enlazada con RainbowKit en Goerli Testnet. Además se visualiza un widget de información de la cuenta con acciones para COPIAR y DESCONECTAR dicha cuenta enlazada.](https://storage.googleapis.com/papyrus_images/2793dbf6c99200ce6488d3433d32d38e56d3b4119d67f7b12680c31ed78b1f97.png)

La imágen muestra un ejemplo de cuenta enlazada con RainbowKit en Goerli Testnet. Además se visualiza un widget de información de la cuenta con acciones para COPIAR y DESCONECTAR dicha cuenta enlazada.

¡Felicidades!, acabamos de enlazar Metamask con el Frontend de `“kort”`.

* * *

Continuemos,

    pages/
    |-- _app.tsx
    |-- index.tsx
    .env
    package.json
    

Del árbol de archivos en nuestro proyecto nos enfocamos en cuatro elementos.

1.  `page/index.tsx` define la ruta inicial de nuestra DApp, el `index.html`.
    
2.  `_app.tsx` es un archivo reservado de NextJs para personalizar las páginas dentro de `/pages`.
    
3.  `.env` archivo para configurar Variables de entorno y configuración definida por el desarrollador. **NOTA:** No agregues este archivo en tu repositorio, los _.env files_ guardan información privada de nuestros proyectos.
    
4.  `package.json` contiene metadatos y configuración para NodeJs. Acá se definen las [dependencias, scripts y mucho más](https://docs.npmjs.com/cli/v8/configuring-npm/package-json).
    

NextJs tiene el concepto de `“fichero dentro de /pages”` = `“una página”`. Estas _“páginas”_ son por defecto un componente React.

> A este concepto de enrutamiento `“directorio”` → `“fichero template”`, se le conoce como [File based routing system](https://nextjs.org/docs/routing/introduction).

### La configuración de RainbowKit

Con `_app.tsx` podemos modificar cada página del proyecto, agregar estado persistente, layouts compartidas, y más. Es acá dónde inicializamos RainbowKit.

    07  // _app.tsx
    08
    09  const { chains, provider, webSocketProvider } = configureChains(
    10    [chain.mainnet, chain.polygon, chain.optimism],
    11    [
    12      alchemyProvider({
    13        // Obten tu APIKey en https://dashboard.alchemyapi.io
    14      }),
    15      publicProvider(),
    16    ]
    17  )
    18
    

La línea #10 define las redes en las que funcionará nuestra DApp. Cada elemento en este arreglo contiene el `id` de la red, nombre, URLs de conexión RPC y URLs para los [Exploradores de bloques](https://www.criptonoticias.com/criptopedia/anatomia-exploradores-blockchain-cadena-bloques/) de la red.

Líneas #11 y #15 definen los proveedores(`providers`) de la red Ethereum. En el fragmento se usa Alchemy como proveedor RPC inicial para las redes configuradas la línea #10.

`publicProvider` será un Fallback si en una red específica(Ejemplo si el usuario cambia [Gnosis](https://chainlist.org/chain/100)) dicho `provider` no está disponible. Tener en cuenta que `publicProvider` intentará interactuar con Ethereum Mainnet.

> Llamamos `provider` a una abstracción consistente para una red. Básicamente es un cliente con una API estándar para interactuar con la chain.

    24  const wagmiClient = createClient({
    25    autoConnect: true,
    26    connectors,
    27    provider,
    28    webSocketProvider,
    29  })
    

### Configurando Wagmi

RainbowKit es una herramienta para conexión, su funcionalidad vive gracias a Wagmi y sus [React Hooks](https://reactjs.org/docs/hooks-intro.html). Ver más información para configurar Wagmi acá: [https://wagmi.sh/docs/client](https://wagmi.sh/docs/client#configuration)

**Configurando #createClient**

*   `autoConnect: true` indica que Wagmi puede(por defecto) tomar la última Wallet enlazada a nuestro Frontend.
    
*   `connectors` configuración de proveedores de Wallets de nuestra DApp. Por defecto son Metamask, Coinbase, Rainbow Wallet y WalletConnect.
    
*   `provider` es el cliente obtenido de ejecutar `configureChains` en el fragmento de la Línea #9.
    
*   `webSocketProvider` si la ejecución de `configureChains` resuelve con un cliente WebSockets, Wagmi realizará la conexión por WebSockets en vez de HTTP.
    

![Yaaay, Felicidades. Estamos listos para la siguiente etapa.](https://storage.googleapis.com/papyrus_images/136f5036359e0aecfbf4e5cb65d3de330dd559b8dc6bddf8c2d871e90c70809d.gif)

Yaaay, Felicidades. Estamos listos para la siguiente etapa.

Hardhat: Solidity Hello World
-----------------------------

Ahora, vamos a crear nuestro primer **Smart Contract** 😍.

> **NOTA:** Esta guía es para desarrollar Smart Contracts con Solidity y Hardhat como entorno de desarrollo. Existe un editor llamado [Remix](https://remix.ethereum.org/), dónde puedes probar cositas en la EVM antes de moverlas a tu codebase.

Primero, dependencias. Hardhat y [hardhat-toolbox](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox),

    npm i -D hardhat @nomicfoundation/hardhat-toolbox
    

Ahora necesitamos un [archivo de configuración para Hardhat](https://hardhat.org/hardhat-runner/docs/config#available-config-options). En la raíz de nuestro proyecto creamos el archivo `hardhat.config.ts` y pegamos esto:

    // hardhat.config.ts
    import { HardhatUserConfig } from "hardhat/config"
    import "@nomicfoundation/hardhat-toolbox"
    
    const config: HardhatUserConfig = {
      solidity: "0.8.9",
    }
    
    export default config
    

### Tu primer Smart Contract

Para tener más ordenado nuestro código y seguir la convención de archivos en hardhat, vamos a crear una carpeta dónde vivirán nuestros Smart Contracts y otra para definir scripts/tareas que consumen estos Smart Contracts.

En consola, `mkdir contracts scripts`.

Creadas las carpetas, dentro de `contracts/` creamos un archivo llamado `HolaMundo.sol` y pegamos el siguiente contenido:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.9;
    
    contract HolaMundo {
        string hola = "Hola";
        string mundo = "Mundo!!";
    
        function saludar() external view returns (string memory) {
            return string(abi.encodePacked(hola, " ", mundo));
        }
    }
    

### Ejecutando HolaMundo.sol

Dentro de `scripts/` creamos un archivo `deploy.ts` y pegaremos el siguiente contenido:

    import { ethers } from "hardhat"
    
    async function main() {
      const factory = await ethers.getContractFactory("HolaMundo")
      const contract = await factory.deploy()
      await contract.deployed()
      console.log(await contract.saludar())
    }
    
    main().catch((error) => {
      console.error(error)
      process.exitCode = 1
    })
    

Para ejecutar este script, hacemos:

    npx hardhat run scripts/deploy.ts
    

Esto distribuye en local el Smart Contract `“HolaMundo.sol”` usando la [Hardhat Network](https://hardhat.org/hardhat-network/docs/overview#hardhat-network).

* * *

![En la imágen podemos observar un error por una mala configuración en tsconfig.json. Para solventarlo se modifica la configuración de "module" en tsconfig.json a "commonjs".](https://storage.googleapis.com/papyrus_images/b9e1092b3818f753fbbaffc17dd5217a24b2d4ec1bd7cb48fe1f1c197e478b58.png)

En la imágen podemos observar un error por una mala configuración en tsconfig.json. Para solventarlo se modifica la configuración de "module" en tsconfig.json a "commonjs".

Si visualizas este error, tranquilidad. NextJs ha definido que nuestro proyecto será un módulo `“esnext”` para poder hacer [imports dinámicos](https://nextjs.org/docs/advanced-features/dynamic-import), causando este error. Para solventarlo cambiamos la propiedad `“module”` en `tsconfig.json` a `“commonjs”`.

    {
      "compilerOptions": {
        ...tu configuración acá,
        "module": "commonjs"
      },
    }
    

Ejecutamos de nuevo `npx hardhat run scripts/deploy.ts` y Voilà.

![Yaaay. Hola Mundo 👋 ](https://storage.googleapis.com/papyrus_images/d5542b2438a20312ce35605022e23be0f810d81aac63a43207a7e633188eeee9.png)

Yaaay. Hola Mundo 👋

**¿Y si intentamos crear una función que espere un parámetro?**

Hagámoslo…, y por cierto, a este punto ya tienes una base para jugar con lo que se te ocurra con Solidity, mira [ejemplos de Uniswap](https://github.com/Uniswap/v2-core/tree/master/contracts) y tomalos de guía.

### SaludarConNombre()

    function saludarConNombre(string calldata nombre)
        external
        pure
        returns (string memory)
    {
        return string(abi.encodePacked("Hola ", nombre));
    }
    

Antes de invocar nuestra función en el script `deploy.ts`, una pequeña explicación de las palabras _“pure”_, _“external”_ y _“calldata”_ en este contexto.

*   `pure`, una [función _“pura”_](https://en.wikipedia.org/wiki/Pure_function) es aquella que no modifica propiedades que están fuera de su scope. En pocas palabras, `saludarConNombre()` es una función que sólo manipula la data con la que se invocó dicha función, más nunca escribirá ni leerá fuera de su contexto.
    
*   `external` describe la _“visibilidad”_ que la función `saludarConNombre()` tendrá cuando se distribuya en la red. Existen [4 tipos de visibilidad](https://docs.soliditylang.org/en/v0.8.16/cheatsheet.html?highlight=visibility#function-visibility-specifiers), public, private, internal y external.
    
*   `calldata` representa el alojamiento de memoria de la función.
    

Modificamos la función `main()` para agregar saludos a “Seth” y “Atzil”,

    async function main() {
      const factory = await ethers.getContractFactory("HolaMundo")
      const contract = await factory.deploy()
      await contract.deployed()
      console.log(await contract.saludar())
      console.log(await contract.saludarConNombre("Seth"))
      console.log(await contract.saludarConNombre("Atzil"))
    }
    

`npx hardhat run scripts/deploy.ts` una vez más,

![El resultado de ejecutar el comando "npx hardhat run scripts/deploy.ts"](https://storage.googleapis.com/papyrus_images/e5e5b457a91ae9896069faabf50b4ca5b9c10b8505258396e47cf429b8a8e8d2.png)

El resultado de ejecutar el comando "npx hardhat run scripts/deploy.ts"

> `abi.encodePacked` es usado(en este caso) para concatenar strings. La función [encodePacked](https://docs.soliditylang.org/en/v0.8.13/abi-spec.html#non-standard-packed-mode) agrupa los bytes de una variable y retorna los bytes de toda esa agrupación, al final convertimos esos bytes a un string.

Goerli Testnet: Distribuyendo nuestro Smart Contract
----------------------------------------------------

Para esta sección necesitas tener creada una cuenta en [Alchemy](https://www.alchemy.com/), esto para distribuir nuestro contrato en [Goerli Testnet](https://goerli.net/) : )

Como ya has notado, ejecutar los Smart Contracts requiere trabajo repetitivo, a medida que nuestro proyecto crece esto puede generar mucha distorsión.

La comunidad ha adoptado un plugin para agilizar este proceso — [hardhat-deploy](https://github.com/wighawag/hardhat-deploy#hardhat-deploy-in-a-nutshell), el plugin de hardhat que permite definir scripts secuenciales e interactuar con el [Hardhat runtime environment](https://hardhat.org/hardhat-runner/docs/advanced/hardhat-runtime-environment). Ya que esta guía intenta mostrarte lo más usado y adoptado por el ecosistema, vamos a instalarlo.

    npm i -D hardhat-deploy dotenv
    

Ahora agregamos el plugin en `hardhat.config.ts`,

    // hardhat.config.ts
    import { HardhatUserConfig } from "hardhat/config"
    import "@nomicfoundation/hardhat-toolbox"
    import "hardhat-deploy" // Importamos el plugin
    import "dotenv/config" // Paquete para cargar variables de entorno
    

### Configurando Alchemy

Luego de registrarte en Alchemy, crea una nueva App con el nombre que quieras, la descripción que quieras, pero eso sí, la chain será `Ethereum` y en Network marcamos `Goerli`.

![Configuración de una DApp en Alchemy.](https://storage.googleapis.com/papyrus_images/a58dc48290bfa0018161eb13fcd9dfc4743c565c0457dfa3bc6362bbc57f63f6.png)

Configuración de una DApp en Alchemy.

Luego de creado el proyecto, vamos al Dashboard y copiamos el valor de `“API KEY”`

![Dashboard del proyecto Kort. Se visualizan widgets para copiar los valores de la API KEY para conectarnos con Alchemy RPC.](https://storage.googleapis.com/papyrus_images/b35de470806882f16fd4e7939a6227e7c07099d1ba37740a4c26117a1f26e781.png)

Dashboard del proyecto Kort. Se visualizan widgets para copiar los valores de la API KEY para conectarnos con Alchemy RPC.

Agregamos el valor de `API KEY` en nuestro archivo `.env`,

    NEXT_PUBLIC_ENABLE_TESTNETS=true
    ALCHEMY_API_KEY=PEGA TU API KEY ACÁ
    

### Distribuyendo HolaMundo.sol

Creamos un archivo en `deploy/00_HolaMundo.ts` y agregamos lo siguiente:

    // deploy/00_HolaMundo.ts
    import { HardhatRuntimeEnvironment } from "hardhat/types"
    import { DeployFunction } from "hardhat-deploy/types"
    
    const fn: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
      const { getNamedAccounts, deployments } = hre
      const { deployer } = await getNamedAccounts()
      // "deployer" es tomado de hardhat.config.ts#namedAccounts
      await deployments.deploy("HolaMundo", {
        from: deployer,
      })
    }
    
    export default fn
    

> El plugin _hardhay-deploy_ ejecutará los archivos dentro de /deploy en orden, podemos agregar tantos scripts queramos

_¿Deploy?_. Aún no, [espera un poco, un poquito más](https://youtu.be/djVWzPEm7Pg?t=51). Tenemos que definir en hardhat quién será el “_deployer”_ de nuestro Smart Contract.

Para ello necesitamos la “Llave privada” de una Wallet. Para Metamask puedes seguír este post: [https://metamask.zendesk.com/hc/en-us/articles/360015289632](http://metamask.zendesk.com/hc/en-us/articles/360015289632)

Ahora que tenemos nuestra “Llave privada” la agregamos a nuestro `.env`

    NEXT_PUBLIC_ENABLE_TESTNETS=true
    ALCHEMY_API_KEY=PEGA TU API KEY ACÁ
    PRIVATE_KEY=Y ACÁ TU LLAVE PRIVADA
    

Necesitamos agregar `PRIVATE_KEY` a la configuración de Hardhat para Goerli. `hardhat.config.ts` deberá quedar así:

    // hardhat.config.ts
    import { HardhatUserConfig } from "hardhat/config"
    import "@nomicfoundation/hardhat-toolbox"
    import "hardhat-deploy"
    import "dotenv/config"
    
    const ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY
    const PRIVATE_KEY = process.env.PRIVATE_KEY!
    
    const config: HardhatUserConfig = {
      solidity: "0.8.9",
      networks: {
        goerli: {
          url: `https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
          accounts: [PRIVATE_KEY],
        },
      },
      namedAccounts: {
        deployer: 0, // Posición 0 en `networks.<goerli>.accounts[]`
      },
    }
    
    export default config
    

Un último comando,

    npx hardhat deploy --network goerli
    

![Resultado de ejecutar el lanzamiento de HolaMundo.sol](https://storage.googleapis.com/papyrus_images/a44cf9b0db3ef7f737f42018dd57dfd24f58fafcd5dfa6475c5c16f3768c6d95.png)

Resultado de ejecutar el lanzamiento de HolaMundo.sol

* * *

Oye, espera un momento .

**¿ Sabes que acabas de crear y distribuir un Smart Contract en Goerli ?** , te mereces una donita más para el café 💛.

Compartelo con tus amigos, publicalo en tus redes sociales :3

[![]({{DOMAIN}}/editor/youtube/play.png)](https://www.youtube.com/watch?v=gAjR4_CbPpQ)

Hay algo más que podemos hacer para mejorar el deployment, si verificas tu _Smart Contract_ aportas muchos beneficios.

Ejemplo, si visualizas este [Smart Contract](https://goerli.etherscan.io/address/0xA1012F4B18badFd4fA9122fEc7e4de160aD0ffBB#readContract) podrás ver su código fuente, ejecutar sus métodos de escritura/lectura, y obtener información sobre bugs. Todo esto gracias a que dicho contrato está verificado en Etherscan.

* * *

### Full Extras: Verificando nuestro Smart Contract en Etherscan

Al verificar nuestro Smart Contract el código fuente de este será visible, lo cúal genera transparencia a cualquier interesado en la lógica detrás de una DApp. Y además cualquier persona puede interactuar con el contrato desde el Explorador.

Para verificar, primero creamos una cuenta en [https://etherscan.io/apis](http://etherscan.io/apis), copiamos la `API KEY` y agregamos la definición `ETHERSCAN_API_KEY=”TU API KEY”` en `.env`

Configuramos el plugin _hardhat-etherscan_ en `hardhat.config.ts`

    // hardhat.config.ts
    
    // Sacamos la definición ETHERSCAN_API_KEY de .env
    const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY!
    const config: HardhatUserConfig = {
      ...,
      etherscan: {
        apiKey: {
          goerli: ETHERSCAN_API_KEY, // https://goerli.etherscan.io
        },
      },
    }
    
    export default config
    

> El plugin usado es [@nomiclabs/hardhat-etherscan](https://www.npmjs.com/package/@nomiclabs/hardhat-etherscan) y viene instalado junto a [hardhat-toolbox](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox)

Del paso anterior(`Distribuyendo HolaMundo.sol`) debió crearse una carpeta( `deployments/`) con la información del lanzamiento.

En la ruta `deployments/goerli/HolaMundo.json` observaras algo parecido a esto:

    {
      "address": "0xA1012F4B18badFd4fA9122fEc7e4de160aD0ffBB",
      "abi": [
        {
          "inputs": [],
          "name": "saludar",
          "stateMutability": "view",
          "type": "function"
        },
        {
          "name": "saludarConNombre",
          "stateMutability": "pure",
          "type": "function"
        }
      ]
    }
    

Para verificar `HolaMundo.sol` en etherscan necesitamos la propiedad `address`, esta es la dirección dónde se alojó el contrato en la red.

**ABI**(Application Binary Interface) define los métodos y propiedades para interactuar con `HolaMundo.sol`.

### 😋 Quiero verificar HolaMundo.sol ya

Anda, para verificar `HolaMundo.sol` en Goerli ejecutamos:

    npx hardhat verify --network goerli <address>
    

![Ahora si vamos a la ruta de nuestro contrato(address). Veremos una interfaz dónde puedes interactuar : )](https://storage.googleapis.com/papyrus_images/086f395da245f61d9bc07b7cdc9808a24e4c9d3eb953bf72e15047b47a703285.png)

Ahora si vamos a la ruta de nuestro contrato(address). Veremos una interfaz dónde puedes interactuar : )

### 💎 Usando hardhat-deploy

Para automatizar este proceso podemos crear un deploy script en `/deploy`

    // deploy/99_VerifyABIs.ts
    
    import { HardhatRuntimeEnvironment } from "hardhat/types"
    import { DeployFunction } from "hardhat-deploy/types"
    
    // Agrega las chains que ejecutarán `verify`
    const TO_VERIFY_NETWORKS = ["goerli"]
    // Lista el nombre de los Smart Contracts a verificar en EtherScan
    const VERIFY_CONTRACTS = ["HolaMundo"]
    
    const fn: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
      const { name } = hre.network
      // Tomar todos los deployments hasta este momento
      const deployed = await hre.deployments.all()
      // Validar que estoy en una chain que puede ejecutar verify.
      // No vamos a verificar nuestro contrato en Hardhat localhost
      if (TO_VERIFY_NETWORKS.includes(name)) {
        for (let name of VERIFY_CONTRACTS) {
          const contract = deployed[name]
          if (contract) {
            await hre.run("verify:verify", {
              address: contract.address,
            })
          } else throw `Could't find deployment for ${name}`
        }
      }
    }
    
    // Forzar ejecutar esta función al final
    fn.runAtTheEnd = true
    
    export default fn
    

Este script se ejecutará cada cuando hagamos `npx hardhat deploy` : )

Solidity Cardio: Eventos y Variables de estado
----------------------------------------------

En esta sección aprenderemos un poco de los primitivos en Solidity. De antemano comento que no será un tutorial de condicionales, bucles y basis de otros lenguajes de programación.

Tu mayor fuente de información es la [documentación oficial de Solidity](https://docs.soliditylang.org/en/v0.8.16/structure-of-a-contract.html), Google y amigos en comunidades Web3 : )

### Eventos

Los eventos en Solidity tienen muchos usos, exponer información, para por ejemplo comunicarnos con servicios externos de la red y además guardar data.

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.9;
    
    contract NFTLogger {
        // Declaramos un evento con el nombre `NuevaCompra`.
        // En los eventos podemos "emitir" información.
        // Esta puede ser filtrada al marcarse como `indexed`.
        // * NOTA: A estas propiedades indexadas se les llama topics
        event NuevaCompra(address indexed owner, string nft_id);
    
        function comprarNFT() public {
            // Emitimos el evento NuevaCompra
            emit NuevaCompra(msg.sender, "NFT-004");
        }
    }
    

Ver [ejemplo en Etherscan](https://etherscan.io/tx/0x70aef10945b623c025118aae09ff5ac767c12c2db9f484ec3f166d36cdba596b#eventlog).

### Estructuras

Las estructuras(`structs`) en Solidity son un `tipo de dato` que aloja propiedades primitivas, dónde estas propiedades se agrupan como una tupla. _“Objetos”_

    struct UnaLLama {
        bool guapa;
        string nombre;
        uint edad;
    }
    

Para crear una “Llama”, hacemos:

    LLama llama = LLama(true, "Juanita", 33);
    // Creación por posición, LLama(guapa, nombre, edad)
    

**Un pequeño ejemplo con Deploy scripts:**

    // contracts/Llama.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.9;
    
    contract Llama {
        struct UnaLLama {
            bool guapa;
            string nombre;
            uint edad;
        }
    
        function crearLLama(
            bool _guapa,
            string calldata _nombre,
            uint _edad
        ) public pure returns (UnaLLama memory) {
            return UnaLLama(_guapa, _nombre, _edad);
        }
    }
    

    // scripts/deploy.ts
    import { ethers } from "hardhat"
    
    async function main() {
      const factory = await ethers.getContractFactory("Llama")
      const contract = await factory.deploy()
      await contract.deployed()
      console.log(await contract.crearLLama(true, "Juanita 2", 42))
    }
    
    main()
    

### Mappings

Los `mappings` son en pocas palabras una tabla “_clave-valor”_.

    mapping(string => UnaLLama) corralito;
    
    function guardarLlamaEnCorral(
        bool _guapa,
        string calldata _nombre,
        uint _edad
    ) external {
        corralito[_nombre] = crearLLama(_guapa, _nombre, _edad);
    }
    
    function sacarLlamaDeCorral(string calldata _nombre)
        external
        view
        returns (UnaLLama memory)
    {
        return corralito[_nombre];
    }
    

Ejemplo de deploy script,

    async function main() {
      const factory = await ethers.getContractFactory("Llama")
      const ct = await factory.deploy()
      await ct.deployed()
      console.log(await ct.crearLLama(true, "Juanita 2", 42))
      const tx = await ct.guardarLlamaEnCorral(true, "Juanita", 42)
      await tx.wait()
      console.log(await ct.sacarLlamaDeCorral("Juanita"))
    }
    

### ¿ ints, strings, arrays ?

Estos son primitivos en muchos lenguajes de programación y apuesto que ya tienes idea de como usarlos. Vamos, modifica `Llama.sol` y prueba : )

Lista de _“tipos de datos”_ en Solidity: [https://docs.soliditylang.org/en/v0.8.16/types.html](https://docs.soliditylang.org/en/v0.8.16/types.html)

* * *

Wagmi React: Interacción con el Frontend y finalización
-------------------------------------------------------

Sí _NO_ has llevado la guía a la ligera, hasta este punto ya tienes lo suficiente conocimiento para crear tus contratos e integrarlos con el Frontend.

Mi enfoque no es enseñarte React, mucho menos Javascript. Del Frontend, NextJs es importante ya que se usa muchísimo en el Ecosistema, saber el enrutamiento y la estructura de archivos y cómo configurar Wagmi & Rainbowkit es suficiente para arrancar.

> La documentación de estas herramientas es tu fuente de la verdad.

Para esta etapa vamos a necesitar un template que trae todo lo que vimos en la guía. La plantilla ya trae un set de componentes React y una interfaz básica para modificar y jugar con el código.

### La plantilla: NextJS-Rainbow-HH

![https://github.com/D3Portillo/nextjs-rainbow-hh](https://storage.googleapis.com/papyrus_images/e4dbfd0ddc5b69f0e23bff5edd4ffa4a3b6e9dc97122eafd4832658139950354.png)

https://github.com/D3Portillo/nextjs-rainbow-hh

Para usar la plantilla, vamos a [https://github.com/D3Portillo/nextjs-rainbow-hh](https://github.com/D3Portillo/nextjs-rainbow-hh) y clickeamos en _“Use this template”_, agregamos un nombre que deseemos asignar para este repositorio a crear.

![La imágen muestra la interfaz de creación de un repositorio usando la plantilla en https://github.com/D3Portillo/nextjs-rainbow-hh ](https://storage.googleapis.com/papyrus_images/d472ca816f6463b248afad495caf18773e3123ebdcd45f992b5acff26c424bc3.png)

La imágen muestra la interfaz de creación de un repositorio usando la plantilla en https://github.com/D3Portillo/nextjs-rainbow-hh

### Estructura del proyecto

La estructura del proyecto es muy similar a nuestra experimentación anterior. La diferencia es que ahora hay una nueva carpeta(`components/`) que contiene los trozos de interfaz que pintamos en nuestra DApp.

También ha cambiado el nombre de algunas variables de entorno. Unas llevan el prefijo `NEXT_PUBLIC`, esto es porque NextJs tomara las definiciones de entorno sólo al ejecutarse en NodeJs más no en el navegador, [para “permitir” acceder a estas definiciones se antepone NEXT\_PUBLIC por convención y consistencia](https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser).

### GuestBook.sol

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.9;
    
    contract GuestBook {
        event NewNote(address indexed persona, string contenido);
    
        function addNote(string calldata _contenido) external {
            emit NewNote(msg.sender, _contenido);
        }
    }
    

Nuestro proyecto sólamente envía logs al invocar la función `addNote`. Para acceder a los logs desde el frontend, filtramos los registros de la chain con el [React Hook](https://reactjs.org/docs/hooks-intro.html) ubicado en la ruta [lib/hooks/useNotesList.tsx](https://github.com/D3Portillo/nextjs-rainbow-hh/blob/master/lib/hooks/useNotesList.ts#L24)

    import { useEffect, useState } from "react"
    
    import getContract from "@/lib/getContract"
    import { noOp } from "@/lib/helpers"
    
    const GuestBook = getContract("GuestBook")
    function useNotesList() {
      const [list, setList] = useState([] as Note[])
    
      useEffect(() => {
        GuestBook.queryFilter(GuestBook.filters.NewNote())
          .then((list) => {
            return list.map((item) => {
              const {
                args: { persona, contenido },
                transactionHash,
              } = item
              return {
                transactionHash,
                persona,
                contenido,
              }
            })
          })
          .then(setList)
          .catch(noOp)
      }, [])
    
      return list
    }
    
    export default useNotesList
    

### deployments/goerli/GuestBook.json

Esta es la información de los deployments que hagamos (espejo de los deploy scripts en `/deploy`). Por lo que te invito a modificar `/contracts/GuestBook.json` con una feature, agregar condicionales, o por ejemplo:

*   ¿Qué sucede sí mi string está vacío ?, validación de errores.
    
*   Agregar un deploy a Ethereum Mainnet, Solana o Polygon.
    
*   ¿No usar logs para obtener las notas dejadas en la DApp y usar una variable de estado ?
    
*   Convertir cada nota en un [NFT](https://academy.binance.com/en/articles/a-guide-to-crypto-collectibles-and-non-fungible-tokens-nfts) ó [SBT](https://academy.binance.com/en/articles/what-are-soulbound-tokens-sbt)
    
*   ¿ Limitar la cantidad de Notas que puede dejar una persona ?
    

Lo que gustes, vos podes hacer lo que querrás 😋

### Tu Proyecto

Luego de modificar el proyecto ejecuta `npx hardhat run deploy`, levanta nodos locales con `npx hardhat run` y lo más importante, juega, modifica, pregunta : )

Haz deploy de tus cambios porque la información en `/deployments` es mía, de mi cuenta de pruebas. Haz el proyecto tuyo.

Ya habrás notado que la guía es un tutorial de cómo crear el template que acabas de usar, Felicidades!! 🦄. Te invito a leer un poco la documentación de [React](https://reactjs.org/) y [NextJs](https://nextjs.org/), no vendrá mal, y además no debe faltar leer sobre [Hardhat](https://hardhat.org/) y [Solidity](https://docs.soliditylang.org).

Sugerencias, comentarios, quejas; lo que se te ocurra 🥴, más que bienvenid@s :)

Plus Ultra: Lanzando nuestra DApp en Vercel
-------------------------------------------

**Vercel** es una compañía amada por los Frontend devs para lanzar sus proyectos. _“Develop, Preview, Ship”_ es su eslogan y les pega a la perfección.

> Nota random personal: Vercel es una de las empresas dónde quiero trabajar y tirar código. Tengo un crush con su CEO — Guillermo Rauch`(12)`, un _crack_.

Para esta sección necesitamos crear una cuenta en [https://vercel.com/new](https://vercel.com/new), y luego inicias sesión con tu GitHub.

![La imágen muestra la pantalla de inicio de sesión de vercel.com](https://storage.googleapis.com/papyrus_images/a7efb74b792a90a71e720bbebd39184acb0ef3c7087e72fbd8263b112d53ee27.png)

La imágen muestra la pantalla de inicio de sesión de vercel.com

Ahora buscamos el proyecto que vamos a lanzar en Vercel de la lista de repositorios(_en mi caso es “mi-proyecto-guapo”_). Damos a _“Import” y_ configuramos variables de entorno.

![Seleccionando el repositorio dónde vive nuestro proyecto NextJS](https://storage.googleapis.com/papyrus_images/079bc76ed650d9f74b14a0ee06ca59a718cbdb922f66ee3fbd4be14ed8e6af4a.png)

Seleccionando el repositorio dónde vive nuestro proyecto NextJS

Configuramos las variables de entorno. Recuerda que para forzar Goerli seteamos `NEXT_PUBLIC_FORCE_GOERLI_PROVIDER=true` y reemplazas `NEXT_PUBLIC_ALCHEMY_API_KEY` por tu API Key de Alchemy 😛.

![La imágen muestra la configuración de Variables de entorno en el Dashboard de Vecel](https://storage.googleapis.com/papyrus_images/b6179e3bf88a287a3625c3cbede605a872f9e64422f5a83b60396d9d0d6ec4ca.png)

La imágen muestra la configuración de Variables de entorno en el Dashboard de Vecel

Esperamos un momento, y tendremos nuestro DApp con url para compartir 😍

![https://bukrr.vercel.app](https://storage.googleapis.com/papyrus_images/e6e83b6f2ddbe5327c52b82d1245885e99d29a997f3772587b3eeadfc7df565e.png)

https://bukrr.vercel.app

* * *

🤘Genial, hemos aprendido mucho. Ahora tú tienes conocimientos sobre el Ecosistema Web3, Ethereum, Sistemas Distribuidos y puntualmente _“Cómo desarrollar Aplicaciones Descentralizadas”_ :)

Recuerda, la idea de esta guía es demostrar lo más posible cómo desarrollar DApps con un set de herramientas populares y validadas por los desarrolladores. Faltaron un par de cositas que espero con mucha inquietud presentar en otra Guía. Una de ellas es mejorar el consumo de información en el Frontend con [Subgraphs](https://thegraph.com).

Algo más, si te preguntas, ¿Cómo se interconecta la información de Ethereum con servicios externos a la red ?, la respuesta, [Oracles](https://ethereum.org/en/developers/docs/oracles/).

* * *

Si llegaste hasta este punto de la lectura, y bueno; sí cualquier trozo de texto te ayudó para aprendizaje, espero y te sientas orgulloso. Sé que tienes muchas preguntas, pero ahora te será más sencillo buscar lo que no sabes y reforzar lo que sabes.

También, si este fue tu primer bailecito con la Web3, Bienvenido 🥰.

Notas finales y un poco sobre mí
--------------------------------

Me llamo **Denny Portillo**, Salvadoreño y estudiante de [42 Madrid](https://42madrid.com). Trabajo como desarrollador Frontend Web3 en [Daoism Systems](https://daoism.systems). Quiero comentarte con mucha honestidad que en este ecosistema nunca paras de encontrar contenido que aprender. Muchas ocasiones te desesperas por TODO; agrego que esto me divierte, me gusta. No es aburrido y la Web3 tiene mucha vida por delante.

Si te interesa desarrollar DApps, hazlo. Inténtalo, equivócate, práctica, práctica, práctica. No dejes de dudar y preguntar. Únete a comunidades de desarrolladores y crea lo que se te ocurra, : )

¿No sabes a qué comunidad unirte ?, puedes iniciar en [https://buildspace.so](https://buildspace.so/). En Buildspace aprendí a crear Smart Contracts y lanzarlos en una Testnet `(13)`.

Para terminar. No sabes lo que me gustó crear este documento, espero compartas la guía con tus amigos y si tienes comentarios, dudas; arrojalas que estamos para apoyar.

Antes de irte, si gustas, sigueme en Twitter 🚀: [https://twitter.com/d3portillo](https://twitter.com/d3portillo)

Referencias
-----------

1.  The Merge: [https://ethereum.org/en/upgrades/merge](https://ethereum.org/en/upgrades/merge)
    
2.  FOMO: [https://blog.orange.es/consejos-y-trucos/que-es-fomo/](https://blog.orange.es/consejos-y-trucos/que-es-fomo/)
    
3.  Intro to Ethereum: [https://ethereum.org/en/developers/docs/intro-to-ethereum](https://ethereum.org/en/developers/docs/intro-to-ethereum/)
    
4.  Ethereum Virtual Machine: [https://ethereum.org/es/developers/docs/evm](https://ethereum.org/es/developers/docs/evm/)
    
5.  Maquina de Estados: [https://es.wikipedia.org/wiki/Máquina\_de\_estados](https://es.wikipedia.org/wiki/M%C3%A1quina_de_estados)
    
6.  _“Turing Completeness”_ y Modelo de ejecución en la EVM
    
    1.  Turing Complete Blockchain: [https://academy.binance.com/en/glossary/turing-complete](https://academy.binance.com/en/glossary/turing-complete)
        
    2.  Ethereum Yellow Paper #8fea825, Cap. 9 — Execution Model: [https://ethereum.github.io/yellowpaper/paper.pdf](https://ethereum.github.io/yellowpaper/paper.pdf)
        
7.  Linkedin post _“5 Paquetes de React para Frontend Devs en Web3”_: [https://www.linkedin.com/posts/d3portillo\_5-paquetes-de-react-para-frontends-en-web3-activity-6948890361192722432-nXGU](https://www.linkedin.com/posts/d3portillo_5-paquetes-de-react-para-frontends-en-web3-activity-6948890361192722432-nXGU)
    
8.  Ethereum RPC: [https://ethereum.org/en/developers/docs/apis/json-rpc](http://ethereum.org/en/developers/docs/apis/json-rpc/)
    
9.  Moralis vs Infura vs Alchemy: [https://moralis.io/whats-the-difference-between-moralis-alchemy-and-infura](https://moralis.io/whats-the-difference-between-moralis-alchemy-and-infura)
    
10.  Mainnet Network: [https://academy.binance.com/es/glossary/mainnet](https://academy.binance.com/es/glossary/mainnet)
    
11.  Variables de Entorno: [https://es.wikipedia.org/wiki/Variable\_de\_entorno](https://es.wikipedia.org/wiki/Variable_de_entorno)
    
12.  Guillermo es el creador de Socket.io, Mongoose y otras herramientas populares del ecosistema NodeJS. Hay contenido en este documento de su charla _“Merging Design and Development”_, dónde habla sobre _“Consistent UI”_ y Sistemas distribuidos, mirala acá: [https://www.youtube.com/watch?v=3hccXiXI0u8](https://www.youtube.com/watch?v=3hccXiXI0u8)
    
13.  Repositorios usados en la guía
    
    1.  Jeshejojo: [https://github.com/D3Portillo/jeshejojo](https://github.com/D3Portillo/jeshejojo)
        
    2.  Plantilla Bukrr: [https://github.com/D3Portillo/nextjs-rainbow-hh](https://github.com/D3Portillo/nextjs-rainbow-hh)
        

Glosario
--------

*   **Blockend:** El Desarrollo Backend, Frontend y de Smart Contracts para una DApp.
    
*   **DApp:** Aplicación Descentralizada (Decentralized App).
    
*   **ETH:** Ether(Ξ). Token principal y nativo de la red Ethereum.
    
*   **EVM:** Ethereum Virtual Machine.
    
*   **Solidity:** Lenguaje de programación parecido a Javascript para crear Smart Contracts en la EVM.
    
*   **Testnet:** Una copia/instancia para pruebas de una red.
    
*   **WAGMI:** We’re all gonna make it.
    
*   **Vyper:** Lenguaje de programación parecido a Python para crear Smart Contracts en la EVM.

---

*Originally published on [D3Portillo](https://paragraph.com/@d3portillo/web3-creando-tu-primer-app-descentralizada)*
