2

I am writing my own smart contract and I want to call a function from a contract that has already been deployed. The fragment of my code:

function myFunc(address _contractAddress, address _user, uint _price) onlyOwner {
        //... some code ...

        require(_contractAddress.call(bytes4(sha3("func(address, uint256)")), _user, _price));

        //... some code ...
    }

I am using Remix IDE. It shows me this warning:

use of "call": the use of low level "call" should be avoided whenever possible. It can lead to unexpected behavior if return value is not handled properly. Please use Direct Calls via specifying the called contract's interface.

How should I solve this issue? Delegatecall produces similar warning. Maybe there are other ways on how to call other contract's function?

2 Answers 2

2

In newer versions of solidity, you can use either abstract contracts or interfaces.

  • Abstract contracts now need the abstract keyword to compile correctly, and the virtual modifier on functions.
  • Interfaces are much better for your purpose here, in fact, that's what they were desinged for.

I'm pretty sure that interfaces are represented on a low level by abstract contracts with all external virtual functions and no internal data fields.

MyContract.sol:

// SPDX-License-Identifier: Unlicense                                                                               
pragma solidity >0.8.5;

abstract contract OtherContract {
    function otherMethod(address _to, uint _price) external virtual;
}

interface OtherContractInterface {
    function otherMethod(address _to, uint _price) external;
}

contract MyContract {
    uint public unitPrice = 100;

    function myMethod(address _destination, uint _count) external {
        // _destination is a contract that implements OtherContract

        // this uses the interface.
        OtherContractInterface oci = OtherContractInterface(_destination);
        oci.otherMethod(address(this), _count * unitPrice);

        // this code uses the abstract contract
        OtherContract oc = OtherContract(_destination);
        oc.otherMethod(address(this), _count * unitPrice);
    }
}
1

If you know the method to call you can use an abstract contract

contract OtherContract {
    function otherMethod(address _to, uint _price);
}

contract MyContract {
    uint public unitPrice = 100;

    function myMethod(address _destination, uint _count) {
        // _destination is a contract that implements OtherContract
        OtherContract oc = OtherContract(_destination);
        // call method from other contract
        oc.otherMethod(address(this), _count * unitPrice);
    }
}
4
  • my contracts are in separate files so this won't work.
    – EtherPaul
    Aug 25, 2017 at 7:36
  • 1
    If the contracts are in separate files you can import them, or create a file that only has the declarations of the methods a "abstract contract" in solidity parlance.
    – Ismael
    Aug 25, 2017 at 8:51
  • Importing contract is the same as declaring it above in the same file. My situation is that these contracts are deployed separately
    – EtherPaul
    Aug 27, 2017 at 14:58
  • It is a common technique used in crowdsales. You have two independently deployed contracts Crowdsale y CrowdsaleToken. The Crowdsale needs access to CrowdsaleToken, but if you import it in the Crowdsale.sol file it will increase the bytecode. So you create an abstract contract Token with no implementation only the methods declaration and import it from the Crowdsale.
    – Ismael
    Aug 27, 2017 at 19:14

Your Answer

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

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