WEB3DEV

Cover image for Como Desenvolver um DApp no VeChain (III): Componentes e Codificação
Diogo Jorge
Diogo Jorge

Posted on

Como Desenvolver um DApp no VeChain (III): Componentes e Codificação

Parabéns! Você chegou ao último episódio deste tutorial. Aqui vamos juntar tudo o que sabemos e fazer um programa útil: uma ferramenta de transferência de token VTHO. A Sync oficial fornece apenas a funcionalidade de transferência VET, nossas ferramentas VTHO são um complemento muito bom para o status quo.

Preparação

Certifique-se de ter os seguintes itens prontos:

  • Sync, configurada e em execução no seu computador.
  • Uma conta de teste, que já é apresentada na Sync.
  • Alguns VET e VTHO em sua conta de teste.
  • Sync funcionando na rede de teste.

Image description

Se você não sabe como os requisitos acima são feitos, confira o episódio anterior: https://medium.com/@laalaguer/how-to-develop-a-dapp-on-vechain-ii-setup-walk-around-109a01bf7ae9

Configuração em 3 minutos

Ótimo! Agora começamos a construir o verdadeiro DApp da página da web. Vamos configurar o projeto e as necessidades primeiro. Nós vamos usar Vue.js e BootstrapVue como nossa base.

> mkdir vtho-transfer

    > cd vtho-transfer/

    > npm install -g [@vue/cli](http://twitter.com/vue/cli) # Instale o vue-cli.


    > vue create -b -n my-project # Cria um projeto Vue limpo.

    > cd my-project # Agora você está em um espaço de trabalho Vue!

    > npm install vue bootstrap-vue bootstrap # Instalar BootstrapVue.

    > npm install bignumber.js # Biblioteca matemática.

    > npm run serve # Inicia o servidor de desenvolvimento em segundo plano.
Enter fullscreen mode Exit fullscreen mode

Estamos todos prontos! Agora vamos ver nosso precioso projeto na Sync. Abra uma guia e navegue até http://localhost:8080.

Deve ser assim:

Image description

Codificação

Devido à extensão deste tutorial, escrevemos um componente principal e demonstramos as principais funções. O restante do código e um exemplo mais complicado podem ser encontrados no final deste tutorial.

A aparência

O aplicativo deve ser estiloso! Limpe o main.js e adicione uma biblioteca BootstrapVue, é bem simples:

import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue' // Aqui
import 'bootstrap/dist/css/bootstrap.css' // Aqui
import ' bootstrap-vue/dist/bootstrap-vue.css' // Aqui
importa App de './App.vue'

Vue.use(BootstrapVue) // Aqui

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
Enter fullscreen mode Exit fullscreen mode

Coloque o componente na tela do radar editando o App.vue:

<template>
  <div id="app">
    <div>
      <b-card style= "largura máxima: 30rem;" header="Meu endereço aqui">
        <p>Meu valor aqui <span class="text-primary">VTHO</span></p>

        <b-form-group label="To Address:" label-for= "toaddress">
          <b-form-input id="toaddress" v-model.trim="toaddress"></b-form-input>
        </b-form-group>

        <b-form-group label=" Valor da transferência" label-for="toamount">
          <b-input-group append="VTHO">
            <b-form-input id="toamount" type="number" min="0" v-model.number= "toamount">
            </b-form-input>
          </b-input-group>
        </b-form-group>

        <b-button variant="primary" v-on:click="transfer">
          Transfer
        </ b-button>
      </b-card>
    </div>
  </div>
</template>

<script>
export default
 {


}
</script>
Enter fullscreen mode Exit fullscreen mode

Ótimo! Agora salve os dois arquivos e atualize a guia Sync, a página da Web fictícia se parece muito com isso agora:

Image description

Agora que temos o esqueleto, vamos prosseguir para criar as funções para tornar o aplicativo ativo. Crie um arquivo vazio separado ao lado de main.js, nomeie-o como operações.js, e coloque várias funções nele.

Consultar o saldo VTHO

Ok, vamos primeiro criar uma função que consulta o saldo VTHO do contrato VTHO na rede de teste, na verdade, ela pode ser usada para consultar qualquer contrato compatível com VIP180. Deve ser assim:

/**
 * Obtém a quantidade de token do detentor de um contrato.
 * @param {String} addressContract 0x endereço inicial.
 * @param {String} addressHolder 0x endereço inicial.
 */
função async getTokenBalance (addressContract, addressHolder) {
  const balanceOfABI = {
      'constant': true,
      'inputs': [
      {
          'name': '_owner',
          'type': 'address'
      }
      ],
      'name': ' balanceOf',
      'outputs': [
      {
          'name': 'balance',
          'type': 'uint256'
      }
      ],
      'payable': false,
      'stateMutability': 'view',
      'type': 'function'
  }
  / / eslint-disable-next-line
  const balanceOfMethod = connex.thor.account(addressContract).method(balanceOfABI)
  const balanceInfo = await balanceOfMethod.call(addressHolder)
  return balanceInfo
}
Enter fullscreen mode Exit fullscreen mode

Bastante autoexplicativa, esta função getTokenBalance consulta o contrato sobre como quanto token o usuário possui, quando o chamamos, nós o alimentamos com o endereço real do contrato e o endereço da conta do usuário. Observe que usamos a função call() de connex.js, que apresentamos no episódio anterior.

Assinar transação e enviar VTHO

Como assinar a transação e enviá-la para outra pessoa? Simples, apenas usamos a API de assinatura e envio incorporada no connex.js. Vamos criar uma função para isso também. Ainda assim, no operation.js, anexe este código:

/**
 * Transferir token de um para outro.
 * @param {String} addressContract Endereço do contrato.
 * @param {String} signerAddress Impõe quem assina a transação.
 * @param {String} toAddress Destinatário da transferência.
 * @param {String} amountEVM Número grande na string.
 * @param {Number} amountHuman Número normal em Javascript.
 * @param {String} símbolo Symbol do token.
 */
async function
 transferToken (addressContract, signerAddress, toAddress, amountEVM, amountHuman, symbol) {
    const transferABI = {
      'constant': false,
      'inputs': [
        {
          'name': '_to',
          'type': 'address'
        },
        {
          'name': '_value',
          'type': 'uint256'
        }
      ],
      'name': 'transfer',
      'outputs': [
        {
          'name': '',
          'type': 'bool'
        }
      ],
      'payable': false,
      'stateMutability': 'nonpayable',
      'type': 'function'
    }
    // eslint-disable-next-line
    const transferMethod = connex.thor.account(addressContract).method(transferABI)
    const transferClause = transferMethod.asClause(toAddress, amountEVM)
    // eslint-disable-next-line
    const signatureService = connex.vendor.sign('tx')
    signatureService
      .signer(signerAddress) // Aplica signatário
      .comment('Token transfer: ' + amountHuman.toString() + ' ' + symbol)


    let transactionInfo = await signatureService.request([
      {
        comment: 'Hello! Transfer Demo!',
        ...transferClause
      }
    ])
    return transactionInfo
  }
Enter fullscreen mode Exit fullscreen mode

O trecho acima é principalmente sobre transferToken , que é uma ação de transferência de propósito geral. Ele pega o endereço do contrato, endereço do remetente, endereço do destinatário, valor da transferência, depois pede ao connex para assinar a transação e enviar!

Agora termine o operation.js com a seção de exportação como de costume:

 export {
    getTokenBalance,
    transferToken
  }
Enter fullscreen mode Exit fullscreen mode

Formatação de números

No contrato inteligente, os decimais não existem. Todos os números são inteiros. Para apresentar os números até o decimal, aumentamos com precisão de 10 vezes. Então, quando dissermos: 123.456 em linguagem humana, deve ser apresentado em:

123.456 * (10 ^ 18) e depois enviar para a EVM. E vice-versa.
Enter fullscreen mode Exit fullscreen mode

Portanto, precisamos de alguns utilitários como corretor para nos ajudar na formatação de números. Crie um novo arquivo utils.js e coloque o seguinte conteúdo dentro dele:

const BigNumber = require('bignumber.js')
const DECIMALS = function (points) {
  return new BigNumber(10 ** points) // Decimals = 18 na VTHO e maioria dos contratos.
}

/**
 * Transforma uma string em um número grande.
 * @param {String} aString uma string numérica.
 */
const makeBN = function (aString) {
  return BigNumber(aString)
}

/**
 * Transforma um BigNumber em uma string imprimível.
 * @param {BigNumer} aBigNumber Um número grande.
 * @param {Integer} dp Uma integral de precisão, o padrão é 2.
 */
const printBN = function (aBigNumber, dp = 2) {
  return aBigNumber.toFixed(dp)
}

/**
 * Transforma um grande número EVM em humano normal com precisão compreensível.
 * @param {BigNumber} aBigNumber Um grande número EVM.
 * @param {Number} decimais Precisões que o número EVM possui. O padrão é 18.
 */
const evmToHuman = function (aBigNumber, decimals = 18) {
  return aBigNumber.dividedBy(DECIMALS(decimals))
}

/**
 * Transforma um número humano compreensível em um grande número EVM.
 * @param {String} aNumber Um float/int normal da entrada do usuário.
 * @param {Number} decimais Precisões que o número EVM possui. O padrão é 18.
 * @returns {String} Número representado por string.
 */
const humanToEVM = function (aNumber, decimals = 18) {
  const a = makeBN(aNumber)
  return a.multipliedBy(DECIMALS(decimals)).toString(10)
}

/**
 * Atalho para transformar string de número grande EVM em legível por humanos em formato curto.
 * @param {String} aString String representando o número grande da EVM.
 * @param {Number} decimais Precisões que o número EVM possui. O padrão é 18.
 * @param {BigNumber} dp pontos decimais que o resultado deve manter.
 */
const evmToPrintable = function (aString, decimals = 18, dp = 2) {
  const evmNumber = makeBN(aString)
  const humanNumber = evmToHuman(evmNumber, decimals)
  return printBN(humanNumber, dp)
}

export {
  makeBN,
  printBN,
  evmToHuman,
  humanToEVM,
  evmToPrintable
}
Enter fullscreen mode Exit fullscreen mode

Ótimo! Tudo está feito, agora juntamos as coisas e tornamos nosso aplicativo vivo!

Juntar as coisas

Hora de voltar ao App.vue para preencher a seção Javascript.

Em primeiro lugar, vamos chamar o contrato VTHO e exibir nosso saldo VTHO, aqui está o que fiz no código:

  • Correção no endereço VTHO do contrato inteligente.
  • Correção no endereço da minha conta. (Gerado a partir do episódio anterior de tutoriais)
  • Inicialização da consulta de saldo VTHO antes que o componente seja montado.
<script>
const operation = require('./operations.js')
const utils = require('./utils.js')
export default {
  data() {
    return {
      myaddress: '0xa7a609b928c4eac077d0e5640f3fa650746c4fcf',
      myamount: 0,
      contract: '0x000000000000000000000000000456e65726779'
    }
  },
  beforeMount () {
    this.refreshTokenBalance()
  },
  métodos: {
    refreshTokenBalance () {
      operações.getTokenBalance(this.contract, this.myaddress) .then
        (result => {
          this.myamount = utils.evmToPrintable (result['decoded']['balance'], this.decimals)
        })
        .then(() => {
          // eslint-disable-next-line
          const ticker = connex.thor.ticker()
          ticker.next( ).then(() => { this.refreshTokenBalance() })
        })
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode
Observação: você sempre pode usar ticker() em vez de setTimeout() para consultar recursivamente o saldo de sua conta. 😉
Enter fullscreen mode Exit fullscreen mode

Em segundo lugar, adicionamos a função de enviar transações de token VTHO ao botão, para que possamos receber alerta sempre que for bem-sucedido ou falhar.

<script>
: {
 // ... adicionar depois de refreshTokenBalance()
  transfer () { // Confirma e envia uma transferência.
    const evmAmount = utils.humanToEVM(this.toamount.toString(), 18)
    operações.transferToken(this.contract, this.myaddress, this.toaddress, evmAmount, this.toamount, 'VTHO') .then
      (result => { alert('success!')})
      .catch(e => {alert('failed!')})
  }
}
</script>

Ótimo! Agora atualize nosso modelo para vincular a esses dados:
<template>
  <div id="app">
    <div>
      <b-card style="max-width: 30rem;" :header="myaddress">
        <p>{{myamount}} <span class="text-primary">VTHO</span></p>

        <b-form-group label="To Address:" label-for ="toaddress">
          <b-form-input id="toaddress" v-model.trim="toaddress"></b-form-input>
        </b-form-group>

        <b-form-group label= "Transfer Amount" label-for="toamount">
          <b-input-group append="VTHO">
            <b-form-input id="toamount" type="number" min="0" v-model.number ="toamount">
            </b-form-input>
          </b-input-group>
        </b-form-group>

        <b-button variant="primary" v-on:click="transfer">
          Transferir
        < /b-button>
      </b-card>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Agora todo o código está pronto, certifique-se de ter salvo o mesmo:

GitHub repo de todo o código-fonte: [GitHub Link]
Enter fullscreen mode Exit fullscreen mode




Teste o aplicativo

Agora vamos ver nosso primeiro triunfo na jornada VeChain DApp!

No navegador de sincronização, visite http://localhost:8080 e faça o seguinte:

  1. Insira um receptor: 0x422D582C08d7965cD5Fefef1572faaA15783f473
  2. Insira a quantidade: 10 VTHO
  3. Clique no pequeno botão azul “Transfer”.

Então aguarde…. o tempo mágico! A sync solicita que eu desbloqueie minha conta para enviar a transação:

Image description

Claro, inseri a senha corretamente e você pode ver os detalhes da transação na rede de teste aqui

Finalmente, nosso exemplo terminou! Obrigado por trabalhar duro!

Image description

Mais uma coisa

Se você estiver interessado, este código-fonte também está disponível no GitHub abaixo:

https://github.com/laalaguer/token-transfer-demo

A transferência completa do token VeChain é mais complicada, o GitHub está abaixo:

https://github.com/laalaguer/vechain-token-transfer

Este artigo é parte 3 de 3, foi escrito por Vechain Docs e traduzido por Diogo Jorge. O artigo original pode ser encontrado aqui.

Top comments (0)