WEB3DEV

Cover image for Criando um Token ERC20 Encapsulado na Avalanche com o Vyper! ūüźć
Paulo Gio
Paulo Gio

Posted on

Criando um Token ERC20 Encapsulado na Avalanche com o Vyper! ūüźć

Introdução

Neste artigo, vamos descrever os casos de uso de um token ERC20 e explicaremos como cri√°-lo do zero usando o Vyper, implantando na rede de teste da Avalanche, Fuji.

Pré-requisitos

  • Programa√ß√£o b√°sica e experi√™ncia com console/terminal
  • Uma compreens√£o simples de Solidity ou Vyper

Requisitos

O que é um ERC20?

Um contrato inteligente ERC20 controla tokens fungíveis, e o próprio contrato nos permite transferir, gravar e fazer muitas outras coisas interessantes com esse token específico.

A interface do contrato √© muito simples e n√£o inclui muitas informa√ß√Ķes sobre o token em si.

#Fun√ß√Ķes
totalSupply()
balanceOf(account)
transfer(to, amount)
allowance(owner, spender)
approve(spender, amount)
transferFrom(from, to, amount)
Enter fullscreen mode Exit fullscreen mode

Essas seis fun√ß√Ķes fazem parte da fun√ß√£o original definida na EIP20. Podemos estender muitas funcionalidades adicionando mais fun√ß√Ķes (mais recursos) ao nosso contrato inteligente.

Neste artigo vamos criar um contrato inteligente ERC20, que recebe AVAX e retorna WAVAX, nossa implementação encapsulada da criptomoeda.

Vamos permitir que os usu√°rios criem tokens depositando AVAX, queimem tokens e recebam AVAX em troca.

Por que eles s√£o importantes?

Os tokens são uma parte fundamental do espaço web3. Eles podem ser usados de várias maneiras criativas e exclusivas, como compartilhamentos em uma comunidade, valor transacional, moeda em um protocolo e muito mais. Neste tutorial, vamos criar um token que encapsula uma criptomoeda (AVAX neste caso) e esse token pode ser usado em protocolos defi, protocolos web3 e muito mais.

Configuração

Vamos usar o Brownie neste tutorial. Após instalar o Brownie, crie uma nova pasta chamada avalanche-swap e dentro dela execute o seguinte comando:

$ brownie init
Enter fullscreen mode Exit fullscreen mode

Além disso, usaremos o nó Hardhat para testar nossos contratos inteligentes, portanto, dentro da pasta do projeto, execute o seguinte comando:

$ npm install --save-dev hardhat
Enter fullscreen mode Exit fullscreen mode

Contrato Inteligente

Vamos começar com o código-modelo. Criamos um arquivo chamado contracts/WAVAX.vy, definimos a versão do Vyper como >= 0.3.7 e importamos as interfaces ERC20 e ERC20Detailed do Vyper.

# @version >=0.3.7

from vyper.interfaces import ERC20
from vyper.interfaces import ERC20Detailed

implements: ERC20
implements: ERC20Detailed
Enter fullscreen mode Exit fullscreen mode

Eventos

Precisamos definir nossos eventos (events), que s√£o as mensagens que o contrato inteligente emite quando chamado, e as definimos conforme proposto pela EIP20.

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256
Enter fullscreen mode Exit fullscreen mode

Estado

Nosso contrato inteligente precisa de estado, ou de vari√°veis que persistir√£o durante toda a vida do contrato inteligente. Essas vari√°veis cont√™m informa√ß√Ķes que ser√£o √ļteis para nossos usu√°rios e para os m√©todos que definiremos a seguir, como balanceOf, totalSupply e allowance

# @dev nome do token ("Wrapped AVAX")
name: public(String[32])

# @dev símbolo ou ticker do token ("WAVAX")
symbol: public(String[32])

# @dev a quantidade de decimais que o token contém
decimals: public(uint8)

# @dev o saldo de um determinado endereço
balanceOf: public(HashMap[address, uint256])

# @dev endereços podem permitir que outros endereços gastem seus tokens
allowance: public(HashMap[address, HashMap[address, uint256]])

# @dev o n√ļmero de tokens em circula√ß√£o
totalSupply: public(uint256)
Enter fullscreen mode Exit fullscreen mode

Como voc√™ pode ver, definimos uma vari√°vel para armazenar quantos decimais nosso token vai ter. Isso porque o Solidity, principal linguagem de programa√ß√£o utilizada nas blockchains EVM, n√£o tem suporte para uso de decimais, ent√£o definimos os decimais como inteiros. Por exemplo, n√≥s queremos usar 2 casas decimais. Para expressar o n√ļmero 100,99, colocar√≠amos assim, 10099, sendo os √ļltimos dois d√≠gitos a parte decimal real.

Construtor

Ap√≥s concluir o processo anterior, definimos o construtor. Aqui especificamos o nome do token, o s√≠mbolo e o n√ļmero de casas decimais que esse token ter√°.

@external
def __init__():
    self.name = "Wrapped AVAX"
    self.symbol = "WAVAX"
    self.decimals = 18
Enter fullscreen mode Exit fullscreen mode

Métodos internos

Os métodos internos são bem simples. Precisamos de um método para cunhar nossos tokens AVAX encapsulados quando o usuário enviar a quantia que deseja, e outro para queimá-los quando quiser recuperar seus tokens.

@internal
def _mint(_to: address, _value: uint256):
    assert _to != empty(address)
    self.totalSupply += _value
    self.balanceOf[_to] += _value
    log Transfer(empty(address), _to, _value)
Enter fullscreen mode Exit fullscreen mode
@internal
def _burn(_to: address, _value: uint256):
    assert _to != empty(address)
    self.totalSupply -= _value
    self.balanceOf[_to] -= _value
    send(_to, _value)
    log Transfer(_to, empty(address), _value)
Enter fullscreen mode Exit fullscreen mode

Esses dois s√£o m√©todos-padr√£o nas implementa√ß√Ķes do ERC20, pois precisamos de uma maneira de cunhar os tokens e (se assim o desejarmos) queim√°-los tamb√©m.

Métodos externos

Agora precisamos definir os principais métodos de um token ERC20: transfer, transferFrom e approve. Esses três métodos permitem que os detentores dos tokens os utilizem como desejarem.

O método transfer é autoexplicativo e permite que o detentor do token transfira tokens para outro usuário ou um contrato inteligente.

@external
def transfer(_to : address, _value : uint256) -> bool:
    self.balanceOf[msg.sender] -= _value
    self.balanceOf[_to] += _value
    log Transfer(msg.sender, _to, _value)
    return True
Enter fullscreen mode Exit fullscreen mode

O padrão do token precisa de um método approve para habilitar o método transferFrom que definimos a seguir. O método approve fornece ao detentor do token uma maneira de permitir que outra conta gerencie uma quantidade definida de tokens para eles.

@external
def approve(_spender : address, _value : uint256) -> bool:
    self.allowance[msg.sender][_spender] = _value
    log Approval(msg.sender, _spender, _value)
    return True
Enter fullscreen mode Exit fullscreen mode

E o método transferFrom dá ao usuário a capacidade de transferir tokens para outra conta em nome do titular do token ou gerenciar uma quantidade definida de tokens para eles.

@external
def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    self.allowance[_from][msg.sender] -= _value
    log Transfer(_from, _to, _value)
    return True
Enter fullscreen mode Exit fullscreen mode

Como este é um token encapsulado, precisamos de uma maneira de receber a criptomoeda que estamos tentando encapsular e cunhar uma quantidade equivalente de tokens, e também uma maneira de fazer o contrário, queimar vários tokens e receber a criptomoeda equivalente de volta.

Para o método mint (cunhagem), o usuário envia criptomoedas com a chamada do método e recebe o mesmo valor de volta em tokens.

@external
@payable
def mint():
    self._mint(msg.sender, msg.value)
Enter fullscreen mode Exit fullscreen mode

E para o método burn (queima), o usuário passa a quantidade de tokens que deseja queimar, para receber o equivalente em criptomoeda.

@external
def burn(_value: uint256):
    self._burn(msg.sender, _value)
Enter fullscreen mode Exit fullscreen mode

Também definiremos um método padrão. Este método será acionado se um usuário enviar AVAX diretamente para o contrato, sem chamar a função mint. E, por sua vez, o contrato cunhará para esse usuário o equivalente em tokens.

@external
@payable
def __default__():
    self._mint(msg.sender, msg.value)
Enter fullscreen mode Exit fullscreen mode

E é isso. Agora temos um contrato inteligente de token, que cunha tokens encapsulados. O seu contrato deve ficar mais ou menos assim:

# @vers√£o >=0.3.7

from vyper.interfaces import ERC20
from vyper.interfaces import ERC20Detailed

implements: ERC20
implements: ERC20Detailed

event Transfer:
    sender: indexed(address)
    receiver: indexed(address)
    value: uint256

event Approval:
    owner: indexed(address)
    spender: indexed(address)
    value: uint256

# @dev nome do token ("Wrapped AVAX")
name: public(String[32])

# @dev símbolo ou ticker do token ("WAVAX")
symbol: public(String[32])

# @dev a quantidade de decimais que o token contém
decimals: public(uint8)

# @dev o saldo de um determinado endereço
balanceOf: public(HashMap[address, uint256])

# @dev endereços podem permitir que outros endereços gastem seus tokens
allowance: public(HashMap[address, HashMap[address, uint256]])

# @dev o n√ļmero de tokens em circula√ß√£o
totalSupply: public(uint256)


@external
def __init__():
    self.name = "Wrapped AVAX"
    self.symbol = "WAVAX"
    self.decimals = 18


@internal
def _mint(_to: address, _value: uint256):
    assert _to != empty(address)
    self.totalSupply += _value
    self.balanceOf[_to] += _value
    log Transfer(empty(address), _to, _value)


@internal
def _burn(_to: address, _value: uint256):
    assert _to != empty(address)
    self.totalSupply -= _value
    self.balanceOf[_to] -= _value
    send(_to, _value)
    log Transfer(_to, empty(address), _value)


@external
def transfer(_to : address, _value : uint256) -> bool:
    self.balanceOf[msg.sender] -= _value
    self.balanceOf[_to] += _value
    log Transfer(msg.sender, _to, _value)
    return True


@external
def approve(_spender : address, _value : uint256) -> bool:
    self.allowance[msg.sender][_spender] = _value
    log Approval(msg.sender, _spender, _value)
    return True


@external
def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
    self.balanceOf[_from] -= _value
    self.balanceOf[_to] += _value

    self.allowance[_from][msg.sender] -= _value
    log Transfer(_from, _to, _value)
    return True


@external
@payable
def mint():
    self._mint(msg.sender, msg.value)


@external
def burn(_value: uint256):
    self._burn(msg.sender, _value)


@external
@payable
def __default__():
    self._mint(msg.sender, msg.value)
Enter fullscreen mode Exit fullscreen mode

Implantar usando o Brownie

Neste tutorial, vamos usar o Brownie para implantar nossos contratos inteligentes, você pode usar qualquer outro framework de contratos inteligentes se estiver familiarizado com ele. O Hardhat ou o ApeWorx têm suporte para desenvolver e implantar contratos inteligentes do Vyper.

Como estamos implantando na Avalanche, precisamos adicionar a rede principal (mainnet) da Avalanche e a rede de teste (testnet) da Avalanche, Fuji, às nossas redes suportadas. No terminal, digite o seguinte:

$ brownie networks add Avalanche avax-testnet host=https://api.avax-test.network/ext/bc/C/rpc chainid=43113 explorer=https://testnet.snowtrace.io/ name=Fuji
Enter fullscreen mode Exit fullscreen mode
$ brownie networks add Avalanche avax-mainnet host=https://api.avax.network/ext/bc/C/rpc chainid=43114 explorer=https://snowtrace.io/ name=Mainnet
Enter fullscreen mode Exit fullscreen mode

Depois de executarmos esses dois comandos, ser√£o adicionadas as redes Avalanche ao Brownie.

Avalanche
  ‚Ēú‚ĒÄMainnet: avax-mainnet
  ‚ĒĒ‚ĒÄFuji: avax-testnet
Enter fullscreen mode Exit fullscreen mode

Após a conclusão, podemos escrever o script de implantação.

Nosso script é muito simples, pois só vamos pegar nosso contrato inteligente e implantá-lo.

Nosso script verificar√° primeiro se estamos em alguma das redes Avalanche e, se estivermos, implantar√° os contratos inteligentes usando uma carteira real (com algum AVAX nela), caso contr√°rio, assumiremos que estamos trabalhando em nossa rede local e os implantaremos l√°.

Para implantar em uma blockchain ativa (Fuji ou rede principal), precisamos ter uma carteira com algum AVAX nela. Voc√™ pode obter alguns tokens AVAX de teste nesta torneira (faucet). Al√©m disso, precisamos definir nosso arquivo brownie-config.yaml para que o Brownie saiba onde encontrar nossa chave privada e tamb√©m algumas configura√ß√Ķes importantes.

Crie um arquivo brownie-config.yaml na raiz do seu projeto. Ele deve se parecer com isso.

dotenv: .env

networks:
  default: hardhat

wallets:
  from_key: ${PRIVATE_KEY}

compiler:
  vyper:
    version: "0.3.7"
Enter fullscreen mode Exit fullscreen mode

O arquivo de configuração espera que um arquivo .env funcione corretamente. Crie um na raiz do seu projeto e preencha-o com isso.

PRIVATE_KEY="SUA_CHAVE_PRIVADA_AQUI"
Enter fullscreen mode Exit fullscreen mode

Depois de definirmos nossa configuração, precisamos escrever nosso script de implantação. Na pasta scripts crie um novo arquivo chamado deploy.py. Este programa em python será responsável por implantar nossos contratos inteligentes.

O arquivo deploy.py deve se parecer com isto:

from brownie import accounts, network, config, WAVAX


def main():
    supported_networks = ["avax-mainnet", "avax-testnet"]
    active_network = network.show_active()

    deployer = accounts[0]
    if active_network in supported_networks:
        deployer = accounts.add(config["wallets"]["from_key"])

    WAVAX.deploy({"from": deployer})
Enter fullscreen mode Exit fullscreen mode

Para executar este script, escreva o seguinte comando em seu terminal. Isso implantará o contrato no seu nó local do Hardhat.

$ brownie run deploy
Enter fullscreen mode Exit fullscreen mode

Para implant√°-lo em uma rede de testes, escreva o seguinte.

$ brownie run deploy --network avax-testnet
Enter fullscreen mode Exit fullscreen mode

E para implant√°-lo na rede principal da Avalanche, execute o seguinte comando:

$ brownie run deploy --network avax-mainnet
Enter fullscreen mode Exit fullscreen mode

E seria isso sobre o contrato inteligente. Criamos, testamos e implantamos com sucesso nosso contrato inteligente de token encapsulado.

Contrato inteligente na rede de testes (Fuji)

WAVAX

Artigo original publicado por Rafo AV. Traduzido por Paulinho Giovannini.

Top comments (0)