非Owner身份下ContractB调用ContractA的set_data函数失败求助
问题原因
ContractA的set_data函数通过require(owner == msg.sender)限制只有合约部署者(owner)能调用。当你用ContractB调用该函数时,msg.sender是ContractB的合约地址,而非ContractA的owner地址,因此触发权限校验失败。
解决方案
方案1:修改ContractA的代码(推荐)
通过调整权限逻辑,允许ContractB调用set_data,以下是两种可行方式:
方式1:添加白名单机制
修改ContractA,新增可调用地址列表,允许指定合约调用:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; contract contractA{ string data; uint public blocknumber; address public owner; mapping(address => bool) public allowedCallers; // 白名单映射 constructor() payable { owner = msg.sender; allowedCallers[owner] = true; // 默认owner在白名单 } // owner可添加允许调用的地址 function addAllowedCaller(address _caller) public { require(owner == msg.sender, "Only owner can add callers"); allowedCallers[_caller] = true; } function set_data(string memory _data) public { require(allowedCallers[msg.sender], "You are not allowed to call this function"); data = _data; blocknumber = block.number; } }
使用步骤:
- 重新部署修改后的ContractA
- 调用
addAllowedCaller将ContractB的地址加入白名单 - 此时ContractB调用
set_data即可成功
方式2:使用标准权限管理
借助OpenZeppelin的Ownable合约实现更规范的权限控制,支持owner授权其他地址调用:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@openzeppelin/contracts/access/Ownable.sol"; contract contractA is Ownable { string data; uint public blocknumber; constructor() payable Ownable() {} // 继承Ownable,owner自动设为部署者 function set_data(string memory _data) public onlyOwner { data = _data; blocknumber = block.number; } }
使用步骤:
- 部署ContractA后,调用
transferOwnership将权限转移给ContractB地址 - 若不想转移owner权限,可改用AccessControl合约自定义"Setter"角色,支持多地址调用
方案2:无法修改ContractA的情况
如果不能修改ContractA的代码,无法实现非owner身份让ContractB调用set_data——因为该函数的权限校验是硬编码的仅owner可调用。唯一可行的操作是将ContractB的地址设置为ContractA的owner(前提是ContractA有transferOwnership函数),但这会让原owner失去控制权,需谨慎操作。
你的代码小问题
ContractB中contractA public new;存在命名错误:new是Solidity的关键字,不能作为变量名,建议修改为contractA public contractAInstance;以避免编译错误。
内容的提问来源于stack exchange,提问作者Carlos
相关产品推荐
相关产品推荐

