检查 msg.sender 是否是特定类型的合约

Eig*_*ice 4 ethereum solidity smartcontracts web3js

现在,任何人都可以setMyString调用FirstContract. 我试图将对该函数的访问限制为SecondContract. 但不是一个特定的实例,任何类型的合约都SecondContract应该能够调用setMyString.

contract FirstContract{
    String public myString;

    function setMyString(String memory what) public {
        myString=what;
    }
}

contract SecondContract{
    address owner;
    address firstAddress;
    FirstContract firstContract;
    constructor(address _1st){
        owner=msg.sender;
        firstAddress=_1st;
        firstContract=FirstContract(firstAddress);
    }
    function callFirst(String memory what){
        require(msg.sender==owner);
        firstContract.setMyString("hello");
    }
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*jda 5

Solidity 目前没有一种简单的方法来根据接口验证地址。

您可以检查字节码,是否包含指定的签名(公共属性和方法的)。这需要比通常的 StackOverflow 答案更大的范围,所以我只是描述这些步骤而不是编写代码。

首先,定义您要查找的所需签名列表(名称和参数数据类型的 keccak256 哈希的第一个 4 字节)。您可以在我的其他答案中找到有关签名的更多信息(此处此处)

文档中的示例显示了如何获取任何地址(在您的情况下msg.sender)的字节码作为bytes(动态长度数组)。

然后,您需要循环返回的bytes数组并搜索 4 字节签名。

如果全部找到,则意味着msg.sender“实现了接口”。如果外部合约中缺少任何签名,则意味着它没有实现该接口。


但是......我真的建议您重新考虑白名单的方法。是的,您需要维护列表并setIsSecondContract() 成员第一次SecondContract想要调用该函数时调用。但对于s函数setMyString()的所有调用者来说,它的燃气效率更高,并且首先更容易编写和测试功能。FirstContractsetMyString()

contract FirstContract{
    String public myString;
    
    address owner;
    mapping (address => bool) isSecondContract;
    
    modifier onlySecondContract {
        require(isSecondContract[msg.sender]);
        _;
    }
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
    
    function setIsSecondContract(address _address, bool _value) public onlyOwner {
        isSecondContract[_address] = _value;
    }

    function setMyString(String memory what) public onlySecondContract {
        myString=what;
    }
}
Run Code Online (Sandbox Code Playgroud)