Quanto mais desenvolvimento de contrato inteligente tivermos, maior será a necessidade de ter kits de ferramentas de desenvolvimento que possam ajudar os desenvolvedores a implementar, testar e implantar com facilidade e rapidez. No que diz respeito aos kits de ferramentas de desenvolvimento de blockchain, muitas vezes ouvimos falar de Truffle e Hardhat, no entanto, a Opensea acaba de lançar uma nova versão de seu contrato inteligente chamado seaport, que é inicializado usando o Foundry.
O que é exatamente Foundry?
Foundry é um kit de ferramentas de desenvolvimento de contrato inteligente que gerencia suas dependências, compila seu projeto, executa testes, implementa e permite que você interaja com a cadeia a partir da linha de comando.
O Foundry é rápido em comparação com outros kits de ferramentas de desenvolvimento de contratos inteligentes, pois é escrito em Rust. O recurso mais interessante do Foundry é, na verdade, sua capacidade de permitir que os desenvolvedores implementem seus testes no Solidity e é altamente personalizável.
Instalação
Se você estiver usando Linux ou macOS, execute o seguinte comando:
curl -L <https://foundry.paradigm.xyz> | bash
Isso fará o download do foundryup
. Em seguida, instale o Foundry executando:
foundryup
Se você usa o Windows, precisa compilar a partir do código-fonte para obter o Foundry.
Baixe e execute rustup-init
de rustup.rs. Ele iniciará a instalação em um console.
Depois disso, execute o seguinte para criar o Foundry a partir da fonte:
cargo install --git <https://github.com/foundry-rs/foundry> foundry-cli anvil --bins --locked
Inicialização do projeto
Com o Foundry instalado, podemos criar nosso projeto executando este comando no diretório preferencial onde precisamos manter o projeto:
forge init foundry-project
Após rodar o comando acima, deverá gerar um projeto com a seguinte estrutura:
foundry-project
├─ lib
│ └─ forge.std
├─ src
│ └─ Contract.sol
├─ script
│ └─ Contract.s.sol
├─ test
│ └─ Contrat.t.sol
└─ foundry.toml
Como podemos ver, o projeto é gerado com alguns diretórios, o diretório lib
contém todas as dependências necessárias para o projeto, é semelhante a um node_modules
. O diretório src
mantém a implementação do contrato inteligente, o script
armazena scripts de solidity que podem ser usados para a implantação, o diretório test
contém todos os arquivos de teste e, por último, o arquivo foundry.toml
é usado para manter a configuração do projeto.
Implementação do projeto
Vamos implementar um contrato inteligente básico, pois este tutorial se trata de uma introdução. Então vamos criar o arquivo Counter.sol
dentro da pasta src
e adicionar os seguintes códigos:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
address owner;
int private count;
constructor (int _count){
owner = msg.sender;
count = _count;
}
function getCount () public view returns (int) {
return count;
}
function incrementCount () public {
require(msg.sender == owner, "Unauthorized");
count++;
}
function decrementCount () public {
require(msg.sender == owner, "Unauthorized");
count--;
}
}
Neste trecho de código, basicamente implementamos o contrato de contador que contém um construtor que inicializa owner
& count
e também possui três funções para obter, incrementar e decrementar o contador, no qual apenas o proprietário pode incrementar ou decrementar.
O projeto pode ser construído para gerar a ABI usando o seguinte comando:
forge build
Implementação do teste
Vamos criar o arquivo de teste chamado Counter.t.sol
no diretório test
com os seguintes casos de teste:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "src/Counter.sol";
contract CounterTest is Test {
Counter counter;
function setUp() public {
counter = new Counter(2);
}
function testGetCount() public {
int value = counter.getCount();
assertEq(value, 2);
}
function testIncrementCount() public {
counter.incrementCount();
int value = counter.getCount();
assertEq(value, 3);
}
function testIncrementCountFail() public {
vm.prank(address(0));
vm.expectRevert("Unauthorized");
counter.incrementCount();
}
function testDecrementCount() public {
counter.decrementCount();
int value = counter.getCount();
assertEq(value, 1);
}
function testDecrementCountFail() public {
vm.prank(address(0));
vm.expectRevert("Unauthorized");
counter.decrementCount();
}
}
Antes de tudo estamos importando o forge-std.Test.sol
que encapsula um conjunto de funções utilitárias necessárias para escrever o teste e fizemos o mesmo com o Counter.sol
que é o contrato inteligente que está sendo testado.
Em seguida, estamos configurando nosso teste inicializando nosso contrato inteligente de contador com 2 como valor padrão. Estamos aproveitando a função AssertEq
vinda do forge-std.Test.sol
para comparar se o valor retornado após a chamada da função getCount
é igual ao passado durante a inicialização.
Você pode ver no cenário de falha do teste, estamos usando novas palavras-chave como vm.prank
e vm.expectRevert
, essas funções referem-se a códigos de trapaça no Foundry, eles são usados para manipular o ambiente de teste para obter situações da vida real.
A função vm.prank()
é usada para definir msg.sender
para o endereço especificado para a próxima chamada. Estamos literalmente usando isso aqui para mudar o proprietário. E a vm.expectRevert
ajuda a interceptar uma situação de falha, passando a mensagem de erro exata.
Depois de executar o comando forge test
, você poderá obter o seguinte resultado:
Implantação do Projeto
Para implantar nosso contrato inteligente, precisamos renomear Contract.s.sol
para Counter.s.sol
e adicionar o conteúdo abaixo:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
import { Counter } from "src/Counter.sol";
contract CounterScript is Script {
function run() public {
vm.startBroadcast();
new Counter(2);
vm.stopBroadcast();
}
}
O script possui a função run
que será chamada para executar a implantação. A vm.startBroadcast
cria transações que podem ser assinadas e enviadas posteriormente na cadeia e a vm.stopBroadcast
interrompe a coleta de transações para transmissão posterior na cadeia.
Antes de executar o script que irá implantar nosso contrato inteligente na testnet BSC, vamos adicionar o arquivo .env
no diretório raiz do projeto, contendo as seguintes chaves:
BSC_RPC=https://data-seed-prebsc-1-s2.binance.org:8545
PRIVATE_KEY=A chave privada de sua carteira
Agora podemos executar o seguinte comando para dar acesso shell às nossas variáveis env:
Em seguida, executamos o comando de implantação
forge create --rpc-url $BSC_RPC --private-key $PRIVATE_KEY script/Counter.s.sol:CounterScript
Em caso de implantação bem-sucedida, você deve obter a seguinte saída no terminal:
Conclusão
O framework Foundry ainda pode ser uma novidade no espaço web 3, porém já chamou a atenção de grandes empresas como a Opensea por todas as vantagens que oferece, a começar pela velocidade, customização e capacidade de escrever testes em Solidity. Será exagero afirmar que superará outras ferramentas de desenvolvimento de contatos inteligentes, mas vale a pena ficar de olho no seu desenvolvimento.
Este tutorial cobre apenas os fundamentos. Para saber mais sobre o Foundry, acesse a documentação oficial.
Esse artigo é uma tradução feita por @bananlabs. Você pode encontrar o artigo original aqui
Oldest comments (0)