WEB3DEV

Cover image for Desenvolva sua Criptomoeda Fiori usando o Embark com o Quorum
Paulo Gio
Paulo Gio

Posted on • Atualizado em

Desenvolva sua Criptomoeda Fiori usando o Embark com o Quorum

Após as duas publicações bem informativas dos meus colegas sobre como desenvolver contratos inteligentes do Quorum com Truffle e Remix, vou mostrar um framework alternativo para o mesmo propósito chamado Embark.

Este artigo seria de interesse para os desenvolvedores de blockchain de nível iniciante.

Embark é um framework que ajuda no desenvolvimento e implantação de aplicativos descentralizados na Ethereum. Ele contém um painel que ajuda o desenvolvedor a navegar em seus contratos, o status e a configuração da rede. Isso torna tudo muito simples para:

  • conectar-se a diferentes redes (redes privadas, testnets, mainnet)
  • implantar e atualizar contratos inteligentes
  • testar contratos inteligentes
  • integrar outras tecnologias descentralizadas em aplicativos, como armazenamento descentralizado (IPFS) e protocolos de comunicação descentralizados (Whisper)

Para fins de teste e desenvolvimento, o Embark usa uma blockchain simulada local, portanto, não há necessidade de pagar gás para prototipar rapidamente. Os dados de toda a cadeia são excluídos toda vez que finalizamos o processo.

Pré-requisitos

Instalação do Embark

Depois que todas as ferramentas de pré-requisitos locais estiverem configuradas, obter o Embark pode ser tão fácil quanto abrir seu terminal e digitar:

npm install -g embark
Enter fullscreen mode Exit fullscreen mode

Se você encontrar problemas com a instalação, pode ser útil verificar a página de solução de problemas do Embark e os problemas do Embark no Github.

Para verificar a instalação, execute o comando abaixo, que deve imprimir a versão do Embark:

$ embark --version
4.1.0
Enter fullscreen mode Exit fullscreen mode

Crie um novo projeto

No seu terminal execute:

embark new <Nome do Projeto>
Enter fullscreen mode Exit fullscreen mode

Isso deve criar seu projeto de teste. Podemos chamá-lo de FioriToken. Sim, vamos tentar criar uma implementação simples do token ERC20 da Ethereum baseado na biblioteca OpenZeppelin!

Crie um contrato inteligente

Em sua pasta FioriToken -> contratos, crie um novo arquivo 'FioriToken.sol' e cole o seguinte código nele:

pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract MyFioriToken is ERC20 {
    string public name;
    string public symbol;
    uint256 public decimals;

    constructor(string _name, string _symbol, uint8 _decimals)
      ERC20()
      public 
    {
      name = _name;
      symbol = _symbol;
      decimals = _decimals;
    }

    function deposit() public payable returns (bool) {
      uint256 value = msg.value * 10**decimals;
      increaseAllowance(msg.sender, value);
      return mint(msg.sender, value);
    }

    function mint(address to, uint256 amount) public returns (bool) {
      _mint(to, amount);
      return true;
    }
}
Enter fullscreen mode Exit fullscreen mode

Não se preocupe se o código parecer confuso agora! Discutiremos em detalhes o que esse código faz um pouco abaixo.

Configurar ambiente local

No momento, para compilar o contrato, precisamos concluir várias ações de configuração conforme abaixo:

  • Abra o arquivo embark.json.
    • Atualize o projeto Embark para usar o compilador Solidity correto. Para fazer isso, abra o arquivo em seu projeto Embark. Encontre a linha que começa com "solc": e atualize a linha para ler "solc": "0.4.24",.
    • Salve o arquivo embark.json.
  • Abra o arquivo contract.js.
    • Para configurar sua implantação de contrato local, encontre a seção de contratos a seguir
contracts: {
      // example:
      //SimpleStorage: {
      //  args: [ 100 ]
      //}
    }
Enter fullscreen mode Exit fullscreen mode

e substitua-o pelo código abaixo para que fique assim:

contracts: {
      MyFioriToken: {
       args: [ "My Fiori Token", "FIO", 0 ]
      }
    }
Enter fullscreen mode Exit fullscreen mode
  • Salve o arquivo contract.js.
  • Abra o terminal.

    • Instale a dependência (importamos a biblioteca openzeppelin no contrato Solidity acima). Basta executar o comando abaixo dentro da pasta do seu projeto:

      npm install [email protected]
      

Compilar contrato

Agora execute embark build em seu terminal e você verá que o contrato foi compilado e implantado localmente. A saída conteria as mensagens principais “Finished deploying” e “Finished building” destacadas em verde semelhante à abaixo:

https://blogs.sap.com/wp-content/uploads/2019/08/1_Build_success_2.png

Contrato de teste

Ao trabalhar com blockchains, não podemos subestimar a importância de bons testes. Como desenvolvedores, temos que garantir que o código implantado em uma rede blockchain seja o mais resiliente possível a bugs e eventos infelizes. Uma das melhores coisas que podemos fazer para garantir que isso aconteça, em primeiro lugar, é testá-lo antes de implantá-lo. Todos os testes devem ser reprodutíveis e tão exaustivos quanto possível.

Testes para contratos Ethereum (Quorum) são escritos em JavaScript. Essa linguagem oferece muitos recursos para facilitar o desenvolvimento orientado a testes. A ponte entre qualquer contrato Ethereum e um teste de JavaScript é chamada Web3.js. Essa biblioteca ajuda a conectar-se a um nó Ethereum (local ou remoto) e testar um contrato na rede por meio do JavaScript e suas bibliotecas.

Vamos escrever nossos testes dentro do ambiente gerado pelo Embark, o que significa que muitas coisas já foram feitas para facilitar nossa vida:

  • Toda vez que executarmos testes com embark test, nosso contrato será automaticamente compilado e implantado localmente.
  • As contas dos contratos implantados em particular serão devolvidas para nós, para que possamos usá-las para testes imediatamente.
  • web3 será exposto para todos os testes como um objeto global e seus métodos podem ser consumidos diretamente.
  • O assert do Node será exposto globalmente sem dependências adicionais.
  • Quaisquer bibliotecas adicionais para asserções avançadas (Chai) também podem ser conectadas e usadas.

Você pode ler mais sobre a configuração de teste do Embark aqui.

No entanto, em nosso código, criaremos uma nova instância de contrato manualmente antes de cada caso de teste, conforme o trecho de código abaixo:

const MyFioriToken = require('Embark/contracts/MyFioriToken');

contract("MyFioriToken", function (accounts) {

  const _name = "Fiori Token";
  const _symbol = "FIO";
  const _decimals = 0;
  let fcInstance;

  beforeEach(async function () {
    fcInstance = await MyFioriToken.deploy({ arguments: [_name, _symbol, _decimals] }).send();
  });

  it("Deve fazer algo como Caso de Teste 1", async function () {
    ...
  });

  it("Deve fazer algo como Caso de Teste 2", async function () {
    ...
  });

});
Enter fullscreen mode Exit fullscreen mode

O código acima é bem óbvio: importamos a definição do contrato da pasta do projeto, instanciamos o contrato com valores iniciais e pré-definimos os casos de teste.

No entanto, há um pequeno problema se você não usou o web3 antes. Há uma chamada de método send(), que interage com a rede blockchain e altera seu estado implantando o contrato. Você deve usar o send() toda vez que quiser chamar um método de contrato, que força a execução de uma transação na rede (funções setter). Por outro lado, o método call() é usado para métodos de contrato, que não alteram o estado da rede (funções getter).

Observe o uso do operador await na chamada deploy dentro da função async. O operador é usado lá para aguardar a resolução de uma promessa JavaScript. As chamadas assíncronas são muito usadas em testes de blockchain porque as chamadas de contrato inteligente que alteram o estado do contrato são enviadas para a rede como transações e devem ser mineradas, o que pode levar um tempo considerável.

Tokenização

Sim, vamos tentar criar uma implementação simples baseada na biblioteca OpenZeppelin!

Como você sabe, houve vários esforços de tokenização de ativos do mundo real para negociar em blockchains.

Tokenização é o conceito de atribuir um “token” como uma unidade de valor a um ativo específico que ele representa. No domínio da blockchain, isso significa criar um token digital para representar um ativo que pode ser mantido e negociado rapidamente pela rede.

As especificações ERC famosas (significa Ethereum Request for Comments) permitem que diferentes implementações de token sigam uma interface de programação compartilhada. ERC20 é a definição de um token básico fungível (intercambiável) que pode ser enviado na Ethereum.

Vários projetos de blockchain venderam tokens ERC20 representando ações ou direitos de voto para arrecadar fundos em ICOs (Ofertas Iniciais de Moedas). Tokens não fungíveis, geralmente na forma de tokens ERC721, são usados ​​para representar itens exclusivos, como colecionáveis ​​(por exemplo, Cryptokitties) e arte digital (por exemplo, SuperRare).

Existem algumas bibliotecas seguras que simplificam o desenvolvimento dos tokens ERC20. Uma delas é a implementação do OpenZeppelin, que já foi devidamente testada, para que possamos reutilizá-la em nosso projeto aqui.

O contrato em si é bem simples e básico, não contém regras rígidas sobre como o contrato é instanciado e quantos tokens ele deve fornecer na criação. Isso depende totalmente de nós.

No trecho de código acima, já criamos um contrato com seu próprio mecanismo de fornecimento. Ele não produz nenhuma quantidade fixa de tokens na criação, mas é capaz de cunhar uma certa quantidade de tokens para uma conta com um método especial chamado deposit.

Adicionando mais alguns casos de teste

Portanto, para testar nosso mecanismo de fornecimento, devemos criar alguns casos de teste.

Primeiramente, vamos verificar que quando um novo contrato é criado, ele não possui fornecimento de tokens e os saldos das contas são 0:

it("Deve criar um contrato com oferta zero", async function () {
  let result = await fcInstance.methods.totalSupply().call();
  assert.equal(result, 0);
});

it("Deve criar um contrato com saldo zero para uma conta", async function () {
  const account0 = accounts[0];
  let result = await fcInstance.methods.balanceOf(account0).call();
  assert.equal(result, 0);
});
Enter fullscreen mode Exit fullscreen mode

Em seguida, vamos verificar se os tokens são cunhados e atribuídos a uma conta pelo método deposit:

it("Deve cunhar tokens para uma conta", async function () {
  const account0 = accounts[0];
  await fcInstance.methods.deposit().send({ from: account0, value: 10 });
  const result = await fcInstance.methods.balanceOf(account0).call();
  const balance = parseFloat(result);
  assert.equal(balance, 10);
});
Enter fullscreen mode Exit fullscreen mode

Depois disso, podemos facilmente garantir que os tokens sejam transferidos com sucesso entre as contas. Cunhamos 10 tokens para cada conta, depois transferimos 2 de uma para outra e verificamos os saldos:

it("Deve passar tokens entre contas", async function () {
  const account0 = accounts[0];
  const account1 = accounts[1];

  await fcInstance.methods.deposit().send({ from: account0, value: 10 });
  const result0 = await fcInstance.methods.balanceOf(account0).call();
  const balance0 = parseFloat(result0);
  assert.equal(balance0, 10);

  await fcInstance.methods.deposit().send({ from: account1, value: 10 });
  const result1 = await fcInstance.methods.balanceOf(account1).call();
  const balance1 = parseFloat(result1);
  assert.equal(balance1, 10);

  await fcInstance.methods.transfer(account1, 2).send({ from: account0 });
  const result2 = await fcInstance.methods.balanceOf(account1).call();
  const balance2 = parseFloat(result2);
  assert.equal(balance2, 12);

  const result3 = await fcInstance.methods.balanceOf(account0).call();
  const balance3 = parseFloat(result3);
  assert.equal(balance3, 8);
});
Enter fullscreen mode Exit fullscreen mode

Podemos adicionar outro caso de teste, que falhará nesta fase porque não introduzimos nenhuma proteção contra vários depósitos:

it("Deve bloquear tokens de cunhagem para a mesma conta duas vezes", async function () {
  const account0 = accounts[0];
  await fcInstance.methods.deposit().send({ from: account0, value: 10 });
  await fcInstance.methods.deposit().send({ from: account0, value: 10 });
  const result = await fcInstance.methods.balanceOf(account0).call();
  const balance = parseFloat(result);
  assert.equal(balance, 10);
});
Enter fullscreen mode Exit fullscreen mode

Portanto, para manter uma lista de todas as contas que foram depositadas com qualquer quantidade de tokens pelo menos uma vez, podemos adicionar um mapeamento chamado _toppedUpAccounts e aprimorar o método deposit com uma verificação adicional:

pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract MyFioriToken is ERC20 {
    string public name;
    string public symbol;
    uint256 public decimals;
    mapping(address => bool) private _toppedUpAccounts;

    constructor(string _name, string _symbol, uint8 _decimals)
      ERC20()
      public 
    {
      name = _name;
      symbol = _symbol;
      decimals = _decimals;
    }

    function deposit() public payable returns (bool) {
      bool result = false;
      if (!_toppedUpAccounts[msg.sender]) {
        uint256 value = msg.value * 10**decimals;
        increaseAllowance(msg.sender, value);
        result = mint(msg.sender, value);
        if (result) {
          _toppedUpAccounts[msg.sender] = result;
        }
      }

      return result;
    }

    function mint(address to, uint256 amount) public returns (bool) {
      _mint(to, amount);
      return true;
    }
}
Enter fullscreen mode Exit fullscreen mode

Então agora todos os casos de teste devem ser executados com sucesso no embark test:

https://blogs.sap.com/wp-content/uploads/2019/08/2_Test_success.png

Você pode encontrar o código-fonte para este projeto aqui no meu repositório público.

Implantação

Eu recomendo que você siga o guia oficial para implantar seu contrato no Quorum via Remix.

Conclusão

Embora a funcionalidade mostrada não tenha representação gráfica de capacidade, ela pode funcionar como uma base sólida para alguns conceitos interessantes. Espero desenvolvê-la e descrevê-la ainda mais no futuro próximo.

Obrigado por ler!

Artigo publicado por Anton Efremov. Traduzido por Paulinho Giovannini.

Top comments (0)