GitHub Repo:- https://github.com/PradhumnaPancholi/Figbot
Ei pessoal! Há pouco tempo, estava aprendendo o Dapp Tools , pois possui ferramentas fantásticas para desenvolver e auditar contratos inteligentes. E embora tenha adorado a experiência, logo soube que está em fase clandestina de desenvolvimento. Isso significa que usuários casuais/individuais não podem depender de mantenedores para suporte e atualizações.
Então me deparei com o Foundry . Ele tem tudo o que o Dapp Tools oferece além da execução simbólica integrada (o que não é um problema para mim, pois uso o Manticor e da Trail of Bits ). E isso está relacionado à auditoria, portanto, não é um obstáculo no desenvolvimento de contratos inteligentes por qualquer trecho da imaginação.
Depois de trabalhar um pouco com o Foundry, gostei da experiência e quis compartilhar isso com outras pessoas. Por isso, este artigo.
Este artigo abordará os benefícios do Foundry, o processo de instalação, o desenvolvimento de um NFT (porque todos estão interessados nisso), o teste do contrato e a implantação com o Figment Datahub .
O Foundry é um kit de ferramentas incrivelmente rápido, portátil e modular para o desenvolvimento de aplicativos Ethereum escrito em Rust.
A fundição é composta por três componentes:
- Forge: estrutura de teste Ethereum (como Truffle, Hardhat e Dapptools).
- Cast: canivete suíço para interagir com contratos inteligentes EVM, enviar transações e obter dados da cadeia.
- Anvil: nó Ethereum local, semelhante a Ganache, Hardhat Network
O foco de hoje será em Forge. Mas estarei postando artigos detalhados sobre Casta e Bigorna nas próximas semanas.
Por que Fundição:
Existem muitas ferramentas de desenvolvimento de contratos inteligentes, como Truffle, Hardhat e Brownie. Mas uma das minhas principais razões para procurar ferramentas Dapp em primeiro lugar foram os testes nativos de Solidity. Escrever contratos inteligentes não é difícil ao alternar entre estruturas como Hardhat e Brownie. E são ferramentas incríveis com plugins, mas é preciso ser bem versado em JavaScript/TypeScript e Python para realizar testes.
O Foundry nos permite escrever nossos testes nativamente no Solidity. Isso economiza muito tempo na integração de novos desenvolvedores e torna o processo mais tranquilo. Em minha experiência em ajudar as pessoas a navegar no desenvolvimento de contratos inteligentes, aprendi que a melhor e mais eficiente maneira de os desenvolvedores juniores se envolverem com projetos DAO/mantidos pela comunidade é escrevendo testes e aprendendo sobre a própria base de código. Lembro que Scupy Trooples mencionou uma vez que eles usaram a mesma abordagem ao desenvolver o Alchemix Finance no Bankless .
Além disso, fuzzing integrado, códigos de trapaça, Cast e Anvil o tornam um conjunto sólido para testar contratos inteligentes. Haverá artigos mais detalhados sobre esses componentes em breve. [Fácil de integrar analisador estático]
Vamos mergulhar e construir um projeto NFT agora.
Instalação:
Se você estiver no Mac ou Linux, tudo o que você precisa fazer é executar dois comandos:
curl -L https://foundry.paradigm.xyz | bash
foundryup
Certifique-se de fechar o terminal antes de executar o foundryup
.
E voilá! Você está pronto.
Para Windows, você precisa ter o Rust instalado e depois:
cargo install --git https://github.com/foundry-rs/foundry --locked
Configuração do projeto:
Para este artigo, criaremos um projeto NFT simples chamado Figbots.
Comece criando um diretório chamado “Figbots”. E execute forge init
assim que estiver dentro do diretório. Este comando criará um projeto de fundição para você com git
inicializado.
Vamos dar uma olhada rápida na estrutura de pastas. Você tem três pastas principais, ou seja, src, lib e test. Muito auto-explicativo aqui, você escreve seus contratos em src
, testes em test
, e lib
contém todas as bibliotecas que você instalou, por exemplo, OpenZeppelin. Além disso, você obtém o foundry.toml
que contém todas as configurações como hardhat.config.js
e brownie-config.yaml
se você tiver usado essas estruturas. Outra coisa interessante é o .github, onde você pode escrever suas ações do Github. Acho muito útil para testes quando se trabalha em equipe.
Vamos começar a construir! Criaremos um NFT simples chamado Figbot com suprimento, custo (para cunhagem) e retirada limitados. Com essa abordagem, podemos cobrir arestas para diferentes testes. Em primeiro lugar, renomeie Contract.sol
e test/Contract.t.sol
para Figbot.sol
e Figbot.t.sol
respectivamente. Agora, não podemos escrever contratos inteligentes sem o Openzeppelin, podemos?
A instalação de bibliotecas com Foundry é um pouco diferente de Hardhat e Brownie. Não temos pacotes npm ou pip. Instalamos bibliotecas diretamente do Source (repositório do GitHub) no Foundry.
forge install Openzeppelin/openzeppelin-contracts
Agora podemos importar a extensão ERC721URIStorage.sol para criar nosso NFT. Para verificar se está tudo certo, podemos executar o comando forge build
, que irá compilar nosso projeto. O compilador gritará com você se houver algo errado. Caso contrário, você obterá uma compilação bem-sucedida.
Gerenciando dependências
Assim como qualquer outro gerenciador de pacotes, o Forge permite que você use forge install <lib>,
forge remove <lib>
e forge update <lib>
para gerenciar suas dependências.
Vamos concluir o contrato NFT:
Estaremos usando três contratos do Openzeppelin. Contadores, ERC721URIStorage e Ownable. Hora de carregar nosso recurso para IPFS usando Pinata . Usamos o contrato Ownable para definir o owner
do endereço de implantação e temos acesso ao modificador onlyOwner
para permitir que apenas o proprietário retire fundos. Counters
para nos ajudar com id(s) de token e ERC721URIStorage
para manter o contrato NFT simples.
Definindo a variável de estado:
-
MAX_SUPPLY
para 100 -
COST
para 0,69 éter -
TOKEN_URI
para CID, recebemos de Pinata
-
Usando o contador para id de token:
-
using Counters for Counters.Counter;
-
Counters.Counter private tokenIds;
-
Construtor ERC721:
-
constructor() ERC721(“Figbot”, “FBT”) {}
-
Função de hortelã:
- Verifique se
msg.value
é maior queCOST
- Verifique se
tokenIds.current()
é maior ou igual aMAX_SUPPLY
- Execute
_safeMint
e_setTokenURI
- Verifique se
Função de retirada:
-
function withdrawFunds() external onlyOwner { uint256 balance = address(this).balance; require(balance > 0, "No ether left to withdraw"); (bool success, ) = (msg.sender).call{value: balance}(""); require(success, "Withdrawal Failed"); emit Withdraw(msg.sender, balance); }
-
Função TotalSupply:
-
function totalSupply() public view returns (uint256) { return _tokenIds.current(); }
-
Testando o contrato:
Como todos sabemos, testar nossos contratos inteligentes é muito importante. Nesta seção, escreveremos alguns testes para obter uma compreensão sólida do forge test
e nos acostumarmos a escrever testes na solidez nativa. Seremos três códigos de trapaça Foundry (eu os amo!) Para gerenciar os estados da conta para se adequar ao nosso cenário de teste.
Estaremos testando para os seguintes cenários:
- Fornecimento máximo
- hortelã de sucesso
- Falha na cunhagem devido a saldo insuficiente
- Retirar (pelo proprietário)
códigos de trapaça
Como podemos ter uma lógica complexa em nossos contratos inteligentes. E espera-se que eles se comportem de maneira diferente dependendo do estado, da conta usada para invocar, do tempo etc. Para lidar com esses cenários, podemos usar cheatcodes para gerenciar o estado do blockchain. Podemos usar esses cheatcodes usando vm
instance, que faz parte da biblioteca de Test
do Foundry.
Nós estaremos usando três cheatcodes em nossos testes:
startPrank
: Definemsg.sender
para todas as chamadas subseqüentes até questopPrank
seja chamado.stopPrank
:Pára uma partida ativa iniciada por
startPrank
, redefinindomsg.sender
etx.origin
para os valores antesstartPrank
ser chamado.deal
: Define o saldo de um endereço fornecido para o saldo fornecido.
Configurar
O Foundry vem com uma biblioteca de teste integrada. Começamos importando esta biblioteca de teste, nosso contrato (aquele que queremos testar), definindo o teste, configurando as variáveis e a função setUp
.
pragma solidity ^0.8.13; import"forge-std/Test.sol"; import "../src/Figbot.sol"; contract FigbotTest is Test { Figbot figbot; address owner = address(0x1223); address alice = address(0x1889); address bob = address(0x1778); function setUp() public { vm.startPrank(owner); figbot = new Figbot(); vm.stopPrank(); } }
Para variáveis de estado, criamos uma variável figbot
do tipo Figbot
. Este também é o lugar onde gosto de definir contas de usuário. No Foundry, você pode descrever um endereço usando a sintaxe address(0x1243)
. você pode usar quaisquer quatro caracteres alfanuméricos para isso. Criei as contas denominadas owner, Alice e bob, respectivamente.
Agora nossa função setUp
. Este é um requisito para escrever testes no Foundry. É aqui que fazemos todas as implantações e coisas dessa natureza. Usei o cheatcode startPrank
para mudar o usuário para o “proprietário”. Por padrão, o Foundry usa um endereço específico para implantar contratos de teste. Mas isso torna mais difícil testar funções com privilégios especiais, como withdrawFunds
. Portanto, mudamos para a conta de "proprietário" para esta implantação.
Teste MaxSupply:
Começando com um teste de asserção simples para aprender a convenção do Foundry. Por convenção, todas as funções de teste devem ter o prefixo test
. E usamos assertEq
para testar se dois valores são iguais.
Chamamos nossa função MaxSupply
e testamos se o valor do resultado é 100, conforme descrevemos em nosso contrato. E usamos forge test
para executar nossos testes.
E voilá!!! temos um teste aprovado.
Menta de teste:
Agora que escrevemos um teste simples, vamos escrever um com cheatcodes. A função principal do nosso contrato.
- Mude a conta de usuário para Alice.
- Defina o saldo de Alice para 1 éter
- Chame a função mint
- Verifique se
balanceOf
Alice é 1
TestFail Mint:
Temos outra função de teste usada para testes que esperamos falhar. O prefixo usado para tal teste é testFail
. Testaremos se a função mint
reverte se o chamador não tiver fundos suficientes.
- Mude a conta de usuário para Bob
- Defina o saldo de Bob para 0,5 ether (nosso NFT é 0,69 ether)
- Chame a função mint (ela será revertida por não ter fundos suficientes)
- Verifique se
balanceOf
Bob é 1
Como mint não passou, o saldo de Bob não será 1. Portanto, ele falhará, exatamente para o que usamos testFail
. Então, quando você executar forge test
, ele passará.
Retirada de teste:
Aqui vamos testar uma função que somente o “proprietário” pode executar com sucesso. Para este teste, iremos:
- Mude o usuário para Bob
- Dê à conta de Bob o saldo de 1 éter
- Crie um Figbot da conta de Bob (isso dará ao contrato um saldo de 0,69 ether)
- Mude o usuário para a conta do proprietário
- Execute a função de
withdrawFunds
de fundos (se for bem-sucedida, deve fazer com que o saldo do proprietário seja 0,69 ether) - Para verificar, afirmamos se o saldo do proprietário é 0,69 ether
Implantação:
Agora que testamos nosso contrato, é hora de implantá-lo. Precisamos de chaves privadas para uma carteira (com algum ETH de teste Rinkeby) e um URL RPC. Para nossa URL RPC, usaremos Figment DataHu .
O Figment DataHub nos fornece infraestrutura para desenvolver na Web 3. Ele suporta várias cadeias como Ethereum, Celo, Solana, Terra, etc.
Configurando o Figment DataHub:
- Crie uma conta no Figment DataHub .
- Clique em “Criar novo aplicativo”.
- Preencha o nome do aplicativo.
- Escolha “Staging” para o ambiente.
- Selecione “Ethereum” nas opções fornecidas.
Você pode obter seu URL RPC para Rinkeby na guia "Protocolos".
Abra seu terminal para inserir essas duas coisas como variáveis de ambiente.
export FIG_RINKEBY_URL=<Your RPC endpoint> export PVT_KEY=<Your wallets private key>
Assim que tivermos as variáveis de ambiente, estamos prontos para implantar
forge create Figbot --rpc-url=$FIG_RINKEBY_URL --private-key=$PVT_KEY
Verificação:
Estamos quase terminando aqui. Até agora, escrevemos, testamos e implantamos um contrato inteligente com Foundry e Figment DataHub. Mas ainda não terminamos totalmente. Agora vamos verificar nosso contrato. Precisamos configurar nossa chave de API Etherscan para isso.
export ETHERSCAN_API=<Your Etherscan API Key>
E agora podemos verificar nosso contrato inteligente.
forge verify-contract --chain-id <Chain-Id> --num-of-optimizations 200 --compiler-version <Compiler Version> src/<Contract File>:<Contract> $ETHERSCAN_API
Parabéns! Agora você pode escrever, testar e implantar contratos inteligentes usando o Foundry. Espero que você tenha gostado e aprendido com este artigo. Eu realmente gostei de escrever isso. Sinta-se livre para me deixar saber seus pensamentos sobre isso.