Instalación de HardHat en Ubuntu 20.04
Una de las primera cosas que debemos hacer en el desarrollo de contratos inteligentes y aplicaciones descentralizadas es la instalación de las herramientas de desarrollo. En esta entrada veremos cómo realizar la instalación de las herramientas.
Requisitos Previos
Veamos ahora los requisitos que necesitamos de base para la instalación:
- NodeJS: https://nodejs.org/es/download/
- NPM: Si no viene preinstalado con nodeJS
- Git: https://git-scm.com/downloads
Si no tienes este entorno instalado y quieres hacer uso de diferentes versiones de NodeJS en local te recomendamos encarecidamente que instales:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
Para luego instalar la versión de Node que nosotros queramos, por ejemplo:
nvm use 16
Creación del directorio del proyecto
Como siempre necesitaremos crear una carpeta para el proyecto por ejemplo con el comando:
mkdir miproyecto
Después nos meteremos en él
cd miproyecto
Y crearemos la estructura básica de NPM con:
npm init
Instalación de Hardhat
Hardhat es uno de los principales entornos de desarrollo que tenemos para solidity y la EVM. que básicamente es un gestor de tareas y plugins para el desarrollo de contratos inteligentes. Veamos cómo instalarlo.
Con el fichero package.json ya creado ya podemos empezar a introducir las dependencias del proyecto empezando por Hardhat:
npm install --save-dev hardhat
Esto instalará todas las dependencias y nos las colocará como siempre en la carpeta node_modules.
Si quisiéramos disponer del comando hardhat a nivel de sistema lo podríamos instalar de manera global:
npm i -g hardhat
Ya va siendo hora de que empecemos a versionar este proyecto con git:
git init
Estaría bien que creáramos un .gitignore para evitar subir al repositorio git remoto todo lo no necesario.
.idea
package-lock.json
En mi caso la carpeta de configuración de Jetbrains, y el package-lock.json
Añadiremos los ficheros a Git:
git add package.json .gitignore
Y haremos nuestro primer commit:
git commit -m 'primer commit'
Creación del proyecto
Ya va siendo hora de crear el proyecto para ello usaremos del comando global:
hardhat
O si hemos hecho la instalación en local con:
npx hardhat
Esto nos sacará la selección de creación del proyecto:
Como queremos empezar de manera suave seleccionaremos “Create a basic sample project” y vamos dejando las opciones por defecto:
Aunque lo suyo es tuviéramos soporte de Typescript, pero eso lo dejaremos para más adelante.
Estructura del proyecto Hardhat
Cuando termine de ejecutar el generador de proyecto nos dejará una estructura base para el proyecto:
Vemos un poco por encima la estructura:
- miproyecto:
- contracts -> lugar para los contratos inteligentes
- Greeter.sol -> ejemplo de contrato inteligente
- scripts -> scripts de despliegue normalmente
- sample-script.js -> ejemplo de despliegue
- test -> carpeta para las pruebas
- sample-test.js -> ejemplo de prueba
- .gitignore
- hardhat.config.js -> fichero de configuración para hardhat
- package.json
- package-lock.json
- README.md
- contracts -> lugar para los contratos inteligentes
Cabe destacar las dependencias de desarrollo que nos han colocado en el package.json:
"@nomiclabs/hardhat-ethers": "^2.0.5",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"chai": "^4.3.6",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.6.2",
En estos casos usamos lo siguiente:
- chaiJS: lanzamiento de pruebas
- waffle: para las pruebas de contratos inteligentes
- ethersJS: para la conexión a la cadena de bloques y contratos inteligentes
- hardhat-ethers y hardhat-waffle que son los plugins de conexión con estas dos bibliotecas
Si estuviéramos usando la versión avanzada de Typescript deberíamos añadir la siguiente estructura:
- scripts
- deploy.ts -> fichero de despliegue Typescript
- test
- index.ts -> fichero de pruebas Typescript
- .env.example -> fichero de definición del entorno
- .eslintignore -> fichero de exclusiones de eslint
- .eslintrc.js -> fichero de configuración de eslint
- .npmignore -> fichero de exclusiones de npm
- .prettierignore -> fichero de exclusiones de prettier
- .prettierrc -> fichero de configuración de prettier
- .solhintignore -> fichero de exclusión de solhint
- .solhint.json -> fichero de configuración de solhint
- tsconfig.json -> fichero de configuración de Typescript
Por supuesto la lista de dependencias crece bastante:
"@nomiclabs/hardhat-ethers": "^2.0.5",
"@nomiclabs/hardhat-etherscan": "^3.0.3",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@typechain/ethers-v5": "^7.2.0",
"@typechain/hardhat": "^2.3.1",
"@types/chai": "^4.3.0",
"@types/mocha": "^9.1.0",
"@types/node": "^12.20.47",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"chai": "^4.3.6",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-promise": "^5.2.0",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.6.2",
"hardhat": "^2.9.2",
"hardhat-gas-reporter": "^1.0.8",
"prettier": "^2.6.1",
"prettier-plugin-solidity": "^1.0.0-beta.13",
"solhint": "^3.3.7",
"solidity-coverage": "^0.7.20",
"ts-node": "^10.7.0",
"typechain": "^5.2.0",
"typescript": "^4.6.3"
Comandos de Hardhat
A partir de este momento ya deberíamos ser capaces de usar los comandos de hardhat sobre nuestro proyecto.
Compilación
empezando por la compilación de los contratos desde la instalación local:
npx hardhat compile
Si todo ha ido bien debería poder compilar los contratos inteligentes, en este caso del Greeter.sol que viene de ejemplo:
Downloading compiler 0.8.4
Compiled 2 Solidity files successfully
Lanzamiento de Pruebas
Las pruebas son cruciales en los contratos inteligentes porque una vez desplegados en producción ya no hay marcha atrás, lo desplegado desplegado queda para siempre en la cadena de bloques. Y salvo que tengamos técnicas de actualización de contratos inteligentes no se va a poder modificar su comportamiento.
Por lo que para lanzar la prueba diseñada dentro de la carpeta test en el fichero sample-test.js o index.ts en el caso de haber activado Typescript debemos ejecutar este comando:
npx hardhat test
Con lo que tendremos uns salida similar a la siguiente:
Greeter
Deploying a Greeter with greeting: Hello, world!
Changing greeting from 'Hello, world!' to 'Hola, mundo!'
✔ Should return the new greeting once it's changed (493ms)
1 passing (497ms)
Despliegue de contratos inteligentes
En el caso de realizar un despliegue en una blockchain local, waffle en nuestro caso usaremos:
npx hardhat run scripts/sample-script.js
o en el caso de usar Typescript:
npx hardhat run scripts/deploy.ts
Obtendremos una salida similar a la siguiente:
Deploying a Greeter with greeting: Hello, Hardhat!
Greeter deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Donde nos dará la dirección de despliegue del contrato inteligente en local.
Conexión desde Metamask u otra wallet de navegador
Si queremos enganchar nuestra metamask a un nodo local arrancado con waffle deberemos ejecutar:
npx hardhat node
Con esto nos ofrecerá un servidor local al que conectarnos a la URL http://127.0.0.1:8545/ por HTTP y Websocket JSON-RPC. Nos mostrará las direcciones generadas por waffle, unas 20 en total, cada una de ellas con 10000 ETH de mentira para probar.
Es importante recordar que estas direcciones no deberíamos usarlas JAMÁS para realizar ningún despliegue en pruebas (redes de testing de las blockchains) o en producción (en las blockchains de verdad).
Para añadir la red de pruebas en local a Metamask iremos a Configuración -> Redes-> Agregar Red Y rellenaremos la nueva red:
- Network Name: Localhost 8545
- New RPC URL: http://loclahost:8545/
- Chain ID: 31337
- Currency Symbol: ETH
- Block Explorer URL: vacio (es decir, no pones nada)
Una vez seleccionada la red deberíamos importar una dirección desde el nodo. Como vimos antes nos permitía ver las 20 direcciones y sus claves privadas. La clave privada es lo que usaremos para importar la dirección desde Metamask desde Importar Cuenta.
Teniendo seleccionado la clave privada copiamos la clave privada de una de las direcciones por ejemplo la cuenta 0 y la pegamos en el campo “Pegue aquí la cadena de la clave privada” y pulsa el botón “Importar”.
Si hemos hecho correctamente la importación deberíamos ver el saldo inicial de la cuenta que acabamos de importar si tenemos seleccionada la red correcta y la cuenta importada.
Notas finales
Conviene recordar también que para nuestra conveniencia y no mezclar las cuentas lo suyo sería disponer de un navegador con Metamask instalado diferente al que usemos habitualmente para nuestras cuentas de verdad.
Por ejemplo podrías usar Brave, Firefox, Chromium o Vivaldi para el desarrollo y dejar Chrome para producción.
Repositorios de ejemplo
- Repositorio Javascript Básico: https://github.com/pepesan/ejemplo_hardhat_js
- Repositorio Typescript “Complejo”: https://github.com/pepesan/ejemplo_hardhat_typescript
Comments