第4节:Fork 测试
小白入门:https://github.com/dukedaily/solidity-expert ,欢迎star转发,文末加V入群。
职场进阶: https://dukeweb3.com
Fork 测试指在本地复制主网状态,直接与真实合约(Uniswap、Aave、USDC 等)交互。对集成测试和攻击复现极为有用。
启动 Fork
两种方式:命令行 flag 或代码内切换。
命令行方式
forge test --fork-url $MAINNET_RPC
所有测试都在 mainnet fork 上跑。
代码内切换(推荐)
import {Test} from "forge-std/Test.sol";
contract ForkTest is Test {
uint256 mainnetFork;
function setUp() public {
mainnetFork = vm.createSelectFork(vm.envString("MAINNET_RPC"));
}
// ...
}
更灵活:可同时 fork 多条链并在测试中切换。
指定区块高度
锁定区块保证测试可复现:
vm.createSelectFork(vm.envString("MAINNET_RPC"), 19_500_000);
也可在命令行加 --fork-block-number 19500000。
与真实合约交互
示例:读取 USDC 总供应量。
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract UsdcTest is Test {
IERC20 usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
function setUp() public {
vm.createSelectFork(vm.envString("MAINNET_RPC"));
}
function test_UsdcTotalSupply() public view {
uint256 supply = usdc.totalSupply();
assertGt(supply, 0);
}
}
伪装链上鲸鱼
从鲸鱼地址 prank 转走资金,免去复杂的 swap 逻辑:
address whale = 0x40B38765696e3d5d8d9d834D8AaD4bB6e418E489;
function test_TransferFromWhale() public {
vm.prank(whale);
usdc.transfer(alice, 10_000e6);
assertEq(usdc.balanceOf(alice), 10_000e6);
}
多 Fork 切换
uint256 mainnet = vm.createFork(vm.envString("MAINNET_RPC"));
uint256 arbitrum = vm.createFork(vm.envString("ARB_RPC"));
vm.selectFork(mainnet);
// 在 mainnet 上执行
vm.selectFork(arbitrum);
// 切到 arbitrum
适合测试跨链桥、多链部署。
RPC 与环境变量
在项目根目录 .env 中配置:
MAINNET_RPC=https://eth-mainnet.g.alchemy.com/v2/<KEY>
ARB_RPC=https://arb-mainnet.g.alchemy.com/v2/<KEY>
forge test 自动加载 .env。确保 .env 已加入 .gitignore,勿把密钥提交到仓库。
小结
Fork 测试把"链上生产环境"当作一个可控测试夹具,是审计与集成测试的利器。下一节讲如何用 Fuzz / Invariant 让测试自动生成挑战性输入。