WEB3DEV Español

Cover image for Una Guía Completa para el Desarrollo de dApps con ethers.js y web3.js
Juan José Gouvêa
Juan José Gouvêa

Posted on

Una Guía Completa para el Desarrollo de dApps con ethers.js y web3.js

Las aplicaciones descentralizadas (dApps) han revolucionado la forma en que interactuamos con redes blockchain y contratos inteligentes. Para permitir una comunicación fluida con la blockchain de Ethereum, los desarrolladores se apoyan en bibliotecas especializadas como ethers.js y web3.js. En este artículo, exploraré las funcionalidades, diferencias y usos prácticos de estas dos populares bibliotecas JavaScript para el desarrollo de dApps. Ya seas un desarrollador experimentado o un principiante en el espacio blockchain, esta guía tiene como objetivo brindarte una comprensión completa de ethers.js y web3.js y cómo aprovechar su potencia para tu próximo proyecto dApp.

Entendiendo ethers.js

Ethers.js surgió como una biblioteca avanzada diseñada para interactuar con la blockchain de Ethereum. Sus principales características incluyen simplicidad, rapidez y type safety (nunca convierte valores explícita o implícitamente de un tipo a otro). Creado con TypeScript, ethers.js ofrece una API intuitiva para gestionar cuentas, manejar transacciones e interactuar con contratos inteligentes. Vamos a profundizar en algunas de sus principales funcionalidades:

Como Ethers.js vai ser usado

Gestión de Cuentas

Ethers.js facilita la generación de carteras Ethereum, el acceso a detalles de la cuenta y la firma de transacciones de forma segura. Aquí tienes un ejemplo de cómo crear una cartera Ethereum usando ethers.js:

const { ethers } = require("ethers");

const wallet = ethers.Wallet.createRandom();
console.log("Address:", wallet.address);
console.log("Private Key:", wallet.privateKey);
Enter fullscreen mode Exit fullscreen mode

Procesamiento de Transacciones

El envío y recepción de transacciones es un aspecto esencial en el desarrollo de dApps. Ethers.js simplifica este proceso, proporcionando a los desarrolladores las herramientas para crear y transmitir transacciones sin inconvenientes. A continuación, se muestra cómo enviar ether de una cuenta a otra:

const { ethers } = require("ethers");

const privateKey = "YOUR_PRIVATE_KEY";
const provider = ethers.getDefaultProvider("rinkeby");
const wallet = new ethers.Wallet(privateKey, provider);

const recipientAddress = "RECIPIENT_ADDRESS";
const transaction = {
    to: recipientAddress,
    value: ethers.utils.parseEther("1.0"), // Sending 1 ether
};

(async () => {
    const tx = await wallet.sendTransaction(transaction);
    console.log("Transaction hash:", tx.hash);
})();
Enter fullscreen mode Exit fullscreen mode

Interacción con Contratos Inteligentes

Ethers.js utiliza las interfaces binarias de aplicaciones (ABIs) de contratos inteligentes para interactuar con los contratos inteligentes de Ethereum. A continuación se muestra un ejemplo de cómo desplegar un contrato de token ERC20 simple e interactuar con él usando ethers.js:

const { ethers } = require("ethers");
const erc20ABI = require("./path/to/erc20ABI.json");

const privateKey = "YOUR_PRIVATE_KEY";
const provider = ethers.getDefaultProvider("rinkeby");
const wallet = new ethers.Wallet(privateKey, provider);

const contractAddress = "CONTRACT_ADDRESS";
const erc20Contract = new ethers.Contract(contractAddress, erc20ABI, wallet);

// Enviar 1 ether
(async () => {
    const accountAddress = "ACCOUNT_ADDRESS";
    const balance = await erc20Contract.balanceOf(accountAddress);
    console.log("Balance:", balance.toString());
})();
Enter fullscreen mode Exit fullscreen mode

Entendiendo web3.js

Web3.js es otra biblioteca ampliamente utilizada para el desarrollo de dApps en Ethereum, respaldada por la propia Fundación Ethereum. Su versatilidad y el amplio soporte de la comunidad la hacen una opción popular entre los desarrolladores. Vamos a profundizar en algunas de sus principales funcionalidades:

Como o web3.js vai usar<>/center

Gestión de Cuentas

Similar a ethers.js, web3.js facilita la creación de cuentas, el acceso y la firma de transacciones. Aquí tienes un ejemplo de cómo crear una cuenta Ethereum usando web3.js:

const Web3 = require("web3");

const providerUrl = "https://rinkeby.infura.io/v3/YOUR_INFURA_API_KEY";
const web3 = new Web3(providerUrl);

const account = web3.eth.accounts.create();
console.log("Address:", account.address);
console.log("Private Key:", account.privateKey);
Enter fullscreen mode Exit fullscreen mode

Procesamiento de Transacciones

Web3.js proporciona una interfaz JSON-RPC para el procesamiento de transacciones, lo que permite a los desarrolladores crear y ejecutar transacciones con facilidad. A continuación se muestra un ejemplo de cómo enviar ether de una cuenta a otra usando web3.js:

const Web3 = require("web3");

const providerUrl = "https://rinkeby.infura.io/v3/YOUR_INFURA_API_KEY";
const web3 = new Web3(providerUrl);

const privateKey = "YOUR_PRIVATE_KEY";
const senderAddress = "SENDER_ADDRESS";
const recipientAddress = "RECIPIENT_ADDRESS";

web3.eth.accounts.wallet.add(privateKey);
const tx = {
    from: senderAddress,
    to: recipientAddress,
    value: web3.utils.toWei("1", "ether"),
};

web3.eth.sendTransaction(tx)
    .on("transactionHash", (hash) => {
    console.log("Transaction hash:", hash);
    })
    .on("receipt", (receipt) => {
    console.log("Transaction receipt:", receipt);
    });
Enter fullscreen mode Exit fullscreen mode

Interacción con Contratos Inteligentes

La interacción con los contratos inteligentes de Ethereum es muy sencilla con web3.js. Aquí tienes un ejemplo de cómo configurar un objeto de contrato, llamar a métodos del contrato y recibir eventos emitidos por el contrato:

const Web3 = require("web3");
const contractABI = require("./path/to/contractABI.json");

const providerUrl = "https://rinkeby.infura.io/v3/YOUR_INFURA_API_KEY";
const web3 = new Web3(providerUrl);

const contractAddress = "CONTRACT_ADDRESS";
const contractInstance = new web3.eth.Contract(contractABI, contractAddress);

// Llama al método de contrato
(async () => {
    const result = await contractInstance.methods.someMethod().call();
    console.log("Result:", result);
})();

// Escucha a los eventos del contrato
contractInstance.events.SomeEvent()
    .on("data", (event) => {
    console.log("Event data:", event.returnValues);
    })
    .on("error", (error) => {
    console.error("Error:", error);
    });
Enter fullscreen mode Exit fullscreen mode

Comparando ethers.js y web3.js

Tanto ethers.js como web3.js tienen sus fortalezas y casos de uso, lo que los convierte en herramientas valiosas para el desarrollo de dApps. Vamos a explorar los principales factores a considerar al comparar las dos bibliotecas.

Seguridad de Tipos y Diseño de API:

Ethers.js destaca por su soporte para TypeScript, ofreciendo una seguridad de tipo mejorada e integridad de código. Para los desarrolladores familiarizados con TypeScript, ethers.js ofrece una experiencia de desarrollo más estructurada y sólida. Por otro lado, web3.js no soporta TypeScript, pero su API basada en JavaScript sigue siendo más familiar para aquellos desarrolladores sin experiencia previa en TypeScript.

Soporte de la Comunidad y Documentación:

Web3.js cuenta con un amplio respaldo de la comunidad debido a su respaldo por la Fundación Ethereum y su adopción generalizada. Como resultado, web3.js tiene una gran cantidad de recursos, tutoriales y proyectos guiados por la comunidad. Sin embargo, ethers.js está ganando popularidad y tiene una comunidad activa, con una documentación oficial bien mantenida y un contenido en aumento contribuido por la comunidad.

Tamaño y Rendimiento:

Ethers.js es conocido por su pequeño tamaño y rendimiento eficiente, lo que lo convierte en una excelente opción para aplicaciones donde el espacio mínimo y el rendimiento óptimo son esenciales. Por otro lado, web3.js es una biblioteca más grande con características adicionales, lo que puede afectar el rendimiento en ciertos escenarios. Los desarrolladores necesitan sopesar los compromisos entre características y rendimiento al hacer su elección.

Eligiendo la Biblioteca Adecuada para la dApp

La elección de la biblioteca correcta para tu dApp depende de varios factores. Considera los siguientes aspectos para tomar una decisión informada:

Complejidad del Proyecto:

Para dApps relativamente sencillas, ethers.js o web3.js pueden ser adecuados. Sin embargo, para proyectos más complejos que requieran una comprobación de tipos robusta y un enfoque de desarrollo estructurado, ethers.js puede ser la opción más adecuada. Por otro lado, la amplia comunidad y los diversos casos de uso de web3.js pueden ser beneficiosos para dApps ambiciosos y orientados a la comunidad.

Familiaridad del Desarrollador:

Considera el conjunto de habilidades y la familiaridad de tu equipo de desarrollo. Si tu equipo ya es competente en TypeScript y valora la seguridad de tipo, ethers.js puede alinearse bien con su experiencia. Por otro lado, web3.js puede ser preferido si tu equipo está más cómodo con el JavaScript tradicional y tiene experiencia previa con la biblioteca.

Requisitos de Rendimiento:

Para aplicaciones donde el rendimiento es una máxima prioridad, el pequeño tamaño y rendimiento optimizado de ethers.js pueden ser la mejor opción. Por otro lado, los recursos adicionales y el mayor ecosistema de web3.js pueden ser beneficiosos para proyectos donde el rendimiento no es la principal preocupación.

Ejemplo Práctico: Construyendo un dApp Simple

Vamos a construir un dApp de votación simplificado usando ethers.js o web3.js. La dApp permitirá a los usuarios votar por su opción favorita y los votos se registrarán en la blockchain Ethereum utilizando un contrato inteligente.

Pila (stack) de Código Front-end:

  • HTML: El archivo HTML para crear la estructura básica de la interfaz de votación.
  • CSS: El archivo CSS para estilizar la interfaz de votación.
  • JavaScript: El archivo JavaScript para interactuar con el contrato inteligente Ethereum usando ya sea ethers.js o web3.js.

HTML (index.html):

<!DOCTYPE html>
<html>
  <head>
    <title>Simple Voting dApp</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div class="container">
      <h1>Vote for Your Favorite Option</h1>
      <div class="options">
        <button id="option1">Option 1</button>
        <button id="option2">Option 2</button>
      </div>
      <div class="result">
        <p>Option 1 Votes: <span id="votesOption1">0</span></p>
        <p>Option 2 Votes: <span id="votesOption2">0</span></p>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.min.js"></script>
    <script src="app.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

CSS (styles.css):

    body {
    font-family: Arial, sans-serif;
    background-color: #f7f7f7;
    margin: 0;
    padding: 0;
}

.container {
    max-width: 600px;
    margin: 0 auto;
    padding: 20px;
    background-color: #ffffff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
    text-align: center;
}

.options {
    display: flex;
    justify-content: center;
    gap: 20px;
}

button {
    padding: 10px 20px;
    font-size: 16px;
    cursor: pointer;
}

.result {
    margin-top: 20px;
}

.result p {
    margin: 0;
}

span {
    font-weight: bold;
}
Enter fullscreen mode Exit fullscreen mode

JavaScript (app.js):

    const providerUrl = "https://rinkeby.infura.io/v3/YOUR_INFURA_API_KEY";
const web3 = new Web3(providerUrl);

const contractABI = [...]; // Substituir pela ABI de seu contrato inteligente implantado
const contractAddress = "CONTRACT_ADDRESS"; // Substitui pelo endereço de seu contrato inteligente
const votingContract = new web3.eth.Contract(contractABI, contractAddress);

const option1Button = document.getElementById("option1");
const option2Button = document.getElementById("option2");
const votesOption1Element = document.getElementById("votesOption1");
const votesOption2Element = document.getElementById("votesOption2");

option1Button.addEventListener("click", async () => {
    await vote(1);
});

option2Button.addEventListener("click", async () => {
    await vote(2);
});

async function vote(option) {
    const accounts = await web3.eth.getAccounts();
    const sender = accounts[0];

    try {
    const result = await votingContract.methods.vote(option).send({ from: sender });
    console.log("Transaction hash:", result.transactionHash);
    updateVoteCounts();
    } catch (error) {
    console.error("Vote error:", error);
    }
}

async function updateVoteCounts() {
    const option1Votes = await votingContract.methods.getVoteCount(1).call();
    const option2Votes = await votingContract.methods.getVoteCount(2).call();

    votesOption1Element.textContent = option1Votes;
    votesOption2Element.textContent = option2Votes;
}
Enter fullscreen mode Exit fullscreen mode

Pila de Código Backend:

  • Solidity: El código del contrato inteligente Solidity para el mecanismo de votación.

Solidity (Voting.sol):

    // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Voting {
    mapping(uint256 => uint256) public voteCounts;

    function vote(uint256 option) public {
        require(option == 1 || option == 2, "Invalid option");
        voteCounts[option]++;
    }

    function getVoteCount(uint256 option) public view returns (uint256) {
        require(option == 1 || option == 2, "Invalid option");
        return voteCounts[option];
    }
}
Enter fullscreen mode Exit fullscreen mode

Desplegar el Contrato Inteligente:

👣 Compila el contrato inteligente de Solidity (Voting.sol) usando el compilador de Solidity.

👣 Despliega el contrato inteligente compilado en la red de prueba Rinkeby usando Remix, Truffle o Hardhat.

👣 Obtén la dirección del contrato y la ABI después del despliegue.

Reemplaza "YOUR_INFURA_API_KEY" con tu clave de API real de Infura y "[...]" en el código JavaScript con la ABI real de tu contrato inteligente desplegado.

Ethers.js y web3.js son herramientas valiosas para el desarrollo de dApps Ethereum, cada una con sus propias fortalezas y ventajas. Al comprender sus funcionalidades y comparar sus recursos, puedes tomar una decisión informada al seleccionar la biblioteca que mejor se adapte a las necesidades específicas de tu dApp. Ya sea que priorices la seguridad de tipo, el apoyo de la comunidad o el rendimiento, ambas bibliotecas ofrecen soluciones potentes para la creación de aplicaciones descentralizadas intrigantes e innovadoras.

Este artículo fue escrito por Harith D. Jayawardhane y traducido por @junowoz. El original se puede leer aquí.

Discussion (0)