tutoriales.com

Tokenización de Activos Fungibles en Web3: Creando un Token ERC-20 con OpenZeppelin y Hardhat 💰

Este tutorial te guiará paso a paso en la creación de un token fungible (ERC-20) en la blockchain. Utilizaremos las robustas librerías de OpenZeppelin para la implementación del contrato inteligente y Hardhat como nuestro entorno de desarrollo para probar y desplegar el token.

Intermedio20 min de lectura10 views
Reportar error

La tokenización de activos fungibles es uno de los pilares de la economía descentralizada y una de las aplicaciones más comunes de la tecnología blockchain. Un token fungible es, por definición, intercambiable por otro de su mismo tipo, como el dinero fiduciario o las acciones de una empresa. En el mundo de Web3, estos tokens se materializan a menudo a través del estándar ERC-20 en la red Ethereum, o estándares compatibles en otras cadenas de bloques.

Este tutorial te proporcionará los conocimientos y las herramientas necesarias para diseñar, implementar, probar y desplegar tu propio token ERC-20. Al final, tendrás una comprensión clara de cómo funcionan estos tokens y cómo interactuar con ellos.

¿Qué es un Token ERC-20? 📖

El estándar ERC-20 (Ethereum Request for Comments 20) es una especificación técnica utilizada en la blockchain de Ethereum para la implementación de tokens fungibles. Fue propuesto en 2015 por Fabian Vogelsteller y se ha convertido en el estándar de facto para la creación de la gran mayoría de tokens en Ethereum y redes compatibles (BNB Chain, Polygon, Avalanche, etc.).

Un token ERC-20 define un conjunto de reglas básicas que un contrato inteligente debe seguir, permitiendo que los tokens sean interoperables con cualquier aplicación o cartera que soporte el estándar. Esto incluye:

  • Total Supply: La cantidad total de tokens en existencia.
  • Balance Of: Consulta el balance de tokens de una dirección específica.
  • Transfer: Mueve tokens de una dirección a otra.
  • Approve: Permite a una dirección gastar tokens en nombre de otra.
  • Allowance: Consulta cuántos tokens se ha permitido gastar a una dirección.

Estos métodos, junto con dos eventos (Transfer y Approval), son la base de cómo los tokens ERC-20 funcionan y se mueven en la blockchain.

💡 Consejo: La fungibilidad es clave. Piensa en un billete de 10 euros: cualquier billete de 10 euros es igual de válido que otro. Lo mismo ocurre con los tokens ERC-20.

Herramientas Necesarias 🛠️

Antes de sumergirnos en el código, necesitamos configurar nuestro entorno de desarrollo. Aquí están las herramientas que utilizaremos:

  • Node.js y npm (o Yarn): Para gestionar nuestros paquetes de JavaScript.
  • Hardhat: Un entorno de desarrollo flexible y extensible para Ethereum.
  • Solidity: El lenguaje de programación para escribir contratos inteligentes.
  • OpenZeppelin Contracts: Una biblioteca de contratos inteligentes seguros y probados para implementar los estándares ERC.
  • MetaMask: Una cartera de Ethereum para interactuar con la red.

Instalación de Node.js y npm

Si aún no tienes Node.js y npm instalados, descárgalos desde el sitio web oficial: nodejs.org. Verifícalos con:

node -v
npm -v

Configuración del Proyecto Hardhat

  1. Crea un nuevo directorio para tu proyecto:
mkdir MiTokenERC20
cd MiTokenERC20
  1. Inicializa un nuevo proyecto npm:
npm init -y
  1. Instala Hardhat:
npm install --save-dev hardhat
  1. Inicializa un proyecto Hardhat:
npx hardhat
Selecciona `Create a JavaScript project` cuando te lo pregunten. Esto creará la estructura básica de carpetas (`contracts`, `scripts`, `test`) y archivos (`hardhat.config.js`).

5. Instala OpenZeppelin Contracts:

npm install @openzeppelin/contracts
Esta librería es fundamental para implementar estándares ERC de forma segura.

6. Instala las dependencias adicionales para testing y despliegue (opcional pero recomendado):

npm install --save-dev @nomicfoundation/hardhat-toolbox dotenv
`hardhat-toolbox` incluye herramientas para testing, verificación y un `ether.js` más moderno. `dotenv` nos servirá para gestionar variables de entorno (claves privadas, IDs de API).
📌 Nota: Después de instalar `hardhat-toolbox`, verifica que tu `hardhat.config.js` esté actualizado para incluirlo. Hardhat puede preguntar si deseas actualizar el archivo.

Diseñando Nuestro Token 🎯

Para este tutorial, crearemos un token llamado 'MiToken' con el símbolo 'MTK' y una oferta inicial de 1,000,000 de tokens. También haremos que sea mintable (se pueden crear más tokens después del despliegue) y burnable (se pueden destruir tokens). Estas funcionalidades son comunes y se implementan fácilmente con OpenZeppelin.

Estructura del Contrato

Nuestro contrato MiToken.sol será relativamente sencillo gracias a OpenZeppelin:

  • Importará ERC20.sol para la funcionalidad básica ERC-20.
  • Importará ERC20Capped.sol si queremos un suministro máximo.
  • Importará Ownable.sol para tener un propietario que pueda realizar acciones privilegiadas (como acuñar o quemar).
  • Importará ERC20Mintable.sol y ERC20Burnable.sol para las funciones de acuñado y quemado.
⚠️ Advertencia: Siempre audita y prueba exhaustivamente cualquier contrato antes de desplegarlo en una red principal. OpenZeppelin es seguro, pero tu implementación personalizada podría introducir vulnerabilidades.

Implementación del Contrato Inteligente (Solidity) ✍️

Crea un nuevo archivo MiToken.sol dentro de la carpeta contracts.

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Mintable.sol"; // Para versiones más antiguas, pero para ^0.8.20 se suele integrar la lógica de acuñamiento manualmente o usar roles.

// En versiones recientes de OpenZeppelin (>=4.x), la funcionalidad de acuñado no viene con un contrato 'ERC20Mintable' separado, 
// sino que se espera que el desarrollador añada la lógica de acuñado y los permisos (por ejemplo, con Ownable o AccessControl).
// Para este tutorial, implementaremos una función 'mint' simple restringida al propietario usando 'Ownable'.

contract MiToken is ERC20, Ownable, ERC20Burnable {
    // Constructor: Se ejecuta una vez al desplegar el contrato.
    // Inicializa el nombre y el símbolo del token.
    // El propietario es quien despliega el contrato.
    constructor() 
        ERC20("MiToken", "MTK") 
        Ownable(msg.sender) 
    {
        // Acuñamos el suministro inicial al propietario que despliega el contrato.
        // Los tokens ERC-20 tienen 18 decimales por defecto. Para 1,000,000 tokens, necesitamos 1,000,000 * (10 ** 18).
        _mint(msg.sender, 1_000_000 * (10 ** 18));
    }

    /**
     * @dev Función para acuñar nuevos tokens.
     * Solo el propietario del contrato puede llamar a esta función.
     * @param to Dirección a la que se acuñarán los tokens.
     * @param amount Cantidad de tokens a acuñar (expresada en unidades base, por ejemplo, 1 token = 1e18).
     */
    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }

    // La función `burn` ya está disponible a través de la herencia de `ERC20Burnable`.
    // Simplemente llama a `super._burn(account, amount)` o `_burn(account, amount)`.
}

Explicación del Código

  • // SPDX-License-Identifier: MIT y pragma solidity ^0.8.20;: Especifica la licencia y la versión del compilador Solidity.
  • import "@openzeppelin/contracts/...": Importamos los contratos base de OpenZeppelin.
    • ERC20.sol: Contiene la implementación básica del estándar ERC-20.
    • Ownable.sol: Un patrón de control de acceso que asigna un owner al contrato y permite restringir funciones solo a ese owner.
    • ERC20Burnable.sol: Añade la funcionalidad para que los poseedores de tokens puedan quemar sus propios tokens (burn).
  • contract MiToken is ERC20, Ownable, ERC20Burnable: Nuestro contrato MiToken hereda de estos tres contratos, obteniendo sus funcionalidades.
  • constructor() ERC20("MiToken", "MTK") Ownable(msg.sender):
    • El constructor se ejecuta solo una vez cuando el contrato se despliega.
    • Llama a los constructores de ERC20 para establecer el nombre (MiToken) y el símbolo (MTK).
    • Llama al constructor de Ownable para establecer el msg.sender (la dirección que despliega el contrato) como el propietario inicial.
    • _mint(msg.sender, 1_000_000 * (10 ** 18));: Acuñamos 1,000,000 de tokens al propietario. Los tokens ERC-20 generalmente tienen 18 decimales, por lo que multiplicamos por 10^18 para obtener la cantidad correcta en unidades base.
  • function mint(address to, uint256 amount) public onlyOwner: Esta función personalizada permite al propietario acuñar nuevos tokens y enviarlos a una dirección específica. El modificador onlyOwner garantiza que solo el propietario pueda llamar a esta función.
  • Importante: Para versiones de OpenZeppelin más recientes (4.x y posteriores), no existe un contrato ERC20Mintable.sol independiente de la misma forma que ERC20Burnable.sol. La estrategia común es añadir una función mint personalizada y protegerla con Ownable o AccessControl, como hemos hecho aquí.

Configuración de Hardhat para Despliegue ⚙️

Necesitaremos configurar hardhat.config.js para poder desplegar nuestro contrato en una red de prueba (como Sepolia o Polygon Mumbai). Para esto, usaremos dotenv para cargar variables de entorno de un archivo .env.

  1. Crea un archivo .env en la raíz de tu proyecto:
ALCHEMY_API_KEY=tu_clave_api_de_alchemy_o_infura
PRIVATE_KEY=tu_clave_privada_de_metamask
<div class="callout warning">⚠️ <strong>Advertencia:</strong> NUNCA publiques tu clave privada en un repositorio público. Usa `.gitignore` para excluir `.env`. Tu clave privada es como la clave de tu bóveda bancaria.</div>

2. Añade la siguiente configuración a hardhat.config.js:

require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

const ALCHEMY_API_KEY = process.env.ALCHEMY_API_KEY;
const SEPOLIA_PRIVATE_KEY = process.env.PRIVATE_KEY;

module.exports = {
solidity: "0.8.20",
networks: {
sepolia: {
url: `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
accounts: [SEPOLIA_PRIVATE_KEY],
},
// Puedes añadir otras redes como Polygon Mumbai aquí si lo deseas
// mumbai: {
//   url: `https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
//   accounts: [SEPOLIA_PRIVATE_KEY],
// },
},
};
*   **ALCHEMY_API_KEY:** Obtén una clave API gratuita de [Alchemy](https://www.alchemy.com/) o [Infura](https://infura.io/).
*   **PRIVATE_KEY:** Es la clave privada de tu cuenta de MetaMask (la que usarás para desplegar y pagar las tarifas de gas). Para obtenerla, abre MetaMask, haz clic en los tres puntos de tu cuenta, selecciona "Detalles de la cuenta" y luego "Exportar clave privada".
🔥 Importante: Asegúrate de que la cuenta de MetaMask asociada a tu clave privada tenga ETH de prueba para pagar las tarifas de gas en la red Sepolia. Puedes obtener ETH de prueba de un 'faucet' (grifo) de Sepolia.

Creación del Script de Despliegue 🚀

Crearemos un script en la carpeta scripts para desplegar nuestro contrato MiToken. Crea un archivo deploy.js dentro de la carpeta scripts.

const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();

  console.log("Desplegando contratos con la cuenta:", deployer.address);

  const initialBalance = await deployer.getBalance();
  console.log("Balance de la cuenta antes del despliegue:", hre.ethers.utils.formatEther(initialBalance), "ETH");

  const MiToken = await hre.ethers.getContractFactory("MiToken");
  const miToken = await MiToken.deploy();

  await miToken.deployed();

  console.log("MiToken desplegado en la dirección:", miToken.address);

  const finalBalance = await deployer.getBalance();
  console.log("Balance de la cuenta después del despliegue:", hre.ethers.utils.formatEther(finalBalance), "ETH");
  console.log("Costo total del despliegue:", hre.ethers.utils.formatEther(initialBalance.sub(finalBalance)), "ETH");

  // Opcional: Verificar el suministro total y el balance del propietario
  const totalSupply = await miToken.totalSupply();
  console.log("Suministro total de MiToken:", hre.ethers.utils.formatUnits(totalSupply, 18), "MTK");

  const ownerBalance = await miToken.balanceOf(deployer.address);
  console.log("Balance del propietario (deployer) de MiToken:", hre.ethers.utils.formatUnits(ownerBalance, 18), "MTK");
}

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

Compilación y Despliegue del Contrato ✨

¡Es hora de compilar y desplegar nuestro token!

1. Compilar el Contrato

Desde la raíz de tu proyecto, ejecuta:

npx hardhat compile

Si todo está correcto, verás un mensaje de éxito. Esto creará los artefactos del contrato (.json) en la carpeta artifacts.

2. Desplegar en la Red de Prueba (Sepolia)

Para desplegar en Sepolia, usa el script que creamos:

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

Si el despliegue es exitoso, verás la dirección del contrato de MiToken en la consola. ¡Felicidades, has desplegado tu propio token ERC-20!

💡 Consejo: Guarda la dirección del contrato desplegado. La necesitarás para interactuar con tu token y verificarlo en Etherscan.
1. Configurar Entorno Node.js, Hardhat, OpenZeppelin 2. Escribir Contrato Solidity Desarrollo de MiToken.sol 3. Configurar Hardhat hardhat.config.js, .env 4. Script de Despliegue Crear deploy.js para la red 5. Compilar Contrato npx hardhat compile 6. Desplegar en Red de Prueba Despliegue final en Sepolia

Interactuando con el Token Desplegado 🌐

Ahora que tu token está en la red de prueba, puedes interactuar con él de varias maneras.

Usando la Consola de Hardhat

Hardhat tiene una consola integrada que te permite interactuar con tus contratos desplegados.

  1. Inicia la consola de Hardhat con tu red:
npx hardhat console --network sepolia
  1. Dentro de la consola, obtén una instancia de tu contrato:
const MiToken = await ethers.getContractFactory("MiToken");
const miToken = await MiToken.attach("DIRECCIÓN_DE_TU_TOKEN_DESPLEGADO");
const [deployer, addr1, addr2] = await ethers.getSigners();

// Consulta el nombre y símbolo
console.log("Nombre:", await miToken.name());
console.log("Símbolo:", await miToken.symbol());

// Consulta el balance del propietario
const ownerBalance = await miToken.balanceOf(deployer.address);
console.log("Balance del propietario:", ethers.utils.formatUnits(ownerBalance, 18));

// Transfiere tokens a otra dirección
await miToken.transfer(addr1.address, ethers.utils.parseUnits("100", 18));
console.log("Balance de addr1 después de la transferencia:", ethers.utils.formatUnits(await miToken.balanceOf(addr1.address), 18));

// Quema tokens (solo si la cuenta tiene balance suficiente)
await miToken.connect(deployer).burn(ethers.utils.parseUnits("50", 18));
console.log("Balance del propietario después de quemar:", ethers.utils.formatUnits(await miToken.balanceOf(deployer.address), 18));

// Acuña nuevos tokens (solo el propietario puede hacerlo)
await miToken.connect(deployer).mint(addr2.address, ethers.utils.parseUnits("200", 18));
console.log("Balance de addr2 después de acuñar:", ethers.utils.formatUnits(await miToken.balanceOf(addr2.address), 18));

// Salir de la consola
.exit

Verificación en Etherscan

Es una buena práctica verificar tu contrato en Etherscan (o el explorador de bloques equivalente para tu red). Esto permite a otros ver el código fuente verificado del contrato y asegura la transparencia.

  1. Asegúrate de tener instalado el plugin de verificación de Hardhat:
npm install --save-dev @nomicfoundation/hardhat-verify
  1. Configura tu clave API de Etherscan en .env y hardhat.config.js:
// .env
ETHERSCAN_API_KEY=tu_clave_api_de_etherscan
// hardhat.config.js
// ... otras configuraciones ...
require("@nomicfoundation/hardhat-verify");

const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY;

module.exports = {
// ...
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},
};
  1. Verifica tu contrato después del despliegue:
npx hardhat verify --network sepolia DIRECCION_DE_TU_TOKEN_DESPLEGADO
Una vez verificado, puedes ir a Sepolia Etherscan (sepolia.etherscan.io) y buscar la dirección de tu contrato para ver su código fuente, transacciones y más.

Pruebas de Contratos Inteligentes (Opcional pero Recomendado) ✅

La escritura de pruebas es crucial para asegurar la funcionalidad y seguridad de tu contrato. Hardhat facilita esto con su integración de Mocha y Chai. La plantilla de Hardhat ya crea una carpeta test.

Crea un archivo MiToken.test.js dentro de la carpeta test.

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("MiToken", function () {
  let MiToken;
  let miToken;
  let deployer;
  let addr1;
  let addr2;
  let addrs;

  const initialSupply = ethers.utils.parseUnits("1000000", 18); // 1,000,000 tokens

  beforeEach(async function () {
    // Obtiene las cuentas de prueba proporcionadas por Hardhat
    [deployer, addr1, addr2, ...addrs] = await ethers.getSigners();

    // Despliega el contrato antes de cada prueba
    MiToken = await ethers.getContractFactory("MiToken");
    miToken = await MiToken.deploy();
    await miToken.deployed();
  });

  describe("Deployment", function () {
    it("Debería establecer el nombre y el símbolo correctos", async function () {
      expect(await miToken.name()).to.equal("MiToken");
      expect(await miToken.symbol()).to.equal("MTK");
    });

    it("Debería asignar el suministro total al desplegador", async function () {
      const deployerBalance = await miToken.balanceOf(deployer.address);
      expect(deployerBalance).to.equal(initialSupply);
      expect(await miToken.totalSupply()).to.equal(initialSupply);
    });

    it("Debería establecer el desplegador como el propietario", async function () {
      expect(await miToken.owner()).to.equal(deployer.address);
    });
  });

  describe("Transactions", function () {
    it("Debería transferir tokens entre cuentas", async function () {
      // Transferir 50 tokens del desplegador a addr1
      await miToken.transfer(addr1.address, ethers.utils.parseUnits("50", 18));
      const addr1Balance = await miToken.balanceOf(addr1.address);
      expect(addr1Balance).to.equal(ethers.utils.parseUnits("50", 18));

      const deployerBalance = await miToken.balanceOf(deployer.address);
      expect(deployerBalance).to.equal(initialSupply.sub(ethers.utils.parseUnits("50", 18)));
    });

    it("Debería fallar si el remitente no tiene suficientes tokens", async function () {
      const initialDeployerBalance = await miToken.balanceOf(deployer.address);
      // Intentar transferir más tokens de los que tiene el desplegador a addr1
      await expect(
        miToken.connect(addr1).transfer(deployer.address, ethers.utils.parseUnits("1", 18))
      ).to.be.revertedWith("ERC20: transfer amount exceeds balance");
    });

    it("Debería actualizar los balances después de la aprobación y la transferencia from", async function () {
      // El desplegador aprueba a addr1 para gastar 100 tokens
      await miToken.approve(addr1.address, ethers.utils.parseUnits("100", 18));
      const allowance = await miToken.allowance(deployer.address, addr1.address);
      expect(allowance).to.equal(ethers.utils.parseUnits("100", 18));

      // addr1 gasta 50 tokens del desplegador y los envía a addr2
      await miToken.connect(addr1).transferFrom(deployer.address, addr2.address, ethers.utils.parseUnits("50", 18));
      expect(await miToken.balanceOf(addr2.address)).to.equal(ethers.utils.parseUnits("50", 18));
      expect(await miToken.balanceOf(deployer.address)).to.equal(initialSupply.sub(ethers.utils.parseUnits("50", 18)));
      expect(await miToken.allowance(deployer.address, addr1.address)).to.equal(ethers.utils.parseUnits("50", 18));
    });
  });

  describe("Minting", function () {
    it("Solo el propietario debería poder acuñar tokens", async function () {
      const mintAmount = ethers.utils.parseUnits("500", 18);
      const initialTotalSupply = await miToken.totalSupply();

      await miToken.connect(deployer).mint(addr1.address, mintAmount);
      expect(await miToken.balanceOf(addr1.address)).to.equal(mintAmount);
      expect(await miToken.totalSupply()).to.equal(initialTotalSupply.add(mintAmount));

      // Intentar acuñar con una cuenta que no es el propietario debería revertir
      await expect(
        miToken.connect(addr1).mint(addr2.address, mintAmount)
      ).to.be.revertedWith("Ownable: caller is not the owner");
    });
  });

  describe("Burning", function () {
    it("Los usuarios deberían poder quemar sus propios tokens", async function () {
      const burnAmount = ethers.utils.parseUnits("10", 18);
      const initialDeployerBalance = await miToken.balanceOf(deployer.address);
      const initialTotalSupply = await miToken.totalSupply();

      await miToken.connect(deployer).burn(burnAmount);

      expect(await miToken.balanceOf(deployer.address)).to.equal(initialDeployerBalance.sub(burnAmount));
      expect(await miToken.totalSupply()).to.equal(initialTotalSupply.sub(burnAmount));
    });

    it("Debería fallar si se intenta quemar más tokens de los que se poseen", async function () {
      const burnAmount = ethers.utils.parseUnits("10000000", 18); // Más de lo que tiene el desplegador
      await expect(
        miToken.connect(deployer).burn(burnAmount)
      ).to.be.revertedWith("ERC20: burn amount exceeds balance");
    });
  });
});

Para ejecutar las pruebas:

npx hardhat test

Si todas las pruebas pasan, verás un resultado similar a:

  MiToken
    Deployment
      ✅ Debería establecer el nombre y el símbolo correctos
      ✅ Debería asignar el suministro total al desplegador
      ✅ Debería establecer el desplegador como el propietario
    Transactions
      ✅ Debería transferir tokens entre cuentas
      ✅ Debería fallar si el remitente no tiene suficientes tokens
      ✅ Debería actualizar los balances después de la aprobación y la transferencia from
    Minting
      ✅ Solo el propietario debería poder acuñar tokens
    Burning
      ✅ Los usuarios deberían poder quemar sus propios tokens
      ✅ Debería fallar si se intenta quemar más tokens de los que se poseen


  10 passing (XXXms)

Próximos Pasos y Consideraciones Avanzadas 🚀

Has creado y desplegado un token ERC-20 funcional. Este es solo el comienzo. Aquí hay algunas ideas para continuar:

  • ERC20Capped: Añade un límite máximo al suministro total de tu token.
  • ERC20Pausable: Permite al propietario pausar todas las transferencias de tokens en caso de emergencia.
  • ERC20Snapshot: Permite tomar 'instantáneas' de los balances de los tokens en un momento dado, útil para airdrops o sistemas de votación.
  • Implementar un Token de Utilidad: Diseña un caso de uso real para tu token (por ejemplo, para pagar tarifas en una dApp, votar en una DAO, o como recompensa).
  • Auditorías y Seguridad: Para proyectos en producción, es esencial realizar auditorías de seguridad profesionales.
  • Integración con Front-end: Crea una interfaz de usuario simple (usando React, Vue, o Svelte) para interactuar con tu token usando bibliotecas como Ethers.js o Web3.js.
🔥 Importante: La seguridad es primordial en Web3. Siempre usa contratos probados y auditados como los de OpenZeppelin, y entiende cada línea de código que escribes o implementas.

Preguntas Frecuentes (FAQ) sobre Tokens ERC-20

¿Cuál es la diferencia entre un token y una moneda (coin)?

Una 'moneda' (coin) es la criptomoneda nativa de una blockchain (ej. ETH de Ethereum, BTC de Bitcoin), utilizada para pagar tarifas de transacción y asegurar la red. Un 'token' es un activo que reside en una blockchain existente y está construido sobre un estándar (ej. ERC-20 en Ethereum). Los tokens pueden representar una amplia gama de activos o utilidades.

¿Puedo cambiar los parámetros de mi token después de desplegarlo?

No directamente. Los contratos inteligentes son inmutables una vez desplegados. Si necesitas cambiar la lógica de tu token, generalmente tendrás que desplegar un nuevo contrato y migrar los usuarios (o utilizar un patrón de contrato actualizable, como los proxies, que son más avanzados).

¿Por qué se usan 18 decimales por defecto en ERC-20?

Históricamente, Ethereum usaba 18 decimales para ETH (1 wei = 10^-18 ETH). Este número se adoptó para los tokens ERC-20 para mantener la compatibilidad y permitir una alta granularidad, lo que es útil para representar valores pequeños sin perder precisión. Sin embargo, puedes configurar un número diferente de decimales si lo deseas, pero 18 es el más común.

Completado Desarrollo Web3 Solidity

100% Hecho

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!