Calling external contract in solidity dynamically
Asked Answered
M

2

17

I am trying to make a contract have a function that is capable of calling functions of another contract. The key part of my goal is that the contract should not be able to be deployed without any import statements and will not know the name of the contract by default. In other words the user of this contract would input the called contracts data (i.e. address, name) as parameters. What is the best way to accomplish this?

Madalene answered 30/3, 2017 at 0:32 Comment(0)
B
14

Not sure why this was downvoted.

If I understand the question correctly, you want to deploy the contract without knowledge of the specific details of the contracts it will have to communicate with.

You can greatly simplify this by assuming knowledge of their interfaces.

You can define interfaces without importing contract code. Define the function interfaces and leave the function definitions empty:

contract WidgetInterface {

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

}

Use that Interface contract to talk to actual contracts:

WidgetInterface w = WidgetInterface(actualContractAddress);

In my opinion it will usually be possible and advisable to register authorized/valid contracts as you go. Maintain a list of the contracts it can safely talk to, along these lines:

if(!isAuthorized(actualContractAddress)) throw; 

where actualContractAddress is supplied by sender and isAuthorized() is a function you have worked out to query an internal registry.

Hope it helps.

Bonham answered 30/3, 2017 at 1:0 Comment(3)
Dumb question. Once I have the instance, w. How do I call it's doSomething method? Is it as simple as w.doSomething();?Insurrection
This is the correct answer. Although the overloading of the Type is not clear. IERC721 MyContract; then MyContract = IERC721(address);Kalfas
That's instantiation. MyContract is the ERC721 Interface (type) located at the address.Bonham
I
7

You can do this by using an interface, as suggested by Rob Hitchens, or you could define the interface dynamically and execute a method by using .call, .callcode, .delegatecall.

Here's an example:

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;
    }
}

Test can be defined in a separate file. ContractsCaller doesn't need to know anything about Test besides its address and the signature of the method it's calling.

The signature of the method is the first 4 bytes of the method name and the types of its parameters:

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

More information about .call, .callcode, .delegatecall.

Index answered 31/3, 2017 at 9:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.