如何在Foundry测试中以EOA地址调用合约自定义函数?
Foundry测试中以EOA地址调用合约函数的方法
直接使用this.customFunction()不可行——这种调用方式下,msg.sender会是测试合约本身的地址,而非你指定的EOA地址。要让目标EOA作为msg.sender调用合约函数,你需要用Foundry内置的vm cheatcode,以下是两种常用实现方式:
1. 使用vm.prank()或vm.startPrank()
- 单次调用场景:先用
vm.prank(EOA地址)指定后续一次调用的msg.sender,再直接调用合约函数 - 多次调用场景:用
vm.startPrank(EOA地址)开启持续伪装,之后所有合约调用的msg.sender都会是该EOA,结束时用vm.stopPrank()关闭
示例代码:
pragma solidity ^0.8.13; import "forge-std/Test.sol"; import "../src/MyERC20.sol"; contract MyERC20Test is Test { MyERC20 public myERC20; address public user = makeAddr("user"); // 生成测试用EOA地址 function setUp() public { myERC20 = new MyERC20(); } // 单次调用示例 function testCustomFunctionWithPrank() public { vm.prank(user); myERC20.customFunction(); // 验证状态修改(示例:假设customFunction会记录调用者) assertEq(myERC20.lastCaller(), user); } // 多次调用示例 function testMultipleCallsWithStartPrank() public { vm.startPrank(user); myERC20.customFunction(); myERC20.anotherStateChangingFunction(); // 此调用msg.sender同样为user vm.stopPrank(); } }
2. 使用vm.broadcast()
如果你需要模拟真实链上交易的广播行为(比如生成交易记录、验证gas消耗),可以用vm.broadcast(EOA地址),后续的合约调用会以该EOA作为发起者,效果和prank类似,但会完整模拟交易流程。
示例代码:
function testCustomFunctionWithBroadcast() public { vm.broadcast(user); myERC20.customFunction(); assertEq(myERC20.lastCaller(), user); }
补充说明
makeAddr("user")是Foundry提供的工具函数,快速生成无关联的测试EOA,无需私钥。如果需要给该地址分配ETH,可使用deal(user, 1 ether)。- 所有
vmcheatcode仅在测试合约中可用,不会影响主网部署的合约逻辑。
内容的提问来源于stack exchange,提问作者Tahlil
相关产品推荐
相关产品推荐

