5

I have read a number of posts about making calls between contracts, but I can't get this simple example to work that involves two contracts that are already deployed on my private Ethereum blockchain.

The pattern I'm trying to create is:
i- 'Caller' receives call to 'proxyRequest' function
ii- Caller uses the the _target parameter and calls the 'registrationRequest' function at the supplied address.
iii- 'UserRegistered' event in 'CallMe' should fire.

But the problem is that the 'call' function in 'Caller' always returns false. Any pointers would be appreciated.

If I use Web3 and create a transaction that calls the 'registrationRequest' function directly in 'CallMe', then it works fine.

contract Caller
{
    event SendingTransaction(address indexed _requestor, uint8 indexed action);     

    address public minter;
    bytes public email;      // hash of the email address

    modifier onlyOwner {
    if (msg.sender != minter)
        throw;
       _;
    }

    function() {
        throw;
    }

    function Caller(bytes _email) {

        // constructor
        minter= msg.sender;
        email= _email;
    }

    function proxyRequest(address _target, string _payload) onlyOwner public {

        SendingTransaction(_target, 1);
        // Event fires OK when I subscribe to it via Web3 code.

        if (!_target.call("registrationRequest",_target, _payload))
        {
            SendingTransaction(_target, 2);
            // Event fires OK when I subscribe to it via Web3 code.
        }
        else
        {
            SendingTransaction(_target, 3);
            // Event NEVER fires
        }


    }

}

Second contract.

pragma solidity ^0.4.7;

contract CallMe
{
    event UserRegistered(address indexed _from, string _attr);

    address public minter;     // keep track of the entity that created the contract

    modifier onlyOwner {
        if (msg.sender != minter)
            throw;
        _;
    }

    function CallMe() {
        minter = msg.sender;
    }

    function() { 
        throw;
    }

    function registrationRequest(address _toAdd, string _code) {

        // this event fires ok if I invoke it via web3
        // this event DOES NOT fire ok if function invoked by 'Caller'
        UserRegistered(_toAdd, _code);
    }


    function getMinter() constant returns (address) {
        return minter;
    }
}

1 Answers1

3

To call function from another contract you need to provide sha3 hash of function's signature (see solidity docs and this excellent answer):

_target.call(bytes4(sha3("registrationRequest(address,string)")), _target, _payload);

Another option is to explicitly convert address to CallMe:

CallMe cm = CallMe(_target);
cm.registrationRequest(_target, _payload);

Please note the difference: _target.call(..) returns false if call was not successful, while cm.registrationRequest(..) throws an exception.


Here is a script to run a test with node.js and testrpc. You can see that UserRegistered is fired and SendingTransaction(_target, 3) is fired too.

$ node test.js 
callme 0xf29c07da3e712ccda8fac94a9af499774bdbeeaa
caller 0x56157bb7ee83e749b5368f4c47ffc406fc653e5a
SendingTransaction { _requestor: '0xf29c07da3e712ccda8fac94a9af499774bdbeeaa',
  action: { [String: '1'] s: 1, e: 0, c: [ 1 ] } }
SendingTransaction { _requestor: '0xf29c07da3e712ccda8fac94a9af499774bdbeeaa',
  action: { [String: '3'] s: 1, e: 0, c: [ 3 ] } }
UserRegistered { _from: '0xf29c07da3e712ccda8fac94a9af499774bdbeeaa',
  _attr: '' }

But there is a problem with _attr argument not showing in UserRegistered event. This is due to Solidity's limitation on passing variable-sized arguments.

max taldykin
  • 2,966
  • 19
  • 27
  • I tried out the _target.call(bytes4(sha3("registrationRequest(address,string)")), _target, _payload); but could not get it to work. I also tried using bytes32 instead of string but could also not get it to work. – BokkyPooBah Jan 11 '17 at 05:18
  • This may be the case, I have not tried to compile/run the code (and is not able to do this right now). Can you please give me more details on what actually does not work? UserRegistered is not fired? – max taldykin Jan 11 '17 at 05:36
  • Yup. UserRegistered is not fired. I tried call, callcode and delegatecall - see http://ethereum.stackexchange.com/questions/3667/difference-between-call-callcode-and-delegatecall . – BokkyPooBah Jan 11 '17 at 05:39
  • 1
    Just tested and it's ok. Please see updated answer. – max taldykin Jan 11 '17 at 08:18