首页>>资讯>>学院

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

2024-01-31 11:42:07 318

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


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


初始化


创建新项目


创建新项目:


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 作弊吗码


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


上下文 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`[8] 获取所有功能。


余额


// 为某地址设置余额

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`[9],用于捕获内部 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[10]。


// 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`[11]。


// 返回绝对值

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[12] 协助支持, 在 DeCert 构建可信履历,为自己码一个未来。


参考资料


[1]

登链翻译计划: https://github.com/lbc-team/Pioneer


[2]

翻译小组: https://learnblockchain.cn/people/412


[3]

Tiny 熊: https://learnblockchain.cn/people/15


[4]

learnblockchain.cn/article…: https://learnblockchain.cn/article/7344


[5]

Foundry: https://learnblockchain.cn/docs/foundry/i18n/zh/index.html


[6]

gist: https://gist.github.com/MiloTruck/30cd9b051176da8b76fe7dc81996eaf9


[7]

作弊码参考: https://learnblockchain.cn/docs/foundry/i18n/zh/cheatcodes/index.html


[8]

Forge Std 的Test: https://learnblockchain.cn/docs/foundry/i18n/zh/reference/forge-std/


[9]

forge-std/std-errors: https://learnblockchain.cn/docs/foundry/i18n/zh/reference/forge-std/std-errors.html


[10]

forge-std/std-assertions: https://learnblockchain.cn/docs/foundry/i18n/zh/reference/forge-std/std-assertions.html


[11]

forge-std/std-math: https://learnblockchain.cn/docs/foundry/i18n/zh/reference/forge-std/std-math.html


[12]

DeCert.me: https://decert.me/

声明:本网站所有相关资料如有侵权请联系站长删除,资料仅供用户学习及研究之用,不构成任何投资建议!