WEB3DEV

Cover image for Como criar um token ERC-223
Adriano P. Araujo
Adriano P. Araujo

Posted on

Como criar um token ERC-223

Neste artigo, abordarei o processo de criação de um token ERC-223. O token pode ser criado em qualquer cadeia compatível com EVM, como Ethereum, Arbitrum, Optimism e muitas outras.

Você precisará de:

  • Navegador

  • Carteira

  • Moeda nativa (ETH na Ethereum) para cobrir a taxa de gás

  • IDE, neste exemplo estou usando o Remix

O que é um ERC-223?

ERC-223 é um padrão de token na Ethereum.

O padrão ERC-223 define os detalhes técnicos e a lógica que um token deve implementar para tornar todos os tokens compatíveis com ERC-223 semelhantes entre si. O padrão ERC-223 foi desenvolvido para corrigir uma vulnerabilidade de segurança no padrão ERC-20 que causou danos financeiros de $90.000.000 a $200.000.000 aos usuários de tokens Ethereum durante 2023.

Você pode encontrar mais recursos ERC-223 e a história dos padrões de tokens Ethereum aqui: https://dexaran.github.io/erc223/

Por que devo usar o ERC-223?

  • Muitos fundos foram perdidos devido a falhas de segurança do ERC-20. Se você se preocupa com a segurança dos fundos de seus usuários, então não deve usar o ERC-20. O ERC-223 é o análogo mais próximo projetado com segurança em mente.

  • O EIP-7417  torna os tokens ERC-20 e ERC-223 intercambiáveis. Qualquer pessoa pode converter tokens ERC-20 para ERC-223 ou vice-versa usando o serviço Token Converter.

  • O ERC-223 faz com que os tokens se comportem de maneira idêntica ao Ether, sem requisitos extras, sem código adicional e, portanto, menos chances de introduzir um novo problema. A lógica de transferência de Ether é minimalista, limpa e completamente suficiente para atender às necessidades dos desenvolvedores de contratos inteligentes.

  • O ERC-223 é a proposta mais debatida na história da Ethereum. Todas as suas ressalvas são minuciosamente pesquisadas e corrigidas.

  • A lógica de depositar tokens em um contrato é a diferença chave entre o ERC-20 e o ERC-223. No caso do ERC-20, um usuário deve autorizar o contrato a retirar tokens e, em seguida, executar uma função que os retirará. Isso é um par de duas transações diferentes, e o mecanismo de autorizar terceiros a manipular os fundos dos usuários não é a melhor ideia em um mundo sem confiança descentralizado. No caso do ERC-223, o usuário precisa simplesmente enviar tokens para o contrato de destino, e o depósito será executado no lado do destinatário exatamente da mesma maneira que é feito com depósitos de Ether.

Principais pontos sobre tokens ERC-223

Os códigos-fonte do token ERC-223 de referência podem ser obtidos aqui: https://github.com/Dexaran/ERC223-token-standard/

Qualquer token compatível com ERC-223 DEVE implementar as seguintes funções:

Total Supply


function totalSupply() view returns (uint256)

Enter fullscreen mode Exit fullscreen mode

Um método que define o fornecimento total de seus tokens. É importante observar que esta função pode conter lógica específica do token que exclui alguns tokens do fornecimento se eles foram "queimados" em algum endereço de propósito. Por exemplo, 0xdead000000000000000000000000000000000000.

Balance Of


function balanceOf(address _owner) view returns (uint256)

Enter fullscreen mode Exit fullscreen mode

Um método que retorna o número de tokens que um endereço possui.

Transfer


function transfer(address _to, uint _value) returns (bool)

function transfer(address _to, uint _value, bytes calldata _data) returns (bool)

Enter fullscreen mode Exit fullscreen mode

Essas duas funções de transferência movem tokens do saldo do usuário que iniciou a transação para o endereço _to. A função sem o parâmetro _data está lá por uma questão de compatibilidade com a função de transferência ERC-20, ou seja, para qualquer carteira que operava com tokens ERC-20, enviar ERC-223 seria o mesmo.

É importante observar que ambas as funções transfer estão notificando o destinatário se ele for um contrato e, portanto, o destinatário pode lidar com uma transação de token ERC-223 recebida. Por exemplo, o destinatário pode aceitar apenas o token ERC-223 especificado e rejeitar qualquer outra coisa. Com o ERC-20, não era possível rejeitar um token incorreto.

Além dessas funções obrigatórias, é recomendável implementar funções opcionais para melhorar a operabilidade do token.

Name, Symbol, Decimals


function name() view returns (string memory)

function symbol() view returns (string memory)

function decimals() view returns (uint8)

Enter fullscreen mode Exit fullscreen mode

Essas funções são herdadas do ERC-20. O Name exibe o nome dos tokens, por exemplo, "Token Dex223". O  Symbol exibe um ticker do token. A maioria das exchanges permite tickers com até 5 símbolos, por exemplo, "D223".

 Decimals é uma variável especial que seria usada pelas carteiras para exibir tokens. Não há números fracionários em Solidity, então, para exibir uma fração de um token, os desenvolvedores definem suas casas decimais e as interfaces do usuário dividem a quantidade real de tokens armazenados no contrato por 10^decimals. Por exemplo, o USDT tem 6 casas decimais. Se um usuário tiver 2381000 USDT retornado pela função balanceOf, então a carteira exibiria um saldo de 2,381 USDT.

Standard


function standard() public view returns (string memory)

Enter fullscreen mode Exit fullscreen mode

Embora esta função seja opcional, é altamente recomendável implementá-la em produção. Isso tornaria muito mais simples para carteiras e serviços que interagem com tokens determinar se um token é ERC-20 ou ERC-223 sem mergulhar na lógica dos tokens.

Tokens ERC-20 e ERC-223 podem ter um conjunto idêntico de funções, o que dificulta a diferenciação para interfaces do usuário. A principal diferença é a lógica interna da função transfer.

A função standard do padrão ERC-223 deve retornar uma única string "223".

approve & transferFrom


function approve(address spender, uint256 value) external returns (bool)

function transferFrom(address from, address to, uint256 value) external returns (bool)

Enter fullscreen mode Exit fullscreen mode

Embora essas funções não façam parte do padrão ERC-223 e não sejam necessárias para a operabilidade de um token ERC-223, elas podem ser adicionadas ao contrato do token para torná-lo totalmente compatível com serviços projetados para tokens ERC-20.

Deve ser observado, no entanto, que approve & transferFrom é um método de transferência legado  que foi introduzido em 2015 no ERC-20 apenas para corrigir um bug nos primeiros dias da EVM que não existe desde 2017. Não há razão real para confiar nesses métodos de transferência em sistemas descentralizados e sem confiança atualmente.

Escrevendo o Contrato Inteligente

Abra o Remix ou sua IDE e crie um novo contrato.

Você pode copiar o código da implementação de referência na EIP-223, minha implementação de referência ou simplesmente usar o código abaixo:


pragma solidity ^0.8.0;

abstract contract IERC223Recipient {
    function tokenReceived(address _from, uint _value, bytes memory _data) public virtual returns (bytes4) { return 0x8943ec02; }

}



library Address {

    function isContract(address account) internal view returns (bool) {
        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;

    }

}



contract ERC223Token {

    event Transfer(address indexed from, address indexed to, uint value, bytes data);


    string  private _name     = "My ERC-223 Token";
    string  private _symbol   = "MTKN";
    uint8   private _decimals = 18;
    uint256 private _totalSupply;
    mapping(address => uint256) private balances;


    constructor()

    {

        balances[msg.sender] = 100 * 10 ** _decimals;
        _totalSupply         = 100 * 10 ** _decimals;
        emit Transfer(address(0), msg.sender, 100 * 10 ** _decimals, hex"000000");

    }



    function name()                    public view returns (string memory) { return _name; }
    function symbol()                  public view returns (string memory) { return _symbol; }
    function decimals()                public view returns (uint8)         { return _decimals; }
    function standard()                public view returns (string memory) { return "223"; }
    function totalSupply()             public view returns (uint256)       { return _totalSupply; }
    function balanceOf(address _owner) public view returns (uint256)       { return balances[_owner]; }


    function transfer(address _to, uint _value, bytes calldata _data) public returns (bool success)

    {

        balances[msg.sender] = balances[msg.sender] - _value;
        balances[_to] = balances[_to] + _value;
        if(Address.isContract(_to)) {

            IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data);

        }

        emit Transfer(msg.sender, _to, _value, _data);
        return true;

    }

    function transfer(address _to, uint _value) public returns (bool success)

    {

        bytes memory _empty = hex"00000000";
        balances[msg.sender] = balances[msg.sender] - _value;
        balances[_to] = balances[_to] + _value;
        if(Address.isContract(_to)) {

            IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty);

        }

        emit Transfer(msg.sender, _to, _value, _empty);
        return true;

    }

}

Enter fullscreen mode Exit fullscreen mode

Primeiro, precisaremos de dois contratos auxiliares:

  1. IERC223Recipient: Este é um contrato de interface que define uma função tokenReceived. Qualquer contrato que queira aceitar tokens ERC-223 deve implementar o IERC223Recipient, caso contrário, os tokens serão automaticamente rejeitados e não haverá maneira de depositá-los no contrato por meio da função transfer.

  2. Address library: Essa biblioteca é necessária para determinar se o destinatário da transferência ERC-223 é um contrato ou não. Se houver um bytecode no endereço do destinatário, consideramos que é um contrato.

Em seguida, a lógica do Token ERC-223 deve ser implementada. No nosso caso, o contrato será atribuído a um name, "My ERC-223 Token", símbolo "MTKN" e 18 casas decimais (padrão para a maioria dos tokens na Ethereum).


constructor()

    {

        balances[msg.sender] = 100 * 10 ** _decimals;

        _totalSupply         = 100 * 10 ** _decimals;

        emit Transfer(address(0), msg.sender, 100 * 10 ** _decimals, hex"000000");

    }

Enter fullscreen mode Exit fullscreen mode

Essas linhas criarão 100 tokens e atribuirão ao saldo do remetente da transação.

E o evento Transfer(address(0), msg.sender, 100 * 10 ** _decimals, hex”000000") indica a criação dos tokens como se fossem enviados do endereço 0x0.

Implantando o contrato com a MetaMask

Obtenha a MetaMask se você ainda não o tiver.

Vá para a guia Deploy & Run Transactions. Para a implantação, use a opção Injected Provider embaixo de Environment.

Antes da implantação, certifique-se de que a sua MetaMask está configurada para a rede correta e que o contrato ERC223Token é o contrato selecionado para implantação.

Finalmente, clique no botão Deploy para implantar seu contrato. Confirme a transação na MetaMask.

Ótimo trabalho! Seu token foi implantado.

Implantando o contrato com bytecode

Compile o contrato.

Certifique-se de mudar para o ERC223Token (ERC223Token.sol) após a conclusão da compilação (o Address seria exibido por padrão, já que o Remix classifica todos os contratos compilados em ordem alfabética).

Clique em copiar o bytecode.

Cole seu bytecode em sua carteira que permite implantar o bytecode do contrato. Envie a transação e aguarde a confirmação.

Parabéns! Você acabou de criar seu token ERC-223.

Exemplo de Token ERC-223

Aqui está como um token ERC-223 parece na rede principal da Ethereum:

https://etherscan.io/address/0xcce968120e6ded56f32fbfe5a2ec06cbf1e7c8ed


Este artigo foi escrito por Dexaran e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.

Top comments (0)