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.
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.
Estamos todos prontos! Agora vamos ver nosso precioso projeto na Sync. Abra uma guia e navegue até http://localhost:8080.
Deve ser assim:
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')
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>
Ótimo! Agora salve os dois arquivos e atualize a guia Sync, a página da Web fictícia se parece muito com isso agora:
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
}
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
}
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
}
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.
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
}
Ó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>
Observação: você sempre pode usar ticker() em vez de setTimeout() para consultar recursivamente o saldo de sua conta. 😉
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>
Agora todo o código está pronto, certifique-se de ter salvo o mesmo:
GitHub repo de todo o código-fonte: [GitHub Link]
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:
- Insira um receptor: 0x422D582C08d7965cD5Fefef1572faaA15783f473
- Insira a quantidade: 10 VTHO
- 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:
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!
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.
Oldest comments (0)