
Foundry类似于cargo或npm。
参考文献:https://www.hackquest.io/
关键词
- pass,表示测试通过
Foundry介绍
Foundry 是一个 Solidity 框架,用于构建、测试、模糊、调试和部署Solidity 智能合约。
Foundry 用 Rust 语言编写,包含了一系列的可以与 Ethereum 网络交互的工具。主要有:
Forge 用来进行合约的测试。
Cast 很方便的与合约进行交互,发交易,查询链上数据。
Anvil 可以模拟一个私有节点。
Chisel 可以在命令行快速的有效的实时的写合约,测试合约。
OTHER INFO
基于rust。
FORGE
项目管理工具,类似于npm。
forge init PROJECT_NAME
项目初始化。创建一个项目。
项目目录结构
1 | D:\foundry_test\hello_foundry>tree |
forge build
编译合约。默认输出到out文件夹。
forge test
测试合约。测试用例。
用法
- forge test: 测试test下所有合约;
- forge test –match-path test/Counter.t.sol:指定要测试的文件夹。
- forge test –match-contract CounterTest –match-test test_Increment 命令,用 –match-contract 来指定测试合约的名称,其中 –match-test 用来指定调用的测试方法。
-v
/-vv
/-vvv
/-vvvv
:打印日志级别,v越多表示级别越高。- vv:打印日志,断言,预期结果,错误原因;
- vvv:打印测试失败的失败堆栈调用
- vvvv:打印所有的堆栈调用
- vvvvv:包括以上所有,另外包含对象的创建等信息。
--watch
:监听文件更改,文件一旦更改就运行测试。--run-all
:与watch一起用,当文件更改就重新运行所有测试。
基本要求
1 | pragma solidity 0.8.10; |
- setUp为初始化方法。
- 对于方法名:
- 测试方法必须以test作为开头,而且有分类:
以test开头
:这个方法的要求是要执行成功,也就是没有报错;以testFail开头
:这个方法的要求是要执行失败,也就是有报错;
- 测试方法必须以test作为开头,而且有分类:
- 所有的测试方法必须有
external
或public
。声明为internal
或private
的方法不会被forge处理。
修改要求的测试结果
1 | function test_CannotSubtract43() public { |
作为uint的testNumber执行后会变成负数,会报错,这是本来的流程。
这个方法以test开头,但vm.expectRevert(stdError.arithmeticError);
修改了pass的条件,含义为“期待出现arithmeticError”,也就是这里“如果出现arithmeticError,则pass,与testFail
功能类似。
打印测试日志
console2.log
:与printf的使用方法一致。
forge create/合约部署
合约部署和验证。也可以用solidity-scripting来实现,不过这里不介绍。
准备
部署:测试币账号、区块链节点的RPC_URL;
验证:区块链浏览器的ETHERSCAN_API_KEY
准备获取
RPC_URL:可以从Alchemy获取。
ETHERSCAN_API_KEY:在以太坊区块链浏览器中创建 app,会分配对应的 API KEY TOKEN。
EXAMPLE
部署一个ERC20合约为例。合约只有一个构造函数,用来指定Token的名称、标识符、精度及初始发行量信息。
1 | // SPDX-License-Identifier: UNLICENSED |
需要安装包transmissions11/solmate。forge install transmissions11/solmate
部署
1 | forge create \ |
RPC_URL: 即RPCURL
private-key: 钱包私钥
verify: 验证合约
- MyContract:实际部署的合约。
constructor-args: 可选,构造函数参数。
–broadcast 部署到网络中。
forge verify-contract/验证合约
1 | forge verify-contract \ |
基本信息:
-
the_contract_address:合约地址。
: :合约源码的路径及合约名称,如果合约文件中包含多个合约,需要使用 :MyContract 这种方式指定具体的合约。 - etherscan-api-key:区块链浏览器的 API KEY TOKEN,用于验证合约。
以及部署合约时的环境信息:
- constructor-args:合约构造器的参数,以 ABI-encoded 形式提供,如果没有构造器参数,该属性可忽略。
- compiler-version:合约编译器版本。如果没有指定则会自动检测。
- num-of-optimizations:Solidity 编译器在进行优化时迭代运行的次数。请注意,如果在验证时未设置优化次数,则默认为 0,而如果在部署时未设置,则默认为 200,因此,如果保留默认编译设置,需要使用–num-of-optimizations 200 来确保验证通过。
- chain-id:测试网的ID,sepolia 测试网为 11155111。
- watch:用于查询验证结果。
solidity-scripting 更方便的部署与验证
forge create输入的参数过多,可以使用脚本更方便的进行部署合约。(注意不是js)
简述:使用solidity写一个Script:从环境变量中取参数,然后部署到区块链中。
- 首先创建
.env
。(我以为这个.env可以自动输入,直到后面的教程居然来了句source .env
,我可去,这个操作可以的,只是我没想到居然这样)*****
的
1 | // 区块链 RPC 节点地址 |
- source一下。
- 编辑foundry.toml,这里可以使用环境变量。
1 | [rpc_endpoints] |
- 创建一个脚本(==script==)。在script文件夹下,创建一个MyToken.s.sol文件,输入以下内容。
1 | // SPDX-License-Identifier: UNLICENSED |
- 运行脚本
1 | # 加载 .env 文件中的变量 |
接下来会打印部署结果,以及部署的合约地址。
CAST
基本介绍
cast是Foundry用于执行以太坊RPC调用的命令行工具,可以使用Cast进行智能合约的调用、发送交易或检索链数据。
1 | cast <subcommand> |
EXAMPLE
比如cast获取代币的总供应量.
1 | cast call 0x6b175474e89094c44da98b954eedeac495271d0f "totalSupply()(uint256)" --rpc-url <your rpc url> 8603853182003814300330472690 |
使用cast发送消息.
1 | cast send --private-key <Your Private Key> 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc $(cast from-utf8 "hello world") --rpc-url http://127.0.0.1:8545/ |
获取链上信息
首先要设定环境变量ETH_RPC_URL
,然后执行以下命令即可。
cast chain-id
: 获取当前链的IDcast chain
: 获取当前链的名称cast client
获取当前客户端版本cast gas-price
获取当前的gas价格cast block-number
获取当前最新的区块号cast basefee
获取指定区块的基础费用cast block <BLOCK ID>
:获取指定区块的详细信息。区块高度,时间戳,交易数等。cast age
:获取指定区块的具体时间。
获取账户信息
cast balance <ADDRESS | ENS_NAME.eth>
ADDRESS:地址。
ENS_NAME.eth: ENS名称。
可以通过地址或者ENS名称查询账户余额。
发送交易
发送交易/调用合约函数
1 | cast send --private-key <private_key_addr> <contract_addr> "exampleFunc(uint256)" <argument_value_of_the_function> |
EXAMPLE
存款函数
1 | cast send --private-key PRIVATE_KEY CONTRACT_ADDR "deposit(uint256)" 10 |
其他
如果出现不存在的函数,则会触发fallback函数: cast send --private-key <private_key_addr> <contract_addr> "dummy()"
可以触发receive函数:cast send --private-key <private_key_addr> <contract_addr> --value 10gwei
获取合约代码
1 | cast etherscan-source <contract_address> |
可以获取到智能合约的源代码。