名称: web3-foundry
描述: 用于Solidity开发的Foundry工具链参考。适用于使用forge、cast、anvil或chisel时。涵盖构建、测试(单元、模糊、不变性、分叉)、部署和验证。
Foundry 工具链参考
核心命令
| 工具 |
用途 |
forge |
构建、测试、部署、验证 |
cast |
与合约交互、编码/解码 |
anvil |
本地以太坊节点 |
chisel |
Solidity REPL |
forge — 构建与测试
forge build # 编译
forge test # 运行所有测试
forge test -vvvv # 最大详细程度(追踪)
forge test --match-test testMint # 运行特定测试
forge test --match-contract MintTest # 运行特定合约
forge test --gas-report # 燃气使用报告
forge coverage # 测试覆盖率
forge snapshot # 燃气快照
forge inspect Contract storage-layout # 存储布局
forge inspect Contract methods # 函数选择器
测试模式
单元测试
function test_Mint() public {
uint256 balBefore = token.balanceOf(alice);
vm.prank(alice);
token.mint(100);
assertEq(token.balanceOf(alice), balBefore + 100);
}
setUp 模式
function setUp() public {
token = new MyToken();
alice = makeAddr("alice");
vm.deal(alice, 10 ether);
}
模糊测试
function testFuzz_Transfer(uint256 amount) public {
amount = bound(amount, 1, token.balanceOf(alice));
vm.prank(alice);
token.transfer(bob, amount);
assertEq(token.balanceOf(bob), amount);
}
分叉测试
forge test --fork-url $ETH_RPC_URL # 分叉主网
forge test --fork-url $ETH_RPC_URL --fork-block-number 19000000 # 固定区块
function test_SwapOnUniswap() public {
// 针对真实主网状态进行测试
vm.createSelectFork("mainnet");
// ... 与已部署合约交互
}
不变性测试
function invariant_totalSupply() public {
assertEq(token.totalSupply(), handler.ghost_mintedTotal() - handler.ghost_burnedTotal());
}
关键作弊码
| 作弊码 |
用途 |
vm.prank(addr) |
下一次调用来自 addr |
vm.startPrank(addr) |
所有调用来自 addr 直到 stopPrank |
vm.deal(addr, amount) |
设置ETH余额 |
vm.warp(timestamp) |
设置 block.timestamp |
vm.roll(blockNum) |
设置 block.number |
vm.expectRevert(selector) |
预期下一次调用会回退 |
vm.expectEmit(true,true,false,true) |
预期事件 |
vm.mockCall(addr, data, returnData) |
模拟外部调用 |
vm.label(addr, "name") |
在追踪中标记地址 |
makeAddr("name") |
确定性地址 |
vm.envUint("VAR") |
读取环境变量 |
部署
脚本模式
// script/Deploy.s.sol
contract DeployScript is Script {
function run() external {
uint256 deployerKey = vm.envUint("DEPLOYER_KEY");
vm.startBroadcast(deployerKey);
MyContract c = new MyContract(arg1, arg2);
console.log("部署地址:", address(c));
vm.stopBroadcast();
}
}
# 模拟(不广播)
forge script script/Deploy.s.sol --rpc-url $RPC_URL
# 部署
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast
# 部署 + 验证
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast --verify
cast — 合约交互
# 读取合约
cast call $ADDR "balanceOf(address)" $USER --rpc-url $RPC
# 写入(发送交易)
cast send $ADDR "transfer(address,uint256)" $TO $AMOUNT --private-key $KEY --rpc-url $RPC
# 编码调用数据
cast calldata "transfer(address,uint256)" $TO $AMOUNT
# 解码调用数据
cast 4byte-decode 0xa9059cbb...
# ABI 编码
cast abi-encode "constructor(string,string)" "MyToken" "MTK"
# 读取存储槽
cast storage $ADDR 0 --rpc-url $RPC
# 获取区块信息
cast block latest --rpc-url $RPC
# 单位转换
cast to-wei 1.5 ether # 1500000000000000000
cast from-wei 1000000000000000000 # 1.0
anvil — 本地节点
anvil # 启动本地节点
anvil --fork-url $ETH_RPC_URL # 分叉主网
anvil --fork-url $URL --fork-block-number 19000000 # 固定分叉
# 模拟账户
cast rpc anvil_impersonateAccount $WHALE_ADDR
cast send --from $WHALE_ADDR $TOKEN "transfer(address,uint256)" $ME $AMOUNT --unlocked