Contrato inteligente "Hello World" para iniciantes - Fullstack
Este guia é para você que é iniciante em desenvolvimento de blockchain e não sabe por onde começar ou como implantar e interagir com contratos inteligentes. Vamos percorrer a criação e implantação de um contrato inteligente simples na rede de teste Goerli usando MetaMask (opens in a new tab), Solidity (opens in a new tab), Hardhat (opens in a new tab) e Alchemy (opens in a new tab).
Você precisará de uma conta Alchemy para concluir este tutorial. Cadastre-se para obter uma conta gratuita (opens in a new tab).
Se você tiver dúvidas a qualquer momento, sinta-se à vontade para entrar em contato no Discord da Alchemy (opens in a new tab)!
Parte 1 - Criar e implantar seu contrato inteligente usando Hardhat
Conectar à rede Ethereum
Existem muitas maneiras de fazer solicitações para a cadeia Ethereum. Para simplificar, usaremos uma conta gratuita na Alchemy, uma plataforma de desenvolvedores de blockchain e API que nos permite comunicar com a cadeia Ethereum sem termos que executar nosso próprio nó. A Alchemy também possui ferramentas de desenvolvedor para monitoração e análise. Neste tutorial, vamos aproveitá-las para entender o que está acontecendo nos bastidores da implantação do nosso contrato inteligente.
Crie seu aplicativo e sua chave de API
Assim que criar uma conta na Alchemy, você poderá gerar uma chave de API criando um aplicativo. Isso permitirá que você faça solicitações à rede de teste Goerli. Se você não está familiarizado com redes de teste, pode ler o guia da Alchemy para escolher uma rede (opens in a new tab).
No painel da Alchemy, encontre o menu suspenso Apps na barra de navegação e clique em Criar App.
Dê ao seu aplicativo o nome 'Hello World' e escreva uma breve descrição. Selecione Staging como seu ambiente e Goerli como sua rede.
Observação: certifique-se de selecionar Goerli, ou este tutorial não funcionará.
Clique em Create app. Seu aplicativo aparecerá na tabela abaixo.
Crie uma conta Ethereum
Você precisa de uma conta Ethereum para enviar e receber transações. Usaremos o MetaMask, uma carteira virtual no navegador que permite aos usuários gerenciar o endereço de sua conta Ethereum.
Você pode baixar e criar uma conta MetaMask gratuitamente aqui (opens in a new tab). Quando você estiver criando uma conta, ou se já tiver uma, certifique-se de mudar para a “Rede de Teste Goerli” no canto superior direito (para não lidarmos com dinheiro real).
Etapa 4: Adicione ether de um Faucet
Para implantar nosso contrato inteligente na rede de teste, precisaremos de um pouco de ETH falso. Para obter ETH na rede Goerli, vá a um faucet da Goerli e insira o endereço de sua conta Goerli. Observe que as faucets da Goerli podem ser um pouco instáveis recentemente - consulte a página de redes de teste para uma lista de opções para tentar:
Observação: devido ao congestionamento da rede, isso pode demorar um pouco. ``
Passo 5: Verifique seu saldo
Para verificar se o ETH está em sua carteira, vamos fazer uma solicitação eth_getBalance (opens in a new tab) usando a ferramenta de composição da Alchemy (opens in a new tab). Ele mostrará a quantidade de ETH em nossa carteira. Para saber mais, confira o breve tutorial da Alchemy sobre como usar a ferramenta de composição (opens in a new tab).
Insira o endereço da sua conta MetaMask e clique em Send Request. Você verá uma resposta que se parece com o trecho de código abaixo.
1{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" }Observação: Este resultado está em wei, não em ETH. Wei é usado como a menor denominação de ether.
Ufa! O nosso dinheiro falso está todo lá.
Passo 6: Inicialize nosso projeto
Primeiro, precisaremos criar uma pasta para o nosso projeto. Navegue para a sua linha de comando e insira o seguinte.
1mkdir hello-world2cd hello-worldAgora que estamos dentro da pasta do nosso projeto, usaremos o npm init para inicializar o projeto.
Se você ainda não tiver o npm instalado, siga estas instruções para instalar o Node.js e o npm (opens in a new tab).
Para a finalidade deste tutorial, não importa como você responde às perguntas de inicialização. Veja como fizemos isso para referência:
1nome do pacote: (hello-world)2versão: (1.0.0)3descrição: contrato inteligente hello world4ponto de entrada: (index.js)5comando de teste:6repositório git:7palavras-chave:8autor:9licença: (ISC)1011Prestes a escrever para /Users/.../.../.../hello-world/package.json:1213{14 "name": "hello-world",15 "version": "1.0.0",16 "description": "contrato inteligente hello world",17 "main": "index.js",18 "scripts": {19 "test": "echo \"Error: no test specified\" && exit 1"20 },21 "author": "",22 "license": "ISC"23}Exibir tudoAprove o package.json e estamos prontos!
Passo 7: Baixe o Hardhat
Hardhat é um ambiente de desenvolvimento para compilar, implementar, testar e depurar seu software de Ethereum. Ele ajuda os desenvolvedores na criação de contratos inteligentes e dapps localmente antes de implantar na cadeia real.
Dentro do nosso projeto hello-world, execute:
1npm install --save-dev hardhatConfira esta página para mais detalhes sobre as instruções de instalação (opens in a new tab).
Passo 8: Crie um projeto Hardhat
Dentro da pasta do nosso projeto hello-world, execute:
1npx hardhatVocê deve então ver uma mensagem de boas-vindas e a opção de selecionar o que quer fazer. Selecione "criar uma hardhat.config.js vazia":
1888 888 888 888 8882888 888 888 888 8883888 888 888 888 88848888888888 8888b. 888d888 .d88888 88888b. 8888b. 8888885888 888 "88b 888P" d88" 888 888 "88b "88b 8886888 888 .d888888 888 888 888 888 888 .d888888 8887888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.8888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888910👷 Bem-vindo ao Hardhat v2.0.11 👷1112O que você quer fazer? …13Crie um projeto de exemplo14❯ Crie um arquivo hardhat.config.js vazio15SairExibir tudoIsso gerará um arquivo hardhat.config.js no projeto. Usaremos isso mais tarde no tutorial para especificar a configuração do nosso projeto.
Passo 9: Adicione pastas de projeto
Para manter o projeto organizado, vamos criar duas novas pastas. Na linha de comando, navegue para o diretório raiz do seu projeto hello-world e digite:
1mkdir contracts2mkdir scriptscontracts/é onde manteremos nosso arquivo de código do contrato inteligente hello worldscripts/é onde manteremos os scripts para implantar e interagir com nosso contrato
Passo 10: Escreva nosso contrato
Você pode estar se perguntando: quando vamos escrever código? Está na hora!
Abra o projeto hello-world no seu editor favorito. Contratos inteligentes são mais comumente escritos em Solidity, que usaremos para escrever nosso contrato inteligente.
- Navegue para a pasta
contractse crie um novo arquivo chamadoHelloWorld.sol - Abaixo está um exemplo de contrato inteligente "Hello World" que usaremos neste tutorial. Copie o conteúdo abaixo no arquivo
HelloWorld.sol.
Observação: certifique-se de ler os comentários para entender o que este contrato faz.
1// Especifica a versão do Solidity, usando versionamento semântico.2// Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity >=0.7.3;45// Define um contrato chamado `HelloWorld`.6// Um contrato é uma coleção de funções e dados (seu estado). Depois de implantado, um contrato reside em um endereço específico na blockchain Ethereum. Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html7contract HelloWorld {89 //Emitido quando a função de atualização é chamada10 //Os eventos de contratos inteligentes são uma forma de o seu contrato comunicar que algo aconteceu na blockchain para o front-end do seu aplicativo, que pode estar 'ouvindo' certos eventos e agir quando eles acontecem.11 event UpdatedMessages(string oldStr, string newStr);1213 // Declara uma variável de estado `message` do tipo `string`.14 // As variáveis de estado são variáveis cujos valores são permanentemente armazenados no armazenamento do contrato. A palavra-chave `public` torna as variáveis acessíveis de fora de um contrato e cria uma função que outros contratos ou clientes podem chamar para acessar o valor.15 string public message;1617 // Semelhante a muitas linguagens orientadas a objetos baseadas em classes, um construtor é uma função especial que só é executada na criação do contrato.18 // Os construtores são usados para inicializar os dados do contrato. Saiba mais:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors19 constructor(string memory initMessage) {2021 // Aceita um argumento de string `initMessage` e define o valor na variável de armazenamento `message` do contrato.22 message = initMessage;23 }2425 // Uma função pública que aceita um argumento de string e atualiza a variável de armazenamento `message`.26 function update(string memory newMessage) public {27 string memory oldMsg = message;28 message = newMessage;29 emit UpdatedMessages(oldMsg, newMessage);30 }31}Exibir tudoEste é um contrato inteligente básico que armazena uma mensagem quando da sua criação. Ele pode ser atualizado chamando a função update.
Passo 11: Conecte o MetaMask e o Alchemy ao seu projeto
Nós criamos uma carteira MetaMask, uma conta da Alchemy e escrevemos nosso contrato inteligente. Agora é hora de conectar os três.
Toda transação enviada da sua carteira requer uma assinatura usando sua chave privada única. Para fornecer essa permissão ao nosso programa, podemos armazenar nossa chave privada com segurança em um arquivo de ambiente. Também armazenaremos uma chave de API para o Alchemy aqui.
Para saber mais sobre o envio de transações, confira este tutorial (opens in a new tab) sobre como enviar transações usando web3.
Primeiro, instale o pacote dotenv na pasta do seu projeto:
1npm install dotenv --saveEm seguida, crie um arquivo .env no diretório raiz do projeto. Adicione sua chave privada do MetaMask e o URL da API HTTP da Alchemy a ele.
Seu arquivo de ambiente deve ser nomeado .env, caso contrário, não será reconhecido como um arquivo de ambiente.
Não o nomeie como process.env ou .env-custom ou qualquer outra coisa.
- Siga estas instruções (opens in a new tab) para exportar sua chave privada
- Veja abaixo para obter o URL da API HTTP da Alchemy
Seu .env deve ficar assim:
1API_URL = "https://eth-goerli.alchemyapi.io/v2/sua-chave-de-api"2PRIVATE_KEY = "sua-chave-privada-metamask"Para realmente conectar isso ao nosso código, faremos referência a essas variáveis em nosso arquivo hardhat.config.js na etapa 13.
Etapa 12: Instalar o Ethers.js
Ethers.js é uma biblioteca que facilita a interação e o envio de solicitações ao Ethereum ao incorporar métodos padrões JSON-RPC a outros métodos mais amigáveis ao usuário.
O Hardhat nos permite integrar plugins (opens in a new tab) para ferramentas adicionais e funcionalidades estendidas. Aproveitaremos o plugin Ethers (opens in a new tab) para a implantação do contrato.
No diretório do seu projeto, digite:
npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0"Passo 13: Atualize o hardhat.config.js
Adicionamos várias dependências e plugins até agora. Agora precisamos atualizar o hardhat.config.js para que nosso projeto saiba sobre todos eles.
Atualize seu hardhat.config.js para ficar assim:
1/**2 * @type import('hardhat/config').HardhatUserConfig3 */45require("dotenv").config()6require("@nomiclabs/hardhat-ethers")78const { API_URL, PRIVATE_KEY } = process.env910module.exports = {11 solidity: "0.7.3",12 defaultNetwork: "goerli",13 networks: {14 hardhat: {},15 goerli: {16 url: API_URL,17 accounts: [`0x${PRIVATE_KEY}`],18 },19 },20}Exibir tudoPasso 14: Compile nosso contrato
Para ter certeza de que tudo está funcionando, vamos compilar nosso contrato. A tarefa compile é uma das tarefas incorporadas do hardhat.
Na linha de comando, execute:
npx hardhat compileVocê pode receber um aviso sobre identificador de licença SPDX não fornecido no arquivo de origem, mas não precisa se preocupar com isso — esperamos que todo o resto esteja bem! Se não, você sempre pode enviar uma mensagem no Discord da Alchemy (opens in a new tab).
Passo 15: Escreva nosso script de implantação
Agora que nosso contrato está escrito e nosso arquivo de configuração está pronto, é hora de escrever o script de implantação do contrato.
Navegue até a pasta scripts/ e crie um novo arquivo chamado deploy.js, adicionando o seguinte conteúdo a ele:
1async function main() {2 const HelloWorld = await ethers.getContractFactory("HelloWorld")34 // Iniciar a implantação, retornando uma promessa que resolve para um objeto de contrato5 const hello_world = await HelloWorld.deploy("Hello World!")6 console.log("Contrato implantado no endereço:", hello_world.address)7}89main()10 .then(() => process.exit(0))11 .catch((error) => {12 console.error(error)13 process.exit(1)14 })Exibir tudoA Hardhat faz um trabalho incrível explicando o que cada uma dessas linhas de código faz em seu tutorial de Contratos (opens in a new tab), nós adotamos as explicações deles aqui.
1const HelloWorld = await ethers.getContractFactory("HelloWorld")Uma ContractFactory no ethers.js é uma abstração usada para implantar novos contratos inteligentes, então, HelloWorld aqui é uma fábrica (opens in a new tab) para instâncias do nosso contrato "olá, mundo". Ao usar o plugin hardhat-ethers ContractFactory e Contract, as instâncias são conectadas ao primeiro signatário (proprietário) por padrão.
1const hello_world = await HelloWorld.deploy()Chamar deploy() em uma ContractFactory iniciará a implantação e retornará uma Promise que resolve para um objeto Contract. Este é o objeto que tem um método para cada uma de nossas funções de contrato inteligente.
Etapa 16: Implantar nosso contrato
Finalmente estamos prontos para implantar o nosso contrato inteligente! Navegue até a linha de comando e execute:
npx hardhat run scripts/deploy.js --network goerliVocê deverá ver algo assim:
Contrato implantado no endereço: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570Por favor, salve este endereço. Nós o usaremos mais tarde neste tutorial.
Se formos ao etherscan da Goerli (opens in a new tab) e procurarmos o endereço do nosso contrato, devemos conseguir ver que ele foi implantado com sucesso. A transação ficará parecida com isto:
O endereço From deve corresponder ao endereço da sua conta MetaMask e o endereço To dirá Criação de Contrato. Se clicarmos na transação, veremos o nosso endereço de contrato no campo To.
Parabéns! Você acaba de implantar um contrato inteligente em uma rede de teste Ethereum.
Para entender o que está acontecendo nos bastidores, vamos navegar até a guia Explorer no nosso painel da Alchemy (opens in a new tab). Se você tem vários aplicativos Alchemy, certifique-se de filtrar por aplicativo e selecionar Hello World.
Aqui você verá alguns métodos JSON-RPC que Hardhat/Ethers fizeram nos bastidores para nós quando chamamos a função .deploy(). Dois métodos importantes aqui são eth_sendRawTransaction (opens in a new tab), que é a solicitação para escrever nosso contrato na cadeia Goerli, e eth_getTransactionByHash (opens in a new tab), que é uma solicitação para ler informações sobre nossa transação a partir do hash. Para saber mais sobre como enviar transações, confira nosso tutorial sobre como enviar transações usando Web3.
Parte 2: Interaja com seu contrato inteligente
Agora que implantamos com sucesso um contrato inteligente na rede Goerli, vamos aprender como interagir com ele.
Crie um arquivo interact.js
Este é o arquivo onde escreveremos nosso script de interação. Usaremos a biblioteca Ethers.js que você instalou anteriormente na Parte 1.
Dentro da pasta scripts/, crie um novo arquivo chamado interact.js e adicione o seguinte código:
1// interact.js23const API_KEY = process.env.API_KEY4const PRIVATE_KEY = process.env.PRIVATE_KEY5const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESSAtualize seu arquivo .env
Usaremos novas variáveis de ambiente, então precisamos defini-las no arquivo .env que criamos anteriormente.
Precisaremos adicionar uma definição para a nossa API_KEY da Alchemy e o CONTRACT_ADDRESS onde nosso contrato inteligente foi implantado.
Seu arquivo .env deve ter a seguinte aparência:
# .envAPI_URL = "https://eth-goerli.alchemyapi.io/v2/<sua-chave-de-api>"API_KEY = "<sua-chave-de-api>"PRIVATE_KEY = "<sua-chave-privada-metamask>"CONTRACT_ADDRESS = "0x<seu endereço de contrato>"Obtenha a ABI do seu contrato
A do nosso contrato é a interface para interagir com nosso contrato inteligente. O Hardhat gera automaticamente uma ABI e a salva em HelloWorld.json. Para usar a ABI, precisaremos analisar o conteúdo adicionando as seguintes linhas de código ao nosso arquivo interact.js:
1// interact.js2const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json")Se quiser ver a ABI, você pode imprimi-la no seu console:
1console.log(JSON.stringify(contract.abi))Para ver sua ABI impressa no console, navegue até seu terminal e execute:
npx hardhat run scripts/interact.jsCrie uma instância do seu contrato
Para interagir com nosso contrato, precisamos criar uma instância dele em nosso código. Para fazer isso com Ethers.js, precisaremos trabalhar com três conceitos:
- Provedor - um provedor de nós que lhe dá acesso de leitura e escrita ao blockchain
- Signatário - representa uma conta Ethereum que pode assinar transações
- Contrato - um objeto Ethers.js representando um contrato específico implantado on-chain
Usaremos a ABI do contrato da etapa anterior para criar nossa instância do contrato:
1// interact.js23// Provedor4const alchemyProvider = new ethers.providers.AlchemyProvider(5 (network = "goerli"),6 API_KEY7)89// Signatário10const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider)1112// Contrato13const helloWorldContract = new ethers.Contract(14 CONTRACT_ADDRESS,15 contract.abi,16 signer17)Exibir tudoSaiba mais sobre Provedores, Signatários e Contratos na documentação do ethers.js (opens in a new tab).
Leia a mensagem inicial
Lembra-se quando implantamos nosso contrato com a initMessage = "Hello world!"? Agora vamos ler essa mensagem armazenada em nosso contrato inteligente e imprimi-la no console.
Em JavaScript, funções assíncronas são usadas ao interagir com redes. Para saber mais sobre funções assíncronas, leia este artigo do Medium (opens in a new tab).
Use o código abaixo para chamar a função message em nosso contrato inteligente e ler a mensagem inicial:
1// interact.js23// ...45async function main() {6 const message = await helloWorldContract.message()7 console.log("A mensagem é: " + message)8}9main()Exibir tudoDepois de executar o arquivo usando npx hardhat run scripts/interact.js no terminal, devemos ver esta resposta:
1A mensagem é: Hello world!Parabéns! Você leu com sucesso os dados do contrato inteligente da blockchain Ethereum, parabéns!
Atualize a mensagem
Em vez de apenas ler a mensagem, também podemos atualizar a mensagem salva em nosso contrato inteligente usando a função update! Muito legal, não é?
Para atualizar a mensagem, podemos chamar diretamente a função update em nosso objeto de Contrato instanciado:
1// interact.js23// ...45async function main() {6 const message = await helloWorldContract.message()7 console.log("A mensagem é: " + message)89 console.log("Atualizando a mensagem...")10 const tx = await helloWorldContract.update("Esta é a nova mensagem.")11 await tx.wait()12}13main()Exibir tudoNote que na linha 11, fazemos uma chamada para .wait() no objeto da transação retornada. Isso garante que nosso script espere a transação ser minerada na blockchain antes de sair da função. Se a chamada .wait() não for incluída, o script pode não ver o valor da message atualizada no contrato.
Leia a nova mensagem
Você deve ser capaz de repetir o passo anterior para ler o valor atualizado da message. Tire um momento para ver se você consegue fazer as alterações necessárias para imprimir esse novo valor!
Se precisar de uma dica, veja como seu arquivo interact.js deve se parecer neste ponto:
1// interact.js23const API_KEY = process.env.API_KEY4const PRIVATE_KEY = process.env.PRIVATE_KEY5const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS67const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json")89// provedor - Alchemy10const alchemyProvider = new ethers.providers.AlchemyProvider(11 (network = "goerli"),12 API_KEY13)1415// signatário - você16const signer = new ethers.Wallet(PRIVATE_KEY, alchemyProvider)1718// instância do contrato19const helloWorldContract = new ethers.Contract(20 CONTRACT_ADDRESS,21 contract.abi,22 signer23)2425async function main() {26 const message = await helloWorldContract.message()27 console.log("A mensagem é: " + message)2829 console.log("Atualizando a mensagem...")30 const tx = await helloWorldContract.update("esta é a nova mensagem")31 await tx.wait()3233 const newMessage = await helloWorldContract.message()34 console.log("A nova mensagem é: " + newMessage)35}3637main()Exibir tudoAgora, apenas execute o script e você deverá ver a mensagem antiga, o status de atualização e a nova mensagem impressa em seu terminal!
npx hardhat run scripts/interact.js --network goerli
1A mensagem é: Hello World!2Atualizando a mensagem...3A nova mensagem é: Esta é a nova mensagem.Ao executar esse script, você pode perceber que a etapa Atualizando a mensagem... leva um tempo para carregar antes que a nova mensagem seja carregada. Isso se deve ao processo de mineração; se você tiver curiosidade em rastrear transações enquanto elas estão sendo mineradas, visite o mempool da Alchemy (opens in a new tab) para ver o status de uma transação. Se a transação for descartada, também é útil verificar o Goerli Etherscan (opens in a new tab) e pesquisar pelo hash da sua transação.
Parte 3: Publique seu contrato inteligente no Etherscan
Você fez todo o trabalho duro de dar vida ao seu contrato inteligente; agora é hora de compartilhá-lo com o mundo!
Ao verificar seu contrato inteligente no Etherscan, qualquer pessoa pode visualizar seu código-fonte e interagir com seu contrato inteligente. Vamos começar!
Passo 1: Gere uma chave de API na sua conta Etherscan
Uma chave de API do Etherscan é necessária para verificar que você é o proprietário do contrato inteligente que está tentando publicar.
Se você ainda não tem uma conta no Etherscan, cadastre-se para obter uma (opens in a new tab).
Depois de fazer o login, encontre seu nome de usuário na barra de navegação, passe o mouse sobre ele e selecione o botão My profile.
Na página do seu perfil, você deverá ver uma barra de navegação lateral. Na barra de navegação lateral, selecione API Keys. Em seguida, pressione o botão "Add" para criar uma nova chave de API, nomeie seu aplicativo hello-world e pressione o botão Create New API Key.
Sua nova chave de API deve aparecer na tabela de chaves de API. Copie a chave de API para sua área de transferência.
Em seguida, precisamos adicionar a chave de API do Etherscan ao nosso arquivo .env.
Depois de adicioná-la, seu arquivo .env deve ter a seguinte aparência:
1API_URL = "https://eth-goerli.alchemyapi.io/v2/sua-chave-de-api"2PUBLIC_KEY = "seu-endereco-de-conta-publica"3PRIVATE_KEY = "seu-endereco-de-conta-privada"4CONTRACT_ADDRESS = "seu-endereco-de-contrato"5ETHERSCAN_API_KEY = "sua-chave-etherscan"Contratos inteligentes implantados com Hardhat
Instale o hardhat-etherscan
Publicar seu contrato no Etherscan usando o Hardhat é simples. Você precisará primeiro instalar o plugin hardhat-etherscan para começar. hardhat-etherscan verificará automaticamente o código-fonte do contrato inteligente e a ABI no Etherscan. Para adicionar isso, no diretório hello-world, execute:
1npm install --save-dev @nomiclabs/hardhat-etherscanUma vez instalado, inclua a seguinte declaração no topo do seu hardhat.config.js e adicione as opções de configuração do Etherscan:
1// hardhat.config.js23require("dotenv").config()4require("@nomiclabs/hardhat-ethers")5require("@nomiclabs/hardhat-etherscan")67const { API_URL, PRIVATE_KEY, ETHERSCAN_API_KEY } = process.env89module.exports = {10 solidity: "0.7.3",11 defaultNetwork: "goerli",12 networks: {13 hardhat: {},14 goerli: {15 url: API_URL,16 accounts: [`0x${PRIVATE_KEY}`],17 },18 },19 etherscan: {20 // Sua chave de API para o Etherscan21 // Obtenha uma em https://etherscan.io/22 apiKey: ETHERSCAN_API_KEY,23 },24}Exibir tudoVerifique seu contrato inteligente no Etherscan
Certifique-se de que todos os arquivos estão salvos e todas as variáveis .env estão configuradas corretamente.
Execute a tarefa verify, passando o endereço do contrato e a rede onde ele está implantado:
1npx hardhat verify --network goerli ENDERECO_DO_CONTRATO_IMPLANTADO 'Hello World!'Certifique-se de que DEPLOYED_CONTRACT_ADDRESS é o endereço do seu contrato inteligente implantado na rede de teste Goerli. Além disso, o argumento final ('Hello World!') deve ser o mesmo valor de string usado durante a etapa de implantação na parte 1.
Se tudo correr bem, você verá a seguinte mensagem no seu terminal:
1Código-fonte enviado com sucesso para o contrato2contracts/HelloWorld.sol:HelloWorld em 0xendereco-do-contrato-implantado3para verificação no Etherscan. Aguardando resultado da verificação...456Contrato HelloWorld verificado com sucesso no Etherscan.7https://goerli.etherscan.io/address/<endereco-do-contrato>#contractsParabéns! O código do seu contrato inteligente está no Etherscan!
Confira seu contrato inteligente no Etherscan!
Ao navegar para o link fornecido no seu terminal, você poderá ver o código do seu contrato inteligente e a ABI publicados no Etherscan!
Uhuuuu - você conseguiu, campeão! Agora qualquer pessoa pode chamar ou escrever em seu contrato inteligente! Mal podemos esperar para ver o que você construirá em seguida!
Parte 4 - Integrando seu contrato inteligente com o frontend
Ao final deste tutorial, você saberá como:
- Conectar uma carteira MetaMask ao seu dapp
- Ler dados do seu contrato inteligente usando a API Alchemy Web3 (opens in a new tab)
- Assinar transações Ethereum usando o MetaMask
Para este dapp, usaremos o React (opens in a new tab) como nosso framework de frontend; no entanto, é importante notar que não gastaremos muito tempo explicando seus fundamentos, pois estaremos focados principalmente em trazer funcionalidades da Web3 para o nosso projeto.
Como pré-requisito, você deve ter um nível de entendimento de iniciante em React. Caso contrário, recomendamos concluir o tutorial oficial de Introdução ao React (opens in a new tab).
Clone os arquivos iniciais
Primeiro, vá para o repositório GitHub hello-world-part-four (opens in a new tab) para obter os arquivos iniciais deste projeto e clone este repositório em sua máquina local.
Abra o repositório clonado localmente. Observe que ele contém duas pastas: starter-files e completed.
starter-files- trabalharemos neste diretório, conectaremos a UI à sua carteira Ethereum e ao contrato inteligente que publicamos no Etherscan na Parte 3.completedcontém todo o tutorial concluído e deve ser usado apenas como referência se você ficar preso.
Em seguida, abra sua cópia de starter-files no seu editor de código favorito e navegue até a pasta src.
Todo o código que escrevermos ficará na pasta src. Editaremos o componente HelloWorld.js e os arquivos JavaScript util/interact.js para dar ao nosso projeto a funcionalidade da Web3.
Confira os arquivos iniciais
Antes de começarmos a codificar, vamos explorar o que nos é fornecido nos arquivos iniciais.
Coloque seu projeto react para funcionar
Vamos começar executando o projeto React em nosso navegador. A beleza do React é que uma vez que nosso projeto esteja sendo executado no nosso navegador, qualquer alteração que salvarmos será atualizada ao vivo em nosso navegador.
Para iniciar o projeto, navegue para o diretório raiz da pasta starter-files e execute npm install no seu terminal para instalar as dependências do projeto:
cd starter-filesnpm installAssim que a instalação for concluída, execute npm start em seu terminal:
npm startIsso deve abrir http://localhost:3000/ (opens in a new tab) no seu navegador, onde você verá o frontend do nosso projeto. Ele deve consistir em um campo (um local para atualizar a mensagem armazenada em seu contrato inteligente), um botão "Conectar Carteira" e um botão "Atualizar".
Se você tentar clicar em qualquer um dos botões, notará que eles não funcionam — isso ocorre porque ainda precisamos programar sua funcionalidade.
O componente HelloWorld.js
Vamos voltar para a pasta src em nosso editor e abrir o arquivo HelloWorld.js. É muito importante que entendamos tudo neste arquivo, pois é o principal componente do React no qual vamos trabalhar.
No topo deste arquivo, você notará que temos várias declarações de importação necessárias para fazer nosso projeto funcionar, incluindo a biblioteca React, os hooks useEffect e useState, alguns itens do ./util/interact.js (descreveremos em mais detalhes em breve!) e o logotipo da Alchemy.
1// HelloWorld.js23import React from "react"4import { useEffect, useState } from "react"5import {6 helloWorldContract,7 connectWallet,8 updateMessage,9 loadCurrentMessage,10 getCurrentWalletConnected,11} from "./util/interact.js"1213import alchemylogo from "./alchemylogo.svg"Exibir tudoEm seguida, temos nossas variáveis de estado que atualizaremos após eventos específicos.
1// HelloWorld.js23//Variáveis de estado4const [walletAddress, setWallet] = useState("")5const [status, setStatus] = useState("")6const [message, setMessage] = useState("Sem conexão com a rede.")7const [newMessage, setNewMessage] = useState("")Veja aqui o que cada uma das variáveis representa:
walletAddress- uma string que armazena o endereço da carteira do usuáriostatus- uma string que armazena uma mensagem útil que guia o usuário sobre como interagir com o dappmessage- uma string que armazena a mensagem atual no contrato inteligentenewMessage- uma string que armazena a nova mensagem que será escrita no contrato inteligente
Após as variáveis de estado, você verá cinco funções não implementadas: useEffect ,addSmartContractListener, addWalletListener , connectWalletPressed e onUpdatePressed. Explicaremos o que elas fazem abaixo:
1// HelloWorld.js23//chamado apenas uma vez4useEffect(async () => {5 //TODO: implementar6}, [])78function addSmartContractListener() {9 //TODO: implementar10}1112function addWalletListener() {13 //TODO: implementar14}1516const connectWalletPressed = async () => {17 //TODO: implementar18}1920const onUpdatePressed = async () => {21 //TODO: implementar22}Exibir tudouseEffect(opens in a new tab)- este é um hook do React que é chamado após a renderização do seu componente. Como ele tem um prop de array vazio[]passado para ele (veja a linha 4), ele só será chamado na primeira renderização do componente. Aqui, carregaremos a mensagem atual armazenada em nosso contrato inteligente, chamaremos nossos ouvintes de contrato inteligente e de carteira e atualizaremos nossa interface do usuário para refletir se uma carteira já está conectada.addSmartContractListener- esta função configura um ouvinte que observará o eventoUpdatedMessagesdo nosso contrato HelloWorld e atualizará nossa interface do usuário quando a mensagem for alterada em nosso contrato inteligente.addWalletListener- esta função configura um ouvinte que detecta alterações no estado da carteira MetaMask do usuário, como quando o usuário desconecta sua carteira ou troca de endereços.connectWalletPressed- esta função será chamada para conectar a carteira MetaMask do usuário ao nosso dapp.onUpdatePressed- essa função será chamada quando o usuário quiser atualizar a mensagem armazenada no contrato inteligente.
Perto do final desse arquivo, temos a interface de usuário do nosso componente.
1// HelloWorld.js23//a UI do nosso componente4return (5 <div id="container">6 <img id="logo" src={alchemylogo}></img>7 <button id="walletButton" onClick={connectWalletPressed}>8 {walletAddress.length > 0 ? (9 "Conectado: " +10 String(walletAddress).substring(0, 6) +11 "..." +12 String(walletAddress).substring(38)13 ) : (14 <span>Conectar Carteira</span>15 )}16 </button>1718 <h2 style={{ paddingTop: "50px" }}>Mensagem Atual:</h2>19 <p>{message}</p>2021 <h2 style={{ paddingTop: "18px" }}>Nova Mensagem:</h2>2223 <div>24 <input25 type="text"26 placeholder="Atualize a mensagem no seu contrato inteligente."27 onChange={(e) => setNewMessage(e.target.value)}28 value={newMessage}29 />30 <p id="status">{status}</p>3132 <button id="publishButton" onClick={onUpdatePressed}>33 Atualizar34 </button>35</div>36 37</div>38)Exibir tudoSe você examinar este código com atenção, notará onde usamos nossas várias variáveis de estado em nossa interface do usuário:
- Nas linhas 6-12, se a carteira do usuário estiver conectada (ou seja,
walletAddress.length > 0), exibimos uma versão truncada dowalletAddressdo usuário no botão com o ID "walletButton;" caso contrário, ele simplesmente diz "Conectar Carteira". - Na linha 17, exibimos a mensagem atual armazenada no contrato inteligente, que é capturada na string
message. - Nas linhas 23-26, usamos um componente controlado (opens in a new tab) para atualizar nossa variável de estado
newMessagequando a entrada no campo de texto muda.
Além de nossas variáveis de estado, você também verá que as funções connectWalletPressed e onUpdatePressed são chamadas quando os botões com os IDs publishButton e walletButton são clicados, respectivamente.
Finalmente, vamos abordar onde este componente HelloWorld.js é adicionado.
Se você for ao arquivo App.js, que é o componente principal do React que atua como um contêiner para todos os outros componentes, você verá que nosso componente HelloWorld.js é injetado na linha 7.
Por último, mas não menos importante, vamos conferir mais um arquivo fornecido a você, o arquivo interact.js.
O arquivo interact.js
Como queremos seguir o paradigma M-V-C (opens in a new tab), queremos um arquivo separado que contenha todas as nossas funções para gerenciar a lógica, os dados e as regras do nosso dapp e, em seguida, exportar essas funções para o nosso frontend (nosso componente HelloWorld.js).
👆🏽Este é o propósito exato do nosso arquivo interact.js!
Navegue até a pasta util em seu diretório src e você notará que incluímos um arquivo chamado interact.js que conterá todas as nossas funções e variáveis de interação com o contrato inteligente e a carteira.
1// interact.js23//export const helloWorldContract;45export const loadCurrentMessage = async () => {}67export const connectWallet = async () => {}89const getCurrentWalletConnected = async () => {}1011export const updateMessage = async (message) => {}Exibir tudoVocê notará no topo do arquivo que comentamos o objeto helloWorldContract. Mais tarde neste tutorial, descomentaremos este objeto e instanciaremos nosso contrato inteligente nesta variável, que então exportaremos para nosso componente HelloWorld.js.
As quatro funções não implementadas após nosso objeto helloWorldContract fazem o seguinte:
loadCurrentMessage- esta função lida com a lógica de carregar a mensagem atual armazenada no contrato inteligente. Ela fará uma chamada de leitura para o contrato inteligente Hello World usando a API Alchemy Web3 (opens in a new tab).connectWallet- esta função conectará a MetaMask do usuário ao nosso dapp.getCurrentWalletConnected- esta função verificará se uma conta Ethereum já está conectada ao nosso dapp ao carregar a página e atualizará nossa interface do usuário de acordo.updateMessage- esta função atualizará a mensagem armazenada no contrato inteligente. Ela fará uma chamada de escrita para o contrato inteligente Hello World, então a carteira MetaMask do usuário terá que assinar uma transação Ethereum para atualizar a mensagem.
Agora que entendemos com o que estamos trabalhando, vamos descobrir como ler do nosso contrato inteligente!
Passo 3: Leia do seu contrato inteligente
Para ler do seu contrato inteligente, você precisará configurar com sucesso:
- Uma conexão de API com a cadeia Ethereum
- Uma instância carregada do seu contrato inteligente
- Uma função para chamar a função do seu contrato inteligente
- Um ouvinte para observar as atualizações quando os dados que você está lendo do contrato inteligente mudarem
Isso pode parecer muitos passos, mas não se preocupe! Vamos guiá-lo passo a passo sobre como fazer cada um deles! :)
Estabeleça uma conexão de API com a cadeia Ethereum
Então, lembra como na Parte 2 deste tutorial, usamos nossa chave Web3 da Alchemy para ler do nosso contrato inteligente (opens in a new tab)? Você também precisará de uma chave Web3 da Alchemy em seu dapp para ler da cadeia.
Se você ainda não tiver, primeiro instale o Alchemy Web3 (opens in a new tab) navegando até o diretório raiz dos seus starter-files e executando o seguinte no seu terminal:
1npm install @alch/alchemy-web3O Alchemy Web3 (opens in a new tab) é um wrapper em torno do Web3.js (opens in a new tab), fornecendo métodos de API aprimorados e outros benefícios cruciais para facilitar sua vida como desenvolvedor web3. Ele foi projetado para exigir uma configuração mínima, para que você possa começar a usá-la no seu aplicativo imediatamente!
Em seguida, instale o pacote dotenv (opens in a new tab) no diretório do seu projeto, para termos um local seguro para armazenar nossa chave de API depois de buscá-la.
1npm install dotenv --savePara nosso dapp, usaremos nossa chave de API Websockets em vez da nossa chave de API HTTP, pois ela nos permitirá configurar um ouvinte que detecta quando a mensagem armazenada no contrato inteligente muda.
Depois de ter sua chave de API, crie um arquivo .env no seu diretório raiz e adicione sua URL de Websockets da Alchemy a ele. Depois disso, seu arquivo .env deve ter a seguinte aparência:
1REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/<chave>Agora, estamos prontos para configurar nosso ponto de extremidade Alchemy Web3 em nosso dapp! Vamos voltar ao nosso interact.js, que está aninhado dentro da nossa pasta util, e adicionar o seguinte código no topo do arquivo:
1// interact.js23require("dotenv").config()4const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY5const { createAlchemyWeb3 } = require("@alch/alchemy-web3")6const web3 = createAlchemyWeb3(alchemyKey)78//export const helloWorldContract;Acima, primeiro importamos a chave da Alchemy do nosso arquivo .env e depois passamos nossa alchemyKey para createAlchemyWeb3 para estabelecer nosso ponto de extremidade Alchemy Web3.
Com este ponto de extremidade pronto, é hora de carregar nosso contrato inteligente!
Carregando seu contrato inteligente Hello World
Para carregar seu contrato inteligente Hello World, você precisará do endereço do contrato e da ABI, ambos podem ser encontrados no Etherscan se você concluiu a Parte 3 deste tutorial.
Como obter a ABI do seu contrato no Etherscan
Se você pulou a Parte 3 deste tutorial, pode usar o contrato HelloWorld com o endereço 0x6f3f635A9762B47954229Ea479b4541eAF402A6A (opens in a new tab). Sua ABI pode ser encontrada aqui (opens in a new tab).
A ABI de um contrato é necessária para especificar qual função um contrato invocará, bem como para garantir que a função retorne dados no formato que você espera. Depois de copiar a ABI do nosso contrato, vamos salvá-la como um arquivo JSON chamado contract-abi.json em seu diretório src.
Seu contract-abi.json deve ser armazenado na sua pasta src.
Armados com o endereço do nosso contrato, ABI e o ponto de extremidade da Alchemy Web3, podemos usar o método de contrato (opens in a new tab) para carregar uma instância do nosso contrato inteligente. Importe a ABI do seu contrato no arquivo interact.js e adicione o endereço do seu contrato.
1// interact.js23const contractABI = require("../contract-abi.json")4const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A"Agora podemos finalmente descomentar nossa variável helloWorldContract e carregar o contrato inteligente usando nosso ponto de extremidade AlchemyWeb3:
1// interact.js2export const helloWorldContract = new web3.eth.Contract(3 contractABI,4 contractAddress5)Para recapitular, as primeiras 12 linhas do seu interact.js devem ter a seguinte aparência:
1// interact.js23require("dotenv").config()4const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY5const { createAlchemyWeb3 } = require("@alch/alchemy-web3")6const web3 = createAlchemyWeb3(alchemyKey)78const contractABI = require("../contract-abi.json")9const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A"1011export const helloWorldContract = new web3.eth.Contract(12 contractABI,13 contractAddress14)Exibir tudoAgora que nosso contrato está carregado, podemos implementar nossa função loadCurrentMessage!
Implementando loadCurrentMessage no seu arquivo interact.js
Esta função é super simples. Faremos uma chamada assíncrona simples da web3 para ler do nosso contrato. Nossa função retornará a mensagem armazenada no contrato inteligente:
Atualize o loadCurrentMessage no seu arquivo interact.js para o seguinte:
1// interact.js23export const loadCurrentMessage = async () => {4 const message = await helloWorldContract.methods.message().call()5 return message6}Como queremos exibir este contrato inteligente em nossa interface do usuário, vamos atualizar a função useEffect em nosso componente HelloWorld.js para o seguinte:
1// HelloWorld.js23//chamado apenas uma vez4useEffect(async () => {5 const message = await loadCurrentMessage()6 setMessage(message)7}, [])Observe que só queremos que nosso loadCurrentMessage seja chamado uma vez durante a primeira renderização do componente. Em breve, implementaremos o addSmartContractListener para atualizar automaticamente a interface do usuário após a alteração da mensagem no contrato inteligente.
Antes de mergulharmos em nosso ouvinte, vamos conferir o que temos até agora! Salve seus arquivos HelloWorld.js e interact.js e vá para http://localhost:3000/ (opens in a new tab)
Você notará que a mensagem atual não diz mais "Sem conexão com a rede". Em vez disso, ela reflete a mensagem armazenada no contrato inteligente. Incrível!
Sua interface do usuário agora deve refletir a mensagem armazenada no contrato inteligente
Agora, falando daquele ouvinte...
Implemente addSmartContractListener
Se você se lembrar do arquivo HelloWorld.sol que escrevemos na Parte 1 desta série de tutoriais (opens in a new tab), lembrará que há um evento de contrato inteligente chamado UpdatedMessages que é emitido após a invocação da função update do nosso contrato inteligente (veja as linhas 9 e 27):
1// HelloWorld.sol23// Especifica a versão do Solidity, usando versionamento semântico.4// Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma5pragma solidity ^0.7.3;67// Define um contrato chamado `HelloWorld`.8// Um contrato é uma coleção de funções e dados (seu estado). Depois de implantado, um contrato reside em um endereço específico na blockchain Ethereum. Saiba mais: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 //Emitido quando a função de atualização é chamada12 //Os eventos de contratos inteligentes são uma forma de o seu contrato comunicar que algo aconteceu na blockchain para o front-end do seu aplicativo, que pode estar 'ouvindo' certos eventos e agir quando eles acontecem.13 event UpdatedMessages(string oldStr, string newStr);1415 // Declara uma variável de estado `message` do tipo `string`.16 // As variáveis de estado são variáveis cujos valores são permanentemente armazenados no armazenamento do contrato. A palavra-chave `public` torna as variáveis acessíveis de fora de um contrato e cria uma função que outros contratos ou clientes podem chamar para acessar o valor.17 string public message;1819 // Semelhante a muitas linguagens orientadas a objetos baseadas em classes, um construtor é uma função especial que só é executada na criação do contrato.20 // Os construtores são usados para inicializar os dados do contrato. Saiba mais:https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) {2223 // Aceita um argumento de string `initMessage` e define o valor na variável de armazenamento `message` do contrato.24 message = initMessage;25 }2627 // Uma função pública que aceita um argumento de string e atualiza a variável de armazenamento `message`.28 function update(string memory newMessage) public {29 string memory oldMsg = message;30 message = newMessage;31 emit UpdatedMessages(oldMsg, newMessage);32 }33}Exibir tudoEventos de contratos inteligentes são uma forma de o seu contrato comunicar que algo aconteceu (ou seja, houve um evento) na blockchain para seu aplicativo de front-end, que pode estar 'ouvindo' eventos específicos e tomar uma ação quando eles acontecem.
A função addSmartContractListener irá ouvir especificamente o evento UpdatedMessages do nosso contrato inteligente Hello World e atualizará nossa interface do usuário para exibir a nova mensagem.
Modifique addSmartContractListener para o seguinte:
1// HelloWorld.js23function addSmartContractListener() {4 helloWorldContract.events.UpdatedMessages({}, (error, data) => {5 if (error) {6 setStatus("😥 " + error.message)7 } else {8 setMessage(data.returnValues[1])9 setNewMessage("")10 setStatus("🎉 Sua mensagem foi atualizada!")11 }12 })13}Exibir tudoVamos detalhar o que acontece quando o ouvinte detecta um evento:
- Se ocorrer um erro quando o evento for emitido, ele será refletido na interface do usuário por meio de nossa variável de estado
status. - Caso contrário, usaremos o objeto
dataretornado. Odata.returnValuesé um array indexado em zero onde o primeiro elemento no array armazena a mensagem anterior e o segundo elemento armazena a atualizada. No total, em um evento bem-sucedido, definiremos nossa stringmessagepara a mensagem atualizada, limparemos a stringnewMessagee atualizaremos nossa variável de estadostatuspara refletir que uma nova mensagem foi publicada em nosso contrato inteligente.
Finalmente, vamos chamar nosso ouvinte em nossa função useEffect para que ele seja inicializado na primeira renderização do componente HelloWorld.js. No total, sua função useEffect deve ter a seguinte aparência:
1// HelloWorld.js23useEffect(async () => {4 const message = await loadCurrentMessage()5 setMessage(message)6 addSmartContractListener()7}, [])Agora que podemos ler do nosso contrato inteligente, seria ótimo descobrir como escrever nele também! No entanto, para escrever em nosso dapp, primeiro devemos ter uma carteira Ethereum conectada a ele.
Então, a seguir, abordaremos a configuração de nossa carteira Ethereum (MetaMask) e, em seguida, a conexão dela ao nosso dapp!
Passo 4: Configure sua carteira Ethereum
Para escrever qualquer coisa na cadeia Ethereum, os usuários devem assinar transações usando as chaves privadas de suas carteiras virtuais. Para este tutorial, usaremos o MetaMask (opens in a new tab), uma carteira virtual no navegador usada para gerenciar o endereço da sua conta Ethereum, pois torna a assinatura de transações superfácil para o usuário final.
Se quiser entender mais sobre como as transações na Ethereum funcionam, confira esta página da Ethereum Foundation.
Baixe o MetaMask
Você pode baixar e criar uma conta MetaMask gratuitamente aqui (opens in a new tab). Ao criar uma conta, ou se você já tiver uma, certifique-se de mudar para a “Rede de Teste Goerli” no canto superior direito (para não lidarmos com dinheiro real).
Adicione ether de uma Faucet
Para assinar uma transação na blockchain Ethereum, precisaremos de um pouco de Eth falso. Para obter Eth, você pode ir para a FaucETH (opens in a new tab) e inserir o endereço da sua conta Goerli, clicar em “Solicitar fundos”, selecionar “Rede de Teste Ethereum Goerli” no menu suspenso e, finalmente, clicar no botão “Solicitar fundos” novamente. Em seguida, você deve ver Eth em sua conta MetaMask!
Verifique seu saldo
Para verificar novamente se nosso saldo está lá, vamos fazer uma solicitação eth_getBalance (opens in a new tab) usando a ferramenta de composição da Alchemy (opens in a new tab). Ela mostrará a quantidade de Eth na sua carteira. Depois de inserir o endereço da sua conta da MetaMask e clicar em "Send Request", você verá uma resposta como esta:
1{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}OBSERVAÇÃO: Este resultado está em wei, não em eth. Lembre-se de que "Wei" é a menor unidade de ether. A conversão de wei para eth é: 1 eth = 10¹⁸ wei. Então, se convertemos 0xde0b6b3a7640000 para decimal, temos 1*10¹⁸ wei, que é igual a 1 eth.
Ufa! Nosso dinheiro falso está todo lá! 🤑
Passo 5: Conecte o MetaMask à sua interface do usuário
Agora que nossa carteira MetaMask está configurada, vamos conectar nosso dapp a ela!
A função connectWallet
Em nosso arquivo interact.js, vamos implementar a função connectWallet, que podemos chamar em nosso componente HelloWorld.js.
Vamos modificar connectWallet para o seguinte:
1// interact.js23export const connectWallet = async () => {4 if (window.ethereum) {5 try {6 const addressArray = await window.ethereum.request({7 method: "eth_requestAccounts",8 })9 const obj = {10 status: "👆🏽 Escreva uma mensagem no campo de texto acima.",11 address: addressArray[0],12 }13 return obj14 } catch (err) {15 return {16 address: "",17 status: "😥 " + err.message,18 }19 }20 } else {21 return {22 address: "",23 status: (24 <span>25 <p>26 {" "}27 🦊 <a target="_blank" href={`https://metamask.io/download`}>28 Você deve instalar o MetaMask, uma carteira virtual Ethereum, no seu navegador.29 </a>30 </p>31 </span>32 ),33 }34 }35}Exibir tudoEntão, o que esse bloco gigante de código faz exatamente?
Bem, primeiro, ele verifica se o window.ethereum está habilitado no seu navegador.
window.ethereum é uma API global injetada pelo MetaMask e outros provedores de carteira que permite que sites solicitem as contas Ethereum dos usuários. Se aprovado, ele pode ler dados das blockchains às quais o usuário está conectado e sugerir que o usuário assine mensagens e transações. Confira a documentação do MetaMask (opens in a new tab) para mais informações!
Se o window.ethereum não estiver presente, isso significa que o MetaMask não está instalado. Isso resulta no retorno de um objeto JSON, onde o address retornado é uma string vazia, e o objeto JSX status informa que o usuário deve instalar o MetaMask.
Agora, se o window.ethereum estiver presente, é aí que as coisas ficam interessantes.
Usando um loop try/catch, tentaremos nos conectar ao MetaMask chamando window.ethereum.request({ method: \"eth_requestAccounts\" }); (opens in a new tab). Chamando esta função o MetaMask irá abrir no navegador, onde o usuário será solicitado a conectar sua carteira ao seu dapp.
- Se o usuário optar por conectar,
method: "eth_requestAccounts"retornará um array que contém todos os endereços de conta do usuário conectados ao dapp. No total, nossa funçãoconnectWalletretornará um objeto JSON que contém o primeiroaddressneste array (veja a linha 9) e uma mensagem destatusque solicita ao usuário que escreva uma mensagem para o contrato inteligente. - Se o usuário rejeitar a conexão, o objeto JSON conterá uma string vazia para o
addressretornado e uma mensagem destatusque reflete que o usuário rejeitou a conexão.
Agora que escrevemos esta função connectWallet, o próximo passo é chamá-la em nosso componente HelloWorld.js.
Adicione a função connectWallet ao seu componente de interface do usuário HelloWorld.js
Navegue para a função connectWalletPressed em HelloWorld.js e atualize-a para o seguinte:
1// HelloWorld.js23const connectWalletPressed = async () => {4 const walletResponse = await connectWallet()5 setStatus(walletResponse.status)6 setWallet(walletResponse.address)7}Observe como a maior parte de nossa funcionalidade está abstraída de nosso componente HelloWorld.js do arquivo interact.js? É assim que respeitamos o paradigma M-V-C!
Em connectWalletPressed, nós simplesmente fazemos uma chamada await para a nossa função connectWallet importada e, usando sua resposta, atualizamos nossas variáveis status e walletAddress através de seus hooks de estado.
Agora, vamos salvar ambos os arquivos (HelloWorld.js e interact.js) e testar nossa interface do usuário até agora.
Abra seu navegador na página http://localhost:3000/ (opens in a new tab) e pressione o botão "Conectar Carteira" no canto superior direito da página.
Se você tiver o MetaMask instalado, você será solicitado a conectar sua carteira ao seu dapp. Aceite o convite para se conectar.
Você deve ver que o botão da carteira agora reflete que seu endereço está conectado! Demais! 🔥
Em seguida, tente atualizar a página... que estranho. Nosso botão de carteira está nos pedindo para conectar o MetaMask, mesmo que já esteja conectado...
No entanto, não tema! Podemos facilmente resolver isso (entendeu?) implementando getCurrentWalletConnected, que verificará se um endereço já está conectado ao nosso dapp e atualizará nossa interface do usuário de acordo!
A função getCurrentWalletConnected
Atualize sua função getCurrentWalletConnected no arquivo interact.js para o seguinte:
1// interact.js23export const getCurrentWalletConnected = async () => {4 if (window.ethereum) {5 try {6 const addressArray = await window.ethereum.request({7 method: "eth_accounts",8 })9 if (addressArray.length > 0) {10 return {11 address: addressArray[0],12 status: "👆🏽 Escreva uma mensagem no campo de texto acima.",13 }14 } else {15 return {16 address: "",17 status: "🦊 Conecte-se ao MetaMask usando o botão superior direito.",18 }19 }20 } catch (err) {21 return {22 address: "",23 status: "😥 " + err.message,24 }25 }26 } else {27 return {28 address: "",29 status: (30 <span>31 <p>32 {" "}33 🦊 <a target="_blank" href={`https://metamask.io/download`}>34 Você deve instalar o MetaMask, uma carteira virtual Ethereum, no seu navegador.35 </a>36 </p>37 </span>38 ),39 }40 }41}Exibir tudoEste código é muito semelhante à função connectWallet que acabamos de escrever na etapa anterior.
A principal diferença é que, em vez de chamar o método eth_requestAccounts, que abre o MetaMask para o usuário conectar sua carteira, aqui chamamos o método eth_accounts, que simplesmente retorna uma matriz contendo os endereços do MetaMask atualmente conectados ao nosso dapp.
Para ver esta função em ação, vamos chamá-la em nossa função useEffect do nosso componente HelloWorld.js:
1// HelloWorld.js23useEffect(async () => {4 const message = await loadCurrentMessage()5 setMessage(message)6 addSmartContractListener()78 const { address, status } = await getCurrentWalletConnected()9 setWallet(address)10 setStatus(status)11}, [])Exibir tudoObserve que usamos a resposta da nossa chamada para getCurrentWalletConnected para atualizar nossas variáveis de estado walletAddress e status.
Agora que você adicionou este código, vamos tentar atualizar a janela do nosso navegador.
Ótimoooo! O botão deve dizer que você está conectado e mostrar uma visualização do endereço de sua carteira conectada - mesmo depois de atualizar!
Implemente addWalletListener
O passo final na configuração da nossa carteira dapp é implementar o ouvinte de carteira, para que nossa interface atualize quando o estado mudar, como quando o usuário desconecta ou troca de contas.
No seu arquivo HelloWorld.js, modifique sua função addWalletListener para o seguinte:
1// HelloWorld.js23function addWalletListener() {4 if (window.ethereum) {5 window.ethereum.on("accountsChanged", (accounts) => {6 if (accounts.length > 0) {7 setWallet(accounts[0])8 setStatus("👆🏽 Escreva uma mensagem no campo de texto acima.")9 } else {10 setWallet("")11 setStatus("🦊 Conecte-se ao MetaMask usando o botão superior direito.")12 }13 })14 } else {15 setStatus(16 <p>17 {" "}18 🦊 <a target="_blank" href={`https://metamask.io/download`}>19 Você deve instalar o MetaMask, uma carteira virtual Ethereum, no seu navegador.20 </a>21 </p>22 )23 }24}Exibir tudoAposto que você nem precisa da nossa ajuda para entender o que está acontecendo aqui neste ponto, mas, para fins de completude, vamos detalhar rapidamente:
- Primeiro, nossa função verifica se o
window.ethereumestá ativado (ou seja, se o MetaMask está instalado).- Se não estiver, simplesmente definimos nossa variável de estado
statuscomo uma string JSX que solicita ao usuário que instale o MetaMask. - Se estiver habilitado, configuramos o listener
window.ethereum.on("accountsChanged")na linha 3 que escuta por mudanças de estado na carteira MetaMask, que incluem quando o usuário conecta uma conta adicional ao dapp, troca de contas ou desconecta uma conta. Se houver pelo menos uma conta conectada, a variável de estadowalletAddressé atualizada como a primeira conta no arrayaccountsretornado pelo listener. Caso contrário, owalletAddressé definido como uma string vazia.
- Se não estiver, simplesmente definimos nossa variável de estado
Por último, mas não menos importante, devemos chamá-la em nossa função useEffect:
1// HelloWorld.js23useEffect(async () => {4 const message = await loadCurrentMessage()5 setMessage(message)6 addSmartContractListener()78 const { address, status } = await getCurrentWalletConnected()9 setWallet(address)10 setStatus(status)1112 addWalletListener()13}, [])Exibir tudoE é isso! Concluímos com sucesso a programação de toda a funcionalidade da nossa carteira! Agora para nossa última tarefa: atualizar a mensagem armazenada em nosso contrato inteligente!
Passo 6: Implemente a função updateMessage
Tudo bem, pessoal, chegamos à reta final! Na updateMessage do seu arquivo interact.js, faremos o seguinte:
- Certificar-se de que a mensagem que desejamos publicar em nosso contrato inteligente é válida
- Assinar nossa transação usando o MetaMask
- Chamar esta função do nosso componente de frontend
HelloWorld.js
Isso não levará muito tempo; vamos terminar este dapp!
Tratamento de erros de entrada
Naturalmente, faz sentido ter algum tipo de tratamento de erro de entrada no início da função.
Queremos que nossa função retorne mais cedo se não houver extensão MetaMask instalada, se não houver carteira conectada (ou seja, o address passado é uma string vazia) ou se a message for uma string vazia. Vamos adicionar o seguinte tratamento de erro a updateMessage:
1// interact.js23export const updateMessage = async (address, message) => {4 if (!window.ethereum || address === null) {5 return {6 status:7 "💡 Conecte sua carteira MetaMask para atualizar a mensagem na blockchain.",8 }9 }1011 if (message.trim() === "") {12 return {13 status: "❌ Sua mensagem não pode ser uma string vazia.",14 }15 }16}Exibir tudoAgora que temos o tratamento de erro de entrada adequado, é hora de assinar a transação via MetaMask!
Assinando nossa transação
Se você já está confortável com transações Ethereum da web3 tradicional, o código que escreveremos a seguir será muito familiar. Abaixo do seu código de tratamento de erro de entrada, adicione o seguinte a updateMessage:
1// interact.js23//configurar parâmetros da transação4const transactionParameters = {5 to: contractAddress, // Obrigatório, exceto durante publicações de contrato.6 from: address, // deve corresponder ao endereço ativo do usuário.7 data: helloWorldContract.methods.update(message).encodeABI(),8}910//assinar a transação11try {12 const txHash = await window.ethereum.request({13 method: "eth_sendTransaction",14 params: [transactionParameters],15 })16 return {17 status: (18 <span>19 ✅{" "}20 <a target="_blank" href={`https://goerli.etherscan.io/tx/${txHash}`}>21 Veja o status da sua transação no Etherscan!22 </a>23 <br />24 ℹ️ Assim que a transação for verificada pela rede, a mensagem será atualizada automaticamente.25 </span>26 ),27 }28} catch (error) {29 return {30 status: "😥 " + error.message,31 }32}Exibir tudoVamos detalhar o que está acontecendo. Primeiro, configuramos nossos parâmetros de transações, onde:
toespecifica o endereço do destinatário (nosso contrato inteligente)fromespecifica o signatário da transação, a variáveladdressque passamos para nossa funçãodatacontém a chamada para o métodoupdatedo nosso contrato inteligente Hello World, recebendo nossa variável de stringmessagecomo entrada
Então, fazemos uma chamada de espera, window.ethereum.request, onde pedimos ao MetaMask para assinar a transação. Observe que, nas linhas 11 e 12, estamos especificando nosso método eth, eth_sendTransaction, e passando nossos transactionParameters.
Neste ponto, a MetaMask irá abrir no navegador e pedirá que o usuário assine ou rejeite a transação.
- Se a transação for bem-sucedida, a função retornará um objeto JSON onde a string JSX
statussolicita ao usuário que verifique o Etherscan para mais informações sobre sua transação. - Se a transação falhar, a função retornará um objeto JSON onde a string
statustransmite a mensagem de erro.
No total, nossa função updateMessage deve ter a seguinte aparência:
1// interact.js23export const updateMessage = async (address, message) => {4 //tratamento de erro de entrada5 if (!window.ethereum || address === null) {6 return {7 status:8 "💡 Conecte sua carteira MetaMask para atualizar a mensagem na blockchain.",9 }10 }1112 if (message.trim() === "") {13 return {14 status: "❌ Sua mensagem não pode ser uma string vazia.",15 }16 }1718 //configurar parâmetros da transação19 const transactionParameters = {20 to: contractAddress, // Obrigatório, exceto durante publicações de contrato.21 from: address, // deve corresponder ao endereço ativo do usuário.22 data: helloWorldContract.methods.update(message).encodeABI(),23 }2425 //assinar a transação26 try {27 const txHash = await window.ethereum.request({28 method: "eth_sendTransaction",29 params: [transactionParameters],30 })31 return {32 status: (33 <span>34 ✅{" "}35 <a target="_blank" href={`https://goerli.etherscan.io/tx/${txHash}`}>36 Veja o status da sua transação no Etherscan!37 </a>38 <br />39 ℹ️ Assim que a transação for verificada pela rede, a mensagem será atualizada automaticamente.40 </span>41 ),42 }43 } catch (error) {44 return {45 status: "😥 " + error.message,46 }47 }48}Exibir tudoPor último, mas não menos importante, precisamos conectar nossa função updateMessage ao nosso componente HelloWorld.js.
Conecte updateMessage ao frontend HelloWorld.js
Nossa função onUpdatePressed deve fazer uma chamada de espera para a função updateMessage importada e modificar a variável de estado status para refletir se nossa transação foi bem-sucedida ou falhou:
1// HelloWorld.js23const onUpdatePressed = async () => {4 const { status } = await updateMessage(walletAddress, newMessage)5 setStatus(status)6}É super limpo e simples. E adivinhe só... SEU DAPP ESTÁ COMPLETO!!!
Vá em frente e teste o botão Atualizar!
Crie seu próprio dapp personalizado
Uhuuu, você chegou ao final do tutorial! Para recapitular, você aprendeu como:
- Conectar uma carteira MetaMask ao seu projeto de dapp
- Ler dados do seu contrato inteligente usando a API Alchemy Web3 (opens in a new tab)
- Assinar transações Ethereum usando o MetaMask
Agora você está totalmente equipado para aplicar as habilidades deste tutorial para construir seu próprio projeto de dapp personalizado! Como sempre, se tiver alguma dúvida, não hesite em nos contatar para obter ajuda no Discord da Alchemy (opens in a new tab). 🧙♂️
Depois de concluir este tutorial, conte-nos como foi sua experiência ou se você tem algum feedback, marcando-nos no Twitter @alchemyplatform (opens in a new tab)!
Última atualização da página: 26 de fevereiro de 2026





