Faala Devs!! Iremos juntos também aprender um pouco mais sobre o Hardhat, pois neste artigo vamos compilar e testar nosso contrato de "Hello World".
Você encontra o código fonte do projeto neste respositório sob a branch #beginners-guide-part-iii
.
Estrutura do Contrato Inteligente
Um contrato, no conceito do Solidity, é um conjunto de códigos (functions) e dados (state), que residem em um específico endereço na rede blockchain Ethereum.
fig. 1 - estrutura básica de um contrato inteligente
A estrutura de um contrato é muito semelhante a uma classe de outra linguagem orientada a objetos como vemos a seguir, fazendo disso um motivo que torna o aprendizado de Solidity mais simples. O arquivo de código fonte do Solidity pode conter qualquer número de definições de contrato, diretivas de importação de biblioteca e diretivas de pragma.
Cada contrato pode conter declarações de Variáveis de Estado, Funções, Modificadores de Função, Eventos, Tipos de Estrutura and Tipos de Enum. Além disso, contratos podem herdar de outros contratos.
Contrato de armazenamento
Vamos iniciar por um exemplo simples. Neste contrato estamos armazenando uma informação na Blockchain do tipo uint (falaremos mais no futuro) e resgatamos o seu conteúdo. Sem problemas se você não entender tudo neste momento, iremos entrar em mais detalhes depois.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.8.1;
import "hardhat/console.sol";
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
License
A primeira linha informa sob qual licença de uso esta registrada o contrato, neste caso a GPL-3.0.
DICA: A declaração da licença não é obrigatório mas é uma boa prática.
Pragma
Na linha seguinte estamos simplesmente dizendo que o código fonte foi escrito para a versão 0.4.16 do Solidity ou mais recente e não quebra sua funcionalidade (até, mas não incluindo a versão 0.8.1). Isso é para garantir que o contrato não se comporte de forma diferente com uma nova versão do compilador. A palavra chave pragma é chamada desta maneira, porque, no geral pragmas são instruções para o compilador sobre como tratar o código fonte.
Imports
Muitas vezes temos a necessidade de utilizar funções que estão em outros contratos ou mesmo fazer uso de bibliotecas externas, para atender a esta necessidade podemos realizar a importação por meio da cláusula import como visto abaixo.
Assinatura do Contrato
Em contract SimpleStorage efetivamente declaramos o inicio de um novo contrato atribuindo a ele o nome de SimpleStorage. Contratos assim como em linguagens de orientação a objetos podem estender outros contratos ou implementar interfaces. Assunto esse que não será abordado em nosso guia por hora.
Variáveis de Estado
Os tipos de dados em solidity são explícitos, ou seja nós precisamos definir através de uma palavra chave qual é o tipo da variável.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
contract SimpleStorage {
uint storedData; //variável de estado
A linha uint storedData
declara uma variável de estado chamada "storedData" do tipo uint (integer não assinado de 256 bits). Você pode pensar nisso como uma única coluna de um registro em um banco de dados que pode ser consultado e alterado chamando funções do código que gerenciam o banco de dados. No caso do Ethereum, ele é sempre o contrato proprietário. E neste caso, as funções set e get podem ser usadas para modificar ou recuperar o valor da variável.
Em resumo as variáveis de estado são valores armazenados permanentemente na memória de contrato.
Para acessar uma variável de estado, você não precisa do prefixo this.
, como é comum em outras linguagens.
Funções
As funções são unidades executáveis de código dentro de um contrato. Elas tratam de encapsular trechos de código para serem executados sempre que necessário.
function soma(uint a, uint b) external pure returns(uint) {
return a + b;
}
No exemplo acima temos a função "soma" que recebe 2 parâmetros uint a, uint b
e retorna um uint
.
Mais para frente iremos abordar os outros itens que compõem uma função como visibilidade, acessibilidade e modificadores.
Hello World Solidity
Vamos colocar a mão na massa finalmente!!! Neste momento replicar o famoso "Hello World"em Solidity.
Se você está seguindo esta séria desde o início, neste momento já possuí o projeto beginners-guide-to-solidity. Caso não recomendo que volte acessa a Parte II e siga as instruções para criar o projeto.
Certo, para darmos início acesse a pasta raiz do projeto e crie um diretório chamado contracts e dentro dele o arquivo HelloWorld.sol conforme a seguir.
$ cd beginners-guide-to-solidity
$ mkdir contracts && cd contracts
$ touch HelloWorld.sol
Vamos criar o contrato HelloWorld definindo o License, Pragma e os Imports necessários.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "hardhat/console.sol";
contract HelloWorld {
}
Agora criemos a função "sayHello", ela não deve receber nenhum parâmetro mas deve retornar uma string
. Já que não iremos nem escrever qualquer informação na Blockchain a função deve possuir o modificador de acesso View
e como iremos acessar ela de fora do contrato o modificador de visibilidade External
. Veja como fica nossa função a seguir.
function sayHello() external view returns(string memory) {
console.log("Function sayHello foi invocada.");
return "Hello World Solidity";
}
Sendo esta a versão final do nosso contrato HelloWorld, muito simples né!?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "hardhat/console.sol";
contract HelloWorld {
function sayHello() external view returns(string memory) {
console.log("Function sayHello foi invocada.");
return "Hello World Solidity";
}
}
Compilando o Contrato Inteligente
Agora que escrevemos o contrato vamos compilar e ver se tudo correu bem até aqui. ;-)
Para isso basta digitar no terminal:
$ npx hardhat compile
Após a compilação você tera uma mensagem semelhante a essa:
Compiled 2 Solidity files successfully
Excelente contrato compilado e pronto para uso, mas antes de fazer o delivery na rede local vamos escrever alguns testes para garantir que tudo está fucionando corretamente.
Testando o contrato inteligente com Testes Unitários
Maravilha, contrato criado e compilado com sucesso, agora vamos escrever alguns testes unitários para garantir que ele realize o que foi programado para fazer, neste caso, retornar uma string
com o valor "Hello World Solidity".
Para isso vamos criar um novo diretório chamado test
na raiz do nosso projeto e dentro dele um arquivo chamado HelloWorld.js
.
$ mkdir test && cd test
$ touch HelloWorld.js
Excelente, agora copie e cole o trecho de código abaixo no arquivo HelloWorld.js, iremos falar dele em seguida.
const { expect } = require('chai');
describe('Hello World Contract', function () {
let HelloWorldContract;
let helloWorldContractDeployed;
beforeEach(async function () {
HelloWorldContract = await ethers.getContractFactory('HelloWorld');
helloWorldContractDeployed = await HelloWorldContract.deploy();
});
describe('Call Function Say Hello', function () {
it('Should be return Hello World Solidity when call the function sayHello', async function () {
const helloWorldMessage = await helloWorldContractDeployed.sayHello();
expect('Hello World Solidity').to.equal(helloWorldMessage);
});
});
});
Agora no terminal digite npx hardhat test
. Ao final do teste você poderá ver uma mensagem semelhante a esta:
Hello World Contract
Call Function Say Hello
Function sayHello foi invocada.
✔ Should be return Hello World Solidity when call the function sayHello (38ms)
1 passing (734ms)
Podemos ver inclusive que na terceira linha a nossa mensagem que enviamos para o console do HardHat pode ser apresentada.
Explicando o teste
Agora que o nosso teste passou com sucesso, vamos à explicação sobre o que faz cada linha do teste.
const { expect } = require('chai');
Realizamos a importação da biblioteca de assertions.
describe("Hello World Contract", function () {
let HelloWorldContract;
let helloWorldContractDeployed;
Apenas definimos uma descrição melhor para o nosso grupo de testes para o contrato e definimos algumas variáveis que usamos mais a frente.
beforeEach(async function () {
HelloWorldContract = await ethers.getContractFactory('HelloWorld');
helloWorldContractDeployed = await HelloWorldContract.deploy();
});
Antes de cada teste realizamos o delivery do nosso contrato.
O ContractFactory
no ethers.js é uma abstração utilizada para efetuar o deploy de novos contratos, e HelloWorld
é a factory utilizada para instanciar o nosso contrato.
Após a chamada do deploy()
nosso ContractFactory
vai iniciar o deploy do nosso contrato e devolver uma Promisse
que resolve o nosso contrato. Este sendo o objeto que contém as funções do nosso contrato com a qual podemos interagir.
describe("Call Function Say Hello", function ()
Define uma descrição para o nosso grupo de testes que podem vir a seguir, no nosso caso apenas um teste.
it('Should be return Hello World Solidity when call the function sayHello', async function () {
const helloWorldMessage = await helloWorldContractDeployed.sayHello();
expect('Hello World Solidity').to.equal(helloWorldMessage);
});
Teste propriamente dito, onde await helloWorldContractDeployed.sayHello()
resolvemos a promisse com o resultado da chamada a função sayHello()
dentro do nosso contrato e realizamos a assertion em expect("Hello World Solidity").to.equal(helloWorldMessage)
.
Conclusão
Neste artigo pudemos conhecer um pouco melhor a estrutura de um Smart Contract, bem como realizar a criação e teste unitário do nosso primeiro contrato inteligente, o famoso Hello World.
E é isso por hoje, pessoal!
Chegamos ao final de mais um artigo, espero que tenha sido útil e que você tenha aprendido algo novo.
Caso tenha alguma dúvida, comentário ou tenha encontrado algum erro, por favor, envie-me um email. Ficarei feliz em ouvir de você.
Se desejar receber novos artigos diretamente em seu e-mail, por favor, assine a nossa Newsletter. E se você já é um assinante, muito obrigado!
Aproveito e deixo um convite para nos conectarmos no Twitter e LinkedIn.
👋 Obrigado por ler até o final e até o próximo artigo !!!