在Solidity中动态地调用外部合约

17

我正在尝试让一个合约拥有一个能够调用另一个合约函数的功能。我的目标的关键部分是,该合约不应该能够在没有任何import语句的情况下进行部署,并且默认情况下不知道合约的名称。换句话说,该合约的使用者将输入被调用合约的数据(即地址、名称)作为参数。如何最好地实现这一点?

2个回答

14

不确定为什么这个被投票否决了。

如果我正确理解问题的话,您想在不知道它将需要与之通信的具体合约的情况下部署合约。

您可以通过假设知道它们的接口来极大简化此过程。

您可以定义接口而无需导入合约代码。定义函数接口并保留函数定义为空:

contract WidgetInterface {

   function doSomething() returns(uint) {}
   function somethingElse() returns(bool isTrue) {}

}
使用该接口合约与实际合约进行通信:
WidgetInterface w = WidgetInterface(actualContractAddress);

在我看来,通常情况下,将授权/有效的合同随时注册是可行且明智的。沿着这样的方向维护一个列表,其中包含它可以安全交流的合同:

if(!isAuthorized(actualContractAddress)) throw; 

其中actualContractAddress由发送方提供,isAuthorized()是您编写的用于查询内部注册表的函数。

希望这可以帮助您。


1
蠢问题。一旦我有了实例“w”。如何调用它的“doSomething”方法?就像这样简单吗:w.doSomething(); - JoshOrndorff
这是正确的答案。虽然类型的重载不清楚。 IERC721 MyContract; 然后 MyContract = IERC721(address); - eodgooch
那就是实例化(instantiation)。MyContract 是 ERC721 接口(类型),位于该地址。 - Rob Hitchens

7
您可以通过使用接口(正如 Rob Hitchens 建议的那样)来实现此功能,或者您可以动态定义接口并使用 .call、.callcode 或 .delegatecall 执行方法。
以下是一个示例:
contract ContractsCaller {

    function execute(address contractAt, uint _i, bytes32 _b) returns (bool) {
        return contractAt.call(bytes4(sha3("testMethod(uint256,bytes32)")), _i, _b);
    }
}

contract Test {

    uint256 public i;
    bytes32 public b;

    function testMethod(uint256 _i, bytes32 _b) {
        i = _i;
        b = _b;
    }
}

测试可以在单独的文件中定义。除了其地址和调用方法的签名外,ContractsCaller不需要了解关于Test的任何信息。

方法的签名是方法名称的前4个字节和其参数类型:

bytes4(sha3("testMethod(uint256,bytes32)"))

更多关于.call、.callcode、.delegatecall的信息,请点击此处

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接