¿Qué es Hardhat Ethereum?

¿Qué es Hardhat Ethereum?

Hardhat es un ambiente de desarrollo diseñado para facilitar la creación y despliegue de aplicaciones Web3, soportado por Ethereum Foundation y altamente usado por grandes compañías dedicadas a construir la siguiente generación de la World Wide Web.

Hardhat nos ayuda desde el despliegue de un nodo local de Ethereum que incluye cuentas precargadas con una gran cantidad de ethers de prueba hasta el despliegue de nuestra aplicación en un nodo local o en una red de pruebas (Testnet) de Ethereum usando simples configuraciones de red que veremos más adelante.

Otras herramientas populares en el ecosistema son Ganache y Truffle.

Fuente: hardhat.org

Instalación

Para instalar Hardhat primero necesitamos instalar Node.js, para lo cual puedes ejecutar los comandos a continuación de acuerdo al SO que estes usando.

Linux (Ubuntu):

sudo apt update
sudo apt install curl git
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

MacOS:

Podemos usar Homebrew para instalación y automáticamente la ultima version disponible sera instalada:

brew install node

También puedes usar Node Version Manager (NVM):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install 18
nvm use 18
nvm alias default 18
npm install npm --global # Upgrade npm to the latest version

Windows:

Actualmente el sitio oficial de Hardhat recomienda instalar node usando el subsistema de Windows para Linux (WSL2) ya que como muchos sabemos Windows no es la opción favorita para los desarrolladores.

Puedes seguir este enlace para acceder al sitio oficial de Microsoft y continuar con los pasos de instalación de Node en Windows si prefieres usar este sistema operativo o si te sientes aventurero.


Ahora que tenemos Node en nuestro sistema operativo es momento de instalar Hardhat creando un nuevo proyecto con la ayuda de Node:

mkdir hardhat-example
cd hardhat-example
npm init

Ahora podemos instalar Hardhat:

npm install --save-dev hardhat

En el mismo directorio que instalamos Hardhat ejecutamos el siguiente comando:

npx hardhat

Selecciona "Create an empty hardhat.config.js" con el teclado y presiona la tecla Enter.

Nota: npm 7 y posteriores hacen la instalación de las dependencias de Hardhat mucho mas fáciles.

Cuando Hardhat se ejecuta busca el archivo hardhat.config.js más cercano empezando del directorio actual. Normalmente, este archivo vive en la raíz del proyecto y una configuración vacía es suficiente para que Hardhat empiece a trabajar.

Contratos Inteligentes (Smart Contracts)

En principio, el concepto de los contratos inteligentes puede ser un poco difícil de digerir, asumiendo que entiendes los conceptos básicos de Blockchain podemos decir que un contrato inteligente es un protocolo de transacciones cuyo propósito es controlar que los eventos y acciones dentro de el acuerdo al que se haya llegado entre las partes sea automáticamente ejecutado.

Por ejemplo, un caso práctico de la ejecución de un contrato inteligente dentro del Blockchain sucede en el arrendamiento o compra de un apartamento, el cual podría ser ejecutado cuando la parte arrendadora deposite cierta cantidad de Ethers a una cuenta manejada por el contrato y, a su vez, el arrendador pueda generar una acción de conformidad de entrega del inmueble.

Cuando ambos aprueben su conformidad, automáticamente el contrato inteligente transfiere los fondos al arrendador evitando un banco como intermediario (por ejemplo). En caso de no verificar la constancia de ambas partes, el contrato podría ejecutar la devolución de los fondos depositados por el arrendatario o la transferencia parcial al arrendador si la lógica del contrato así lo estipula.

Ahora veamos cómo luce un contrato inteligente en la práctica. Ethereum usa el lenguaje Solidity para la creación de contratos inteligentes.

⚠️
En este post no entraremos en mucho detalle acerca del lenguaje, pero puedes encontrar mas información en la página oficial de Solidity. Si te familiarizas con JavaScript, el lenguaje te resultara muy familiar.

Para empezar crearemos un nuevo directorio llamado contracts y dentro del mismo un archivo al que llamaremos Token.sol

// SPDX-License-Identifier: UNLICENSED
// Los archivos de Solidity deben iniciar con pragma.
// Sera usado por el compilador para validar su version.

pragma solidity ^0.8.9;

// Este es el building block principal del contrato.
contract Token {
    
    // Variables de tipo String para identificar el token.
    
    string public name = "My Hardhat Token";
    string public symbol = "MHT";
    
    // El monto fijo de tokens.
    
    uint256 public totalSupply = 1000000;
    
    // Variable de tipo address usada para guardar cuentas.
    
    address public owner;
    
    // El tipo mapping es un mapa de tipo key/value map. 
    // Aquí guardaremos los balances de las cuentas.
    
    mapping(address => uint256) balances;
    
    // El evento Transfer ayuda a las aplicaciones fuera del Blockchain
    // a entender lo que pasa con el contrato.
    
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    
    /**
     * Contract initialization.
     */
    
    constructor() {
        
        // EL total del suministro es asignado al sender de la transacción,
        // que es la cuenta encargada de hacer deploy del contrato.
        
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }
    /**
     * Función para transferir tokens.
     *
     */
    function transfer(address to, uint256 amount) external {
        
        // Verifica si el que envió la transacción tiene suficientes tokens.
        // Si la función “require” evalúa falso entonces la
        // transacción es revertida.
        
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // Transfiere el monto.
        
        balances[msg.sender] -= amount;
        balances[to] += amount;

        // Notifica a la ampliación fuera del blockchain 
	    // sobre la transferencia.
        
        emit Transfer(msg.sender, to, amount);
    }
    /**
     * Función de solo lectura para obtener el balance del token 
	 * de una cuenta dada.
     *
     * El modificador `view` indica que no se hará ninguna modificación 
     * al estado del contrato y una transacción no es necesaria.
     */
     
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}

Compilar los contratos

Para compilar el contrato necesitas ejecutar en tu terminal:

npx hardhat compile 

Si todo va bien, podrás ver el siguiente mensaje:

$ npx hardhat compile
Compiling 1 file with 0.8.9
Compilation finished successfully

Nuestro contrato fue compilado satisfactoriamente. ¡Felicidades! Acabas de crear tu primer contrato inteligente.

Deploy del Contrato Inteligente

Instalamos Ethers, una implementación de una billetera en Ethereum con utilidades que nos ayudará en el proceso. En la misma terminal ejecutamos:

npm i ethers @nomiclabs/hardhat-waffle

Luego creamos una carpeta llamada scripts y dentro creamos el archivo deploy.js y pegamos el código a continuación.

const { ethers } = require("hardhat");
async function main() {
  const Token = await ethers.getContractFactory("Token");
  // Comienza el deploy, retornando una promesa que se resuelve 
  // en un objeto tipo contract
  const token = await Token.deploy();
  await token.deployed();
  console.log("Token Contract deployed to: ", token.address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error)
    process.exit(1)
});

Ahora copiamos y pegamos el código a continuación al archivo hardhat.config.js

/* hardhat.config.js */
require("@nomiclabs/hardhat-waffle")

module.exports = {
  defaultNetwork: "hardhat",
  networks: {
    hardhat: {
      chainId: 1337
    },
  },
  solidity: {
    version: "0.8.4",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  }
}

Levantamos un nodo de prueba ejecutando el siguiente comando en la terminal:

npx hardhat node

Y veremos una lista con 19 cuentas que pueden ser utilizadas para probar nuestro contrato. Por defecto la primera cuenta será utilizada para hacer el deploy de nuestro contrato inteligente.

Ahora podemos hacer el deploy de nuestro contrato al nodo local, ejecutando en nuestra terminal el siguiente comando:

npx hardhat --network localhost run scripts/deploy.js

Y verás la dirección del contrato:

Token Contract deployed to: 0x5fbdb2315678afec....xxxx

Hora de probar tu contrato inteligente

Llegó el momento de interactuar con el contrato inteligente, para lo cual Hardhat también nos provee con una consola interactiva JavaScript con la que es posible acceder a las funciones definidas en nuestro contrato.

En una nueva consola ejecuta el siguiente comando:

npx hardhat console

Welcome to Node.js v12.10.0.
Type ".help" for more information.
>

La interacción con la red de Ethereum y los contratos inteligentes son operaciones asíncronas. Por tanto, necesitamos hacer uso de promesas para retornar los valores.

Para hacer todo más fácil, la consola de Hardhat soporta el operador await. Para usar este feature necesitas usar Node 10 o superiores.

Para conectar a una red diferente de la que tenemos por defecto usando el nodo local de Hardhat podemos usar el siguiente comando:

npx hardhat console --network network_name

La cual buscará el nombre de red específico en el archivo de configuración hardhat.config.js, por ejemplo:

networks: {
  hardhat: {
    chainId: 1337
  },
  network_name: {
    url: API_URL,
    accounts: [`0x${PRIVATE_KEY}`]
  }
},

Por ahora usaremos solo el nodo local hardhat y crearemos una instancia del contrato usando ethers Contract Factory.

const Contract = await ethers.getContractFactory("Token")

Después de obtener la instancia necesitamos adjuntar la dirección del contrato que acabamos de hacer deploy para interactuar con el contrato (misma dirección que obtuvimos arriba).

const contract = await Contract.attach("0x5fbdb2315678afec....xxxx")

Ahora puedes interactuar con los métodos del contrato y verás toda la información relacionada a la transacción que se acaba de ejecutar.

Por ejemplo, podemos transferir 100 MHT tokens a una nueva cuenta (puedes usar una de las cuentas disponibles al levantar el nodo con Hardhat excepto la primera, misma usada por defecto para hacer deploy del contrato):

await contract.transfer('0x3C44CdDdB6a900...xxxxx', 100)

Y podrás ver los detalles de la transacción:

{
  hash: '0x6ca133f7770fe478b62ab0608cd1c6f51c097c4426a5296dc4ae15bbd4a2c6cd',
  type: 2,
  accessList: [],
  blockHash: '0x49bc61eb9b90f6b60b75482dc7d58bc6da4f396dba31f7be4b9840365178045e',
  blockNumber: 1,
  transactionIndex: 0,
  confirmations: 1,
  from: '0xf39Fd6e51aad88....xxxxx',
  gasPrice: BigNumber { value: "1875000000" },
  maxPriorityFeePerGas: BigNumber { value: "1000000000" },
  maxFeePerGas: BigNumber { value: "2750000000" },
  gasLimit: BigNumber { value: "29022808" },
  to: '0x3C44CdDdB6a900...xxxxx',
  value: BigNumber { value: "0" },
  nonce: 0,
  data: '0xa9059cbb0000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc0000000000000000000000000000000000000000000000000000000000000064',
  r: '0xa91d4832956a8ac159c809387394a58a687948362d564d1dbcd68e76b09325b0',
  s: '0x0c061826e4dab67ae065e016837cd8457ca34a7c9eac09048258b0e5e5b8b958',
  v: 1,
  creates: null,
  chainId: 1337,
  wait: [Function (anonymous)]
}

Esta consola es de gran utilidad al momento de inspeccionar lo que en realidad está pasando con nuestro contrato y si realmente es lo que esperamos de su comportamiento.

Conclusiones

Hardhat nos provee de todo un completo ecosistema para poder generar un nodo, compilar los contratos inteligentes y poder hacer deploy de estos sin necesidad de utilizar o crear una red privada de Ethereum o depender de la disponibilidad de una red externa, también nos provee los mecanismos para realizar el mismo deploy con las redes disponibles para pruebas que nos provee Ethereum.

Usando Hardhat tenemos todo lo necesario para comenzar a escribir nuestra aplicación Web3.0.

¡Éxito!

⚠️
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Revelo.

Revelo Content Network da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.