No meu artigo anterior, eu abordei como criei um portal GIF na blockchain Solana usando um tutorial no Buildspace. Tenho passado os últimos meses, aprendendo como criar aplicativos Web3 e programar contratos inteligentes nas blockchains Ethereum e Solana. Agora, eu queria testar meus conhecimentos e criar meu próprio aplicativo Web3 que é simples o suficiente para eu fazer por conta própria, mas que ainda use todos os elementos de uma aplicação Web3.
Procurei vários casos de uso de contratos inteligentes e finalmente decidi pela criação de um aplicativo de caridade. Neste artigo, vou falar sobre como fiz isso nas últimas semanas, os desafios que enfrentei ao longo do caminho, assim como minha experiência geral e minhas conclusões.
Visão Geral
- Funcionalidade/Requisitos
- Projeto do meu aplicativo
- Contrato Inteligente/Desenvolvimento Backend
- Desenvolvimento Frontend
- Desafios
- Apresentação do Projeto
- Demonstração
- Próximos Passos
- Considerações Finais
Funcionalidade/Requisitos
Para que este aplicativo de caridade tivesse sucesso, eu queria que funcionasse da seguinte maneira:
- O usuário deve conectar sua carteira Metamask ao site antes de efetuar sua doação.
- O usuário deve ser capaz de selecionar uma instituição de caridade de sua escolha a partir da lista de instituições de caridade disponíveis.
- Para qualquer instituição de caridade selecionada, o usuário deve ser capaz de ver o endereço da instituição de caridade e o valor total doado através do site.
- O usuário deve ser capaz de doar qualquer valor de ETH que desejar, desde que tenha fundos suficientes.
- O botão para doar deve estar desativado inicialmente. O botão deve ser ativado somente se a instituição de caridade for selecionada juntamente com um valor de doação maior que zero e menor que o saldo ETH do usuário.
- Uma vez que a doação seja realizada com sucesso, o usuário deve receber uma mensagem dizendo que sua doação foi bem sucedida e mostrar que o valor doado para a instituição de caridade aumentou.
Projeto do meu aplicativo
Quando decidi como meu aplicativo deveria funcionar, pensei em como deveria projetar o backend e o frontend.
Backend
Para o backend, escolhi escrever um contrato inteligente usando a Solidity com a blockchain Ethereum. Senti que tinha mais experiência com a Solidity e a Ethereum do que com outras opções como Rust e Solana. Além disso, a Ethereum é a blockchain mais amplamente utilizada para a construção de contratos inteligentes.
Frontend
Para o desenvolvimento do frontend, decidi mantê-lo simples e usar o React e o Hardhat. Eu queria ter uma lista de instituições de caridade, e tinha algumas opções de como fazer isso. Explorei várias opções, como usar botões de opção, criar uma lista suspensa, ou permitir que o próprio usuário digite o nome da instituição de caridade. Depois de pesar os prós e contras associados a todas estas opções do ponto de vista do projeto, decidi ficar com a lista suspensa. Esta é uma lista suspensa de instituições de caridade pré-selecionadas que seriam incorporadas no meu aplicativo.
Em relação à quantia a doar, foi uma simples decisão de fazer um campo de entrada no qual o usuário poderia inserir qualquer valor que desejasse doar.
Também precisaria de um botão de "doação" que habilitasse e desabilitasse dinamicamente, com base nas entradas do usuário.
Uma vez que pensei no visual e na essência do frontend, então precisei pensar no projeto estrutural do aplicativo que estabeleceria os componentes do React que eu precisaria. Isto me permitiria entrar no desenvolvimento de forma sistemática.
Contrato Inteligente/Desenvolvimento do Backend
No backend do meu contrato inteligente eu havia analisado várias maneiras de transferir fundos para outra conta, mas segui o que eu pensava ser a maneira mais simples.
Quando um usuário chama uma função (transferFunds), ele tem que enviar fundos junto com a chamada. O valor destes fundos é determinado pelo que o usuário coloca no campo de entrada para a quantia a ser doada à instituição de caridade. Essencialmente, esta etapa em que o usuário envia fundos com a função acontece automaticamente, portanto, não precisei escrever uma linha de código no contrato inteligente para isso.
Você pode pensar nisso, como se o contrato inteligente tivesse sua própria carteira. Quando a função é executada, os fundos são enviados primeiro para o contrato inteligente, depois, a partir daí, precisamos escrever uma linha de código para enviar os fundos do contrato inteligente to.transferir(msg.value)
para o receptor, que neste caso é a instituição de caridade para a qual o usuário quis doar.
Desenvolvimento do Frontend
Achei o desenvolvimento do frontend bastante difícil, especialmente porque eu também tive que conectá-lo ao contrato inteligente ABI e ao endereço. Entretanto, usando o Remix consegui obter a ABI completa para o contrato inteligente, bem como seu endereço na testnet Rinkeby.
React
Para o frontend, decidi usar o React porque ele me ajudaria a realizar dinamicamente várias coisas que eu precisava fazer neste aplicativo. Por exemplo, ele me ajudou a programar a habilitação e desabilitação do botão doar com base nas entradas de diferentes campos, e também me ajudou a mostrar uma mensagem de sucesso quando a transação foi realizada.
Eu usei React com ganchos/componentes funcionais e não componentes de classe, porque isso proporciona uma experiência mais fácil para o desenvolvedor e faz o código parecer mais limpo. Leia mais aqui.
Desafios
Conectando a Carteira Metamask
Eu estava tendo um pouco de dificuldade para programar a lógica de verificar se uma carteira está conectada e, se não estiver, solicitar à Metamask que a conecte. Eventualmente, encontrei uma solução online sobre como fazer isso.
Aqui estou usando uma função chamada ethereum.request()
. Esta função envia um pedido para verificar as contas atuais da Ethereum conectadas ao site.
Aqui, eu verifico se a lista de contas tem algo nela, e se não tem, então eu chamo a função para conectar com a carteira Metamask. Entretanto, se houver uma lista de contas devolvidas, mas a conta atual que está em uso não for a primeira da lista, então ela muda a conta atual para a primeira da lista.
Aqui, eu uso novamente a função ethereum.request()
mas em vez de tentar chamar a lista de contas, ela tenta solicitar mais contas. Depois disso, ela verifica novamente se há uma conta na lista de contas. Se a Metamask não estiver no navegador, então ela verifica outras carteiras, mas se não houver carteiras Ethereum no navegador/extensões do navegador, um alerta será mostrado ao usuário.
Finalmente eu chamo a função checkIfWalletIsConnected()
enquanto a página é carregada.
Se um endereço Ethereum estiver conectado ao site, ele apresentará o CharityApp.
Exibindo o Saldo Atualizado do Beneficiário de Caridade
Após a realização das doações, eu queria encontrar uma maneira de atualizar o saldo da caridade sem atualizar a página. O problema era que a lógica de saber quando a transação foi realizada estava no componente DonateButton.jsx
. Então, eu precisava escrever um código que recuperasse o novo valor do saldo da Metamask e o atualizasse em Recipient.jsx
, mas o problema era que os arquivos não estavam diretamente relacionados. Ao invés disso, ambos tinham um arquivo pai de CharityApp.jsx
.
Então, eu tive que passar o novo saldo de DonateButton.jsx
para CharityApp.jsx
e para Recipient.jsx
. Eis como eu superei este problema.
Ao receber uma mensagem de transação bem sucedida, solicito o novo saldo para o endereço atual do destinatário. Então, chamo uma função que passa este saldo com props (propriedades) e envia o valor para o componente pai.
Como você pode ver, em updateRecipientBalance, estou chamando uma função no arquivo CharityApp.jsx
.
Depois, eu atualizo o estado chamado recipient
. Conservo os mesmos valores, exceto no último campo, onde passo o novo saldo do endereço.
Em seguida, eu passo este estado como props para o meu arquivo recipient.jsx
.
Finalmente, eu converto o número em base 10, porque ethereum.request({ "eth_getBalance" })
retorna um valor hexadecimal.
Habilitação/Desabilitação Automática do Botão Doação
Inicialmente, eu configurei o botão doação para ser desativado, e eu o ativaria somente se as condições abaixo fossem cumpridas.
Estas condições são:
- É escolhida uma instituição de caridade válida (o endereço não é igual a null)
- A quantia que o usuário deseja doar deve ser maior do que 0
- A quantia que o usuário quer doar deve ser menor do que o saldo do usuário
O desafio nesta seção era garantir que toda a lógica fosse colocada no lugar certo, e que todos os cenários possíveis fossem incluídos.
Apresentação do Projeto
Estrutura de pastas de alto nível
Aqui está a principal estrutura de pastas do meu projeto:
- A pasta
artifacts
contém todos os metadados, funções que podem ser chamadas e ABI do contrato inteligente. - A pasta
cache
contém uma lista de todos os contratos inteligentes de Solidity compilados para que eles possam ser facilmente acessados quando executados. - A pasta
contracts
contém todos os contratos inteligentes que são utilizados no aplicativo, que neste caso é apenas um. - A pasta
node_modules
contém todas as dependências que são necessárias para o projeto. - A pasta
public
contém um arquivo HTML que é fornecido por padrão. - A pasta
scripts
contém arquivos de script que podem ser usados para chamar funções diretamente do contrato inteligente. - A pasta
src
contém todos os arquivos fonte, que incluem os componentes React, assim como os arquivos do módulo CSS para alguns componentes. - A pasta
test
contém arquivos de teste para garantir que o contrato inteligente funcione como esperado. - O arquivo
hardhat.config.js
contém algumas declarações de linha de comando para facilitar o uso do Hardhat. - Os arquivos
package-lock.json
epackage.json
contêm detalhes de todas as dependências que estão sendo utilizadas para o projeto. No entanto, o arquivopackage-lock.json
é mais específico.
Aqui está um olhar mais detalhado sobre a pasta src
:
- A pasta
components
contém todos os componentes do React. - A pasta
styles
contém todos os arquivos do módulo CSS. - O arquivo
index.js
é de onde começa toda a produção do React. Ele, juntamente comApp.jsx
, são os únicos arquivos JSX que são apresentados por padrão no projeto.
Demonstração
Próximos Passos
Embora eu tenha completado a funcionalidade básica para a aplicativo, ainda há algumas coisas em que posso trabalhar, como por exemplo:
-
Converter usando a função Wei(): Atualmente, converto de Wei para Ether, dividindo por 10¹⁸. Isto porque eu estava tendo problemas para importar a função do módulo
Web3
. -
Prever o gas necessário para a transação: Atualmente, assumo que o gas total necessário para executar a transação é 0,0001 ETH. Em vez disso, eu gostaria de utilizar um número que leve em conta o gas exato necessário para a execução da transação, na instrução
if
que verifica todos os campos a fim de ativar o botão doar. - Mostrar o valor total doado: Atualmente, meu código procura o saldo do endereço do destinatário para mostrar o quanto foi doado. Entretanto, existe uma falha porque se a instituição de caridade decidir converter todo o ETH que foi doado a eles em dólares, então o saldo será reajustado para 0. Em vez disso, o que posso fazer é programar um mapeamento no lado do contrato inteligente que é atualizado a cada transação para mostrar o valor total real doado.
- Obter o histórico de transações para um usuário ou instituição de caridade: O que eu gostaria de fazer é permitir que o usuário veja todas as doações que fez para instituições de caridade através do meu site, e também gostaria de exibir todas as doações feitas para uma determinada instituição de caridade por todos os usuários.
- Estilo da página: Atualmente minha página utiliza o estilo básico e não é muito atraente visualmente para o usuário.
Considerações finais
Desenvolvi este aplicativo totalmente por conta própria. Isso me deu uma experiência de aprendizado significativa com o uso da Solidity para fazer um contrato inteligente, com React e Hardhat para fazer o frontend. Embora o produto final seja simples, ele me permitiu uma grande avaliação do tipo de esforço que está envolvido na construção de um aplicativo Web3 totalmente funcional. Criá-lo sozinho me deu uma enorme sensação de realização e satisfação, e me motiva a desenvolver mais com a Web3.
Se você chegou até aqui, obrigado por ler e nos vemos no próximo artigo!
Este artigo foi escrito por Sohum Padhye e traduzido por Fátima Lima. O original pode ser lido aqui.
Top comments (0)