Como criar um token ERC20 de maneira simples

Publicados: 2022-03-11

O objetivo deste artigo é demonstrar como criar um token ERC20 no menor tempo possível.

Vamos começar com o básico: O que é um token ERC20?

Nos últimos anos, a especificação do token ERC20 se tornou o padrão de fato para os tokens Ethereum. Em outras palavras, a maioria dos contratos de Ethereum hoje são compatíveis com ERC20. Este artigo detalha como você pode criar seu próprio token Ethereum, mas antes de começarmos, vamos dar uma olhada no padrão ERC20.

Ilustração do token ERC20

O que torna os tokens ERC20 tão atraentes e bem-sucedidos? Existem vários fatores em jogo:

  1. Os tokens ERC20 são simples e fáceis de implantar, como você verá neste tutorial.
  2. O padrão ERC20 resolve um problema significativo, pois os mercados baseados em blockchain e as carteiras de criptografia precisam de um único conjunto padronizado de comandos para se comunicar com a variedade de tokens que gerenciam. Isso inclui regras de interação entre diferentes tokens, bem como regras de compra de token.
  3. Foi a primeira especificação popular a oferecer padronização de token Ethereum. Não foi de forma alguma o primeiro , mas graças à sua popularidade, rapidamente se tornou o padrão da indústria.

Assim como outros tokens Ethereum, os tokens ERC20 são implementados como contratos inteligentes e executados na Ethereum Virtual Machine (EVM) de maneira descentralizada.

Solidity: a linguagem de programação de contrato inteligente

Os contratos inteligentes Ethereum são escritos em Solidity. Embora existam linguagens alternativas, quase ninguém as usa para esse fim. Solidity é semelhante ao JavaScript, então se você tem algum conhecimento de JavaScript, ou mesmo Java e outras linguagens semelhantes a C, você não deve ter problemas para descobrir que um pedaço de código em Solidity tem, mesmo antes de você realmente dominar Solidity o suficiente para usar isto.

É aqui que a diversão começa, pois você deve poder começar a criar um contrato ERC20 simples rapidamente. Esta é uma tarefa direta, simples o suficiente para que este artigo demonstre como você pode escrever e implantar um token ERC20 em menos de uma hora.

O token que criaremos nesta demonstração será uma implementação básica do ERC20, sem muitos sinos e assobios. No entanto, já vi muitos tokens simples semelhantes no mundo real, e eles tendem a se sair muito bem.

Visão geral do padrão de token ERC20

O que é o ERC20?

Simplificando, o padrão ERC20 define um conjunto de funções a serem implementadas por todos os tokens ERC20 para permitir a integração com outros contratos, carteiras ou marketplaces. Este conjunto de funções é bastante curto e 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);

As funções do ERC20 permitem que um usuário externo, digamos um aplicativo de carteira criptográfica, descubra o saldo de um usuário e transfira fundos de um usuário para outro com a devida autorização.

O contrato inteligente define dois eventos definidos especificamente:

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

Esses eventos serão invocados ou emitidos quando um usuário receber direitos para retirar tokens de uma conta e depois que os tokens forem realmente transferidos.

Além das funções ERC20 padrão, muitos tokens ERC20 também apresentam campos adicionais e alguns se tornaram uma parte de fato do padrão ERC20, se não por escrito, na prática. Aqui estão alguns exemplos de tais campos.

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

Aqui estão alguns pontos sobre a nomenclatura ERC20 e Solidity:

  • Uma função public pode ser acessada fora do próprio contrato
  • view basicamente significa constante, ou seja, o estado interno do contrato não será alterado pela função
  • Um event é a maneira do Solidity de permitir que os clientes, por exemplo, o frontend do seu aplicativo, sejam notificados sobre ocorrências específicas dentro do contrato

A maioria das construções da linguagem Solidity deve ser clara se você já possui habilidades essenciais em Java/JavaScript.

Escrevendo um token ERC20 no Solidity

Tokens ERC20 em solidez

Agora que descrevemos o básico e explicamos o que é necessário para criar um token ERC20, é hora de começar a escrever alguma lógica.

Primeiro, precisamos definir dois objetos de mapeamento. Esta é a noção de Solidity para uma matriz associativa ou chave/valor:

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

A expressão mapping(address => uint256) define um array associativo cujas chaves são do tipo address — um número usado para denotar endereços de contas e cujos valores são do tipo uint256 — um inteiro de 256 bits normalmente usado para armazenar saldos de token.

O primeiro objeto de mapeamento, balances , conterá o saldo do token de cada conta do proprietário.

O segundo objeto de mapeamento, allowed , incluirá todas as contas aprovadas para retirada de uma determinada conta juntamente com a soma de retirada permitida para cada uma.

Como você pode ver, o campo de valor do mapeamento permitido é por si só um endereço de conta de plotagem de mapeamento para sua soma de retirada aprovada.

Esses mapeamentos, juntamente com todos os outros campos de contrato, serão armazenados no blockchain e serão minerados , resultando na propagação de alterações para todos os nós de usuários da rede.

O armazenamento Blockchain é caro e os usuários do seu contrato precisarão pagar, de uma forma ou de outra. Portanto, você deve sempre tentar minimizar o tamanho do armazenamento e as gravações no blockchain.

Agora que temos as estruturas de dados necessárias, podemos começar a escrever a lógica ERC20 nas funções apropriadas.

Configurando o número de tokens ICO

Como definimos o número de tokens ICO? Bem, existem várias maneiras de definir o número máximo de tokens da ICO e esse assunto pode valer uma longa discussão por si só.

Para as necessidades do nosso tutorial ECR20, usaremos a abordagem mais simples: Defina a quantidade total de tokens no momento da criação do contrato e inicialmente atribua todos eles ao “proprietário do contrato”, ou seja, a conta que implantou o contrato inteligente:

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

Um construtor é uma função especial chamada automaticamente pelo Ethereum logo após a implantação do contrato. Normalmente é usado para inicializar o estado do token usando parâmetros passados ​​pela conta de implantação do contrato.

msg é uma variável global declarada e preenchida pelo próprio Ethereum. Contém dados importantes para a execução do contrato. O campo que estamos usando aqui: msg.sender contém a conta Ethereum executando a função de contrato atual.

Somente a conta de implantação pode entrar no construtor de um contrato. Quando o contrato é iniciado, esta função aloca tokens disponíveis para a conta 'dono do contrato'.

Obter fornecimento total de token

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

Esta função retornará o número de todos os tokens alocados por este contrato, independentemente do proprietário.

Obter saldo de token do proprietário

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

balanceOf retornará o saldo atual do token de uma conta, identificado pelo endereço de seu proprietário.

Transferir tokens para outra conta

 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 o próprio nome sugere, a função de transfer é usada para mover a quantidade de tokens numTokens do saldo do proprietário para o de outro usuário ou receiver . O proprietário da transferência é msg.sender , ou seja, aquele que executa a função, o que implica que apenas o proprietário dos tokens pode transferi-los para outros.

A maneira do Solidity de afirmar um predicado é require . Neste caso, a conta de transferência tem saldo suficiente para executar a transferência. Se uma instrução require falhar, a transação será imediatamente revertida sem alterações gravadas no blockchain.

Logo antes de sair, a função dispara o evento ERC20 Transfer , permitindo que os ouvintes registrados reajam à sua conclusão.

Aprovar Delegado para Retirar Tokens

Essa função é usada com mais frequência em um cenário de mercado de token.

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

O que approve faz é permitir que um proprietário, ou seja, msg.sender , aprove uma conta delegada - possivelmente o próprio mercado - para retirar tokens de sua conta e transferi-los para outras contas.

Como você pode ver, essa função é usada para cenários em que os proprietários estão oferecendo tokens em um mercado. Ele permite que o marketplace finalize a transação sem esperar pela aprovação prévia.

Ao final de sua execução, esta função dispara um evento de Approval .

Obtenha o número de tokens aprovados para retirada

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

Essa função retorna o número atual aprovado de tokens por um proprietário para um delegado específico, conforme definido na função de approve .

Transferir Tokens por Delegado

A função transferFrom é o par da função de approve , que discutimos anteriormente. Ele permite que um delegado aprovado para retirada transfira fundos do proprietário para uma conta de terceiros.

 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; }

As duas instruções require no início da função são para verificar se a transação é legítima, ou seja, se o proprietário tem tokens suficientes para transferir e se o delegado tem aprovação para (pelo menos) numTokens retirar.

Além de transferir o valor de numTokens do proprietário para o comprador, essa função também subtrai numTokens da permissão do delegado. Isso basicamente permite que um delegado com um determinado subsídio o divida em várias retiradas separadas, o que é um comportamento típico do mercado.

Poderíamos parar por aqui e ter uma implementação válida do ERC20. No entanto, queremos dar um passo adiante, pois queremos um token de força industrial. Isso exige que tornemos nosso código um pouco mais seguro, embora ainda possamos manter o token relativamente simples, se não básico.

Biblioteca SafeMath Solidity

SafeMath é uma biblioteca Solidity destinada a lidar com hackers de uma maneira conhecida por quebrar contratos: ataque de estouro de número inteiro. Nesse ataque, o hacker força o contrato a usar valores numéricos incorretos, passando parâmetros que levarão os inteiros relevantes além de seus valores máximos.

Biblioteca Safemath no Solidity: ilustração

O SafeMath protege contra isso testando o estouro antes de executar a ação aritmética, eliminando assim o perigo de ataque de estouro. A biblioteca é tão pequena que o impacto no tamanho do contrato é mínimo, não incorrendo em desempenho e com poucas penalidades de custo de armazenamento.

Vamos adicionar SafeMath ao nosso 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 declarações assert para verificar a exatidão dos parâmetros passados. Caso a assert falhe, a execução da função será imediatamente interrompida e todas as alterações do blockchain serão revertidas.

Em seguida, vamos adicionar a seguinte instrução apresentando a biblioteca ao compilador Solidity:

using SafeMath for uint256;

Em seguida, substituímos a aritmética ingênua que usamos no início pelas funções 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);

Embalando tudo junto

No Solidity, as funções e eventos de um contrato inteligente são agrupados em uma entidade chamada contrato que você pode traduzir silenciosamente para uma “classe blockchain”. Abaixo está o contrato compatível com ERC20 que criamos, incluindo um Gist do nosso código. Os campos de nome e símbolo podem ser alterados à vontade. A maioria dos tokens mantém o valor decimal em 18, então faremos o mesmo.

Implantação do Contrato Ethereum

Chegou a hora de implantar nosso contrato no blockchain. Após a implantação, nosso contrato será transferido para todos os nós participantes da rede. Todas e quaisquer alterações feitas no contrato serão propagadas para todos os nós participantes.

Os desenvolvedores do Ethereum geralmente empregam ferramentas de implantação como o Truffle. Mesmo Truffle é um exagero para as necessidades limitadas deste artigo, e uma ferramenta online simples chamada Remix será suficiente.

Para usá-lo, você precisará instalar o plug-in MetaMask em seu navegador e uma conta Rinkeby (rede de teste Ethereum) com pelo menos um pouco de Rinkeby Ether. Estes são passos relativamente simples, por isso não entraremos em detalhes.

Caso você não tenha nenhum, vá para MetaMask e Rinkeby para obter links de download e obter instruções claras de instalação e uso.

Agora que temos todos os blocos de construção no lugar, vamos para o Remix e colamos o código acima, incluindo a linha pragma e a biblioteca SafeMath, no editor online.

Em seguida, vamos pular para a segunda guia à direita chamada “ Executar ” e clicar em “ Implantar ”. Um pop-up MetaMask aparecerá nos pedindo para confirmar a transação. Claro, vamos aprová-lo.

texto alternativo da imagem

  • Caixa verde: Verifique se você está em Rinkeby
  • Caixa azul: defina seu fornecimento total de tokens
  • Caixa vermelha: Implante!

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

Parabéns! Você acabou de implantar seu primeiro token ERC20, como um verdadeiro profissional da Ethereum. Conforme prometido, o token é simples e leve, mas totalmente funcional, compatível com o padrão ERC20 e protegido com MathSafe. Ele está pronto para ser comprado, pago e transferido por toda a Blockchain.

Isso é tudo o que existe para contratos inteligentes?

Não, nem perto disso, pois nossa breve demonstração mal arranha a superfície e lida apenas com um aspecto do desenvolvimento de contratos inteligentes.

Os contratos inteligentes podem ser muito mais complexos dependendo da sua lógica de negócios, sua modelagem da interação do usuário, se você permite ou não a criação e gravação de tokens, as alterações do ciclo de vida que você introduz no contrato, a necessidade de recursos de nível de administrador que geralmente vêm com um conjunto de funções autorizado pelo administrador e assim por diante. Você começa a imagem.

Ainda assim, se você puder replicar o que fizemos aqui, essa é uma base sólida para expandir seu conhecimento e passar para contratos mais complexos quando necessário.