Nesse artigo iremos aprender a criar nosso primeiro Token ERC20 e uma aplicação que irá interagir com nosso token.
Token ERC20
Qualquer contrato que siga o padrão ERC20 é considerado um token ERC20.
Os tokens ERC20
fornecem funcionalidades para
- transferir tokens
- permitir que outros transfiram tokens em nome do titular do token
Um exemplo de interface para o token ERC20
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;// Link do arquivo padrão da interface IERC20// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.solinterface IERC20 {function totalSupply() external view returns (uint);function balanceOf(address account) external view returns (uint);function transfer(address recipient, uint amount) external returns (bool);function allowance(address owner, address spender) external view returns (uint);function approve(address spender, uint amount) external returns (bool);function transferFrom(address sender,address recipient,uint amount) external returns (bool);event Transfer(address indexed from, address indexed to, uint value);event Approval(address indexed owner, address indexed spender, uint value);}
Exemplo do contrato do token ERC20
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;import "./IERC20.sol";// Criação do contrato do token PRATICAcontract ERC20 is IERC20 {uint public totalSupply;mapping(address => uint) public balanceOf;mapping(address => mapping(address => uint)) public allowance;string public name = "Solidity na Prática";string public symbol = "PRATICA";uint8 public decimals = 18;// Função responsável por transferir os tokens da carteira// que chamou a função para a carteira recipientfunction transfer(address recipient, uint amount) external returns (bool) {balanceOf[msg.sender] -= amount;balanceOf[recipient] += amount;emit Transfer(msg.sender, recipient, amount);return true;}// Função responsável por aprovar que o contrato interaja com// o saldo da sua carteirafunction approve(address spender, uint amount) external returns (bool) {allowance[msg.sender][spender] = amount;emit Approval(msg.sender, spender, amount);return true;}// Função responsável por transferir tokens de uma carteira sender// para a carteira recipientfunction transferFrom(address sender,address recipient,uint amount) external returns (bool) {allowance[sender][msg.sender] -= amount;balanceOf[sender] -= amount;balanceOf[recipient] += amount;emit Transfer(sender, recipient, amount);return true;}// Função responsável por mintar/criar mais tokens PRATICA// e enviar para a carteira de quem chamou a funçãofunction mint(uint amount) external {balanceOf[msg.sender] += amount;totalSupply += amount;emit Transfer(address(0), msg.sender, amount);}// Função responsável por queimar o tokenfunction burn(uint amount) external {balanceOf[msg.sender] -= amount;totalSupply -= amount;emit Transfer(msg.sender, address(0), amount);}}
Criando seu próprio token ERC20
Para facilitar e padronizar a criação de tokens ERC20
, você pode utilizar a ferramenta OpenZeppelin,
repositório do OpenZeppelin no GitHub com vários exemplos de contratos ERC20
e ERC721
.
Você pode ler a documentação completa sobre tokens ERC20
aqui.
Através do OpenZeppelin, você cria seu token de forma automatizada passando apenas alguns parâmetros como
name
- nome do tokensymbol
- símbolo do seu tokenpremint
- total de tokens que serão criados inicialmente
Entre outras opções, acesse o site da OpenZeppelin e confira a ferramenta completa.
Abaixo, um simples exemplo de token ERC20
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/ERC20.sol";// Para nomear seu contrato, altere MyToken para o nome desejadocontract MyToken is ERC20 {// Criaremos 1000 tokensuint tokenAmount = 1000;constructor(string memory name, string memory symbol) ERC20(name, symbol) {// Mint 1000 tokens para carteira msg.sender// Semelhante como// 1 dollar = 100 cents// 1 token = 1 * (10 ** decimals)_mint(msg.sender, tokenAmount * 10**uint(decimals()));// Se você quizesse por exemplo, criar 1 milhão de tokens// Bastaria trocar o valor do tokenAmount para 1000000}}
Contrato para trocar tokens (Swap de Tokens)
Aqui está um exemplo de contrato TokenSwap
, onde podemos trocar um token ERC20 por outro, onde poderíamos aplicar por exemplo, em uma dapp de jogo NFT, onde
o jogador poderá trocar um token X pelo token Y do jogo, exemplo realizar a troca do token BNB
da BSC pelo nosso token PRATICA
.
Este contrato trocará tokens chamando
transferFrom(address sender, address recipient, uint256 amount)
que realizará a transferência da quantidade passada pelo parâmetro amount
do token PRATICA
do endereço sender
para o endereço recipient
.
Para que a função transferFrom
tenha sucesso, o endereço sender
deve
- ter saldo
amount
maior do que está enviando na transação, contabilizando os valores de taxa de gas - autorizar o
TokenSwap
a interagir e retirar a quantidade deamount
do token de sua carteira através da funçãoapprove
antes de TokenSwap
chamar a função transferFrom
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;// Importa a interface IERC20 através do repositório GitHub do OpenZeppelinimport "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.0.0/contracts/token/ERC20/IERC20.sol";/*Como funciona a troca de tokens1. Alice tem 100 tokens da AliceCoin, que é um token ERC20.2. Bob tem 100 tokens da BobCoin, que também é um token ERC20.3. Alice e Bob querem trocar 10 AliceCoin por 20 BobCoin.4. Alice ou Bob implantam o TokenSwap5. Alice aprova o TokenSwap para retirar 10 tokens da AliceCoin6. Bob aprova o TokenSwap para retirar 20 tokens do BobCoin7. Alice ou Bob chama TokenSwap.swap()8. Alice e Bob negociaram tokens com sucesso.*/contract TokenSwap {IERC20 public token1;address public owner1;uint public amount1;IERC20 public token2;address public owner2;uint public amount2;// Construtor do TokenSwapconstructor(address _token1,address _owner1,uint _amount1,address _token2,address _owner2,uint _amount2) {token1 = IERC20(_token1);owner1 = _owner1;amount1 = _amount1;token2 = IERC20(_token2);owner2 = _owner2;amount2 = _amount2;}// Realiza as validações necessárias para que a troca seja realizada// com sucessofunction swap() public {require(msg.sender == owner1 || msg.sender == owner2, "Não autorizado");require(token1.allowance(owner1, address(this)) >= amount1,"Token 1 - permissão muito baixa");require(token2.allowance(owner2, address(this)) >= amount2,"Token 2 - permissão muito baixa");_safeTransferFrom(token1, owner1, owner2, amount1);_safeTransferFrom(token2, owner2, owner1, amount2);}// Realiza a transferência segura do endereço sender para// o endereço recipient na quantidade de amountfunction _safeTransferFrom(IERC20 token,address sender,address recipient,uint amount) private {bool sent = token.transferFrom(sender, recipient, amount);require(sent, "Falha na transferência do token");}}