Web3Foundry工具链参考 web3-foundry

Foundry 是用于以太坊智能合约开发的快速、可移植、模块化工具链。本技能提供完整的 Foundry 工具链中文参考指南,涵盖 forge(构建、测试、部署)、cast(合约交互)、anvil(本地节点)和 chisel(REPL)的核心命令、测试模式(单元、模糊、分叉、不变性)、关键作弊码、部署脚本和实用操作。适用于 Solidity 开发者进行高效合约开发、测试和部署。关键词:Foundry, Solidity, 智能合约, 以太坊, 区块链开发, 测试, 部署, 工具链

智能合约 0 次安装 0 次浏览 更新于 2/23/2026

名称: 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