Forge主网分叉测试失败但Anvil本地通过问题求助
核心原因:主网分叉与本地Mock的WETH合约差异
本地测试用的是自定义Mock WETH,你可以调用mint直接给地址增发WETH;但主网分叉环境连接的是真实主网WETH合约,它没有公开的mint方法——真实WETH只能通过deposit()存入ETH来兑换,或者从其他地址转账获得。你的测试代码里的weth.mint(mintAmount, guardian)在主网分叉环境下完全无效,导致guardian地址的WETH余额为0,调用safeTransferFrom时因余额不足触发EVM错误,且因为是调用主网合约,错误日志没有详细回滚信息。
具体解决步骤
1. 替换主网分叉环境的WETH mint逻辑
把测试里的weth.mint改成主网WETH支持的方式:给guardian地址转入ETH,然后调用WETH的deposit()生成WETH:
function testBecomeGuardianNoUniswap() public { // 给guardian转ETH,用来兑换WETH vm.deal(guardian, mintAmount); vm.startPrank(guardian); // 调用主网WETH的deposit,把ETH换成WETH weth.deposit{value: mintAmount}(); weth.approve(address(vaultGuardians), mintAmount); address wethVault = vaultGuardians.becomeGuardian(noUniswapAllocationData); vm.stopPrank(); }
2. 增加调试日志,明确错误原因
在测试中加入余额、授权的检查,提前排查问题:
function testBecomeGuardianNoUniswap() public { vm.deal(guardian, mintAmount); vm.startPrank(guardian); weth.deposit{value: mintAmount}(); // 打印guardian的WETH余额 console.log("Guardian WETH balance:", weth.balanceOf(guardian)); weth.approve(address(vaultGuardians), mintAmount); // 打印授权额度 console.log("Approved amount:", weth.allowance(guardian, address(vaultGuardians))); address wethVault = vaultGuardians.becomeGuardian(noUniswapAllocationData); vm.stopPrank(); }
运行测试时用-vvvv参数,就能看到日志输出,确认余额和授权是否正常。
3. 验证主网WETH的调用权限
主网WETH的transferFrom是标准ERC20实现,但要注意:
- 确保
guardian的WETH余额 ≥s_guardianStakePrice - 确保授权额度 ≥
s_guardianStakePrice - 如果
s_guardianStakePrice是动态值,打印出来确认数值是否符合预期
4. 强制捕获主网合约的错误
如果还是看不到详细错误,可以用try/catch包裹调用,打印原始错误数据:
vm.startPrank(guardian); weth.deposit{value: mintAmount}(); weth.approve(address(vaultGuardians), mintAmount); try vaultGuardians.becomeGuardian(noUniswapAllocationData) returns (address wethVault) { // 成功逻辑 } catch (bytes memory reason) { console.logBytes(reason); // 打印原始错误数据 } vm.stopPrank();
对疑问的解答
为什么safeTransferFrom在主网分叉无提示失败?
因为主网分叉调用的是真实合约,safeTransferFrom底层调用主网WETH的transferFrom,如果余额不足,主网WETH会revert但没有自定义错误信息(早期ERC20合约很多用revert字符串而非自定义错误),Foundry在分叉环境下可能不会自动解析这类原始revert信息,导致只显示通用EVM错误。是主网分叉与mock的初始化差异吗?
完全是这个原因:本地Mock WETH是你自己实现的,有mint方法可以直接增发;但主网WETH是真实合约,没有公开的mint权限,你的测试代码在分叉环境下没有正确给测试地址生成WETH,导致后续转账失败。
是否需要补充调试步骤?
非常有必要,建议补充:
- 测试地址的WETH余额检查
- 授权额度检查
s_guardianStakePrice的数值打印- 用
try/catch捕获原始错误数据
内容的提问来源于stack exchange,提问作者NOS Magical

