30

I want to know how to instantiate an existing contract deployed on the blockchain using its address. e.g:

contract A {
    function f1()
    {}
}

A is deployed on the blockchain, and in contract B I want to call the function f1() and get its return. e.g:

contract B {
    address contrac_A=0x123456;

    //call f1 from A
}

How should I call it using the address of A?

4 Answers 4

18

If the deployed contract doesn’t adhere to the ABI, but you know the contract signature (name and argument types) You could use :

contract_address.call(bytes4(sha3("function_name(types)")),parameters_values)

for example : contrac_A.call(bytes4(sha3("f()")) while there is no input no parameters in your exemple.

replace contract_address,function_name,parameters_values by your credentials.

Edit : as sha3 has been deprecated it's better to use instead keccak256 as following: bytes4(keccak256("f()")).

Furthermore, since solidity 0.4.22, the global functions abi.encode(), abi.encodePacked(), abi.encodeWithSelector() and abi.encodeWithSignature() have been defined to encode structured data and therefore helping us to build valid call (they return the needed 4 bytes) as follow :

contract_address.call.value(1 ether).gas(10)(abi.encodeWithSignature("register(string)", "MyName"));

Documentation:

https://github.com/ethereum/wiki/wiki/Solidity-Features#generic-call-method

https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector

2
  • I have seen a function as follows. function transfer(address _to, uint _value, bytes _data, string _custom_fallback) returns (bool success) { ContractReceiver receiver = ContractReceiver(_to); receiver.call.value(0)(bytes4(sha3(_custom_fallback)), msg.sender, _value, _data); return true; } .....What's the use of value(0) here?? Commented Oct 12, 2017 at 11:52
  • 1
    f.call.value(X) is calling f with X wei check ethereum.stackexchange.com/questions/6707/…
    – Badr Bellaj
    Commented Oct 12, 2017 at 13:18
27

Use an abstract contract (preferred)

Further clarifications to @Edmund's answer:

contract A { // This doesn't have to match the real contract name. Call it what you like.
   function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}

contract YourContract {
  function doYourThing(address addressOfA) returns(uint) {
    A my_a = A(addressOfA);
    return my_a.f1(true, 3);
  }
}

This shows using the return value from f1.

Also, if f1 encounters an exception (imagine its implementation is function f1(bool arg1, uint arg2) returns(uint) { throw; }), the exception is propagated and my_a.f1 will also throw and it will revert a transaction that invoked doYourThing.

In practice, you'll have 3 files.

AbstractA.sol contains:

contract A {
   function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}

YourContract.sol contains:

import "AbstractA.sol"

contract YourContract {
  function doYourThing(address addressOfA) returns(uint) {
    A my_a = A(addressOfA);
    return my_a.f1(true, 3);
  }
}

A.sol contains:

contract A {
   // implementation of f1
   function f1(bool arg1, uint arg2) returns(uint) {
       if (arg1) {
           throw;
       } else {
           return arg2;
       }
   }
}

Limitations of using call

call is suggested in @Badr's answer but should be used very carefully. Solidity docs state:

All three functions call, delegatecall and callcode are very low-level functions and should only be used as a last resort as they break the type-safety of Solidity.

Also, the return value of f1 can't be obtained by using call like addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3) because call only returns a bool (false if the call encounters an exception).

This means that the exception must be propagated manually like:

if (!addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)) {
    throw;
}
2
  • 1
    Do we have to include visibility and modifiers when specifying the function signature? Commented Apr 23, 2021 at 20:19
  • 1
    @DigitalJedi Yes, there have been improvements to Solidity since 2017, and they include being explicit about visibility.
    – eth
    Commented May 2, 2021 at 9:52
4
contract A { // This doesn't have to match the real contract name. Call it what you like.
   function f1(){} // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}

contract YourContract 
  function doYourThing() {
    A my_a = A(contract_A);
    my_a.f1();
  }
}
7
  • they are not in the same contract file the compiler will not recongnise the contract A so no A my_a = A(contract_A);
    – Sig Touri
    Commented Oct 31, 2016 at 14:47
  • 1
    Put them in the same file. You don't need the full implementation, just the function signatures. Commented Oct 31, 2016 at 14:51
  • 1
    I am asking about an alredy deployed contract.
    – Sig Touri
    Commented Oct 31, 2016 at 14:58
  • 1
    You don't need the full source code. You must know the name of the method you're calling and what parameters it takes, so stick that in a contract definition called A, leave the function body empty and plonk it above the contract that's going to call it. Commented Oct 31, 2016 at 15:33
  • 1
    Edited my answer to provide context. That really is all you need, it doesn't matter whether the contract is already deployed or not. If your original code won't compile, check the spelling of "function". Commented Oct 31, 2016 at 22:48
0

Here is a Solidity code for the New contract that can call the f1() function from your Old contract. Hope this helps. I tried to keep it as simple as possible.

    import "./Old.sol";    // You import the existing contract. 
        
        
            /**
            * The NEW contract will call the Old one
            */
        
          contract New {
          
               Old OLD; // Intitilize old contract variable (empty)
        
            /**
             * Set the address for Old contract (We call this function and enter the address of the OLD contract)
             */
            function setOldContractAddress(address addr) public {
                OLD = Old(addr);
            }
        
        
             /**
             * Function that allows us to call f1() from the Old contract
             */
            function callOLDcontract() public {
                OLD.f1();
             
                }
            
            }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.