WTF Solidity - Introdução Simplificada às Ferramentas 7: Foundry, um Kit de Desenvolvimento Centrado em Solidity
Recentemente, estou reaprendendo solidity para reforçar os detalhes e também escrevendo um "WTF Solidity - Introdução Simplificada" para iniciantes usarem. Atualizações de 1 a 3 palestras por semana.
Twitter: @0xAA_Science
Comunidade: Discord|Grupo WeChat|Site Oficial wtf.academy
Todo o código e tutoriais são de código aberto no GitHub: github.com/AmazingAng/WTF-Solidity
De acordo com a introdução da ferramenta no site oficial (getfoundry.sh):
Foundry é um kit de ferramentas extremamente rápido, portátil e modular para o desenvolvimento de aplicações Ethereum, escrito em Rust.
Recursos do projeto:
- Site oficial: https://getfoundry.sh
- Repositório GitHub: https://github.com/foundry-rs/foundry
- Documentação: https://book.getfoundry.sh
Explicação da introdução:
- Escrito em Rust: Foundry é totalmente desenvolvido em Rust, o repositório de código-fonte no GitHub é um projeto em Rust. Podemos obter os arquivos binários da Release, ou também podemos compilar e instalar usando o gerenciador de pacotes cargo do Rust compilando e instalando a partir do código-fonte;
- Para o desenvolvimento de aplicações Ethereum: Foundry serve como uma ferramenta "engenharia" para o desenvolvimento de projetos/aplicações Ethereum (linguagem Solidity), fornecendo um ambiente de desenvolvimento Solidity profissional e "cadeia de ferramentas". Com ele, você pode rapidamente e convenientemente completar o gerenciamento de dependências, compilação, execução de testes, implantação, e pode interagir com a cadeia através da linha de comando e scripts Solidity;
- Extremamente rápido: Foundry utiliza ethers-solc e, em comparação com os testes/trabalhos tradicionais auxiliados por Node.js, a construção e execução de testes do Foundry são muito rápidas (criar um projeto, escrever alguns casos de teste e executá-los para sentir o impacto);
- Portátil: Projetos Foundry suportam integração com outros tipos de projetos (como: integração com Hardhat);
- Modular: Através do git submodule & mapeamento de diretórios de construção, é rápido e conveniente introduzir dependências;
Se você se encaixa nas condições abaixo ou teve experiências semelhantes, você definitivamente deve experimentar Foundry:
- Se você é um desenvolvedor de aplicações Ethereum (linguagem Solidity) profissional;
- Você já usou ferramentas como Hardhat.js;
- Você está cansado de esperar por um grande número de casos de teste e precisa de uma ferramenta mais rápida para executar seus casos de teste;
- Você acha que lidar com BigNumber é um pouco 🤏 complicado;
- Você teve a necessidade de completar casos de teste (ou contratos de teste de contratos) usando a própria linguagem Solidity;
- Você acha que gerenciar dependências através do git submodule é mais conveniente (em vez de npm);
- ...
Se você se encaixa nas condições abaixo, Foundry pode não ser adequado para você:
- Iniciantes em Solidity;
- Seu projeto não precisa escrever casos de teste, não precisa de muita automação no aspecto do projeto Solidity;
Esta seção é baseada no Foundry book (https://book.getfoundry.sh), tornando a compreensão dos capítulos mais fácil.
- Criar projetos de desenvolvimento de contratos inteligentes Ethereum (Solidity), trabalhar em projetos existentes;
- Gerenciar dependências de contratos inteligentes Ethereum (Solidity);
- Criar casos de teste escritos em linguagem Solidity (e executar casos de teste rapidamente): e suporta teste de fuzz e teste diferencial e outros métodos de teste convenientes e profissionais;
- Através de Cheatcodes (códigos de trapaça) em casos de teste escritos em linguagem Solidity interagir e afirmar com funcionalidades "fora do ambiente EVM": mudar o endereço da carteira do executor do caso de teste (mudar
msg.sender
), afirmar eventos fora do EVM; - Rastreamento de execução e erros: rastreamento de erros em nível de "pilha de funções" (Traces);
- Implantar contratos e completar automaticamente a verificação de código aberto no scan;
- Suporte no projeto para rastreamento completo do uso de gas: incluindo detalhes do uso de gas do contrato de teste e relatórios de gas;
- Depurador interativo;
O projeto Foundry é composto por várias partes (ferramentas de linha de comando): Forge
, Cast
, Anvil
- Forge: Ferramenta de linha de comando no projeto Foundry para executar inicialização do projeto, gerenciamento de dependências, testes, construção, implantação de contratos inteligentes;
- Cast: Ferramenta de linha de comando no projeto Foundry para interagir com nós RPC. Pode ser usada para chamar contratos inteligentes, enviar dados de transação ou recuperar qualquer tipo de dados na cadeia;
- Anvil: Ferramenta de linha de comando no projeto Foundry para iniciar uma rede de teste/local. Pode ser usada em conjunto com testes de aplicativos front-end e contratos implantados nessa rede de teste ou para interagir através de RPC;
O conteúdo vem da seção Getting Start do Foundry book
Processo a ser completado:
- Instalar Foundry;
- Inicializar um projeto Foundry;
- Entender os contratos inteligentes e casos de teste adicionados durante a inicialização;
- Executar construção & teste;
Para diferentes ambientes:
- MacOS / Linux (e sistemas semelhantes ao Unix):
- Instalação através de
foundryup
(👈 método recomendado pela página inicial do projeto Foundry); - Instalação através da construção a partir do código-fonte;
- Instalação através de
- Windows
- Instalação através da construção a partir do código-fonte;
- Ambiente Docker
- Consulte Foundry Package: https://github.com/gakonst/foundry/pkgs/container/foundry
- GitHub Action: Para construir um fluxo completo de Action
Instalação rápida através de script
Instalação rápida em ambientes com bash
(ou ambientes semelhantes ao Unix)
$ curl -L https://foundry.paradigm.xyz | bash
Após a execução, será instalado o foundryup
, execute-o em seguida
$ foundryup
Se tudo correr bem, agora você pode usar três arquivos binários: forge
, cast
e anvil
.
Inicialize o projeto "hello_wtf" com forge init
$ forge init hello_wtf
Inicializando /Users/username/hello_wtf...
Instalando forge-std em "/Users/username/hello_wtf/lib/forge-std" (url: Some("https://github.com/foundry-rs/forge-std"), tag: None)
Instalado forge-std
Projeto forge inicializado.
Este processo inicializa um projeto Foundry instalando a dependência forge-std
Na estrutura do diretório do projeto, você verá
$ tree -L 2
.
├── foundry.toml # Arquivo de configuração do pacote Foundry
├── lib # Bibliotecas de dependência do Foundry
│ └── forge-std # Dependência básica da ferramenta forge
├── script # Scripts do Foundry
│ └── Counter.s.sol # Script do contrato de exemplo Counter
├── src # Lógica de negócios dos contratos inteligentes, o código-fonte será colocado aqui
│ └── Counter.sol # Contrato de exemplo
└── test # Diretório de casos de teste
└── Counter.t.sol # Caso de teste do contrato de exemplo
Nota:
- As dependências são tratadas como git submodule no diretório
./lib
- Para detalhes sobre o arquivo de configuração do pacote Foundry, consulte: https://github.com/foundry-rs/foundry/blob/master/config/README.md#all-options
Principalmente composto pela lógica de negócios
src
diretório ./src/Counter.sol
:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter { // Um contrato Counter muito simples
uint256 public number; // Mantém um número uint256 público
// Define o conteúdo da variável number
function setNumber(uint256 newNumber) public {
number = newNumber;
}
// Incrementa o conteúdo da variável number
function increment() public {
number++;
}
}
Consulte a documentação do projeto Foundry em Solidity-scripting Este diretório é principalmente composto por scripts de "implantação" (também pode usar esses scripts para chamar funcionalidades vm
fornecidas pelo Foundry para realizar funcionalidades avançadas além da lógica de aplicação, equivalente aos scripts em Hardhat.js).
Veja ./script/Counter.s.sol
:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13; // Licença e identificação da versão Solidity
import "forge-std/Script.sol"; // Importa a biblioteca Script do forge foundry
import "../src/Counter.sol"; // Importa o contrato Counter a ser implantado
// O script de implantação herda o contrato Script
contract CounterScript is Script {
// Função opcional, chamada antes de cada função ser executada
function setUp() public {}
// A função run() é chamada ao implantar o contrato
function run() public {
vm.startBroadcast(); // Começa a gravar chamadas e criações de contratos no script
new Counter(); // Cria o contrato
vm.stopBroadcast(); // Termina a gravação
}
}
O script de implantação do Foundry é um contrato inteligente escrito em Solidity, que, embora não seja implantado, segue a especificação Solidity. Você pode executar o script e implantar o contrato com forge script
.
forge script script/Counter.s.sol:CounterScript
Principalmente composto por casos de teste do contrato
Diretório test
./test/Counter.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol"; // Importa a dependência de teste do forge-std
import "../src/Counter.sol"; // Importa o contrato de negócios a ser testado
// Implementa casos de teste com base na dependência de teste do forge-std
contract CounterTest is Test {
Counter public counter;
// Inicializa o caso de teste
function setUp() public {
counter = new Counter();
counter.setNumber(0);
}
// Baseado no caso de teste inicializado
// Afirma que o retorno do número do contador após o incremento é igual a 1
function testIncrement() public {
counter.increment();
assertEq(counter.number(), 1);
}
// Baseado no caso de teste inicializado
// Executa teste diferencial
// Durante o teste do forge
// Passa diferentes valores uint256 x como parâmetros para a função testSetNumber
// Testa a função setNumber do contador para definir diferentes números para x
// Afirma que o retorno de number() é igual ao parâmetro x do teste diferencial
function testSetNumber(uint256 x) public {
counter.setNumber(x);
assertEq(counter.number(), x);
}
// Teste diferencial: consulte https://book.getfoundry.sh/forge/differential-ffi-testing
}
No diretório do projeto, execute forge build
para completar a construção
$ forge build
[⠒] Compilando...
[⠢] Compilando 10 arquivos com 0.8.17
[⠰] Solc 0.8.17 terminou em 1.06s
Execução do compilador bem-sucedida
Após a construção, execute forge test
para completar o teste
$ forge test
[⠢] Compilando...
Nenhum arquivo alterado, compilação pulada
Executando 2 testes para test/Counter.t.sol:CounterTest
[PASS] testIncrement() (gas: 28312)
[PASS] testSetNumber(uint256) (execuções: 256, μ: 27609, ~: 28387)
Resultado do teste: ok. 2 passaram; 0 falharam; terminado em 9.98ms
Até aqui, você completou o processo de começar a usar Foundry e inicializou um projeto.
Principalmente introduzindo o uso do Foundry Cast, usando Cast na linha de comando para alcançar o efeito do Ethereum (ETH) Blockchain Explorer.
Pratique os seguintes objetivos
- Consultar blocos
- Consultar transações
- Decodificar transações
- Gerenciamento de contas
- Consulta de contratos
- Interação com contratos
- Decodificação de codificação
- Simulação de transações na cadeia local
# $RPC_MAIN substituído pelo endereço RPC necessário
cast block-number --rpc-url=$RPC_MAIN
Resultado da saída:
15769241
Definindo a variável de ambiente
ETH_RPC_URL
como--rpc-url
, você não precisa adicionar--rpc-url=$RPC_MAIN
em cada comando de linha. Aqui, eu configurei diretamente para a rede principal.
# cast block <BLOCK> --rpc-url=$RPC_MAIN
cast block 15769241 --rpc-url=$RPC_MAIN
# Formatar
cast block 15769241 --json --rpc-url=$RPC_MAIN
Resultado da saída:
baseFeePerGas 22188748210
difficulty 0
extraData 0x
gasLimit 30000000
gasUsed 10595142
hash 0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543
logsBloom 0x1c6150404140580410990400a61d01e30030b00100c2a6310b11b9405d012980125671129881101011501d399081855523a106443aef3ab07148626315f721550290981058030b2af90b213961204c6103d2002a076c9e12d0800475b8231f0d06a20100da57c60aa0c008280128284418503340087c8650104c34500c18aa1c2070878008c21c64207d1424000244811415afc507640448122060644c181204ba412f0af11365020880508105551226004c0801c1840183003a42062a5a2444c13266020c00081440008038492740a8204a0c6c050a29d52405b92e4b20f028a97a604c6b0849ca81c4d06009258b4206217803a168824484deb8513242f082
miner 0x4675C7e5BaAFBFFbca748158bEcBA61ef3b0a263
mixHash 0x09b7a94ef1d6c93caaff49ca8bf387652e0e33e116076b61f4d5ee79f0b91f92
nonce 0x0000000000000000
number 15769241
parentHash 0x95c60d89f2275a6a7b1a9545cf1fb6d8c614402cd7311c82bc7972c177f7812d
receiptsRoot 0xe0240d60c448387123e412114cd0165b2af7b926d34bb824f8c544b022aa76f9
sealFields []
sha3Uncles 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
size 149912
stateRoot 0xaa3e9d839e99c4791827c81df9c9129028a320432920205f191e3fb261d0951c
timestamp 1666026803
totalDifficulty 58750003716598352816469
transactions: [
0xc4f5c10e4419698edaf7431df464340b389e4b79db959d58f42e82e8d1ed18ae
0xb90edeacf833ac6cb91a326c775ed86d8047a467404bd8c69782d2260983eaad
0x6f280650e35238ab930c9a0f3163443fffe2efedc5b553f408174d4bcd89cd8d
0x2e0eafea64aaf2f53240a16b11a4f250ba74ab9ca5a1a90e6f2a6e92185877d2
0x34f41d22ed8209da379691640cec5bfb8bf9404ad0f7264709b7959d61532343
0x7569ab5ce2d1ca13a0c65ad52cc901dfc186e8ff8800793550b97760cbe34db2
0xcdeef0ffe859fcf96fb52e22a9789295c6f1a94280df9faf0ebb9d52abefb3e7
0x00d6793f3dbdd616351441b9e3da9a0de51370174e0d9383b4aae5c3c9806c2a
0xff3daf63a431af021351d3da5f2f39a894352328d7f3df96afab1888f5a7093f
0x7938399bee5293c384831c8e5aa698cdb491d568f9ebfb6d5c946f4ef7bf7e51
0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0
0x0435d78a1b62484fbe3a7680d68ba4bdf0d692f087f4a6b70eb377421c58a5dd
0xe16d1fa4d60cca7447850337c63cdf7b888318cc1bbb893b115f262dc01132d7
0x44af4f696dcfedee682d7e511ad2469780443052565eea731b86b652a175c05e
0xe88732f92ac376efb6e7517e66fc586447e0d065b8686556f2c1a7c3b7a519ce
0x7ee890b096e97fc0c7e3cf74e0f0402532e0f3b8fa0e0c494d3d691d031f57e7
...]
# Semelhante ao provider.getTransaction do ethersjs
# cast tx <HASH> [FIELD] --rpc-url=$RPC
# Semelhante ao provider.getTransactionReceipt do ethersjs
# cast receipt <HASH> [FIELD] --rpc-url=$RPC
cast tx 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0 --rpc-url=$RPC
cast receipt 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0 --rpc-url=$RPC
# Para obter apenas os logs
cast receipt 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0 logs --rpc-url=$RPC
Resultado da primeira linha de comando:
blockHash 0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543
blockNumber 15769241
from 0x9C0649d7325990D98375F7864eA167B5EAdCD46a
gas 313863
gasPrice 35000000000
hash 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0
input 0x38ed173900000000000000000000000000000000000000000000000332ca1b67940c000000000000000000000000000000000000000000000000000416b4849e6ba1475000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a00000000000000000000000000000000000000000000000000000000634d91c1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000097be09f2523b39b835da9ea3857cfa1d3c660cbb0000000000000000000000001bbf25e71ec48b84d773809b4ba55b6f4be946fb
nonce 14
r 0x288aef25af73a4d1916f8d37107ef5f24729a423f23acc38920829c4180fe794
s 0x7644d26a91da02ff1e774cc821febf6387b8ee9f3e3085140b781819d0d8ede0
to 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
transactionIndex 10
v 38
value 0
Resultado da segunda linha de comando:
blockHash 0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543
blockNumber 15769241
contractAddress
cumulativeGasUsed 805082
effectiveGasPrice 35000000000
gasUsed 114938
logs [{"address":"0x97be09f2523b39b835da9ea3857cfa1d3c660cbb","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a","0x000000000000000000000000f848e97469538830b0b147152524184a255b9106"],"data":"0x00000000000000000000000000000000000000000000000332ca1b67940c0000","blockHash":"0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543","blockNumber":"0xf09e99","transactionHash":"0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0","transactionIndex":"0xa","logIndex":"0x2","removed":false},{"address":"0x1bbf25e71ec48b84d773809b4ba55b6f4be946fb","topics":["0x06b541ddaa720db2b10a4d0cdac39b8d360425fc073085fac19bc82614677987","0x000000000000000000000000f848e97469538830b0b147152524184a255b9106","0x000000000000000000000000f848e97469538830b0b147152524184a255b9106","0x0000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a"],"data":"0x0000000000000000000000000000000000000000000000044b0a580cbdcfc0d90000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","blockHash":"0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543","blockNumber":"0xf09e99","transactionHash":"0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0","transactionIndex":"0xa","logIndex":"0x3","removed":false},{"address":"0x1bbf25e71ec48b84d773809b4ba55b6f4be946fb","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000f848e97469538830b0b147152524184a255b9106","0x0000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a"],"data":"0x0000000000000000000000000000000000000000000000044b0a580cbdcfc0d9","blockHash":"0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543","blockNumber":"0xf09e99","transactionHash":"0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0","transactionIndex":"0xa","logIndex":"0x4","removed":false},{"address":"0xf848e97469538830b0b147152524184a255b9106","topics":["0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1"],"data":"0x00000000000000000000000000000000000000000000213ebfba613ffdcdd6ad0000000000000000000000000000000000000000000018b4b7f855bdcaac3b14","blockHash":"0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543","blockNumber":"0xf09e99","transactionHash":"0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0","transactionIndex":"0xa","logIndex":"0x5","removed":false},{"address":"0xf848e97469538830b0b147152524184a255b9106","topics":["0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822","0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d","0x0000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a"],"data":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000332ca1b67940c00000000000000000000000000000000000000000000000000044b0a580cbdcfc0d90000000000000000000000000000000000000000000000000000000000000000","blockHash":"0x016e71f4130bac96a20761acbc0ba82a77c26f85513f1661adfd406d1c809543","blockNumber":"0xf09e99","transactionHash":"0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0","transactionIndex":"0xa","logIndex":"0x6","removed":false}]
logsBloom 0x00200000000000000000000080000000000000000000000000010000000008000000000000800000000000000000000000000000002000000000000000000000000000000000000000000008000000200000000000000000000000400000100000000000800000002000000000000000000000400000000000010000000000000000000000000005000000000040000000000000000080000004004000000000000084100000000000000000000000000000040000000000000000000040000000002000000000000000000000000000000000000001000002000000020000000000000000000000000000000000000004000000000000000000000000000
root
status 1
transactionHash 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0
transactionIndex 10
type 0
Cast pode decodificar o nome do método a partir do Ethereum Signature Database.
# cast 4byte <SELECTOR> para decodificar o nome da transação
cast 4byte 0x38ed1739
Resultado da saída:
swapExactTokensForTokens(uint256,uint256,address[],address,uint256)
Usando Keccak-256 para calcular o nome do método O seletor de função é os primeiros 4 bytes do hash Keccak-256 do protótipo da função[1]. Isso permite que a EVM identifique a função a ser chamada com precisão.
Assinatura da transação:
# cast sig <SIG>
cast sig "swapExactTokensForTokens(uint256,uint256,address[],address,uint256)"
Resultado da saída:
0x38ed1739
Portanto, você pode ver que o resultado final é 0x38ed1739
Alguns nomes de métodos podem não estar disponíveis, você pode carregar a assinatura para o Ethereum Signature Database usando cast upload-signature <SIG>
.
# Obter calldata
cast tx 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0 input --rpc-url=$RPC
# Pode usar este método para decodificar os dados da transação, semelhante ao método de decodificação do etherscan
# cast pretty-calldata <CALLDATA>
cast pretty-calldata 0x38ed173900000000000000000000000000000000000000000000000332ca1b67940c000000000000000000000000000000000000000000000000000416b4849e6ba1475000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a00000000000000000000000000000000000000000000000000000000634d91c1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000097be09f2523b39b835da9ea3857cfa1d3c660cbb0000000000000000000000001bbf25e71ec48b84d773809b4ba55b6f4be946fb
Resultado da saída:
Métodos possíveis:
- swapExactTokensForTokens(uint256,uint256,address[],address,uint256)
------------
[0]: 00000000000000000000000000000000000000000000000332ca1b67940c0000
[1]: 00000000000000000000000000000000000000000000000416b4849e6ba14750
[2]: 00000000000000000000000000000000000000000000000000000000000000a0
[3]: 0000000000000000000000009c0649d7325990d98375f7864ea167b5eadcd46a
[4]: 00000000000000000000000000000000000000000000000000000000634d91c1
[5]: 0000000000000000000000000000000000000000000000000000000000000002
[6]: 00000000000000000000000097be09f2523b39b835da9ea3857cfa1d3c660cbb
[7]: 0000000000000000000000001bbf25e71ec48b84d773809b4ba55b6f4be946fb
# Uso: cast run --rpc-url <URL> <TXHASH>
cast run 0x20e7dda515f04ea6a787f68689e27bcadbba914184da5336204f3f36771f59f0
Resultado da execução:
No resultado, você pode ver o gás consumido pela execução, bem como o processo de chamada de métodos e os eventos emitidos. Isso permite entender o processo interno de um hash. Ferramentas como BlockSec Building BlockChain Security Infrastructure e Tenderly | Ethereum Developer Platform podem ser usadas em conjunto para análise.
# Criar uma nova conta
# cast wallet new [OUT_DIR]
cast wallet new
# Criar uma nova conta keystore com senha
# cast wallet new <PATH>
cast wallet new ~/Downloads
Resultado da primeira linha de comando:
Successfully created new key pair.
Address: 0xDD20b18E001A80d8b27B8Caa94EeAC884D1c****
Private Key: edb4444199bddea91879c0214af27c0c7f99****bf18e46ba4078a39ccdbe0bc
Resultado da segunda linha de comando:
Enter secret:
Created new encrypted keystore file: `/Users/EasyPlux/Downloads/b5832df5-21e9-4959-8c85-969eec9c0***`\nPublic Address of the key: 0x58c1C8f6A7D92A9b20A5343949cd624570Ab****
# Duas maneiras de assinar, a primeira carregando a chave privada do keystore criado anteriormente, a segunda inserindo diretamente sua própria chave privada.
cast wallet sign <MESSAGE> --keystore=<PATH>
cast wallet sign <MESSAGE> -i
cast wallet verify --address <ADDRESS> <MESSAGE> <SIGNATURE>
cast etherscan-source <endereço do contrato>
cast etherscan-source 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --etherscan-api-key='chave'
#cast etherscan-source -d <caminho>
# Aqui, já inseri o endereço $WETH na variável de ambiente, se não tiver feito isso, pode usar o endereço do contrato diretamente
cast etherscan-source $WETH -d ~/Downloads
Chamando o método balanceOf
do contrato WETH, para verificar o saldo da conta 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
#cast call [OPÇÕES] [PARA] [ASSINATURA] [ARGS]... [COMANDO] --rpc-url=$RPC
cast call $WETH "balanceOf(address)" 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --rpc-url=$RPC
# Saída
# 0x0000000000000000000000000000000000000000000000230d12770f2845219c
# Formatar saída adicionando um formato de retorno ao parâmetro
cast call $WETH "balanceOf(address)(uint256)" 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --rpc-url=$RPC
# Saída
# 646577988758891995548
Com base na ABI, é possível reverter para o código Solidity
# cast interface [OPÇÕES] <CAMINHO_OU_ENDEREÇO>
cast interface ./weth.abi
cast --to-hex
cast --to-dec
cast --to-unit
cast --to-wei
cast --to-rlp
cast --from-rlp
Definindo a variável de ambiente ETH_RPC_URL
como --rpc-url
, você não precisa adicionar --rpc-url=$RPC_MAIN
em cada comando de linha. Aqui, configurei diretamente para a rede principal.
Definindo a variável de ambiente ETHERSCAN_API_KEY
, você pode substituir diretamente --etherscan-api-key
.
Adicionando --json
pode formatar a saída
cast block 15769241 --json --rpc-url=$RPC_MAIN
Anvil, assim como Hardhat e Ganache do Truffle, é um nó Ethereum local, que também possui funcionalidades de fork.
anvil
anvil --accounts=<NUM> --balance=<NUM>
anvil --mnemonic=<MNEMONIC>
anvil --fork-url=$RPC --fork-block-number=<BLOCK>
anvil_* -> hardhat_*
anvil_impersonateAccount
anvil_setStorageAt
Código localizado em WTFSolidity/Topics/Tools/TOOL07_Foundry/hello_wtf
Estrutura do diretório de código:
.
├── broadcast
│ └── Counter.s.sol
├── foundry.toml # Arquivo de configuração do foundry
├── lib
│ └── forge-std
├── node_modules # Diretório de pacotes npm, também pode usar forge install
│ └── @openzeppelin
├── package-lock.json
├── package.json
├── script
│ └── Counter.s.sol # Contrato de script
├── src
│ └── Counter.sol
└── test
├── Counter.t.sol
└── Test.t.sol # Contrato de teste
forge init <nome_dir>
# Inicializar projeto com template
forge init --template <caminho_template> <nome_dir>
forge build -w
# Três vs mostram informações detalhadas de log, incluindo rastreamento de pilha de erros de testes falhos
forge test -vvv
# Quatro vs mostram rastreamento de pilha de todos os testes e rastreamento de configuração de testes falhos
forge test -vvvv
# Modo de atualização em tempo real
forge test -vvv -w
# Para imprimir logs, é necessário -vv ou mais
Usando console2.log("teste")
para imprimir:
function testSetNumber(uint256 x) public {
console2.log("testNumber: %s==============", x);
counter.setNumber(x);
assertEq(counter.number(), x);
}
Usando emit log
para imprimir:
function testNumberIs42() public {
emit log("teste");
assertEq(testNumber, 42);
}
Alterar block.timestamp
:
function testCheatCode()public {
console2.Log("antes:", block.timestamp);
vm.warp(1000);
console2.log("depois:", block.timestamp);
}
Alterar msg.sender
(pode simular conta de administrador):
// Apenas a primeira vez tem efeito
vm.prank(address)
// Efeito múltiplo
vm.startPrank(address)
...código
vm.stopPrank()
Alterar saldo da conta (também pode ser usado para alterar o saldo da maioria dos tokens ERC20):
function testCheatCode()public{
console2.Log("antes:", alice.balance);
vm.deal(alice,1 ether);
console2.Log("depois:", alice.balance);
}
forge install [OPÇÕES] <usuário_github>/<projeto_github>@<tag>
npm init -y
npm i @openzeppelin/contracts
// yarn add @openzeppelin/contracts
Após a instalação, é necessário configurar o foundry.toml
para incluir o diretório node_modules
nas bibliotecas.
[profile.default]
src = 'src'
out = 'out'
libs = ['lib','node_modules']
forge test --gas-report
# Obter informações relacionadas ao contrato, como abi, bytecode, etc.
forge inspect <CONTRATO> <CAMPO>
# Gerar snapshot de gas
forge snapshot
# Comparar o arquivo de snapshot atual com as últimas alterações para verificar se o gas foi reduzido
forge snapshot --diff
# Debugger interativo
forge script script/Counter.s.sol --debug
# Debugger de transações na cadeia
forge run --debug
Nesta palestra, introduzimos ferramentas de desenvolvimento centradas em Solidity e mostramos como usar o Foundry para compilar, implantar e testar contratos inteligentes. Como os scripts de implantação e teste do Foundry são escritos em Solidity, isso elimina a necessidade de os desenvolvedores aprenderem JavaScript, economizando tempo e oferecendo mais oportunidades para praticar Solidity. Recomendamos que todos experimentem.
Usando o framework Foundry para acelerar o desenvolvimento de contratos inteligentes Comandos cast - Foundry Book https://twitter.com/wp__lai