Como criar seu primeiro Smart Contract em Solidity com HardHat

Cripto

Como criar seu primeiro Smart Contract em Solidity com HardHat

Luiz Duarte
Escrito por Luiz Duarte em 01/11/2022
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Atualizado em 28/03/24!

Se você não possui experiência alguma com Node.js/JavaScript, recomendo começar por este outro tutorial, que usa ferramentas menos profissionais e mais simples.

Se o Bitcoin foi o grande catalisador para o surgimento das criptomoedas modernas como conhecemos, a Ethereum foi a grande catalisadora para o surgimento de milhares de outras criptomoedas, NFTs e a própria Web 3.0 que vem se falando cada vez mais. Vitalik Buterin, criador da rede Ethereum e seu time, vislumbraram na tecnologia blockchain não apenas a possibilidade de criar um dinheiro virtual P2P, ou seja descentralizado e seguro, como a oportunidade de permitir a criação de “contratos inteligentes” (smart contracts). Assim, qualquer programador ao redor do mundo poderia publicar seus códigos para serem executados na rede Ethereum e com isso iniciar o surgimento de todo um ecossistema ainda maior e mais vibrante (embora ainda de menor capitalização) do que o Bitcoin original.

Em 2014, foi Gavin Wood, um dos fundadores da Ethereum, que teve a ideia de criar a linguagem Solidity, especificamente para a codificação de Smart Contracts na rede Ethereum e demais redes compatíveis (forks, como a BNB Smart Chain que surgiu anos mais tarde). Os smart contracts escritos em Solidity são publicados na rede e toda vez que acionados por clientes, rodam em um interpretador chamado EVM, a Ethereum Virtual Machine, semelhante ao que acontece com a VM do Java, caso você conheça.

A linguagem Solidity é hoje a principal tecnologia relacionada a smart contracts que você deve estudar se deseja aprender a criar aplicações que rodam na blockchain, principalmente Dex, Defi, DAOs e é claro, dapps Web3. Uma linguagem jovem, semelhante ao padrão ECMA para quem está acostumado com programação JS, mas com tipagem estática. Aliás, os contratos em si lembram muito as classes existentes em outras linguagens Orientadas à Objetos.

A minha ideia com este tutorial é lhe dar uma introdução nesta linguagem e tecnologia, lhe despertando então interesse (e capacidade) por conhecer mais sobre este universo que não pára de crescer. Acredito estar desta forma colaborando com o desenvolvimento de novos profissionais neste meio, principalmente aqueles sem grandes conhecimentos do idioma Inglês, onde você encontra muito material acerca de Solidity.

Neste tutorial usaremos o HardHat. Se quiser entender mais a fundo o que é o HardHat, recomendo este vídeo.

Então vamos lá!

#1 – Ambiente

Primeiro é importante entender que não tem uma única forma de criar os seus smart contracts com Solidity. Em outro tutorial aqui do blog eu mostrei como fazer com a ferramenta Remix, por exemplo. Eu vou mostrar aqui da forma como eu aprendi e que considero mais profissional. Mais tarde, sinta-se livre para abandonar o que ensinarei e seguir o seu próprio caminho.

Você vai precisar primeiramente do Node.js, pois ele é a base para outras ferramentas que vamos usar. Então vá até o site oficial e baixe a versão LTS para sua máquina, instalando-a até o final (marcando tudo que ela perguntar durante o processo). Também vou usar aqui o editor de código Visual Studio Code, que é gratuito e pode ser baixado no site oficial.

As instalações são bem diretas, mas se precisar de ajuda, o vídeo abaixo pode te ajudar.

Um dos motivos de eu recomendar o Visual Studio Code ao invés de outros editores é que além dele ser gratuito, leve e multiplataforma, ele tem a possibilidade de instalarmos extensões para diferentes linguagens, como no caso da extensão Solidity da empresa Nomic Foundation, que eu recomendo que instale na aba de extensões assim que estiver com o VS Code aberto a primeira vez.

Todo o restante do tutorial abaixo pode ser aprendido no vídeo a seguir, caso prefira assistir ao invés de ler.

Agora que você preparou o seu editor de código e o Node já está devidamente instalado também, é hora de instalarmos o HardHat. O HardHat é um toolkit, uma suíte de ferramentas para ajudar na criação de smart contracts e que vai acelerar bastante a nossa produtividade nesse tipo de desenvolvimento. Ele é desenvolvido em Node.js e por isso que precisamos ter o Node instalado antes dele.

Para instalar o HardHat vamos usar o NPM, o gerenciador de pacotes do Node. Primeiro crie uma pasta para o seu projeto, vou chamar de hello-solidity-hardhat e depois inicialize ela com o NPM e instale o HardHat, como abaixo.

Este comando vai baixar e instalar todos os arquivos do HardHat no seu projeto o que pode demorar um bocado, então não se assuste.

Quando terminar, você poderá criar o seu primeiro projeto HardHat. Para isso, rode o comando abaixo para inicializar o configurador de projeto HardHat.

Isso irá iniciar um assistente de configuração que irá te fazer algumas perguntas. A primeira é a mais importante que é sobre usar ou não TypeScript e essa é a principal vantagem do HardHat sobre o Truffle, seu maior concorrente e que já ensinei aqui no blog em outro tutorial. O HardHat possui suporte nativo ao TypeScript então vamos aproveitar e usar esta opção. Já as demais opções pode ir sempre de opção padrão até o final e como resultado você terá a estrutura do seu projeto criada automaticamente, como abaixo.

Essa estrutura inicial é de um projeto chamado Lock e você encontrará os contratos dele na pasta contracts, sendo os arquivos com extensão “.sol” (de Solidity). Nada importante pra gente, pode ignorar.

Curso Node.js e MongoDB

#2 – Criando o Hello World

Como vamos criar o nosso contrato do zero e ele vai ser bem simples, recomendo excluir todo o conteúdo da pasta contracts, deixando a mesma vazia, bem como o conteúdo das pastas scripts e test. Na scripts vão os scripts de deploy e na test, os de teste, mas escreveremos nossos próprios scripts mais à frente.

Agora, na pasta de contracts, vamos criar o nosso arquivo HelloWorld.sol, que vai ser o nosso arquivo de contrato.

Assim que tiver criado este arquivo em branco, tem duas instruções iniciais que devemos colocar. Uma delas é a licença do seu código-fonte, que você pode incluir usando o atalho spdx e apertando Enter, que vai adicionar a licença MIT. Tendo interesse em mudar a licença para outra à sua escolhe, fique à vontade.

A segunda instrução é a versão do compilador de Solidity que será usada para compilar este contrato. Isso porque assim como funciona com a linguagem Java, C# e outras, nós escrevemos o programa (contrato neste caso) em uma linguagem e ela precisa ser compilada para uma linguagem de máquina que será interpretada pela EVM (Ethereum Virtual Machine) mais tarde. Ao longo do tempo novas versões da linguagem são lançadas com novas funcionalidades e portanto é importante especificar qual a versão que você precisa para o seu projeto.

Para iso, use o atalho pragma apertando Enter, que vai adicionar uma instrução de versão para você, que deve ser preenchida com a versão de Solidity que foi instalada junto do HardHat na sua máquina.

Ao término destas duas instruções, o seu arquivo deve estar assim (minha versão é a 0.8.24. Se você não souber a sua versão, basta digitar qualquer uma que a mensagem de erro vai te informar a versão que você possui ao passar o mouse por cima do erro.

Abaixo destas informações todas é que vamos começar a codificar nosso primeiro contrato. Se você já conhece alguma linguagem orientada à objetos antes, vai se sentir em casa pois escrever um contrato é muito semelhante a escrever classes. Para começar, você define o seu contrato usando a palavra reservada contract e definindo o seu escopo entre chaves.

Dentro do contrato você pode colocar suas propriedades e funções, assim como faria com classes e começaremos declarando uma propriedade chamada message, apenas para guardar o conteúdo de uma mensagem.

O tipo da variável definimos como string (texto), o modificador de acesso colocamos como public (o que indica que pode ser acessado de fora do contrato), o nome da variável colocamos message (mensagem em Inglês) e atribuímos o valor entre aspas Hello World para ela, da mesma forma que faríamos em JavaScript e tantas outras linguagens de programação.

Outros tipos válidos para variáveis, dentre muitos:

  • bool: true ou false;
  • int: números inteiros (com variações em bits como int8, int256, etc);
  • uint: inteiros positivos (sem sinal, unsigned, com variações em bits como uint8, uint256, etc);
  • address: endereços na rede;

Da mesma forma, o processo de criação de uma função também é bem simples e abaixo segue um exemplo de função helloWorld.

Neste exemplo usamos a palavra reservada function para dizer que vamos escrever uma função, damos o nome à mesma (camel case) e abrimos parênteses para definir os parâmetros, que optei aqui por não ter nenhum. Na sequência definimos o modificador de acesso (public, indicando que ela pode ser chamada fora deste contrato), o tipo de função (usei view pois vamos precisar visualizar uma informação do contrato) e a palavra reservada returns para informar o que essa informação retorna, neste caso uma única variável string memory (que explicarei mais tarde o porque do memory).

Talvez o ponto mais diferentão aqui seja a palavra reservada view, que indica que esta função vai ler o “estado” do contrato, ou seja, as suas propriedades/variáveis internas. Outra opção seria a palavra reservada pure, que indica que esta é uma função pura, ou seja, sem estado, sem usar variáveis externas. É importante ressaltar desde já que o uso de variáveis de classe ou de função impactam diretamente no custo das chamadas à este contrato, o que exploraremos futuramente aqui no blog. E por último também temos as funções payable, que permitem que alguém envie fundos (pague) para usar a função.

Além disso, outro ponto que é bacana reforçar é quanto ao modificador de acesso, public, que se não for informado vai ser private por padrão, ou seja, sem acesso externo.

O conteúdo da função em si dispensa explicações e agora que temos nosso HelloWorld codificado, é hora de testarmos ele.

#3 – Testando o Hello World

Testes são um parte crucial do desenvolvimento de qualquer software mas Solidity coloca isso em outro patamar. Isso porque como seu contrato ficará visível na blockchain e na maioria das vezes ele envolverá dinheiro, é crucial que ele esteja em pleno funcionamento e que seja seguro. Não apenas isso, as transações na blockchain são imutáveis então não temos margem para corrigir pequenas coisinhas depois, como é comum no mundo web.

Dito isso, vá até a sua pasta de test e crie um arquivo HelloWorld.test.ts nela, embora este nome seja apenas uma recomendação, pode ser o nome que quiser.

Dentro deste arquivo vamos escrever os testes unitários do nosso contrato, para isso o Truffle vai nos fornecer uma série de ferramentas que vai deixar a experiência muito próxima de usando libs de testes JS como Tape e Jest. Caso esteja familiarizado com alguma destas bibliotecas ou outras concorrentes como Mocha, Chai e Jasmine, se sentirá em casa.

Vamos começar nossa suíte de testes importando o que será necessário.

A função loadFixture serve para fazer o setup do Smart Contract apenas uma vez, com uma função que ainda vamos criar, e recarregar seu estado inicial antes de todos os testes. Já o expect é a função de asserção dos testes, via Chai, e a Ethers é uma biblioteca JS para comunicação com blockchains EVM compatible (baseadas em Ethereum), já falei dela aqui em outros tutoriais do blog (como este).

Agora para criar a estrutura padrão dos testes chame a função describe, defina um nome para a suíte de testes e na função de callback que é o segundo parâmetro, iremos colocar nossos futuros testes.

Como mencionei antes, usaremos um recurso do HardHat chamado fixtures, onde o contrato é instalado apenas uma vez e reiniciado antes de cada teste automaticamente. Para conseguirmos usar este recurso devemos criar a função de fixture, como no exemplo abaixo. Esta função deve estar dentro do callback do describe.

Aqui a gente começa pegando algumas carteiras de exemplo que serão usadas nos testes. A primeira que você pega é sempre o owner do contrato e as demais são de carteiras alternativas. Depois, carregamos nosso contrato HelloWorld que criamos anteriormente e fazemos o deploy dele. No retorno da função de fixture nós devolvemos um objeto com estes artefatos que serão usados pelos testes

Agora para escrever os testes em si, você pode adicionar chamadas à função it quantas vezes quiser, logo depois da função deployFixture, como abaixo.

Neste teste de exemplo, o único que vamos precisar, nós damos um nome ao teste, seguido da função de teste que nada mais está fazendo do que chamando nossa função de deploy, pegando o contrato instalado por ela, chamando a função do nosso contrato (helloWorld, lembra?) e analisando o retorno dela através da função expect.

A função expect é quem vai dizer se nosso teste passou ou não, baseado no booleano resultante da expressão lógica que passamos à ela, no caso a comparação literal com a frase que deve estar em nosso contrato, na variável message.

Para rodar esta bateria de testes é bem simples, basta abrir o terminal e uma vez dentro da pasta do seu projeto rodar o comando abaixo do HardHat, certificando-se de estar rodando o terminal como administrador.

Isso vai fazer com que o HardHat rode os testes, lhe apresentando os resultados como abaixo.

E com isso finalizamos o nosso primeiro tutorial de Solidity com HardHat aqui do blog!

Querendo um segundo, um pouco mais avançado? Recomendo esse aqui!

Quer aprender a fazer deploy deste smart contract na blockchain? Leia esse aqui.

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *