Desarrolla tu Primera App Web3 Full Stack | Curso Cyfrin Updraft en Español
Cyfrin Updraft Courses · 1:11:54
Vasiliy Kirochka, a blockchain developer and content creator known as Cromewar, builds a full-stack web3 application in this Spanish-language tutorial. The lesson connects a Solidity contract to a Next.js interface and provides both a frontend template and a completed Simple Storage project for learners to follow and extend.
Speakers
Topics
From Cyfrin Updraft Courses, hosted by Cyfrin.
Transcript
Hola. Así que quieres ser un blockchain developer y no sabes por dónde empezar, pues estás en el lugar correcto. Hoy vas a crear junto a mí tus primeros dos smart contracts y conectarlos a un front-end creado en Nest JS. El proyecto que crearemos hoy será bastante sencillo, pero te da todas las bases que necesitas para empezar a introducirte en este mundillo. Y si te estás preguntando por qué debería interesarme convertirme en un blockchain developer, pues nuestra industria sigue siendo relativamente joven, aunque esperamos llegar a una capitalización de mercado gigantesca para el año 2030 y necesitamos cada vez más gente talentosa y desarrolladores que puedan unirse a la fuerza laboral. De hecho, los sueldos de un blockchain developer rondan alrededor de 125,000 dólares al año y tú podrías
convertirte en uno de esos developers. Así que si te interesa introducirte en este mundillo, sigue viendo porque estamos para empezar. Eso sí, en este vídeo voy a asumir que al menos ya tienes un poquito de conocimientos sobre programación, sabes lo que son las funciones, las variables y bueno, tienes un conocimiento básico de cómo crear un programa. Porque si creásemos un tutorial desde absoluto cero, este vídeo pasaría a convertirse en un curso. Pero si es que quieres un curso desde cero para convertirte en un blockchain developer, tengo que recomendarte el mejor lugar para empezar, Cypher Odra. Aquí encontrarás los mejores cursos enseñados por los líderes de la industria y lo mejor, completamente gratis. Es cierto que de momento los cursos están solamente en inglés y aunque tenemos un buen sistema
de subtítulos, puede que eso genere un poco de dificultad, en especial si no estás muy versado en el inglés. Es por eso que si quieres que esos contenidos sean traducidos a tu idioma, no olvides suscribirte y darle like a este vídeo, porque de esa forma nos estarás apoyando y diciendo que quieres más contenido para desarrolladores completamente en español. Con eso dicho, vamos a empezar explicándote de qué van los smart contracts de este proyecto. Este smart contract va a ser bastante sencillo, vamos a crear uno que nos permita almacenar un número favorito y vamos a tener las funciones para almacenarlo y obtenerlo y también vamos a crear una estructura de persona que
tiene un nombre y un número favorito y por supuesto las funciones correspondientes para obtener esa información y para añadir nuevos registros. Todo esto será desplegado en una blockchain local e interactuaremos con este Smart Contract utilizando la plantilla de Front End que vas a tener en la descripción. Al finalizar este proyecto habrás creado tu propio Smart Contract desde cero incluyendo su script para ejecución utilizando Foundry, uno de los frameworks más populares y utilizados de la industria.
Habrás creado el Front End necesario con dos componentes necesarios para poder interactuar con ese Smart Contract, conectar Metamask a tu navegador y ejecutar sus funciones y vas a tener una interfaz como esta que te va a permitir conectar tu wallet, interactuar con el Smart Contract y ejecutar sus funciones en tiempo real. Okay, vamos a empezar. Como puedes ver tengo aquí el Remix IDE y abierto, pero no lo vamos a usar. La mayoría de tutoriales que vas a encontrar allá
fuera y en otras plataformas empezarán enseñándote cómo programar Smart Contracts usando Remix IDE y es una buena forma de iniciar, pero seamos honestos, nadie construye un portafolio utilizando Remix. Generalmente es para hacer pruebas rápidas en alguno que otro Smart Contract, pero para hacer desarrollo en serio tendemos a utilizar frameworks de desarrollo y en este caso vamos a utilizar el framework más popular de la actualidad que es Foundry. Así que para la instalación, por favor, vea la página oficial de Foundry. Solo tienes que buscar Foundry book en Google y vas a acceder a esto. Vamos a seleccionar esto para instalarlo y en mi terminal yo voy a pegar este comando. Le voy a dar clic y aquí es la típica de
tutorial de los años 2000. Yo no lo instalo porque yo ya lo tengo. Pero básicamente cuando corras este comando y el proceso termine, te va a dar algo como esto. Cópialo y pégalo en tu terminal para activar las nuevas variables de entorno, lo que te va a permitir utilizar este comando, el comando Foundry app. Esto te va a permitir instalar la última versión de Foundry en tu terminal. Y aunque ya tengas Foundry instalado, siempre es interesante hacer esto para obtener las últimas actualizaciones. Una vez tenemos Foundry instalado en nuestro sistema, podemos iniciar un nuevo proyecto escribiendo forge init. Y esto nos crea un proyecto básico. Voy a abrir mi editor de código en esta carpeta y así es como se ve la estructura básica de un
proyecto en Foundry. Por defecto siempre va a venir con este counter.sol, que es un smart contract de ejemplo que voy a utilizar ahorita para explicarte un par de cosas interesantes de Solidity, un foundry.toml, donde tendremos todas las configuraciones del framework para este proyecto en específico, un readme, si intentas enviar esto a una página como GitHub y lib, que viene a ser la parte de las librerías que se van a utilizar para estos smart contracts que tenemos acá. Por supuesto, tenemos una sección para los scripts y una sección para hacer pruebas, tanto unitarias como de integración. Así que bueno, vamos a empezar. Quiero explicarte cuál es la sintaxis básica de un smart contract
creado en Solidity. Principalmente necesitamos la licencia. Esto se pone como un comentario y empezamos diciendo SPDX license identifier. En este caso es por defecto un license, pero generalmente vas a encontrar licencias MIT o Apache, que son todas de software libre. Luego establecemos la versión de Solidity utilizando la palabra clave pragma Solidity y la versión del compilador y luego declaramos el contrato. La estructura de este contrato se parece mucho a otros lenguajes de programación como lo podrían ser Java con sus clases. Y las funciones, al igual que otros lenguajes de programación, se declaran con la palabra clave function, se determina la función,
entre paréntesis se establece cuáles van a ser los parámetros de entrada y se establece el nivel de acceso de dicha función. Voy a explicar esto con más detalle cuando empecemos a crear nuestro smart contract. Para eso, en la carpeta src voy a dar clic en nuevo archivo y voy a decirle simple storage.sol o {punto} sol. Ahora, ¿por qué si es que estamos haciendo un video de español sigo utilizando nombres en inglés? Simple storage viene a ser algo así como almacén simple. Bueno, pues básicamente porque, aunque estemos hablando en español, los lenguajes de programación siguen siendo en inglés. La palabra function eh no es función, contract no dice contrato y bueno, básicamente todas
las variables y todos los lenguajes de programación funcionan en inglés. Entonces, por convención, aunque vamos a poner los comentarios y vamos a tratar de explicarlo todo de manera coherente en español, es importante tener en cuenta que programar el código en inglés es importante, en especial porque en algún punto otras personas van a leer este código y pues es importante utilizar el estándar. Vamos a empezar con nuestro contrato estableciendo la licencia. Entonces, {slash} {slash} para un comentario, SPDX license identifier y voy a utilizar la licencia del MIT. Luego voy a declarar la versión de pragma Solidity. Como podrás ver, GitHub Copilot es muy bueno y voy a estar utilizando el
autocompletado para hacer las cosas más fáciles durante este vídeo y ya me está recomendando una versión de Solidity. De nuevo, declaramos pragma Solidity, pragma es la palabra clave para declarar cuál es la versión de Solidity que vamos a utilizar. En este caso no voy a usar la versión que me dio GitHub Copilot, sino que voy a utilizar una de las más recientes a fecha de grabación de este vídeo. Y esto me da la oportunidad de explicarte otra cosa importante. Podrán ver que tenemos un símbolo por aquí. Este símbolo nos determina que podemos utilizar cualquier versión empezando por la 0.8.25 y superior. Sin embargo, si es que yo quitara esto, pues estaríamos forzando al compilador a ejecutarse utilizando únicamente esta versión. Es muy
importante saber eso porque podrás ir manejando estas versiones dependiendo del proyecto en el que estés trabajando. Vamos a continuar y vamos a declarar nuestro contrato. Entonces, lo decimos contract simple storage. Como podrás ver, GitHub Copilot es muy bueno y ya me está autocompletando bastantes cosas y en algunos momentos voy a dejar que el autocompletado funcione y en otros no porque quiero explicarte algunas cosas. Vamos a ver cómo declarar variables en Solidity. Existen varios tipos de variables, pero vamos a empezar por la más básica para este vídeo, que es declarar un entero o conocido como un uint.
Y vamos a utilizar el 256. Solidity tiene diferentes tipos de variables enteras. Podemos, por ejemplo, hablar de uint 8. Y como podrás ver, GitHub Copilot me autocompleta los valores que estos pueden obtener. Básicamente, uint 256 nos permite tener un rango de 2 elevado a la 256 menos 1. Básicamente, uint 256 sirve para números, pues, bastante grandes.
Es interesante que sepas esto porque, si bien es cierto, en este contrato simple que vamos a programar el día de hoy, esta diferenciación no es importante, Cuando te vuelvas un giga chat de los smart contracts, vas a entender que a veces utilizar diferentes tipos de uint se puede aprovechar para hacer optimización en los costos de gas de la blockchain. Para este simple tutorial, como sabes, vamos a crear nuestro smart contract que nos permite almacenar un número favorito que va a ser el general para todo el contrato. Entonces, voy a decirle uint 256 public favorite number o my favorite number y le voy a dar un punto y coma.
Todas las sentencias en Solidity, al igual que en lenguajes como JavaScript, requieren que pongas un punto y coma al final. Que esta variable sea pública quiere decir que puede ser libremente accedida desde fuera de este contrato o por cualquier otra función dentro de este proyecto o por cualquier otro contrato dentro de este proyecto. Y ahora vamos a crear nuestra primera función, la función función para al macenar un número favorito. Para eso vamos a usar la palabra clave function, vamos a utilizar la palabra clave store de almacenar en inglés. Y bueno, voy a dejar que ahorita el autocompletado me ayude. Entonces, esta función recibe
como parámetro un uint 256. Y otra cosa interesante es que por convención utilizamos un guion bajo para las variables que son utilizadas en la ejecución de funciones Como podrás ver, my favorite number tiene exactamente el mismo nombre que esta variable que estamos utilizando, sin embargo, esta tiene un guion bajo. Significa que esta es una variable que solamente es usada en el contexto de ejecución de esta función. Por lo tanto, utilizamos esta función para asignar a la variable pública my favorite number cualquier valor que sea asignado al utilizar la función store. Y así como tenemos funciones para almacenar un número,
también tenemos funciones para obtener ese número o los getters que se conocen en inglés. Entonces, aquí voy a hacer un pequeño comentario, getter para obtener el número favorito. Podrás ver que GitHub Copilot me ayuda bastante. Voy a guardar. Entonces, creamos una función llamada retrieve. Va a ser una función pública. Nuevamente, que una función sea pública significa que puede ser accedida en cualquier momento. Y aquí tenemos otra clave llamada view. Como sabrás, la blockchain funciona pues por una cadena de bloques y necesitas ir añadiendo transacción sobre transacción. Cada transacción en la blockchain cuesta dinero y el problema que eso ocasiona es que si tuvieras que gastar dinero cada
que ejecutas una función, pues te saldría un ojo de la cara. Las funciones del tipo view son funciones que no hacen cambios en la blockchain. Básicamente, tú no estás cambiando el valor de esta variable, por lo cual no necesitas hacer ninguna transacción que requiera un costo de gas. Las funciones view te permiten obtener información de la blockchain sin la necesidad de incurrir en ningún costo de gas. La palabra clave return, por otra parte, nos indica qué tipo de variable retorna esta función. Y esto, por supuesto, nos retorna un uint256.
Y usamos el return statement para decirle que nos devuelva my favorite number. Y así de sencillo tenemos la primera instancia de este smart contract. Una cosa interesante de Foundry es que viene con su propia blockchain integrada llamada Anvil. Entonces, si yo vuelvo a mi terminal, voy a limpiarla, de hecho, y escribo la palabra Anvil, podrás ver que me da una blockchain local pues con todas sus public keys, con balances de ether superaltos y todas las private keys que yo puedo utilizar para testear esto. A su vez, me da otra información, como por ejemplo, cuál es el ID de la cadena, cuál es el base fee, cuál es el gas limit, etcétera, etcétera. Y esto está actualmente corriendo en mi local host,
en el puerto 8545. Va a ser esta blockchain la que utilizaremos para desplegar nuestro smart contract y luego la mantendremos corriendo cuando conectemos esto con el front end. Sin embargo, también te voy a dejar unos tips de cómo puedes desplegar eso en una testnet, como puede ser Sepolia, y luego posteriormente, por supuesto, desplegar tus smart contracts en la mainnet. Dicho esto, vamos a continuar. Como sabrás, este smart contract, así como está, está incompleto. Ya tenemos la opción de almacenar el número favorito global y obtener el valor de ese número favorito de manera global. Pero este smart contract también sirve para crear un grupo de personas, personas que tienen
su nombre y pues su número favorito asociado a ellas. Esto me permite explicarte otros conceptos importantes de Solidity. Vamos a empezar con ello. Primero, creamos otro tipo de dato, en este caso vamos a crear un tipo de dato struct. Las estructuras son muy parecidos a los objetos de JavaScript y nos permite declarar un tipo de variable struct, en este caso le llamamos people y va a tener dos variables internas. La primera es el número favorito de la persona y la segunda va a ser un tipo de dato string con su nombre. Entonces, cada que yo cree una nueva instancia de persona, me va a crear una persona con su número favorito y su nombre. Bastante
sencillo y nada diferenciado de otros lenguajes de programación, ¿verdad? Genial, continuemos. Ahora, yo voy a crear muchas personas y para almacenar cada persona me gustaría tener un array de la lista de personas, entonces voy a crear un array de personas. Para lo cual voy a decir people, voy a usar los corchetes. Va a ser una variable pública nuevamente porque quiero que sea fácilmente accesible y voy a decirle lista de personas o list of people en inglés. Voy a guardar esto y ya tengo el struct para almacenar las personas y un array que me va a permitir almacenar varias instancias de estas personas.
Para ello vamos a crear una nueva función que nos permita, pues, empezar a almacenar nuevas personas con su número favorito y su nombre. Podrás notar que estoy siguiendo una convención muy tradicional en todos los lenguajes de programación, que es poner las variables arriba, poner todas las declaraciones acá y las funciones abajo haciendo los getters los que se ponen siempre al final. Si este smart contract tuviera un constructor, pues, pondría el constructor también por arriba. Vamos a crear una nueva función aquí, función para almacenar una persona y le voy a decir function add person, este me va a recibir como parámetro dos cosas, un string memory, también va a recibir un uint 256 con el favorite number. La función va a ser pública y lo que va a
hacer esta función es básicamente añadir a esta lista, a este array de personas usando list of people.push para añadir, creamos una nueva persona y le mandamos su número favorito y su nombre. Recuerda, como te dije antes, las variables que se utilizan aquí con guion bajo son variables que se usan como parámetros de funciones. Ahora, hablemos de memory. Como estas variables son utilizadas en el contexto de la ejecución de una función, eso significa que estas variables son variables temporales y existen dos tipos de variables temporales en solidity. La primera es calldata, que es una palabra clave para especificar que los datos no
se pueden modificar o son básicamente datos que son read only o solo lectura y luego tenemos otro tipo de variables temporales llamadas memory, que es una palabra clave que se utiliza para especificar que los datos se pueden modificar. Básicamente lo que estamos diciendo es que este dato string que le estamos mandando es de tipo memory. ¿Por qué utilizamos memory en un string y no en un uint? Pues básicamente porque a nivel técnico un string es realmente un bytes transformado. Hay bastantes cosas interesantes sobre esto y te dejaré un link en la descripción para que le eches un chequeo. Pero ten en cuenta que como te dije en Solidity existen dos tipos de variables temporales, calldata que
sirven únicamente como variables temporales que solo se utilizan para lectura y memory son variables que pueden ser modificadas. Todos los strings que utilicen tienen que ser memory por lo que te acabo de mencionar que realmente es una transformación utilizando el otro tipo de variable llamado bytes. Vamos a continuar entonces. Ya añadimos la persona a este array de personas, pero obtener la información de un array puede llegar a ser complicado porque básicamente si es que tuviésemos, por ejemplo, déjame mostrarte por aquí.
Imagínate yo tuviese un array con 20 registros, llegar al registro 19, por ejemplo, requeriría mucho gas, básicamente porque también tendríamos que utilizar alguna especie de loop para ir uno por uno hasta llegar a ese punto. Como no queremos gastar tanto gas y queremos acceder de manera instantánea a los datos, es importante utilizar otro tipo de dato aquí también. Eso me da la apertura para un nuevo tipo de dato que te voy a enseñar en esta lección. Y son los mappings, que básicamente se utilizan para crear una clave valor, muy parecido a lo que
podrías ver en formatos de archivo como JSON, donde tienes una clave y su valor. También podría ser muy parecido a un diccionario en Python, donde básicamente vamos a relacionar un tipo de dato con un valor específico. Así que en este caso vamos a relacionar el string de el nombre de la persona y la vamos a relacionar con el uint 256 correspondiente a su número favorito. Para la cual vamos a crear este mapping con la palabra clave mapping, va a ser de un string hacia un uint 256.
Nuevamente lo vamos a declarar como público y vamos a decir que se va a llamar name to favorite number. En este caso en la función store vamos a añadir un nuevo registro. Vamos ya vamos a decirle name to favorite number va a ser igual al favorite number. Entonces, cuando añadamos una persona, en lugar de solo agregarlo al array de personas, vamos a crear esa conexión. Vamos a decirle que name to favorite number, pasando como parámetro el nombre, va a estar relacionado con el favorite number. Básicamente lo que estamos haciendo aquí es, por ejemplo, que si es que yo digo que el nombre es Pedro y su número favorito es 10, cuando yo llame name to favorite number y le
pase el parámetro Pedro, esto me va a devolver 10. Sencillo, ¿verdad? Y para finalizar este smart contract, lo último que vamos a hacer es obtener la información. De la misma manera que obtuvimos la información aquí, utilizando la función retrieve, vamos a decirle aquí function retrieve person favorite number. Va a recibir como un parámetro un string. Recuerda, todos los strings tienen que utilizar memory, name va a ser nuevamente una función pública de tipo view, recuerda las funciones de tipo view no hacen cambios en la blockchain, por lo cual tampoco consumen gas. Esto me va a retornar un uint256 y le voy a decir que me retorne lo que
te dije acá. Si yo le digo name to favorite number y cualquier nombre me debe dar su valor. Esta función nos va a asegurar eso. Entonces cualquier nombre que le pasemos como parámetro debería acceder a este mapping, recuerda el mapping es una relación entre dos tipos de datos y darme el número favorito que está asociado a la cadena de string que vamos a pasar como parámetro aquí. Y así de sencillo, así de fácil, tenemos listo todo nuestro smart contract. Si nunca habías programado un smart contract antes, date una palmadita en la espalda, puesto que acabas de crear tu primer smart contract. De nuevo, me estoy saltando bastantes explicaciones y bastantes cosas por el camino, porque tenemos que hacer que este vídeo sea más
dinámico y sea más digerible. Sin embargo, te recuerdo nuevamente que si quieres tener una guía detallada paso a paso, punto por punto, no olvides chequear Cypher Updraft y tendrás una guía específica, un curso de más de 32 horas para convertirte en un desarrollador experto. Y si sientes que la barrera del lenguaje sigue siendo muy grande en Updraft, haznoslo saber y con gusto traduciremos los cursos a tu propio idioma. Una vez tenemos nuestro smart contract creado, pues vamos a proceder a compilarlo. Para eso voy a volver a mi terminal, déjame que la limpie y le voy a decir force compile.
Esto debería compilar mi smart contract y esto acaba de funcionar sin ningún problema. Volvamos nuevamente a mi editor de código y podrás ver que aquí se me creó una nueva carpeta llamada out. Esta carpeta contiene todos los datos de compilación y el que nos interesa es de este que de aquí que se llama simple storage, simple de Como podrás ver es una cadena larguísima de información en formato json y puesto que tengo la extensión que me permite hacer que esto se vea mejor, solamente con guardar esto se formatea mejor.
Básicamente lo que nos da aquí es la ABI, la ABI es el set de instrucciones que tiene un smart contract, básicamente en la ABI está contenido el nombre de cada función, qué hace, qué parámetros recibe, el tipo de datos que fueron declarados, etcétera, etcétera. El byte code es el código, el código de nuestro smart contract una vez compilado y este byte code, byte code, perdón, es algo que es entendible para la Ethereum Virtual Machine y tenemos otros datos más acá que son un poco más avanzados, incluyendo mucha metadata, pero para este tutorial no los vamos a utilizar.
Voy a cerrar esto y bueno, ya que ya tenemos nuestro smart contract compilado, necesitamos una forma de desplegarlo en la blockchain. Y tenemos varias formas de hacerlo. La forma más fácil de hacerlo para testear que todo va bien es hacerlo directamente desde la terminal utilizando las herramientas que nos provee el mismo foundry. Para lo cual podemos venir a nuestra terminal y decirle forge script y aquí deberíamos pasar algún tipo de script y ah, esta es una parte faltante, por lo cual volvamos a nuestro editor de código y al igual que tenemos un script para
desplegar el counter.sol, creamos uno para desplegar nuestro simple storage. Básicamente la convención de nombres es decirle simple storage.s de script.sol. Y perdonad si digo dot y no punto sol, es la costumbre de hablar en inglés la mayor parte del día. Para lo cual vamos a crear un script que nos va a permitir desplegar este smart contract. Notarás algo interesante y es que a diferencia de otros frameworks, como lo era en su tiempo Brownie, en lugar de utilizar Python o otro lenguaje de programación para ejecutar los scripts que nos permitan desplegar nuestro contrato, creamos otro smart contract llamado simple storage.s.sol.
Y es que básicamente Foundry funciona completamente en Solidity. No necesitas aprender otro lenguaje de programación para utilizar este framework, lo que es un puntazo en su ventaja. Vamos a ver cómo se desplegaría esto. Básicamente tenemos que hacer lo mismo que ya hicimos antes, declarar la licencia, declarar la versión de Solidity y aquí necesitamos importar algunas cosas. Primero necesitamos importar los scripts de la librería estándar de Foundry, entonces le digo, impórtame script from o desde forge -stb/script.sol.
Esta es la librería estándar para poder crear scripts utilizando Solidity y Foundry. Y también vamos a importar el contrato, impórtame simple storage desde src, de esta carpeta y simple storage.sol. Técnicamente yo podría hacer algo como esto borrar guardar y esto seguiría funcionando. Básicamente lo que estoy diciendo, lo que sea que tengas aquí en simple storage tráemelo, pero por muchas razones de optimización de gas, eficiencia de código y de rapidez de ejecución, es importante, y esto te va a separar mucho de otros desarrolladores, que en lugar de importar directamente todo el archivo, lo importes especificando el nombre de el contrato.
Esto es interesante porque esta secuencia de importes se parece de hecho mucho a la secuencia de importes que podemos ver en lenguajes como JavaScript, los que tengan experiencia con React JS, les resultará bastante común hacer este tipo de imports. Ahora vamos a declarar el contrato, contract deploy, porque vamos a desplegar simple storage. Este contrato es un script y esto me da otra ventana para explicarte otro concepto interesante. Como estamos importando script de la librería de script o de forge std, estamos diciendo que este smart contract es un script, por lo cual la herencia en solidity funciona de esta manera, importas lo que
sea que quieras heredar y le dices is de es y el nombre de lo que acabaste de importar. Aquí, como dije, estoy diciendo que deploy simple storage es, en efecto, un script. Voy a abrir esto y aquí todas las funciones de deployment o de despliegue en foundry funcionan de la siguiente manera. Necesitas poner la palabra function run para ejecutar esto. Esta función siempre va a ser external y te va a retornar un instancia del contrato. ¿Qué contrato queremos retornar? Pues queremos retornar simple storage. Y, como pudiste ver, me corregí aquí una s que me faltaba porque no es return sino returns. Abramos las llaves
por aquí y vamos a crear la sintaxis simple. Y para ejecutar estos deployment scripts, utilizamos vm, que es la virtual machine que se crea en representación de la IBM o de la Ethereum virtual machine, start broadcast y vm stop broadcast. Todo lo que pase, todas las transacciones, todo lo que nosotros vamos a crear durante esta ejecución, va a pasar dentro de esto. Abrimos el broadcast y cerramos el broadcast. Por lo cual, dentro de esta función, yo lo que yo puedo decir es simple storage, que es la instancia del contrato, le voy a dar un nombre, en este caso Simple storage, pero te darás cuenta que si hago esto me salen los dos
con color morado. Básicamente porque Simple storage con mayúscula es la instancia o el nombre del contrato y Simple storage con minúscula es el nombre de dicha instancia. Podríamos cambiar esto y en lugar de decir Simple storage Simple storage, solamente podríamos decir algo como My contract o mi contrato para pues evitar la confusión. Lo que yo he visto generalmente es que todo el mundo lo que suele hacer es repetir el mismo nombre, entonces en lugar de usar My contract voy a volver a decir Simple storage, pero ten en cuenta que tiene que ser con la letra minúscula. Si lo haces con letra mayúscula, lo tomará como si fuese una clase u objeto o en este caso un smart contract. Y esto va a ser igual a
new Simple storage y vamos a abrir los paréntesis. Esto es bastante interesante, de hecho, porque al hacer esto le estamos diciendo, "Oye, créame una nueva instancia de Simple storage." Abro los paréntesis no porque esto es una función, sino que en estos paréntesis yo debería enviar las variables de constructor. Este contrato no tiene un constructor, es decir, no requiere ninguna variable definida para su ejecución. Es por eso que dejamos estos paréntesis vacíos. Y aquí, como podrás ver, me está diciendo que es una un local use variable, eso quiere decir que estoy declarando esto, pero no lo estoy utilizando. Y como esta función devuelve Simple storage, me está diciendo que tu función está declarada,
pero no me estás devolviendo nada. Vamos a solucionar esto y vamos a decirme, "Devuélveme el Simple storage." ¿Por qué ponemos el return después del VM broadcast? Esto es muy importante, porque primero inicializamos la instancia de la virtual machine, realizamos las transacciones, cerramos la instancia y únicamente con la instancia cerrada es que devolvemos. Si hacemos esto en ejecución, si pondríamos este return statement aquí, nos daría un error. Es importante que lo hagamos de esta manera. Y así de simple, pues, ya está. Con esto es todo lo que necesitamos para desplegar este smart contract. Pero antes de continuar, quiero hacer una pequeña corrección aquí y es que si bien es cierto que podemos utilizar el mismo nombre simple
storage.s.sol, la verdad sería más interesante o más coherente decir deploy simple storage.s.sol. Básicamente le estoy diciendo, "Oye, este smart contract va a ser utilizado para desplegar el otro contrato que tengo acá." Dicho esto, vamos a probar si todo está funcionando bien, si es que esto va a correr de manera correcta y a su vez que podemos desplegarlo hacia la blockchain. Para lo cual voy a volver a mi terminal, voy a decirle forge script script/deploy Le voy a dar enter, esto va a compilar el contrato y básicamente esto acaba de funcionar de manera correcta. Me acaba
de decir que utilizó esta cantidad de gas y que el smart contract fue desplegado en esta dirección o en esta address. Y me dice, "Si es que tú deseas simular una transacción en una blockchain, pásale una RPC URL o la dirección que se utiliza para desplegar los smart contracts." Ahora, algo importante que sepas es que al hacer yo esto, déjame, de hecho lo ejecuto otra vez, lo que va a hacer es crear una nueva instancia de Anvil, desplegar el smart contract y una vez termine, cerrar la instancia de Anvil y aquí no ha pasado nada. Así que aún cuando me está devolviendo esta address, yo la verdad no puedo interactuar con
este smart contract. Necesito que la blockchain esté corriendo, ya sea mantenerla corriendo de manera local utilizando Anvil o a su vez estar utilizando una live network, como puede ser Sepolia. En este caso, lo que vamos a hacer es abrir una nueva instancia de mi terminal, voy a hacerla bastante más grande para que sea visible y vamos a simplemente correr anvil en ella. Esto va a mantener en segunda instancia corriendo mi blockchain y lo que va a ser interesante aquí es que le voy a decir, oye, utilízame esta dirección. Entonces voy a copiar esto, voy a venir acá y le voy a ir decir forge script script slash deploy simple storage dot sol menos menos RPC URL y lo que acabo de copiar. Le voy a dar enter y aquí me
está dando que la simulación fue completada. Básicamente hizo lo mismo, solamente que este caso ya me está mostrando más información como el gas estimado, el gasto total usado y la cantidad requerida de ethereum que se utilizó. Y me dice, simulación completada. Para realmente mandar esta transacción utiliza la bandera broadcast. Básicamente, aunque yo tengo corriendo todo esto, podrás ver que aquí solo tengo información de el chain ID y de los nuevos bloques que están siendo añadidos, pero yo no veo aquí ningún tipo de transacción. Y es que cuando utilizamos este comando sin el aditivo de decirle menos menos broadcast, lo que realmente va a hacer es crearte una especie de simulación,
pero no va a ejecutar la transacción como tal. Le voy a dar clic en enter y esto me va a dar un pequeño gran error. Y es que básicamente me dice, okay, tú estás utilizando el sender por defecto de foundry, pero necesitas utilizar tu propio sender. Básicamente porque estoy utilizando una wallet address utilizada por defecto cuando se utiliza esto, pero la wallet address que yo debería estar utilizando es una de estas que tengo por acá. Es por lo cual que yo necesito, en lugar de solamente decirle esto, dash dash o slash o menos menos broadcast, darle un poquito más de información. Y aquí le tengo que especificar la private
key que va a firmar esta transacción. Entonces, voy a decir private key, y voy a utilizar una de las private key que me ofrece Anvil por aquí. Voy a escoger la primera, voy a copiar esto, pegarlo por aquí, y ahora sí voy a decirle menos menos broadcast. Le voy a dar enter, y esto debería funcionar, y como puedes ver, esto desplegó de manera correcta mi smart contract en la red local que yo tengo corriendo aquí, que se llama Anvil. Y como podrás ver, si yo voy hasta aquí abajo, aquí se queda registrada la transacción. La transacción con este hash me creó un nuevo contrato con este address, el gas que utilizó, en qué bloque se realizó esta transacción, el
block hash, etcétera, etcétera. ¿Qué pasa si es que yo ejecuto esto de nuevo? Voy a ejecutar de nuevo y voy a crear una nueva instancia. Voy a venir acá, y como podrás ver, esto me genera otra cosa. Me crea una nueva transacción con un nuevo contrato desplegado, con una nueva cantidad de gas y en un nuevo bloque. Y yo puedo seguirle dando, y dando, y dando, y esto va a seguir utilizando y desplegando nuevas instancias del contrato que yo quiero en esta instancia de la red local de Anvil. Y aquí es donde quiero hacer un pequeño inciso. Acabamos de construir este simple smart contract, acabamos de crear
el script para desplegarlo, y nos damos cuenta de que se despliega de manera correcta en nuestra blockchain local. El siguiente paso obvio es empezar a crear pruebas. Deberíamos crear pruebas tanto unitarias como de integración para asegurarnos de que nuestro smart contract funciona como se supone que debería funcionar. En un ambiente de desarrollo profesional, son partes que no deberías saltarte bajo ningún concepto, pero como esto es un vídeo y queremos hacer las cosas más dinámicas, me voy a saltar la parte de los scripts de testing para pasar directamente a la parte en la que vamos a construir el front-end que va a interactuar con este smart contract. Sin embargo, cuando tú estés viendo este vídeo, sabrás que en el link de la descripción está el link del repositorio en GitHub y en ese repositorio sí que tienes los test para
este smart contract que te recomiendo encarecidamente le eches un vistazo. Además, aunque ya lo dije antes durante este vídeo, si sientes que estoy hablando cosas que no entiendes para nada y estoy dando por sentado demasiados conceptos que realmente no estás entendiendo en absoluto, recuerda que este es un vídeo contenido para enseñarte el potencial de las cosas que puedes construir, pero si quieres empezar del cero absoluto, puedes ir a Cypher Node Draft, tomar cualquiera de los cursos, en especial los que son de nivel de entrada y empezar a construir tu carrera desde cero a experto 100% gratis. Si tú deseas que cojamos partes de ese curso o los cursos enteros de Obder en totalidad y los traduzcamos al español, no olvides darle apoyo a este
vídeo dejando tu like y suscribiéndote porque de esa manera sabremos que este contenido es algo de tu interés y nos pondremos a crear muchísimo más para la audiencia hispanohablante. No te canso más con la publicidad y vamos a pasar a la segunda parte que es la creación del front-end de este proyecto. Espero estés listo porque vamos a empezar. En el repositorio asociado a este vídeo también van a encontrar un template para el front-end que vamos a estar utilizando. Básicamente de esta plantilla que he creado que tiene todas las funcionalidades de nuestro smart contract, la capacidad de almacenar un número favorito, obtener dicho número,
crear una nueva persona y obtener el número favorito de esa persona basada en su nombre y por supuesto un botón de conectar que nos va a permitir conectarnos con Metamask, que es la wallet que utilizamos por defecto. Por supuesto, si damos clic en cualquiera de estos botones, de momento no hacen nada porque, pues, por eso es un template. Así que recuerda visitar el link de la descripción. Vas a entrar a este repositorio, vas a copiar el código utilizando SSH o HTTPS, clónalo en tu terminal y una vez que lo tengas clonado es importante que hagamos un npm install para instalar todas las dependencias y un npm run dev para correr el servidor
en el localhost, en el puerto 3000, que es, de hecho, lo que ya te acabo de mostrar. Por supuesto, antes de correr el servidor, te recomiendo que abras el proyecto en tu editor de código Visual Studio Code y podemos empezar. La primera cosa que necesitamos hacer es hacer que este botón de conectar funcione, lo que significa que, básicamente, podamos conectar nuestra Metamask pues, con esta página. Generalmente, lo que haríamos es cambiar una red como se folia, como ya te dije antes, y utilizar esta, pero no vamos a hacerlo de esta manera, básicamente, porque las redes live suelen ser un poco más lentas y, sobre todo, porque últimamente conseguir fondos para estas
faucets tiende a ser más complicado porque suelen requerirte tener fondos reales en tu billetera. Así que, de momento, lo que vamos a hacer es utilizar la red que ya tenemos corriendo de manera local en nuestra terminal, o es decir, la red de Ambil. Para eso necesitamos añadir esta red, pues, a Metamask, así que vamos a hacer eso. Voy a dar clic aquí, voy a expandir la vista, así podemos verlo de manera grande. Como puedes ver, yo ya tengo una red llamada local y te voy a enseñar cómo añadirla tú. Vas a dar clic en añadir network, vas a añadir network de manera manual. Aquí le puedes dar cualquier nombre como red local o lo que tú quieras decirle y aquí en el RPC URL
vamos a decirle http dos puntos y vas a copiar y pegar la URL proporcionada o la IP address proporcionada por Anvil. Si sabes algo de informática sabrás que 127.0.0.1 hace referencia al local host y está corriendo en el puerto 8545. Entonces voy a copiar esto. A mí me dice que hay un error porque yo ya tengo una red corriendo en ese mismo nodo, por lo cual yo no lo voy a añadir. Aquí vamos a darle el chain ID o el ID de la cadena, que es la 31337.
El currency va a ser Ethereum y como es una blockchain local no tiene un explorador de bloques. Aquí no me deja guardarlo porque de nuevo me dice, "Oye, tú ya tienes una red en eso." Pero para ti, una vez lo guardes, vas a poder verla de la siguiente manera. Vamos a poder ir acá y solamente utilizar la red local que añadimos. Déjame cerrar todo esto y podrás ver que aunque añadí esta red, yo sigo apareciendo como que tengo cero fondos por completo aquí y la razón es porque estoy utilizando la cuenta por defecto de Metamask. Para poder utilizar una de estas cuentas tenemos pues que importarlas.
Si te das cuenta, yo aquí ya importé dos de esas cuentas como para hacer pruebas, pero te voy a enseñar cómo importar una tú. Le vas a dar clic en añadir account or wallet, importar cuenta, te va a pedir la private key, vas acá y coges una de las private keys proporcionadas por Anvil, la copias, la pegas, le das importar y así de sencillo tienes la cuenta con todos los fondos en esta red. Y así no tienes que utilizar ninguna faucet y podemos testear smart contract sin ningún problema. Yo voy a volver a la cuenta dos para no hacernos lío y con eso ya estamos listos para crear la integración que nos va a permitir conectar, pues, MetaMask con esta página. Para ello necesitamos hacer que este botón funcione y nos permite
conectarnos con la página. Ahora, este proyecto fue creado utilizando Next JS y también utilizando, pues, React que corre junto con Next JS. Si nunca has usado ninguno de estos frameworks o no eres familiarizado con JavaScript, trata de seguirme poco a poco y recuerda, este es un vídeo que es más como un demo para que vayas construyendo tu portafolio, pero si te gustaría que hagamos un tutorial completo de desarrollo web para desarrolladores de blockchain, haznoslo saber en la caja de comentarios. Para lo cual necesitamos hacer que este componente header, que es el que de hecho contiene el botón que sirve para conectar, pues, nos permita conectar con MetaMask.
Ahora, para nosotros poder hacer todas las conexiones de web tres, vamos a necesitar utilizar una librería llamada Ethers. Si yo voy acá y busco Ethers JS, voy a poder acceder a la documentación oficial y la última versión de Ethers JS es la seis, entonces voy a abrir la documentación de la seis y, pues, aquí tengo toda la información de cómo utilizar la librería de Ethers JS para hacer este tipo de conexiones. A ver, para esto lo que vamos a hacer, lo primero que vamos a hacer, de hecho, es crearnos una nueva carpeta en el directorio raíz de nuestro proyecto, entonces voy a decirle añadir carpeta y le voy a llamar context. Y dentro de este context vamos a crear un nuevo archivo de tipo JavaScript que se va a
llamar MetaMask context.js. Y aquí vamos a añadir toda la funcionalidad utilizando Ethers JS para poder conectarnos, pues, con el navegador. Para lo cual vamos a utilizar, ya que estamos utilizando Next JS, el use client, eso nos permite ejecutar cambios de estado desde el cliente y no tener que depender desde el servidor. Vamos a importar ciertas cosas básicas de React, create context, use context y use state. Y vamos a importar la librería ethers desde ethers. Ahora, si es que yo voy al navegador actualmente y vengo a mi página, me va a decir que todo está funcionando de manera correcta y la razón principal de eso es que si tú te das cuenta en el
package.json son de mi proyecto que es este de aquí, yo ya puse como una dependencia el uso de ethers en la versión 6. Sin embargo, si es que tú quieres usar esto desde cero y no has utilizado nunca esto antes, tendrías que venir a tu terminal y hacer un npm install ethers. Y de esta manera, pues, instalarías esa librería necesaria. Volviendo al código, que siempre abro el smart contract por algún motivo, vamos a crear esta conexión. Esto va a ser bastante fácil, de hecho.
Vamos a crear primero una exportación o una variable, vamos a decirle expórtame una función constante, esto es sintaxis estándar de React. Entonces, voy a decirle un metamask context. Aquí le vamos a pasar una función y esta función, por supuesto, va a tener sus propios children. Y lo que vamos a hacer aquí es declarar unas constantes utilizando use state para saber si es que estamos conectados, cuál es el account y el signer es quien va a firmar las transacciones.
Por cierto, te bastarás preguntando, "Ey, ¿por qué estás saltando tan rápido y estás explicando todas estas cosas?" Recuerda que este es un video y tenemos que hacerlo de la manera más dinámica, pero te recomiendo encarecidamente que si quieres entender esto a mayor profundidad, chequees la documentación de ethers.js y vas a entender por qué necesitamos esto, que es básicamente lo que nuestro Metamask necesita para funcionar de manera correcta, vaya. Vamos a volver acá y vamos a decirle que creo quiero crear una nueva función asíncrona, entonces le voy a decir async function connect to Metamask. Abro paréntesis, abro llaves y dentro de estas llaves le voy a decir si la ventana que estoy utilizando no es una Window 2 de Ethereum, es decir, si no estoy utilizando Metamask, que me dé un error, que me diga en la consola, oye,
no tienes instalado Metamask, no puedes seguir utilizando esto. Y si es que sí tengo instalado Metamask, entonces le voy a crear un try catch statement. Para el catch, lo único que quiero hacer es que me lance en la consola el error que se haya producido y en el try le voy a decir primero necesito declarar un provider, entonces const provider, esto va a ser igual a new ethers .provider. browser provider. Como podrás ver, hay que algo interesante y es que Copilot parece no estar actualizado a la última versión de ethers.js y la anterior versión, la versión 5, realmente utilizaba algo como esto, ethers.providers.webprovider, pero la última versión de ethers, que es la 6, que es la que estamos utilizando,
lo que tenemos que hacer es ethers.browserprovider. Y dentro de este browser provider le vamos a mandar ese window.ethereum. Que es pues que tenemos instalado Metamask en nuestro navegador. Luego necesitamos enviarle una petición al provider para tener acceso a las cuentas, entonces, como esta es una función asíncrona, le voy a decir await provider.send y que me dé las cuentas. ¿Qué es lo que va a dar esto? Me va a dar pues todas las cuentas que tengo aquí en mi Metamask. Una vez tengo las cuentas, le voy a decir por acá oye, quiero que me listes dichas cuentas, entonces const
accounts va a ser igual a nuevamente await, recuerda que todo esto es asíncrono. Provider.list accounts, que es para listar las cuentas. Y luego necesito el signer, const signer es igual a Provider.get signer. Recordemos que el signer es la cuenta en específico que vamos a utilizar para firmar y enviar las transacciones. Luego ya que tengo estas variables y estas variables son variables que voy a necesitar utilizar alrededor de toda la aplicación, necesito setearlas, entonces esto va a ser tan fácil como decirle set is connected to true, porque ya me acabo de conectar. Set account Va a ser accounts.0
o la la account que viene a ser el que acabo de obtener acá. Punto address Y por supuesto el signer, entonces set signer igual al signer que acabo de crear. Como yo necesito utilizar estas variables account, signer y is connected en toda la aplicación, necesito devolver esto como un context provider. Por lo cual fuera de la función le voy a decir retórname Un metamask context provider Con los valores de si está conectado, el account, el signer y por supuesto la función para conectarse a metamask y todos los componentes children de esto.
Por supuesto y si si es que yo voy a devolver un provider, necesito declarar este provider en algún punto, entonces aquí abajo le voy a decir, oye Const metamask Context es igual a create context y el create context por supuesto viene de react. Y por último ya tengo todo el componente creado y solo necesito exportarlo, entonces le voy a decir, oye expórtame Const use metamask, una función Y dentro de esta función lo que le voy a decir es Que me utilice el contexto de el Metamask context. Y con eso, pues, ya tengo todo. Y aquí tengo un carácter de más. Voy a guardar esto y con esto ya
tenemos. Este es todo el componente que vamos a utilizar para conectarnos a Metamask. Una cosa interesante es que de ahora en adelante, si tú vas a utilizar este método con Next JS, ya puedes venir a este proyecto y simplemente copiar este code snippet y utilizarlo, pues, donde quiera que lo necesites. Ahora, para hacer que esto funcione y para hacer que estas variables estén disponibles en todo el proyecto, vamos a necesitar utilizar este context provider. Para lo cual vamos a ir a layout.js, que suele estar en la carpeta app, y vamos a cambiar un poco esto de aquí. Primero lo primero, vamos a importar lo que tenemos que importar.
Entonces, le voy a decir, "Oye, impórtame el Metamask provider de el context {slash} Metamask provider, pero aquí no es un arroba, sino un punto punto, para que me coja el Metamask provider. Déjame poner la dirección bien. Sería punto punto {slash} context {slash} Metamask context. Y una vez tenemos este Metamask provider, ya podemos venir acá. Voy a borrar el class name del body, porque, la verdad, no lo voy a utilizar. Y en lugar de solamente mandar este children, lo que voy a hacer aquí es declarar ese componente Metamask provider. Y este children de acá y este body de acá ya son innecesarios, excepto el de cierre, por supuesto.
Entonces, voy a borrar esto de aquí, voy a guardar. Y así de simple, ya tengo toda mi aplicación encerrada en este provider. Y este provider, pues, ya me va a dar todos estos datos de manera global para toda la aplicación. Esto es muy interesante hacerlo de esta manera en Next JS, porque si estabas utilizando React, simplemente, hubiese tenido que utilizar algo como Redux para hacer que estas variables estén disponibles de manera global. Déjame volver a mi aplicación y ver que todo sigue funcionando, sí, y en efecto esto funciona. Sin embargo, nuestro botón de conectar sigue sin conectarnos, pues porque no estamos utilizando nada de esto, en especial no estamos utilizando la función Connect to Metamask, así que vamos a utilizarla. Para eso vamos a ir
al componente dentro de los componentes del header y en este header vamos a, mientras cliquemos este botón de conectar, pues vamos a conectarnos. Para eso vamos a tener que hacer varios cambios a esto de la siguiente manera. Primero vamos a importar todo lo que tenemos que importar, entonces voy a decirle, impórtame Use Metamask desde el contexto y con eso podemos empezar. Por supuesto, como voy a utilizar estas variables globales, yo quiero decirle const is connected account y Connect to Metamask va a ser igual a Use Metamask. En este return vamos a devolver exactamente lo mismo pero vamos a hacer algunos cambios. Así
que dentro de este div, el div de acá, voy a borrar este botón y le voy a decir quiero que me añadas otro div por aquí y dentro de este div le vamos a decir, le vamos a, más bien a preguntar, oye ¿estás conectado? Si es que sí estás conectado, pues vas a hacer una cosa, en este caso lo que quiero que hagas, si es que sí estás conectado me muestres el account, que en este caso va a ser la wallet address. Y si es que no estás conectado, entonces ahí sí quiero que me des un botón y este botón lo que va a hacer es darme la funcionalidad para conectarme. Entonces voy a dar clic acá y voy a utilizar el
mismo botón que estaba utilizando antes con la diferencia de que en en componente on click voy a utilizar esa función Connect to Metamask. Y algo que me faltó aquí un poco, estoy utilizando tailwind js, es darle un poco de estilos a este account. Entonces, vamos a guardar esto por aquí y veamos si todo está funcionando, para eso voy a volver a mi aplicación, voy a darle click en conectar y voilà, esto en mi caso me conectó automáticamente y eso es porque yo ya estaba conectando esto desde antes. Pero en caso de que no esté conectado, de hecho, déjame desconectar de esta página, desconectar todas las cuentas de esta página, vamos a recargar el local host y suponiendo que no esté
conectado, si le doy click en conectar, esto debería triggerearme metamask, que aquí me sale gigante por algún motivo, me dice que escoja la cuenta que quiero utilizar, como te dije, voy a utilizar esta cuenta, que es la que está conectada con mi módulo o mi nodo de anvil por acá. Y le voy a dar click en next. Confirmar y así de simple, nuestra página web está conectada a metamask. Una vez tenemos metamask, pues ya podemos interactuar con este smart contract. Para interactuar con un smart contract necesitamos varias cosas. Primero, quién va a ser la cuenta que firma, es decir, la cuenta de la cual vamos a lanzar la transacción, esa ya la tenemos, porque básicamente acabamos de conectarlo y ahora necesitamos de parte del smart contract dos cosas, el ABI y
su address. El address lo vamos a tener porque podemos desplegar el contrato aquí y de hecho, como yo volví a correr esta instancia de anvil, voy a volver a mi consola de smart contracts, limpiar mi terminal y le voy a decir forge script y que me vuelva pues, básicamente, a desplegar este contrato. Voy a darle click en enter y esto me va a desplegar una nueva transacción y esta transacción es la que me interesa. El contrato fue creado en esta dirección, entonces, yo voy a copiarme esta dirección, voy a venir a mi editor de código del front end y vamos a crearnos una nueva carpeta por aquí. Voy a decirle que esta carpeta se va a llamar
chain info. Y dentro de chain info me voy a crear un archivo de tipo JSON llamado contract info.json. Y aquí de momento solamente voy a pegar esto y lo voy a poner como un comentario que va a ser el address que vamos a estar utilizando. Ahora necesito obtener el ABI, para eso volvamos a nuestro proyecto de los smart contracts, vamos a out, buscamos nuestro contrato, que en este caso para mí es simple storage, que debería estar por algún punto de aquí, este de aquí, simple storage, abramos esto, voy a dar control S para que se me autoformatee, y aquí tenemos que encontrar la ABI, entonces yo voy a copiar toda esta ABI
de inicio a final, incluyendo el bytecode, que termina más o menos por acá. Voy a copiar todo esto y lo voy a añadir a mi archivo JSON. Para eso me creé esta estructura simple de cualquier archivo JSON, donde le estoy pasando el address de mi smart contract, el nombre que se llama simple storage, y la ABI, que de hecho la voy a pegar ahora mismo. Y por supuesto aquí abajo también voy a pegar el bytecode, así que peguémoslo por acá, y aquí me está faltando una coma. Con esto, en este archivo JSON ya tenemos lo más importante para interactuar con este smart contract, el address, que recuerda es el address que acabamos de desplegar aquí en nuestra
red de anvil, este address va a ser diferente para ti, el ABI y el bytecode. El bytecode no siempre es necesario, depende del framework, pero a mí siempre me gusta incluirlo en todos los proyectos que hago, porque por ejemplo, si llegas a utilizar un framework tipo, no sé, brownie, el bytecode siempre es necesario. Voy a guardar esto, y ahora ya podemos acceder a este componente. Recordarás que nosotros ya tenemos conectada nuestra wallet a la página web. Ahora necesitamos una forma de hacer que este almacenar número favorito funcione. Si es que yo pongo dos, tres, cuatro, lo que sea y le doy clic en almacenar, pues esto debería triggerear una función aquí en Metamask que me permita pues ejecutar esa transacción. Pues vamos a ello. Lo
primero es lo primero y es que vamos a crear una nueva carpeta para eso llamada hooks. Vamos a decirle h o o k s. Quiero dar un pequeño disclaimer aquí y es que esta aplicación se supone que está diseñada para los principiantes y novatos que no tienen mucha experiencia en Next JS o en React JS. Debo decir que existen implementaciones muchísimo más elegantes de aplicar hooks y componentes en Next JS. Yo lo estoy haciendo de esta manera para demostrar cómo se puede hacer, pero todos aquellos que tengan experiencia en el desarrollo web más avanzado sabrán que lo que estoy a punto de hacer no es la estructura más recomendada para
de Next JS o de React. Sin embargo, como te dije, va a servir perfecto para enseñarte los conceptos que quiero enseñar en este vídeo. Dicho este disclaimer, podemos continuar. Dentro de la carpeta hooks, vamos a crearme un nuevo hook que va a ser el hook llamado use store number {punto} js. Este hook va a ser el encargado de ejecutar la transacción utilizando ethers js y pues la conexión que ya tiene con Metamask. Como siempre, como es un proyecto de Next JS, voy a decirle que me utilice el cliente para poder utilizar estas funciones. Vamos a importar ethers js y el contract info que es el que tenemos
por acá en chain information. So, de chain information, cógeme el contract information, que es lo que necesito, como te dije, la abi, el contract address y en algunos casos el byte code. Vamos a venir por acá y vamos a decirle expórtame la función use store number. Vamos a abrir paréntesis, abrir los llaves por aquí y aquí le voy a decir primero const el address del contrato y la ABI, por favor, obtenmelos de el archivo JS o el archivo JSON, perdón, que te acabo de importar y el que acabo de crear acá. Y aquí voy a crear una
nueva función que va se va a ser la función asíncrona almacenar número. Este número no va a venir directamente de aquí, sino que lo paso como parámetro externo, parámetro externo que por supuesto va a ser utilizado en los componentes y enviado desde este formulario. Así que vamos a decir dentro de esto try, como siempre vamos a hacer un catch del error y vamos a decirle que me imprima en consola si es que llega a encontrar algún tipo de error. Y dentro de este try vamos a hacer algo muy parecido de lo que hicimos acá en el context, en el metamask context, que es declarar el provider y este tipo de cosas que necesita metamask. Vamos a tener el provider y vamos a obtener el signer y básicamente aquí voy a declarar
un nuevo contrato, entonces const contract igual a new ethers.contract address ABI y el signer. Aquí básicamente estoy creando una instancia del contrato. ¿Qué el address de deployment y la ABI. Y por último necesito crear la transacción, entonces le voy a decir let transaction o TX es igual a await contract. Y aquí es muy importante porque aquí yo voy a llamar una de las funciones del smart contract.
Si es que utilizo mal el nombre esto no va a funcionar. La ABI es una representación de las funciones de nuestro smart contract, entonces aquí, donde está en nuestro smart contract, la función para almacenar la declaramos como store, entonces tenemos que utilizar exactamente el mismo nombre, store. Voy a darle store y aquí voy a pasar el número, el número que viene como parámetro de esta función obtenido desde el formulario y voy a pasarle otro parámetro para que me haga un control del gas y voy a decir que este va a ser el gas límite o el gas máximo que puedo utilizar. Es buena práctica hacer un transaction.wait para que espere a que la transacción se complete de manera correcta. Y así de
sencillo ya lo tenemos. Utilizamos el provider y el signer, creamos una nueva instancia del contrato utilizando la ABI y el address que obtuvimos en el archivo JSON y lanzamos la transacción store que nosotros ya conocemos porque creamos el smart contract. Lo último que me queda hacer en este archivo es decirle, oye, por favor, retórname el store number. Voy a guardar esto y esto debería funcionar. Básicamente ya tengo el hook creado, entonces yo puedo volver a los componentes, ir a el store number.js y aplicar esa funcionalidad aquí. Para eso vamos a actualizar este componente, así que lo primero lo primero vamos a
importar el hook que acabamos de crear y en lugar de mandar este store number como parámetro aquí, vamos a borrarlo porque vamos a utilizar el que viene, por supuesto, del hook. Para eso le vamos a decir, store number es igual a use store number, que es el hook que como te dije, acabamos de crear. Este formulario ya está listo para recibir ese número, pero aquí solamente quiero verificar que este número esté siendo usado de manera correcta, entonces le voy a decir, number, dos puntos, number number. Y aquí lo único que me estoy asegurando es que el número que se está enviando realmente sea un número y no una cadena de texto o cualquier otra cosa. Ahora bien, antes de continuar aquí tengo que decirte una cosa y es que aquí te hice poner un tx.wait básicamente porque es una buena práctica esperar a un bloque de confirmación. Sin
embargo, ya que estamos utilizando la blockchain local de Anvil, esto sería una pésima idea porque tendríamos que hacer varias cosas para llegar a ese bloque entero, así que voy a quitar esto para que la transacción se ejecute directamente. Entonces, voy a guardar por aquí, guardar por acá y en teoría esto ya debería funcionar, por lo cual voy a ir a mi navegador, voy a poner que por ejemplo el número favorito es 42 y le voy a dar clic en almacenar. Esto te iría a mi operación de Metamask. Voy a darle en confirmar. Y veamos si es que esto fue correctamente. Me dice que es la transferencia está en pending, pero veamos si es que esto es cierto. Como puedes ver, aquí ya tenemos la nueva transacción. La transacción con este hash utilizó este gas y se ejecutó en este bloque. Parece que la transacción
se ejecutó correctamente. Eso quiere decir que ahorita dentro de nuestro smart contract, el nuevo número favorito global es 42. Me gustaría que comprobemos esto también en el front-end y como puedes ver aquí la transacción store ya fue ejecutada correctamente. Si te preguntas por este field de acá, es porque básicamente estaba haciendo pruebas fuera de cámara, pero no te preocupes. La última que acabamos de hacer pues ha funcionado de manera correcta. Entonces, en teoría, si es que yo doy clic en este obtener número favorito, debería obtener dicho 42. Vamos a ver si es cierto y para eso vamos a crear un nuevo hook, ya no para almacenar el número, sino para obtener.
Aquí voy a hacer un poco las cosas más rápido porque va a ser un poco repetir el proceso que ya hicimos. Entonces, básicamente en el hook voy a crear un nuevo hook que se va a llamar use get number.js. Voy a importar nuevamente las cosas que importé antes. Voy a crear la función y dentro de la función voy a declarar el address y la ABI, que es lo que vamos a utilizar. Aquí es porque te dije que hay implementaciones más elegantes de este código, porque aquí estamos reutilizando los mismos statements una y otra vez.
Podríamos hacerlo de maneras diferentes para que esto no sea necesario, pero como es un tutorial quería hacerlo lo más simple posible. Entonces voy a decir asynchronous function get number. Voy a abrir el paréntesis, dos corchetes, voy a guardar y aquí voy a hacer lo mismo que hice antes, declarar el provider y el contrato. El contrato lo voy a obtener a partir de utilizar el address del ABI y en este caso el provider. ¿Por qué utilizo un provider y no un signer? Porque recordemos que la función retrieve del smart contract, aquí déjame hacer grande esto, la función retrieve del smart contract, que es una función de tipo view, que no requiere que firmemos ninguna transacción y solamente es para obtener la información. Entonces para esto no necesitamos el signer, pero
en su lugar utilizamos el provider. Voy a decirle entonces que el número que quiero obtener, o let number, va a ser igual a await contract. Y aquí el autocompletado me dice get number, pero tú y yo sabemos que la función se llama retrieve. Y con esto ya puedo hacer un return de ese número. Entonces voy a decir return number. Por supuesto, todo esto debería ir en un try catch, así que voy a añadir esto. Voy a guardar y por supuesto vamos a retornar ese número por acá. Y así de simple ya tenemos este hook creado, por lo cual vamos a hacer exactamente lo mismo que hicimos para añadir el número y es ir a su componente respectivo, en este caso retrieve number.js
y vamos a hacer los cambios necesarios. Entonces primero lo primero, vamos a importar el hook, al igual que hicimos anteriormente. Entonces import use get number from los hooks y aquí vamos a nuevamente hacer lo mismo que hicimos antes. En lugar de que el retrieve number venga como parámetro de este componente, lo vamos a borrar y en su lugar vamos a utilizarlo directamente por aquí. Entonces, aquí voy a decirle const get number igual a use get number. Y a la vez voy a utilizar un use state para actualizar el estado de esto en caso de que el componente se actualice o le dé clic más de una vez. Entonces, number y set number es igual a use state y de momento que empiecen en null. Aquí
voy a cambiar un poco esto porque en lugar de utilizar el retrieve number, que es solamente una variable, voy a crearme aquí una nueva función que diga const handle retrieve number, va a ser una función asíncrona y dentro de esta función asíncrona voy a decirle const retrieve number va a ser igual a await get number y set number, que es para setear este número que se va a presentar en la interfaz, va a ser igual a el retrieve number. Entonces, cuando use el click o cuando haga el on click en este botón, en lugar de utilizar esa variable, voy a borrar esto y voy a utilizar la nueva
función que acabo de crear, handle retrieve number. Todo lo demás básicamente se mantiene de la misma manera, pero sin embargo, ahorita aunque lo obtenga no lo estoy mostrando en ningún lado, entonces voy a hacer que esto se muestre en pantalla diciéndole, "Oye, si es que no existe un número, no me muestras nada y si es que sí existe un número, créame una nueva etiqueta de tipo P con estos estilos, con mi número favorito y pues pásalo a string." Guardemos todo esto y esto en teoría debería funcionar, así que vamos a ir a nuestra página web nuevamente. Parece que cometí un error. Me dice que use state is not defined y la razón es porque no estoy importando use state de
react. Entonces, voy a poner aquí una coma, voy a abrir esto y le voy a decir use state. Voy y guardar, volvamos acá y esto ya debería funcionar. Entonces, en teoría, aunque no esté conectado, de hecho, si le doy clic en obtener número, esto me debe dar 42. Y así de simple tenemos en la función retrieve. Podrás ver que aquí en el block explorer no se ejecuta ninguna nueva transacción, y es lo que te dije, las funciones view no hacen cambios en la blockchain, por lo tanto, una nueva transacción no es necesaria y solamente me da la información del smart contract. Y esto fue super sencillo, como pudiste ver.
Ahora bien, como podrás observar, tenemos todavía dos componentes restantes en este proyecto, añadir una nueva persona y obtener el número favorito de esa persona a través del mapping. Estos dos hooks restantes van a ser un reto para ti. Ya viste cómo creamos los hooks, cómo nos conectamos con Metamask y el proceso que vas a tener que seguir es exactamente el mismo, definir el provider, crear el contrato utilizando la ABI y el address que ya tienes en el archivo chain info y, pues, utilizar ese hook en dichos componentes.
Sin embargo, para ustedes, quienes se les dificulte esto o solamente quieren tener el proyecto finalizado, por supuesto que en el repositorio de GitHub tendrás el repositorio completo con todas las funciones implementadas. Pero ahora, ahora quiero que te des una palmadita en la espalda. Básicamente, acabas de crear un smart contract desde cero utilizando uno de los frameworks más populares que hay ahí afuera. Acabas de utilizar ese smart contract conectado directamente con tu Metamask, corriendo en una blockchain local y utilizaste un front-end para interactuar con ese smart contract. Con esto, en un solo video, acabas de hacer un montón. Creaste tu smart contract, lo desplegaste, corriste
tu propia blockchain local, la añadiste a tu Metamask, utilizaste y modificaste el front-end, conectaste Metamask al navegador y ahorita eres capaz de interactuar con los Smart Contracts. Y esto esto solamente es un boilerplate, ¿sabes? Ahorita ya tienes el conocimiento básico sobre creación de Smart Contracts, cómo desplegarlos y a su vez cómo crear interfaces que interactúen con ellos. Me voy a repetir en algo que ya dije y no quiero sonar como trompo durante el video, pero este contenido está pensado para que sea una forma fácil de compactar todo esto en un solo video. Obviamente me salté muchas cosas, me salté muchos conceptos y las implementaciones que hice en el frontend no son las mejores. Y la razón, como ya te dije, es que para crear eso
necesitaríamos crear un curso entero. Y si se quieres más contenido en español, no olvides apoyarlo y dejar un like en este video. Sin más que decirte, agradezco mucho por haber creado este proyecto conmigo y por haberme acompañado todo el tiempo que duró este video. Y nos vemos en la próxima ocasión. Adiós.