Foundry 工具使用的全面指南

Foundry是一个专为以太坊智能合约开发设计的快速、现代化的工具链,集成了编译、测试、部署和调试等功能。它用Rust编写,性能卓越,已成为Solidity开发者的首选工具之一。

Foundry 是一个专为以太坊智能合约开发设计的快速、现代化的工具链,集成了编译、测试、部署和调试等功能。它用 Rust 编写,性能卓越,已成为 Solidity 开发者的首选工具之一。 Foundry 中文文档

一、核心组件介绍

Foundry 由四个主要工具组成:

1. Forge 用来进行合约的测试

Forge 是 Foundry 附带的命令行工具。 Forge 可用来测试、构建和部署你的智能合约。

  • 智能合约编译、测试和部署工具
  • 支持 Solidity 和 Vyper
  • 内置 fuzzing 测试功能(随机输入测试)

日志和跟踪 forge test 的默认行为是只显示通过和失败测试的摘要。 你可以通过增加详细程度(使用-v标志)来控制此行为。 每个详细级别都会添加更多信息:

  • 级别 2 (-vv):还会显示测试期间发出的日志。 这包括来自测试的断言错误,显示诸如预期与实际结果等之类的信息。
  • 级别 3 (-vvv):还显示失败测试的堆栈跟踪。
  • 级别 4 (-vvvv):显示所有测试的堆栈跟踪,并显示失败测试的设置(setup)跟踪。
  • 级别 5 (-vvvvv):始终显示堆栈跟踪和设置(setup)跟踪。

Watch模式 当你使用forge test --watch对文件进行更改时,Forge 可以重新运行你的测试。

默认情况下,仅重新运行更改的测试文件。 如果你想重新运行更改的所有测试,你可以使用 forge test --watch --run-all

2. Cast 与合约交互,发交易、查询链上数据

  • 命令行工具,用于与区块链交互
  • 发送交易、调用合约、查询链上数据
  • 支持 JSON-RPC 和 EIP-1193 标准

3. Anvil 模拟私有节点

  • 本地以太坊测试网络(类似 Ganache)
  • 支持快速区块生成、账户预充值
  • 可模拟链上环境进行测试

4. Chisel 交互式 Solidity REPL

  • 可以在命令行快速的有效的实时的写合约,测试合约。
  • 实时测试 Solidity 表达式和合约

二、安装与初始化

Foundryup 是 Foundry 工具链的官方安装程序。 要安装 Foundryup,打开终端并运行以下命令:

curl -L https\://foundry.paradigm.xyz | bash

运行 foundryup 将自动安装最新的版本的 预编译二进制文件forgecastanvil 和 chisel

foundryup  # 安装或更新 Foundry 工具链

三、forge 概述

我们可以使用 Forge 命令行工具,并用它来创建、编译、测试合约项目。

1. 创建新项目: forge init

forge init hello_foundry

项目结构:

$ cd hello_foundry
$ tree -L 2
.
├── README.md
├── foundry.toml
├── lib
│   └── forge-std
├── script
│   └── Counter.s.sol
├── src
│   └── Counter.sol
└── test
    └── Counter.t.sol

6 directories, 5 files
  • src:智能合约目录

  • script :部署脚本文件

  • lib: 依赖库目录

  • test:智能合约测试用例文件夹

  • foundry.toml:配置文件,配置连接的网络URL 及编译选项。

2. 编译项目:forge build

$ forge build
Compiling 27 files with Solc 0.8.19
Solc 0.8.19 finished in 1.08s
Compiler run successful!

如果 foundry.toml 文件未指定 Solc 编译器版本,则默认使用最新的版本。编译好的文件(合约ABI,bytecode ),会放在out的文件夹中。

3. 运行测试:forge test

$ forge test
No files changed, compilation skipped

Ran 2 tests for test/Counter.t.sol:CounterTest
[PASS] testFuzz_SetNumber(uint256) (runs: 256, μ: 30977, ~: 31288)
[PASS] test_Increment() (gas: 31303)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.10ms (7.84ms CPU time)

Ran 1 test suite in 9.41ms (8.10ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)

out 目录包含你的合约工件(artifact,例如 ABI,而 cache 目录被 forge 使用来(记录),以便仅仅去重新编译那些必要编译的内容。

关于测试的一些约定:

  • 测试用例位于test包下,通常使用***.t.sol为结尾来命名测试文件。
  • 测试方法的命名,是由test_ 为前缀,后面遵循驼峰命名法。
  • 继承 forge-std 标准库下的 Test.sol 合约来编写测试用例。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Test, console} from "forge-std/Test.sol";
import {Counter} from "../src/Counter.sol";

contract CounterTest is Test {
    Counter public counter;

    function setUp() public {
        counter = new Counter();
        counter.setNumber(0);
    }

    function test_Increment() public {
        counter.increment();
        assertEq(counter.number(), 1);
    }

    function testFuzz_SetNumber(uint256 x) public {
        counter.setNumber(x);
        assertEq(counter.number(), x);
    }
}

其中的 setUp 函数用于测试前的初始化:创建新合约并为状态变量赋初始值;test_xxx 为被 forge 自动调用的测试函数,assertEq 用来断言修改后的状态变量跟预期值相等,当然还有 assertNotEq 函数用来断言两个数不相等。

4. 部署

Forge 使用  forge create 命令可以部署&验证合约到指定网络,部署时可以完全使用命令行来实现,也可以使用 solidity-scripting 的方式实现。

命令行部署

forge create --rpc-url <your_rpc_url> --private-key <your_private_key> --verify src/MyContract.sol:MyContract --constructor-args <constructor_args>

rpc-url: 即区块链节点 RPC,例如:https://eth-sepolia.g.alchemy.com/v2/xxxxxxxxx

  • private-key: 即钱包私钥,建议创建专门用来开发测试的新钱包。

  • etherscan-api-key: 即区块链浏览器的 API KEY TOKEN,用于验证合约。

  • verify: 验证合约,即在浏览器中开源合约的代码

  • MyContract: 实际部署的合约,由于一个 solidity 中允许存在多个合约,因此这里指定需要部署的合约名称。

  • constructor-args: 合约的构造参数,如果没有,可以不设置该属性

执行结果中会打印出部署的交易 hash 、部署的合约地址以及验证状态:

> forge create --rpc-url https://eth-sepolia.g.alchemy.com/v2/xxxxxx \ 
   --constructor-args "MyToken" "MT" 18 1000000000000000000000  \ 
   --private-key 0xxxxxxx  \ 
   --etherscan-api-key xxxx  \ 
   --verify
   src/MyToken.sol:MyToken

[⠊] Compiling...
No files changed, compilation skipped
Deployer: 0x5CB8896Db7Bf13DE6A6EA362866288e577e4F6C5
Deployed to: 0x9C7DcF024b94d14FFaA04262139f92F3AA837919
Transaction hash: 0x18ac7e8824b1fe19ab79977ec7672f8e8324f621fef01a7c8d971fca152748b8
Starting contract verification...
Waiting for etherscan to detect contract deployment...
Start verifying contract `0x9C7DcF024b94d14FFaA04262139f92F3AA837919` deployed on sepolia

Contract [src/MyToken.sol:MyToken] "0x9C7DcF024b94d14FFaA04262139f92F3AA837919" is already verified. Skipping verification.

脚本部署

通过 forge create 命令进行合约的部署&验证需要输入的参数较多,更推荐的做法是使用 solidity-scripting,它是一种使用 Solidity 以声明方式部署合约的方法,而不是 Javascript。

1.创建 .env 文件保存隐私信息(如:节点 RPC、私钥等),.env 文件应遵循以下格式:

1// 区块链 RPC 节点地址
2SEPOLIA_RPC_URL=xxxx
3// 钱包私钥
4PRIVATE_KEY=xxxx
5// 区块链浏览器的 API KEY TOKEN
6ETHERSCAN_API_KEY=xxxx

2.编辑 foundry.toml 文件,将以下行添加到文件末尾,这里指定了 .env 中配置的变量。

1[rpc_endpoints]
2sepolia = "${SEPOLIA_RPC_URL}"
3
4[etherscan]
5sepolia = { key = "${ETHERSCAN_API_KEY}" }

3.创建测试脚本。项目根目录中创建一个文件夹并将其命名为 script,并在其中创建一个名为 MyToken.s.sol 的文件,这是我们将创建部署脚本的地方。如下:

1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.25;
3
4import {Script} from "forge-std/Script.sol";
5import "../src/MyToken.sol";
6
7contract MyTokenScript is Script {
8
9    function run() external {
10        uint256 deployer = vm.envUint("PRIVATE_KEY");
11
12        vm.startBroadcast(deployer);
13        
14        MyToken myToken = new MyToken("MyToken", "MT", 18, 1000000000000000000);
15        vm.stopBroadcast();
16    }
17}

这个部署脚本本身就是一个智能合约,因此它就像任何其他用 Solidity 编写的智能合约一样,必须指定 pragma version。同时,继承 Forge 标准库中的 Script 合约 contract MyTokenScript is Script ,默认情况下,脚本是通过调用名为 run 的函数(我们的入口点)来执行的。

在项目的根目录执行以下命令:

# 加载 .env 文件中的变量
2source .env
3
4# 部署并验证合约
5forge script script/MyToken.s.sol:MyTokenScript --rpc-url $SEPOLIA_RPC_URL --broadcast --verify -vvvv

Forge 将运行我们的脚本并为我们广播交易——这可能需要一些时间,因为 Forge 还将等待交易收据。 大约一分钟后,您应该会看到类似这样的内容,包含了合约的部署地址、gas 消耗、交易 hash 以及验证结果等。

四、Cast 概述

Cast 是 Foundry 用于执行以太坊 RPC 调用的命令行工具。 你可以进行智能合约调用、发送交易或检索任何类型的链数据——所有这些都来自你的命令行!

要使用 Cast,请在命令行工具运行 cast 命令,然后运行子命令:

1$ cast <subcommand>

例子

比如我们可以使用 cast 来获取 DAI 代币的总供应量:

1
2cast call 0x6b175474e89094c44da98b954eedeac495271d0f "totalSupply()(uint256)" --rpc-url <your rpc url> 8603853182003814300330472690

结果会输出:

13214023094757495931935215279 [3.214e27]

我们可以使用 cast 发送任意消息。 下面是在两个帐户之间发送消息的示例。

1cast send --private-key <Your Private Key> 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc $(cast from-utf8 "hello world") --rpc-url http://127.0.0.1:8545/

获取链上基础信息

获取当前链的 ID

cast chain-id
21(0x1)

获取当前链的名称

cast chain
2ethlive

获取当前客户端的版本

cast client
5Geth/v1.13.13-stable-7f131dcb/linux-amd64/go1.21.7

获取当前 gas 价格

cast gas-price
210325245432

获取区块信息

查询最新的区块号

cast block-number
219732815

获取指定区块的基础费用

cast basefee
211721855264

获取到指定区块的详细信息,如区块高度、时间戳、交易数等。

cast block 12345678
2{
3  "number": "12345678",
4  "timestamp": "1618304000",
5  "transactions": "210",
6  "miner": "0x..."
7  ......
8}

获取指定区块的时间戳

cast age
2Thu Apr 25 13:59:47 2024

获取账户信息

获取特定以太坊账户地址或 ENS 名称的当前余额,单位是 wei。这个命令是日常区块链操作中经常使用的,无论是在开发智能合约、执行交易前的检查,还是简单地监控账户状态。

cast balance 0x123...

使用 ENS 名称查询余额

cast balance vitalik.eth

发送交易

使用 Cast 工具可以发送交易,并与已部署在以太坊链上的智能合约进行交互。掌握这些技能对于智能合约开发者来说至关重要,它允许你执行合约函数、触发合约的 fallback 和 receive 函数。

调用合约上的任何函数

cast send --private-key <private_key_addr> <contract_addr> "exampleFunc(uint256)" <argument_value_of_the_function>

示例:

cast send --private-key 0x123... 0xabc... "deposit(uint256)" 10

这条命令会向地址为 0xabc... 的合约发送一个调用 deposit 函数的请求,存款金额为 10 wei。

触发 Fallback 函数 如果调用合约中不存在的函数,将自动触发 Fallback 函数。这可以用于测试合约的异常处理或特定的功能。

cast send --private-key <private_key_addr> <contract_addr> "dummy()"

示例:

cast send --private-key 0x123... 0xabc... "dummy()"

触发 Receive 函数

通过向合约发送以太币(Ether),可以触发合约的 Receive 函数。这对于接受捐款或处理支付非常有用。

cast send --private-key <private_key_addr> <contract_addr> --value 10gwei

示例: 以下命令展示了如何发送 10 gwei 的以太币到合约,触发接收函数:

cast send --private-key 0x123... 0xabc... --value 10gwei

获取合约代码

获取指定合约的源代码

cast etherscan-source <contract_address>

五、Anvil 概述

Anvil 是 Foundry 附带的本地测试网节点,专为提供一个便于本地测试和开发的以太坊节点而设计。 你可以使用它从前端测试你的合约或通过 RPC 进行交互。

使用

它是一个理想的工具,特别适合需要频繁迭代和即时反馈的开发过程。

只需在命令行中输入 anvil,它将自动启动一个本地节点。启动后,你将看到一系列已生成的开发账户和私钥,以及节点侦听的地址和端口信息。

anvil

输出:

Available Accounts
==================

(0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000.000000000000000000 ETH)
.....

Private Keys
==================

(0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae........
.....

Chain ID
==================

31337

Base Fee
==================

1000000000

Gas Limit
==================

30000000

Genesis Timestamp
==================

1714205976

Listening on 127.0.0.1:8545

基本配置

通过在命令行中执行 anvil -h,你可以查看所有 Anvil 提供的配置选项。这些选项涵盖了从账户管理到节点性能等多个方面,使得 Anvil 成为一个高度灵活和可配置的开发工具。

查看所有配置选项

anvil -h

执行此命令后,你将看到一个详细的帮助菜单,列出了所有可用的命令和参数,以及它们的用途和默认值。

生成和配置开发账户数量

默认情况下,Anvil 生成10个开发账户,但你可以通过以下命令指定生成更多或更少的账户:

anvil -a  <NUM>
          Number of dev accounts to generate and configure
          [default: 10]

设置使用的 EVM 硬分叉版本

anvil --hardfork <HARDFORK>

设置节点监听的端口号

anvil -p, --port <PORT>

例如,设置为端口8546:

anvil -p 8546

六、Chisel 概述

Chisel 是一个 Solidity REPL("读取-评估-打印 循环 "的缩写),它允许开发人员编写和测试 Solidity 代码片段。它提供了一个交互式环境,用于编写和执行 Solidity 代码,同时还提供了一组内置命令,用于处理和调试您的代码。这种工具特别适合进行快速的代码实验和问题调试。

启动

启动 Chisel 非常简单,只需在命令行中输入 chisel 即可。启动后,你可以直接在命令行中编写和测试 Solidity 代码。

chisel

常用

!help | !h

显示所有命令。

!quit | !q

退出 Chisel。

!exec <command> [args] | !e <command> [args]

执行 shell 命令并打印输出。

在 Chisel 中,你可以通过两种主要方式输入代码:表达式和语句。

表达式:

获取地址余额:

1address(0).balance

编码多个参数:

1abi.encode(256, bytes32(0), "Chisel!")

调用视图函数:

1myViewFunc(128)

语句:

语句是指那些旨在保持或修改会话状态的代码片段。这包括变量定义、不改变状态的函数调用以及合约、函数、事件、错误、映射或结构体的定义。要将表达式作为语句执行,可以在其末尾添加分号(;)。 定义变量:

1uint256 a = 0xa57b;

调用状态修改函数或多个函数:

1myStateMutatingFunc(128) || myViewFunc(128);

定义内部函数:

1function hash64(bytes32 _a, bytes32 _b) internal pure returns (bytes32 _hash) {
2  assembly {
3    // Store the 64 bytes we want to hash in scratch space
4    mstore(0x00, _a)
5    mstore(0x20, _b)
6
7    // Hash the memory in scratch space
8    // and assign the result to `_hash`
9    _hash := keccak256(0x00, 0x40)
10  }
11}

定义事件和结构体:

1event ItHappened(bytes32 indexed hash);
2struct Complex256 { uint256 re; uint256 im; }

拓展

安装 tree

brew install tree

solc

Solc(全称 Solidity Compiler)是 Solidity 编程语言的官方编译器,用于将以太坊智能合约的 Solidity 代码编译成 EVM(以太坊虚拟机)字节码,使合约能够在以太坊区块链或兼容的 EVM 链(如 BSC、Polygon 等)上部署和运行。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
mengbuluo222
mengbuluo222
0x9Ff1...FaA5
前端开发求职中... 8年+开发经验,拥有丰富的开发经验,擅长VUE、React开发。