Iniciemos la creación del sitio web para nuestra Dapp de préstamos. Con el contrato inteligente ya desarrollado y testeado con éxito, es hora de construir una interfaz interactiva usando HTML, CSS y JavaScript puro. Este proceso te guiará en la creación de una página web funcional y atractiva, esencial para que los usuarios interactúen con tu Dapp. Aunque nuestro foco es el desarrollo en Solidity, el conocimiento básico de desarrollo web es clave para presentar tu proyecto de manera efectiva. ¡Empecemos! 💪
Dar vida al aspecto visual de tu aplicación de préstamos descentralizada
Parte 1: Creación del Sitio Web Frontend para tu Dapp de Préstamos
Primero, dentro de la carpeta de tu proyecto, crea una nueva carpeta nombrada website/
(puedes ponerle el nombre que quieras).
Vamos a aprender a desarrollar el sitio web utilizando HTML, CSS y JavaScript puro. Comienza creando un archivo llamado index.html
dentro de la carpeta website/
. Añade el siguiente código:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Página de Préstamos</title>
<style>
.box {
display: none;
max-width: 700px;
margin: auto;
}
</style>
<!-- Solo CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
</head>
<body>
</body>
</html>
Esta estructura básica de HTML incluye el título del sitio, que se mostrará en la barra superior del navegador. Dentro de la etiqueta <style>
, puedes agregar tus estilos CSS, que sirve para modificar la apariencia de tu sitio web. HTML, por otro lado, es la estructura y el contenido textual.
Hemos incorporado un enlace a Bootstrap, una biblioteca que facilita la creación del sitio web proporcionando estilos predefinidos. Es como un atajo para diseñar más rápidamente.
A continuación, añadiremos elementos de diseño para que realmente adquiera ese aspecto. Copia el siguiente código y colócalo entre las etiquetas <body> </body>
:
<!-- 1 Barra de Navegación -->
<nav class="navbar navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Dapp de Préstamos DeFi</a>
</div>
</nav>
<!-- 2 Textos Descriptivos -->
<div class="container text-center">
<div class="row">
<div class="col">
Como prestamista: Despliega un nuevo contrato de préstamo, deposita algo de ETH de prueba y comparte la dirección del contrato con tu amigo.
</div>
</div>
<div class="row">
<div class="col">
Como prestatario: Pega la dirección del contrato en el cuadro y solicita algunos fondos. Luego, asegúrate de devolverlos antes de la fecha acordada.
</div>
</div>
</div>
<!-- 3 Botones de Acción -->
<div class="container text-center">
<div class="row">
<div class="col">
<button onclick="showLend()" type="button" class="btn btn-secondary">Quiero prestar cripto</button>
</div>
<div class="col">
<button onclick="showBorrow()" type="button" class="btn btn-secondary">Quiero pedir prestado cripto</button>
</div>
<div class="col">
<button onclick="showRepay()" type="button" class="btn btn-secondary">Quiero devolver mi préstamo</button>
</div>
</div>
</div>
<!-- 4 Formulario para Depositar -->
<form id="lend" class="box" onsubmit="deployAndDeposit(event)">
<div class="mb-3">
<label for="repay-time" class="form-label">Tiempo de devolución en días</label>
<input type="number" oninput="validateRepayInput(event)" class="form-control" id="repay-time" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">Cuántos días tiene el prestatario para devolverte</div>
</div>
<div class="mb-3">
<label for="interest-percentage" class="form-label">Porcentaje de interés</label>
<input type="number" oninput="validateInterest(event)" class="form-control" id="interest-percentage">
<div class="form-text">Entre 0 y 100</div>
</div>
<div class="mb-3">
<label for="deposit-to-lend" class="form-label">Máxima cantidad a prestar</label>
<input type="number" step="0.0001" oninput="validateDeposit(event)" class="form-control" id="deposit-to-lend">
<div class="form-text">En ETH</div>
</div>
<button type="submit" class="btn btn-primary">Desplegar Contrato Inteligente de Préstamo y Depositar</button>
<div class="mb-3">
<br/>
<p id="deployed-contract"></p>
</div>
</form>
<!-- 5 Formulario para Pedir Prestado -->
<form id="borrow" class="box" onsubmit="borrow(event)">
<div class="mb-3">
<label for="lending-borrow-contract" class="form-label">Dirección del contrato de préstamo</label>
<input type="text" class="form-control" id="lending-borrow-contract" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">El contrato de préstamo desplegado</div>
</div>
<div class="mb-3">
<label for="lending-borrow-input" class="form-label">Cantidad a pedir prestado</label>
<input type="number" step="0.0001" oninput="validateBorrowAmount(event)" class="form-control" id="lending-borrow-input">
<div class="form-text">En ETH</div>
</div>
<button type="submit" class="btn btn-primary">Pedir Prestado</button>
</form>
<!-- 6 Bloque de Devolución -->
<form id="repay" class="box" onsubmit="repay(event)">
<div class="mb-3">
<label for="lending-repay-contract" class="form-label">Dirección del contrato de préstamo</label>
<input type="text" class="form-control" id="lending-repay-contract" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">El contrato de préstamo desplegado</div>
</div>
<div class="mb-3">
<label for="repay-input" class="form-label">Cantidad a devolver</label>
<input type="number" step="0.0001" class="form-control" id="repay-input">
</div>
<button type="submit" class="btn btn-primary">Devolver</button>
</form>
Cada sección está marcada con un comentario. En HTML, los comentarios se hacen con <!-- tu comentario -->
, y esta información no se muestra en el sitio, solo es visible para ti como desarrollador.
Si aún no lo has hecho, instala Metamask.io en tu navegador y configura una billetera blockchain. Esto será tu puerta de entrada al mundo de las criptomonedas y es esencial para utilizar la Dapp que estás creando.
Este no es un curso completo de desarrollo web, así que no profundizaremos en cada detalle del código. Sin embargo, te guiaremos a través de cada parte para que comprendas lo que estás escribiendo. Sigue los comentarios marcados del 1 al 6:
- Barra de Navegación: En este primer bloque, estamos integrando la barra de navegación superior. Esta es una barra oscura ubicada en la parte superior del sitio web, que incluye un enlace a la página principal.
- Textos Descriptivos: Aquí añadimos dos textos informativos. El objetivo es orientar a los usuarios sobre cómo interactuar con la aplicación descentralizada (Dapp).
- Botones de Acción: Incorporamos tres botones para ofrecer opciones a los usuarios sobre qué acción desean realizar. Al hacer clic en cada uno, se activa una función de JavaScript, como se indica en el atributo
onclick=""
. - Formulario para Depositar: Este bloque forma la primera sección interactiva del sitio, donde los depositantes pueden especificar el plazo de devolución y el porcentaje de interés. Al pulsar el botón para desplegar el contrato inteligente de préstamo y depositar, se ejecutará la función
desplegarYDepositar(event)
. Posteriormente, aparecerá un popup de Metamask para confirmar la creación del contrato inteligente. Aquí es donde se ejecuta elconstructor()
de tu contrato inteligente de préstamos, como se discutió en secciones anteriores. - Formulario para Pedir Prestado: Tras el despliegue del contrato, los usuarios verán la dirección del mismo, que se compartirá con aquellos que deseen solicitar fondos. Este quinto bloque se muestra al hacer clic en el botón para pedir criptomonedas prestadas. Contiene un formulario donde los prestatarios indican la dirección del contrato de préstamo desplegado y seleccionan la cantidad que desean obtener de los fondos disponibles.
- Bloque de Devolución: Se muestra después de que el usuario elija la opción de devolver el préstamo. Aquí, se debe ingresar la dirección del contrato y la cantidad a devolver. Al confirmar estos datos y pulsar el botón de devolución, se iniciará una transacción en la blockchain, visible a través de Metamask, permitiendo al prestatario devolver el préstamo, ya sea parcial o totalmente.
Hemos abordado mucho contenido, pero no te preocupes. Solo necesitas copiar el código y escribirlo en tu editor de código.
Continúa leyendo la siguiente sección para implementar las funciones de JavaScript.
Parte 2: La Fase Final – Implementación del Código JavaScript
Ahora abordaremos la parte final: la implementación del código JavaScript, que es seguramente la sección más emocionante. En PiensaEnCripto, nos encanta JavaScript por su versatilidad y capacidad para crear prácticamente cualquier aplicación.
Escribiremos la sección completa de JavaScript para que la copies manualmente, función por función, y luego explicaremos el código.
Justo después de tu etiqueta de cierre </body>
y antes de la etiqueta de cierre </html>
, añade este código:
<script type="module">
// 1
import { ethers } from "./ethers.js"
window.ethers = ethers
import jsonPrestamo from './artifacts/contracts/Lending.sol/Lending.json' assert { type: 'json' }
const abiPrestamo = jsonPrestamo.abi
const bytecodePrestamo = jsonPrestamo.bytecode
// 2
let tiempoReembolso = null
let interes = null
let deposito = null
let eth = {
proveedor: null,
direccion: null,
firmante: null,
contratoPrestamo: null,
montoPrestamo: null,
}
// 3
const configurar = async () => {
eth.proveedor = new ethers.providers.Web3Provider(window.ethereum)
eth.direccion = (await eth.proveedor.send("eth_requestAccounts", []))[0]
eth.firmante = eth.proveedor.getSigner(eth.direccion)
}
// 4
window.mostrarPrestar = () => {
[...document.querySelectorAll('.box')].map(box => box.style.display = 'none')
document.querySelector('#lend').style.display = 'block'
}
window.mostrarPedirPrestado = () => {
[...document.querySelectorAll('.box')].map(box => box.style.display = 'none')
document.querySelector('#borrow').style.display = 'block'
}
window.mostrarReembolsar = () => {
[...document.querySelectorAll('.box')].map(box => box.style.display = 'none')
document.querySelector('#repay').style.display = 'block'
}
// 5
window.validarTiempoReembolso = evento => {
evento.target.value = evento.target.value.replace(/[^0-9]*/g,'');
tiempoReembolso = Number(evento.target.value)
}
window.validarInteres = evento => {
evento.target.value = evento.target.value.replace(/[^0-9]*/g,'');
interes = Number(evento.target.value)
}
window.validarDeposito = evento => {
deposito = evento.target.value
}
window.validarMontoPrestamo = e => {
eth.montoPrestamo = e.target.value
}
// 6
window.desplegarYDepositar = async e => {
e.preventDefault()
if (!tiempoReembolso) return alert('Debe establecer el tiempo de reembolso en días')
if (!interes) return alert('Debe establecer el porcentaje de interés')
if (interes < 0 || interes > 100) return alert('El porcentaje de interés debe estar entre 0 y 100')
if (!deposito) return alert('Debe establecer el monto del depósito')
const fabrica = new ethers.ContractFactory(abiPrestamo, bytecodePrestamo, eth.firmante)
eth.contratoPrestamo = await fabrica.deploy(tiempoReembolso, interes, {
value: window.ethers.FixedNumber.from(deposito) // Esto convierte el número a wei
})
console.log('eth.contratoPrestamo', eth.contratoPrestamo)
document.querySelector('#deployed-contract').innerHTML = 'Desplegando contrato...: ' + eth.contratoPrestamo.address
console.log('desplegando...')
await eth.contratoPrestamo.deployTransaction.wait()
console.log('eth.contratoPrestamo', eth.contratoPrestamo)
console.log('desplegado!')
alert('¡Desplegado!')
}
// 7
window.pedirPrestado = async e => {
e.preventDefault()
const direccionContrato = document.querySelector('#lending-borrow-contract').value
const cantidadPrestamo = Number(document.querySelector('#lending-borrow-input').value)
if (cantidadPrestamo <= 0) return alert('Debe establecer la cantidad a pedir prestada')
try {
eth.contratoPrestamo = new ethers.Contract(direccionContrato, abiPrestamo, eth.firmante)
} catch (e) {
return alert('Dirección de contrato de préstamo inválida')
}
const transaccion = await eth.contratoPrestamo.pedirPrestado(
window.ethers.FixedNumber.from(String(cantidadPrestamo))
)
await transaccion.wait()
console.log('Préstamo exitoso.')
alert('¡Préstamo exitoso!')
}
// 8
window.reembolsar = async e => {
e.preventDefault()
const direccionContrato = document.querySelector('#lending-repay-contract').value
const cantidadReembolso = Number(document.querySelector('#repay-input').value)
if (cantidadReembolso <= 0) return alert('Debe establecer la cantidad a reembolsar')
try {
eth.contratoPrestamo = new ethers.Contract(direccionContrato, abiPrestamo, eth.firmante)
} catch (e) {
return alert('Dirección de contrato de préstamo inválida')
}
const transaccion = await eth.contratoPrestamo.reembolsar({
value: window.ethers.FixedNumber.from(String(cantidadReembolso))
})
await transaccion.wait()
console.log('Reembolso exitoso.')
alert('¡Reembolso exitoso!')
}
// 9
configurar()
</script>
Cada sección está marcada con un comentario. Los comentarios en JavaScript comienzan con //
. Simplemente busca cada número para entender a qué nos referimos:
- Uso de
<script type="módulo">
: Iniciamos con la etiqueta<script type="module">
, indicando al navegador que estamos incorporando código JavaScript modular. El atributotype="module"
es esencial para habilitar el uso de módulos ES6 de JavaScript. - Importación de ethers.js: Continuamos con la importación de
ethers.js
, una librería esencial para interactuar con la blockchain desde el navegador. Esto implica copiar el código desde un enlace específico y crear un archivo llamadoethers.js
en nuestro directoriowebsite/
. Esta librería nos permite interactuar con nuestro contrato inteligente de préstamos. Para acceder al ABI del contrato, es necesario compilarlo mediantenpm hardhat compile
y luego copiar la carpetaartifacts/
en nuestro directoriowebsite/
. - Configuración de Variables: Establecemos diversas variables con
let
yconst
, que serán utilizadas más adelante. Por ejemplo,eth
es un objeto que contendrá propiedades importantes para nuestro código. - Creación de la Función
configurar()
: Esta función se encarga de establecer la conexión con la blockchain a través de la variablewindow.ethereum
, proporcionada por Metamask. - Funciones
mostrarPrestar()
,mostrarPedirPrestado()
ymostrarReembolsar()
: Estas funciones tienen como objetivo mostrar y ocultar los formularios correctos al usuario tras hacer clic en los botones correspondientes. - Validación de Datos del Usuario: Implementamos funciones para asegurar que los datos introducidos por el usuario sean correctos y estén adecuadamente formateados.
- Función
desplegarYDepositar()
: Esta función se activa al pulsar el botón para desplegar el contrato inteligente de préstamos y realizar un depósito. Verifica que los datos sean correctos y procede a desplegar una nueva versión del contrato inteligente. - Función
pedirPrestado()
: Recibe la dirección del contrato y ejecuta el método
del mismo. Se utilizapedirPrestado
()window.ethers.FixedNumber.from()
para convertir los valores introducidos a un formato queethers.js
pueda procesar. - Función
reembolsar()
: Similar a la función anterior, esta recibe la dirección del contrato, crea una instancia del mismo y ejecuta el métodorepay()
. Se envía ether junto con la ejecución de la función. - Ejecución de
configurar()
: Por último, ejecutamos la funciónconfigurar()
, que se inicia automáticamente al cargar el sitio web.
¡Eso es todo! La Dapp está lista. Ahora puedes abrir el archivo index.html
en tu navegador para interactuar con la aplicación. Pero recuerda, necesitarás configurar un servidor local para que la app funcione correctamente con Metamask.
Para configurar un servidor local, primero instala http-server
usando tu terminal:
npm i -g http-server
Luego ejecuta lo siguiente en la carpeta raíz de tu proyecto:
http-server website/
Esto servirá la carpeta del sitio web, creando un servidor local accesible a través de http://localhost:8080
.
Interactúa con la Dapp y observa cómo los datos se almacenan permanentemente en la blockchain.
🌟 ¡Enhorabuena! 🌟 Has completado la guía.
💰📊 Gracias por llegar hasta aquí. Sabemos que no es poca cosa, y tu dedicación y esfuerzo en este camino merecen ser celebrados. Nos complace haber compartido contigo estos 3 MINITUTORIALES de Solidity y esperamos que te hayan sido útiles. Continuaremos mejorando y aprendiendo para seguir expandiendo nuestros conocimientos 💪
Piensa en GRANDE, piensa en CRIPTO. 😉🦊