WEB3DEV

Cover image for Construa um dapp com Tezos (edição 2023) - parte 2
Adriano P. Araujo
Adriano P. Araujo

Posted on • Atualizado em

Construa um dapp com Tezos (edição 2023) - parte 2

Parte 2 de 4-> Carteira e tokens do usuário

Configurando a carteira

Agora, vamos falar sobre a carteira.

A carteira é um elemento-chave do seu dapp, sem ela, os usuários não poderão interagir com a blockchain Tezos, o que invalida seu objetivo. Há várias considerações a serem levadas em conta ao configurar a carteira que explicaremos abaixo.

Primeiro, queremos isolar a carteira e suas diferentes interações e valores no mesmo componente, chamado de  Wallet.svelte no nosso exemplo. Ao usar o SDK do Beacon, é crucial manter uma única instância do Beacon em execução para evitar erros.

Quando o componente Wallet é montado, há coisas diferentes que queremos fazer:


onMount(async () => {

    const wallet = new BeaconWallet({

      name: "Tezos dev portal dapp tutorial",

      preferredNetwork: network

    });

    store.updateWallet(wallet);

    const activeAccount = await wallet.client.getActiveAccount();

    if (activeAccount) {

      const userAddress = (await wallet.getPKH()) as TezosAccountAddress;

      store.updateUserAddress(userAddress);

      $store.Tezos.setWalletProvider(wallet);

      await getWalletInfo(wallet);

      // busca os saldos XTZ, tzBTC e SIRS do usuário

      const res = await fetchBalances($store.Tezos, userAddress);

      if (res) {

        store.updateUserBalance("XTZ", res.xtzBalance);

        store.updateUserBalance("tzBTC", res.tzbtcBalance);

        store.updateUserBalance("SIRS", res.sirsBalance);

      } else {

        store.updateUserBalance("XTZ", null);

        store.updateUserBalance("tzBTC", null);

        store.updateUserBalance("SIRS", null);

      }

    }

  });




Enter fullscreen mode Exit fullscreen mode

Criamos a instância do BeaconWallet fornecendo um nome para o dapp ( pode ser o que você quiser ), que será exibido na interface do usuário da carteira e na rede à qual você deseja se conectar ( importada da configuração arquivo ). A instância da carteira é salva no store.

Agora, você deseja verificar se o usuário conectou uma carteira antes. O Beacon acompanhará as conexões ativas no armazenamento local, e é assim que seus usuários podem navegar até o seu dapp e ter a carteira conectada automaticamente!

A instância BeaconWallet fornece uma propriedade client com métodos diferentes, o que você precisa aqui é o getActiveAccount(), que recuperará qualquer conexão ativa armazenada no armazenamento local. Se houver uma conexão ativa, você pode buscar o endereço do usuário e salvá-lo no store, atualizar o store com o endereço do usuário antes de configurar a carteira como assinante $store.Tezos.setWalletProvider(wallet), e obter  as informações necessárias sobre a carteira ( principalmente, o nome da carteira ) com a função getWalletInfo() e, em seguida, buscar os saldos para o endereço conectado com a função fetchBalances() descrita anteriormente. Depois que os saldos são buscados, eles são salvos no store para serem exibidos na interface.

_Nota: TezosAccountAddress é um tipo personalizado que eu gosto de usar para validar endereços Tezos para contas implícitas: type TezosAccountAddress = tz${"1" | "2" | "3"}${string}, o TypeScript levantará um alerta se você tentar usar uma sequência que não corresponda a esse padrão.

Conectando a carteira

O Taquito e o Beacon trabalhando em uníssono tornam muito fácil conectar a carteira. Algumas linhas de código usando as APIs dessas duas bibliotecas essenciais na Tezos farão milagres.

Aqui está como fazê-lo:


const connectWallet = async () => {

  if (!$store.wallet) {

    const wallet = new BeaconWallet({

      name: "Tezos dev portal dapp tutorial",

      preferredNetwork: network

    });

    store.updateWallet(wallet);

  }

  await $store.wallet.requestPermissions({

    network: { type: network, rpcUrl }

  });

  const userAddress = (await $store.wallet.getPKH()) as TezosAccountAddress;

  store.updateUserAddress(userAddress);

  $store.Tezos.setWalletProvider($store.wallet);

 // encontra informações da conta

  await getWalletInfo($store.wallet);

   // busca os saldos XTZ, tzBTC e SIRS do usuário

  const res = await fetchBalances($store.Tezos, userAddress);

  if (res) {

    store.updateUserBalance("XTZ", res.xtzBalance);

    store.updateUserBalance("tzBTC", res.tzbtcBalance);

    store.updateUserBalance("SIRS", res.sirsBalance);

  } else {

    store.updateUserBalance("XTZ", null);

    store.updateUserBalance("tzBTC", null);

    store.updateUserBalance("SIRS", null);

  }

};

Enter fullscreen mode Exit fullscreen mode

A conexão será tratada em uma função específica chamada connectWallet. Se o store não possui uma instância do BeaconWallet ( se o dapp não detectou nenhuma conexão ativa na montagem), você cria essa instância e a salva no store.

Em seguida, você solicita ao usuário que ele selecione uma carteira com o método requestPermissions() presente na instância do BeaconWallet. O parâmetro é um objeto em que você indica a rede à qual deseja se conectar, bem como o URL do nó RPC Tezos com o qual você irá interagir.

Depois que o usuário seleciona uma carteira para usar com o nosso dapp, você obtém o endereço com o método getPKH() na instância BeaconWallet, você atualiza o assinante na instância TezosToolkit passando a instância da carteira para setWalletProvider(), assim você obtém as informações necessárias da carteira e busca os saldos do usuário.

Agora, a carteira está conectada e o usuário recebe seus diferentes saldos, bem como um status de conexão na barra lateral!

IMPORTANTE: No entanto, como você deseja projetar seu dapp, é essencial manter apenas uma única instância do BeaconWallet e é altamente recomendado fazer o mesmo com a instância do TezosToolkit. Criar várias instâncias interfere no estado do seu aplicativo e no Taquito em geral.

Desconectando a carteira

Desconectar a carteira é tão importante quanto conectá-la. Não há nada mais frustrante do que passar horas procurando como desconectar a carteira quando isso não é feito de forma explícita. Lembre-se de que muitos usuários possuem várias carteiras (como Temple ou Kukai) e até mesmo múltiplos endereços dentro da mesma carteira que desejam usar para interagir com o seu dapp. Facilite para eles a desconexão da carteira.


const disconnectWallet = async () => {

  $store.wallet.client.clearActiveAccount();

  store.updateWallet(undefined);

  store.updateUserAddress(undefined);

  connectedNetwork = "";

  walletIcon = "";

};

Enter fullscreen mode Exit fullscreen mode

Existem diferentes etapas para desconectar a carteira e redefinir o estado do dapp:

  • $store.wallet.client.clearActiveAccount()- > mata a conexão atual com Beacon

  • store.updateWallet(undefined)- > remove a carteira do estado para acionar uma recarga da interface

  • store.updateUserAddress(undefined)- > remove o endereço do usuário atual do estado para atualizar a interface do usuário

  • connectedNetwork = ""; walletIcon = ""- > também é necessário para redefinir o estado do dapp e apresentar uma interface na qual nenhuma carteira está conectada

A chamada para a clearActiveAccount() na instância da carteira é a única coisa que você fará em qualquer dapp que estiver construindo, ele removerá todos os dados no armazenamento local e, quando o usuário revisitar o seu dapp, eles não serão conectados automaticamente à carteira.

Considerações de design

Escrever código para interagir com uma carteira em um aplicativo descentralizado é um paradigma muito novo e, embora você possa reutilizar muitos conceitos e boas práticas de sua experiência como desenvolvedor, também há algumas coisas novas a serem lembradas:

  1. Nunca solicite aos usuários que conectem sua carteira depois que o dapp estiver carregado: Ter uma janela de pop-up de carteira na tela logo após o aplicativo ser carregado é irritante. Você deve lembrar que muitos de seus usuários não são técnicos e não entendem que conectar uma carteira é inofensivo, então eles podem ficar desconfiados em relação ao seu dapp se você pedir que conectem sua carteira.

  2. O botão para conectar uma carteira deve se destacar na sua interface, seja pelo tamanho,pela cor diferente ou pela fonte diferente, os usuários não devem gastar mais de alguns segundos para encontrá-lo.

  3. O botão deve estar em uma posição previsível: A maioria dos dapps na Tezos coloca o botão para conectar uma carteira na parte superior esquerda ou superior direita da interface do usuário. Você não é “ criativo ” colocando o botão em outro local, você acabará confundindo seus usuários.

  4. O texto no botão deve ser "Conectar" ou algo semelhante, evite "Sincronizar" ou outras palavras que não sejam "conectar", pois elas podem ter um significado diferente no contexto de um aplicativo descentralizado.

  5. O status da carteira deve ser exibido no dapp. Seja conectado ou desconectado, o usuário deve saber. Além disso, você pode adicionar algumas informações sobre a carteira à qual eles estão usando ( como fazemos neste tutorial ), a rede à qual estão conectados ou seu saldo.

  6. Você deve ativar / desativar as interações do seu dapp que dependem da carteira. Os usuários não devem poder interagir com um recurso do seu aplicativo que exige que a carteira seja conectada, se esse não for o caso.

Buscando saldos do usuário

Uma das características mais importantes do dapp, que também está entre as mais fáceis de ignorar, é buscar os saldos do usuário. Os usuários podem dizer que algo está errado se seus saldos não aparecerem corretamente ou não forem atualizados de acordo após uma interação com o contrato, é por isso que é crucial exibir e atualizar seus saldos.

Como você buscará saldos em diferentes componentes do nosso aplicativo, criará uma função no arquivo utils.ts e importará quando necessário.

Para buscar os saldos, você usará o Taquito para o saldo XTZ do usuário e uma API muito popular nos saldos tezBTC e SIRS, a API TzKT. Se você deseja criar aplicativos mais complexos na Tezos, um bom conhecimento da API TzKT é essencial, pois ela fornece muitos recursos que tornarão seus aplicativos mais ricos em conteúdo, e mais rápidos.

Vamos dar uma olhada no tipo de função:


export const fetchBalances = async (

  Tezos: TezosToolkit,

  userAddress: TezosAccountAddress

): Promise<{

  xtzBalance: number;

  tzbtcBalance: number;

  sirsBalance: number;

} | null> => {

  try {

    // o código estará aqui

  } catch (error) {

    console.error(error);

    return null;

  }

}

Enter fullscreen mode Exit fullscreen mode

A função fetchBalances terá 2 parâmetros: uma instância do TezosToolkit  para buscar o saldo XTZ do usuário e o endereço do usuário para recuperar os saldos que correspondem ao endereço. Isso retornará um objeto com 3 propriedades: xtzBalance, tzbtcBalance, e sirsBalance, ou null se ocorrer algum erro.

Primeiro, vamos buscar o saldo do XTZ:


const xtzBalance = await Tezos.tz.getBalance(userAddress);

if (!xtzBalance) throw "Unable to fetch XTZ balance";

Enter fullscreen mode Exit fullscreen mode

A instância do TezosToolkit inclui uma propriedade chamada tz que permite diferentes ações específicas da Tezos, uma delas é buscar o saldo de uma conta por meio do endereço do método getBalance() que obtém o endereço da conta como parâmetro.

Em seguida, você verifica a existência de um saldo e rejeita a promise se ele não existir. Se existir, o saldo estará disponível como um BigNumber.

Nota: como é o caso na maioria das vezes, o Taquito retorna valores numéricos da blockchain como BigNumber, porque alguns valores podem ser números muito grandes e o JavaScript é notório por ser ruim em lidar com grandes números

Depois que o saldo do XTZ for buscado, você poderá continuar e buscar os saldos do tzBTC e SIRS:


import { tzbtcAddress, sirsAddress } from "./config";



// código anterior para a função

const res = await fetch(

  `https://api.tzkt.io/v1/tokens/balances?account=${userAddress}&token.contract.in=${tzbtcAddress},${sirsAddress}`

);

if (res.status === 200) {

  const data = await res.json();

  if (Array.isArray(data) && data.length === 2) {

    const tzbtcBalance = +data[0].balance;

    const sirsBalance = +data[1].balance;

    if (!isNaN(tzbtcBalance) && !isNaN(sirsBalance)) {

      return {

        xtzBalance: xtzBalance.toNumber(),

        tzbtcBalance,

        sirsBalance

      };

    } else {

      return null;

    }

  }

} else {

  throw "Unable to fetch tzBTC and SIRS balances";

}



Enter fullscreen mode Exit fullscreen mode

Você pode verificar este link para obter mais detalhes sobre como buscar saldos de tokens com a API TzKT. É um simples fetch com um URL criado dinamicamente para incluir o endereço do usuário e os endereços dos contratos para tzBTC e SIRS.

Quando a promise for resolvida com um código 200, isso significa que os dados foram recebidos. Você analisa o JSON com o método .json() na resposta e verificamos se os dados têm a forma esperada, ou seja, uma matriz com 2 elementos.

O primeiro elemento é o saldo tzBTC e o segundo é o saldo do SIRS. Você os armazena em suas próprias variáveis que você atribui aos números antes de verificar se eles foram lançados corretamente com o isNaN. Se tudo correr bem, os 3 saldos serão retornados e, se algo der errado ao longo do caminho, a função retornará null.

Depois de buscar os saldos em qualquer componente do nosso aplicativo, você armazena esses dados no store para atualizar o estado:


const res = await fetchBalances($store.Tezos, userAddress);

if (res) {

  store.updateUserBalance("XTZ", res.xtzBalance);

  store.updateUserBalance("tzBTC", res.tzbtcBalance);

  store.updateUserBalance("SIRS", res.sirsBalance);

} else {

  store.updateUserBalance("XTZ", null);

  store.updateUserBalance("tzBTC", null);

  store.updateUserBalance("SIRS", null);

}

Enter fullscreen mode Exit fullscreen mode

E é isso, você buscou os saldos do usuário em XTZ, tzBTC e SIRS!

Na terceira parte, trocando tokens = >


Este artigo foi escrito por  Claude Barde e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.

Top comments (0)