合约构造函数调用外部合约函数时msg.sender的取值是多少
智能合约构造函数跨合约调用的msg.sender值说明
首先给出明确结论:被调用函数获取到的msg.sender是正处于部署阶段的当前新合约的预计算地址,而非发起部署交易的外部账户(EOA)地址。
原理说明
- EVM在执行合约构造函数之前,就已经通过部署者地址、部署交易的nonce(如果使用CREATE2部署则为salt值、合约字节码哈希等参数)提前计算出了新合约的最终链上地址,这个地址在构造函数执行全程都是固定不变的,不会受部署进度影响。
- 构造函数的执行上下文从一开始就绑定了这个预计算的新合约地址,因此只要是构造函数内部触发的外部合约调用,消息的发起方都会被标记为这个预计算地址,哪怕此时新合约的代码还没有完全写入链上。
验证示例
可以通过以下极简Solidity代码复现验证:
// 被调用的测试合约 contract TargetContract { address public recordedCaller; function saveCaller() external { recordedCaller = msg.sender; } } // 部署时会调用上述测试合约的业务合约 contract NewContract { address public myAddress; constructor(address _targetAddr) { // 构造函数内先获取自身地址 myAddress = address(this); // 调用外部合约方法 TargetContract(_targetAddr).saveCaller(); } }
部署完成后对比两个合约的存储值就会发现:NewContract.myAddress 和 TargetContract.recordedCaller 完全相等,就是新部署合约的链上地址。
注意不要和部署交易的发起方地址混淆:只有部署交易直接执行的顶层上下文中
msg.sender是发起部署的EOA地址,一旦进入新合约的构造函数执行环境,后续所有调用的发起方都会默认使用新合约的预计算地址。
内容的提问来源于stack exchange,提问作者Nerzadler
相关产品推荐
相关产品推荐

