Foundry 常用命令和作弊码速查表

Foundry 常用命令和作弊码速查表

Foundry中常用命令和作弊码的速查表。

还可以在 gist 中找到此速查表。

初始化

创建新项目

创建新项目:

forge init <project_name>

使用模板创建新项目:

forge init --template <template> <project_name>

# 例如
forge init --template https://github.com/zobront/paradigm-ctf paradigm_ctf

在现有项目中使用

初始化 Foundry:

# Create required directories
mkdir out lib

# 添加 `forge-std` 模块到 `lib`
git submodule add https://github.com/foundry-rs/forge-std lib/forge-std

# Create foundry.toml
touch foundry.toml

foundry.toml中指定目录:

[profile.default]
src = "contracts"
out = "out"
lib = "lib"

依赖项

添加依赖项

在现有项目中安装依赖项:

forge install

添加新依赖项:

forge install <dependency>

# 例如
forge install openzeppelin/openzeppelin-contracts

将依赖项添加到现有 git 存储库:

# 不生成 git commit
forge install --no-commit <dependency>

# 不生成 git 库
forge install --no-git <dependency>

重映射

Forge 可以自动推断重映射:

forge remappings > remappings.txt

要自定义重映射,只需将其添加到remappings.txt中:

echo "@openzeppelin/=lib/openzeppelin-contracts/" > remappings.txt

测试

运行测试:

forge test

日志详细程度

  • -vv 显示console.log输出。
  • -vvv 显示失败测试的执行跟踪。
  • -vvvv 显示所有测试的执行跟踪,并显示失败测试的设置跟踪。
  • -vvvvv 显示所有测试的执行和设置跟踪。

运行特定测试:

  • --match-test 运行与指定正则表达式匹配的测试。
  • --match-contract 运行与指定正则表达式匹配的合约中的测试。
  • --match-path 运行与指定路径匹配的源文件中的测试。

分叉网络测试

分叉网络:

forge test --fork-url <rpc_url>

要在分叉环境中识别合约,请使用--etherscan-api-key传递你的 Etherscan API 密钥:

forge test --fork-url <rpc_url> --etherscan-api-key <etherscan_api_key>

Cheatcodes 作弊吗码

参考作弊码参考获取所有可用作弊码。

上下文 context

// 设置 block.timestamp
vm.warp(uint256 timestamp)

// 增加指定秒数到 block.timestamp 
skip(uint256 time)

// 减少指定秒数到 block.timestamp 
rewind(uint256 time) 

// 设置 block.number
vm.roll(uint256 blockNumber)

存储和内存

// 从地址上加载槽位
vm.load(address account, bytes32 slot) 

// 写入数据到槽位
vm.store(address account, bytes32 slot, bytes32 value)

// 设置地址上的代码
vm.etch(address addr, bytes calldata code)

调用者 Caller

// 为下一次调用设置 msg.sender
vm.prank(address msgSender)

// 为之后的一系列调用设置 msg.sender 
vm.startPrank(address msgSender)

// 停止上次的设置
vm.stopPrank()

// 改变之后的一系列调用的 msg.sender 
changePrank(address msgSender) 

// 设置 msg.sender 以及为下一次调用充 ether 
hoax(address who)
hoax(address who, uint256 give)
hoax(address who, address origin)
hoax(address who, address origin, uint256 give)

// 为之后的一系列调用设置msg.sender 以及充 ether 
startHoax(address who)
startHoax(address who, uint256 give)
startHoax(address who, address origin)
startHoax(address who, address origin, uint256 give)

调用 call

// 模拟对 `where` 的调用, 如果 `data` 匹配返回 `retdata`  
vm.mockCall(address where, bytes calldata data, bytes calldata retdata);

// 和上一条类似,但有 msg.value 需要匹配 `value`
vm.mockCall(address where, uint256 value, bytes calldata data, bytes calldata retdata);

示例用法:

function testMockCall() public {
    // Without value
    vm.mockCall(
        address(token),
        abi.encodeWithSelector(token.balanceOf.selector, ALICE),
        abi.encode(10)
    );
    assertEq(token.balanceOf(ALICE), 10);

    // With value
    vm.mockCall(
        address(market),
        10 ether,
        abi.encodeWithSignature("pay(address,uint256)", ALICE, 10 ether),
        abi.encode(true)
    );
    assertTrue(market.pay{value: 10 ether}(ALICE, 10 ether));
}

回滚revert

// 期望一下一个调用revert 
vm.expectRevert()

// 期望下一个调用 revert 并抛出 `message`
vm.expectRevert(bytes calldata message)

//  期望下一个调用 revert 并抛出  `bytes4 data` 错误(用于自定义的 error selectors)
vm.expectRevert(bytes4 data)

快照

// 给当前状态快照
uint256 snapshot = vm.snapshot();

// 还原到快照
vm.revertTo(uint256 snapshot);

标准库

参考 Forge Std 的Test 获取所有功能。

余额

// 为某地址设置余额
deal(address to, uint256 balance)

// 为某地址设置 ERC20 余额
deal(address token, address to, uint256 balance)

//为某地址设置 ERC20 余额 ,如果 adjust 为 true,增加 totalSupply  
deal(address token, address to, uint256 balance, bool adjust)

// 为某地址加指定 `id`  的 ERC721 token  
dealERC721(address token, address to, uint256 id)

// 为某地址加指定 `id`  指定数量的 ERC1155 token  
dealERC1155(address token, address to, uint256 id, uint256 balance)

// 为某地址加指定 `id`  指定数量的 ERC1155 token , 如果 adjust 为 true,增加发行量  
dealERC1155(address token, address to, uint256 id, uint256 balance, bool adjust)

错误

来自 forge-std/std-errors,用于捕获内部 Solidity 错误:

  • stdError.assertionError - assert失败。
  • stdError.arithmeticError - 算术运算失败(例如溢出/下溢)。
  • stdError.divisionError - 除法失败(例如除以零)。
  • stdError.indexOOBError - 访问超出范围的数组元素。
  • stdError.popError - 从空数组中弹出。不适用于外部合约中的空数组。
  • stdError.enumConversionError - 将大于枚举变体数量的数字转换为枚举。
  • stdError.encodeStorageError - 使用内联汇编访问损坏的存储中的数据。
  • stdError.memOverflowError - 分配具有超过 2^64-1 个项目的动态内存数组。
  • stdError.zeroVarError - 通过未初始化的函数指针调用函数。

断言

来自 forge-std/std-assertions

// Fail a test with a message
fail(string memory err)

// Assert true/false
assertTrue(bool data)
assertTrue(bool data, string memory error)

assertFalse(bool data)
assertFalse(bool data, string memory err)

// 断言相等
assertEq(<type> a, <type> b)
assertEq(<type> a, <type> b, string memory err)

// Asserts `a` is approximately equal to `b` with delta in absolute value.
assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta)
assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err)

// Asserts `a` is approximately equal to `b` with delta in percentage, where `1e18` is 100%. 
assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta)
assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err)

地址和密钥

// 创建一个标签地址
address addr = makeAddr(string memory name)

// 创建一个标签地址 和私钥
(address addr, uint256 privateKey) = makeAddrAndKey(string memory name)

// 签名数据
(uint8 v, bytes32 r, bytes32 s) = vm.sign(uint256 privateKey, bytes32 digest)

数学

来自 forge-std/std-math

// 返回绝对值
uint256 v = abs(int256 a)

// 返回绝对差值
uint256 v = delta(uint256 a, uint256 b)
uint256 v = delta(int256 a, int256 b)

//  返回百分比差值, `1e18` 是 100%.
uint256 v = percentDelta(uint256 a, uint256 b)
uint256 v = percentDelta(int256 a, int256 b)

模糊测试

使用vm.assume()指定输入条件。应仅用于狭窄检查:

function testSomething(uint256 v) public {
    vm.assume(v != 0);
    require(v != 0);
    ... 
}

使用bound()限制输入到特定范围:

function testSomething(uint256 v) public {
    v = bound(v, 100, 500);
    require(v >= 100 && v <= 500);
    ... 
}

本翻译由 DeCert.me 协助支持, 在 DeCert 构建可信履历,为自己码一个未来。

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

0 条评论

请先 登录 后评论
翻译小组
翻译小组
0x9e64...7c84
大家看到好的文章可以在 GitHub 提 Issue: https://github.com/lbc-team/Pioneer/issues 欢迎关注我的 Twitter: https://twitter.com/UpchainDAO