Cómo crear un token ERC20 de forma sencilla

Publicado: 2022-03-11

El objetivo de este artículo es demostrar cómo crear un token ERC20 en el menor tiempo posible.

Comencemos con lo básico: ¿Qué es un token ERC20?

En los últimos años, la especificación del token ERC20 se ha convertido en el estándar de facto para los tokens de Ethereum. En otras palabras, la mayoría de los contratos de Ethereum que existen hoy en día cumplen con ERC20. Este artículo detallará cómo puede crear su propio token Ethereum, pero antes de comenzar, echemos un vistazo más de cerca al estándar ERC20.

Ilustración del token ERC20

¿Qué hace que los tokens ERC20 sean tan atractivos y exitosos? Hay varios factores en juego:

  1. Los tokens ERC20 son simples y fáciles de implementar, como verá en este tutorial.
  2. El estándar ERC20 resuelve un problema importante, ya que los mercados basados ​​en cadenas de bloques y las billeteras criptográficas necesitan un único conjunto de comandos estandarizados para comunicarse con la variedad de tokens que administran. Esto incluye reglas de interacción entre diferentes tokens, así como reglas de compra de tokens.
  3. Fue la primera especificación popular en ofrecer la estandarización de tokens de Ethereum. De ninguna manera fue el primero , pero gracias a su popularidad, rápidamente se convirtió en el estándar de la industria.

Al igual que otros tokens de Ethereum, los tokens ERC20 se implementan como contratos inteligentes y se ejecutan en la máquina virtual de Ethereum (EVM) de manera descentralizada.

Solidity: el lenguaje de programación de contratos inteligentes

Los contratos inteligentes de Ethereum están escritos en Solidity. Si bien existen lenguajes alternativos, casi nadie los usa para este propósito. Solidity es similar a JavaScript, por lo que si tiene algún conocimiento de JavaScript, o incluso de Java y otros lenguajes similares a C, no debería tener problemas para darse cuenta de que una pieza de código en Solidity lo hace, incluso antes de que realmente domine Solidity lo suficiente como para usar eso.

Aquí es donde comienza la diversión, ya que debería poder comenzar a crear un contrato ERC20 simple en muy poco tiempo. Esta es una tarea sencilla, lo suficientemente simple como para que este artículo demuestre cómo puede escribir e implementar un token ERC20 en menos de una hora.

El token que crearemos en esta demostración será una implementación básica de ERC20, sin demasiadas campanas y silbatos. Sin embargo, he visto muchos tokens simples similares en el mundo real, y tienden a funcionar bastante bien.

Descripción general del estándar de token ERC20

¿Qué es ERC20?

En pocas palabras, el estándar ERC20 define un conjunto de funciones que implementarán todos los tokens ERC20 para permitir la integración con otros contratos, billeteras o mercados. Este conjunto de funciones es bastante corto y básico.

 function totalSupply() public view returns (uint256); function balanceOf(address tokenOwner) public view returns (uint); function allowance(address tokenOwner, address spender) public view returns (uint); function transfer(address to, uint tokens) public returns (bool); function approve(address spender, uint tokens) public returns (bool); function transferFrom(address from, address to, uint tokens) public returns (bool);

Las funciones de ERC20 permiten a un usuario externo, por ejemplo, una aplicación de billetera criptográfica, averiguar el saldo de un usuario y transferir fondos de un usuario a otro con la debida autorización.

El contrato inteligente define dos eventos específicamente definidos:

 event Approval(address indexed tokenOwner, address indexed spender, uint tokens); event Transfer(address indexed from, address indexed to, uint tokens);

Estos eventos se invocarán o emitirán cuando a un usuario se le otorguen derechos para retirar tokens de una cuenta y después de que los tokens se transfieran realmente.

Además de las funciones estándar de ERC20, muchos tokens ERC20 también cuentan con campos adicionales y algunos se han convertido en una parte de facto del estándar ERC20, si no por escrito, en la práctica. Aquí hay algunos ejemplos de tales campos.

 string public constant name; string public constant symbol; uint8 public constant decimals;

Aquí hay algunos puntos con respecto a ERC20 y la nomenclatura de Solidity:

  • Se puede acceder a una función public fuera del propio contrato.
  • view básicamente significa constante, es decir, el estado interno del contrato no será cambiado por la función
  • Un event es la forma en que Solidity permite que los clientes, por ejemplo, la interfaz de su aplicación, sean notificados sobre ocurrencias específicas dentro del contrato.

La mayoría de las construcciones del lenguaje Solidity deberían ser claras si ya posee habilidades esenciales de Java/JavaScript.

Escribir un token ERC20 en Solidity

Tokens ERC20 en solidez

Ahora que hemos resumido los conceptos básicos y explicado lo que se necesita para crear un token ERC20, es hora de comenzar a escribir algo de lógica.

Primero, necesitamos definir dos objetos de mapeo. Esta es la noción de solidez para una matriz asociativa o clave/valor:

 mapping(address => uint256) balances; mapping(address => mapping (address => uint256)) allowed;

La expresión mapping(address => uint256) define una matriz asociativa cuyas claves son de tipo address , un número que se usa para denotar direcciones de cuentas, y cuyos valores son de tipo uint256 , un entero de 256 bits que normalmente se usa para almacenar saldos de tokens.

El primer objeto de mapeo, balances , contendrá el saldo de fichas de cada cuenta de propietario.

El segundo objeto de mapeo, allowed , incluirá todas las cuentas aprobadas para retirar de una cuenta determinada junto con la suma de retiro permitida para cada una.

Como puede ver, el campo de valor del mapeo permitido es en sí mismo un mapeo que traza la dirección de la cuenta a su suma de retiro aprobada.

Estas asignaciones, junto con todos los demás campos del contrato, se almacenarán en la cadena de bloques y se extraerán , lo que dará como resultado que los cambios se propaguen a todos los nodos de usuarios de la red.

El almacenamiento de blockchain es costoso y los usuarios de su contrato deberán pagar, de una forma u otra. Por lo tanto, siempre debe intentar minimizar el tamaño de almacenamiento y las escrituras en la cadena de bloques.

Ahora que tenemos las estructuras de datos requeridas en su lugar, podemos comenzar a escribir la lógica ERC20 en las funciones apropiadas.

Configuración del número de tokens ICO

¿Cómo establecemos la cantidad de tokens ICO? Bueno, hay varias formas de establecer la cantidad máxima de tokens ICO y este asunto podría valer una discusión larga por sí solo.

Para las necesidades de nuestro tutorial ECR20, utilizaremos el enfoque más simple: establezca la cantidad total de tokens en el momento de la creación del contrato e inicialmente asígnelos todos al "propietario del contrato", es decir, la cuenta que implementó el contrato inteligente:

 uint256 totalSupply_; constructor(uint256 total) public { totalSupply_ = total; balances[msg.sender] = _totalSupply; }

Un constructor es una función especial llamada automáticamente por Ethereum justo después de que se implementa el contrato. Por lo general, se usa para inicializar el estado del token mediante los parámetros que pasa la cuenta de implementación del contrato.

msg es una variable global declarada y poblada por el mismo Ethereum. Contiene datos importantes para la ejecución del contrato. El campo que estamos usando aquí: msg.sender contiene la cuenta de Ethereum que ejecuta la función de contrato actual.

Solo la cuenta de implementación puede ingresar al constructor de un contrato. Cuando se inicia el contrato, esta función asigna tokens disponibles a la cuenta del 'propietario del contrato'.

Obtenga el suministro total de tokens

 function totalSupply() public view returns (uint256) { return totalSupply_; }

Esta función devolverá el número de todos los tokens asignados por este contrato, independientemente del propietario.

Obtener saldo de token del propietario

 function balanceOf(address tokenOwner) public view returns (uint) { return balances[tokenOwner]; }

balanceOf devolverá el saldo token actual de una cuenta, identificado por la dirección de su propietario.

Transferir tokens a otra cuenta

 function transfer(address receiver, uint numTokens) public returns (bool) { require(numTokens <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender] — numTokens; balances[receiver] = balances[receiver] + numTokens; emit Transfer(msg.sender, receiver, numTokens); return true; }

Como sugiere su nombre, la función de transfer se utiliza para mover una cantidad de tokens numTokens del saldo del propietario al de otro usuario o receiver . El propietario de la transferencia es msg.sender , es decir, el que ejecuta la función, lo que implica que solo el propietario de los tokens puede transferirlos a otros.

La forma en que Solidity afirma un predicado es require . En este caso que la cuenta que transfiere tenga saldo suficiente para ejecutar la transferencia. Si falla una declaración require , la transacción se revierte inmediatamente sin cambios escritos en la cadena de bloques.

Justo antes de salir, la función activa la Transfer de eventos ERC20, lo que permite a los oyentes registrados reaccionar ante su finalización.

Aprobar delegado para retirar tokens

Esta función se usa con mayor frecuencia en un escenario de mercado de tokens.

 function approve(address delegate, uint numTokens) public returns (bool) { allowed[msg.sender][delegate] = numTokens; emit Approval(msg.sender, delegate, numTokens); return true; }

Lo que hace la approve es permitir que un propietario, es decir, msg.sender apruebe una cuenta delegada, posiblemente el propio mercado, para retirar tokens de su cuenta y transferirlos a otras cuentas.

Como puede ver, esta función se usa para escenarios en los que los propietarios ofrecen tokens en un mercado. Permite que el mercado finalice la transacción sin esperar una aprobación previa.

Al final de su ejecución, esta función dispara un evento de Approval .

Obtener el número de tokens aprobados para retiro

 function allowance(address owner, address delegate) public view returns (uint) { return allowed[owner][delegate]; }

Esta función devuelve el número actual de tokens aprobados por un propietario a un delegado específico, según lo establecido en la función de approve .

Transferir tokens por delegado

La función transferFrom es el par de la función de approve , que discutimos anteriormente. Permite que un delegado aprobado para retiro transfiera fondos del propietario a una cuenta de terceros.

 function transferFrom(address owner, address buyer, uint numTokens) public returns (bool) { require(numTokens <= balances[owner]); require(numTokens <= allowed[owner][msg.sender]); balances[owner] = balances[owner] — numTokens; allowed[owner][msg.sender] = allowed[from][msg.sender] — numTokens; balances[buyer] = balances[buyer] + numTokens; Transfer(owner, buyer, numTokens); return true; }

Las dos instrucciones require al inicio de la función son para verificar que la transacción es legítima, es decir, que el propietario tiene suficientes tokens para transferir y que el delegado tiene aprobación para (al menos) numTokens para retirar.

Además de transferir la cantidad de numTokens del propietario al comprador, esta función también resta numTokens de la asignación del delegado. Básicamente, esto permite que un delegado con una asignación dada la divida en varios retiros separados, lo cual es un comportamiento típico del mercado.

Podríamos detenernos aquí y tener una implementación ERC20 válida. Sin embargo, queremos ir un paso más allá, ya que queremos un token de fuerza industrial. Esto requiere que hagamos nuestro código un poco más seguro, aunque aún podremos mantener el token relativamente simple, si no básico.

Biblioteca de solidez de SafeMath

SafeMath es una biblioteca de Solidity destinada a lidiar con una de las formas en que los piratas informáticos rompen los contratos: el ataque de desbordamiento de enteros. En un ataque de este tipo, el pirata informático obliga al contrato a utilizar valores numéricos incorrectos al pasar parámetros que llevarán los números enteros relevantes más allá de sus valores máximos.

Biblioteca Safemath en Solidity: ilustración

SafeMath protege contra esto probando el desbordamiento antes de realizar la acción aritmética, eliminando así el peligro de un ataque de desbordamiento. La biblioteca es tan pequeña que el impacto en el tamaño del contrato es mínimo, no incurre en rendimiento y tiene pocas penalizaciones de costos de almacenamiento.

Agreguemos SafeMath a nuestro código:

 library SafeMath { // Only relevant functions function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a — b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } }

SafeMath usa assert para verificar la corrección de los parámetros pasados. Si la assert falla, la ejecución de la función se detendrá de inmediato y todos los cambios de la cadena de bloques se revertirán.

A continuación, agreguemos la siguiente declaración que presenta la biblioteca al compilador de Solidity:

using SafeMath for uint256;

Luego, reemplazamos la aritmética ingenua que usamos al principio con funciones de SafeMath:

 balances[msg.sender] = balances[msg.sender].sub(numTokens); balances[receiver] = balances[receiver].add(numTokens); balances[buyer] = balances[buyer].add(numTokens); balances[owner] = balances[owner].sub(numTokens);

Embalándolo todo junto

En Solidity, las funciones y los eventos de un contrato inteligente se envuelven en una entidad llamada contrato que puede traducir silenciosamente a una "clase de cadena de bloques". A continuación se muestra el contrato compatible con ERC20 que creamos, incluida una parte esencial de nuestro código. Los campos de nombre y símbolo se pueden cambiar a voluntad. La mayoría de las fichas mantienen el valor decimal en 18, por lo que haremos lo mismo.

Implementación del contrato de Ethereum

Ha llegado el momento de implementar nuestro contrato en la cadena de bloques. Tras la implementación, nuestro contrato se transferirá a todos los nodos que participan en la red. Todos y cada uno de los cambios realizados en el contrato se propagarán a todos los nodos participantes.

Los desarrolladores de Ethereum suelen emplear herramientas de implementación como Truffle. Incluso Truffle es excesivo para las necesidades limitadas de este artículo, y bastará con una sencilla herramienta en línea llamada Remix.

Para usarlo, deberá instalar el complemento MetaMask en su navegador y una cuenta de Rinkeby (red de prueba de Ethereum) con al menos algo de Rinkeby Ether. Estos son pasos relativamente simples, por lo que no entraremos en detalles.

En caso de que no tenga ninguno de los dos, diríjase a MetaMask y Rinkeby para obtener enlaces de descarga y obtener instrucciones claras de instalación y uso.

Ahora que tenemos todos los componentes básicos en su lugar, nos dirigiremos a Remix y pegaremos el código anterior, incluida la línea pragma y la biblioteca SafeMath, en el editor en línea.

Luego, pasaremos a la segunda pestaña a la derecha llamada " Ejecutar " y haremos clic en " Implementar ". Aparecerá una ventana emergente de MetaMask pidiéndonos que confirmemos la transacción. Por supuesto, lo aprobaremos.

texto alternativo de la imagen

  • Cuadro verde: asegúrese de estar en Rinkeby
  • Cuadro azul: establezca su suministro total de fichas
  • Cuadro rojo: ¡Desplegar!

Esencia : https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be#file-basicerc20-sol

¡Felicitaciones! Acaba de implementar su primer token ERC20, como un verdadero profesional de Ethereum. Tal como se prometió, el token es simple y liviano, pero totalmente funcional, cumple con el estándar ERC20 y está protegido con MathSafe. Está listo para ser comprado, pagado y transferido a través de Blockchain.

¿Eso es todo lo que hay en los contratos inteligentes?

No, ni siquiera cerca, ya que nuestra breve demostración apenas rasca la superficie y trata únicamente de un aspecto del desarrollo de contratos inteligentes.

Los contratos inteligentes pueden ser mucho más complejos dependiendo de su lógica comercial, su modelado de la interacción del usuario, si permite o no la acuñación y quema de tokens, los cambios del ciclo de vida que introduce en el contrato, la necesidad de capacidades de nivel de administrador que generalmente viene con un conjunto de funciones autorizado por el administrador, etc. Te dan la imagen.

Aún así, si puede replicar lo que hicimos aquí, es una base sólida para ampliar su conocimiento y pasar a contratos más complejos cuando sea necesario.