7

How does one specify gas or value making a call this way:

contract AbstractB {
    function getX() returns(uint);
}

contract A {
    function makeCall(address addressB){
         AbstractB(addressB).getX();
    }
}

The following doesn't work(Error: Member "gas" not found...):

AbstractB(addressB).gas(0).getX();
manidos
  • 4,298
  • 3
  • 31
  • 55
  • Related: http://ethereum.stackexchange.com/questions/6665/call-contract-and-send-value-from-solidity – eth Aug 22 '16 at 10:28

4 Answers4

7

EDIT: I upvoted and recommend @Xavier's answer (@BokkyPooBah's answer is missing () at the end).

It's more type-safe and here's an example showing the return value of getX. You do need to provide non-zero gas:

contract AbstractB {
    function getX() returns(uint) {
        return 3;
    }
}

contract A {
    function makeCall(address addressB) returns(uint) {
        return AbstractB(addressB).getX.gas(1000)();
    }
}

OLD: Use call.gas(g).value(v)(methodId, args) syntax. Not recommended because not type-safe and you don't get the return value of getX.

Example: addressB.call.gas(0).value(1 ether)(bytes4(sha3("getX()")));

Complete example, which should always checks the return value of call:

contract AbstractB {
    function getX() returns(uint);
}

contract A {
    function makeCall(address addressB){
         if (!addressB.call.gas(0).value(1 ether)(bytes4(sha3("getX()")))) {
             throw;
         }
    }
}
eth
  • 85,679
  • 53
  • 285
  • 406
  • thank you very much, good sir!!! I guess, it also means that there's no point in having AbstractB contract at all there? – manidos Aug 22 '16 at 09:34
  • 2
    Yes, but actually the other answers that use AbstractB are safer for type-safety. – eth Aug 22 '16 at 09:36
4

AbstractB(addressB).getX.gas(0)();

Notice the many parentheses: (0)()

2

Try the following:

contract AbstractB {
    function getX() returns(uint);
}

contract A {
    function makeCall(address addressB) {
        AbstractB(addressB).getX.value(1 ether).gas(0);
    }
}

EDIT: As noted by the other answers to this question, the code AbstractB(addressB).getX.value(1 ether).gas(0); above is incorrect and should be replaced by:

        AbstractB(addressB).getX.value(1 ether).gas(0)();
BokkyPooBah
  • 40,274
  • 14
  • 123
  • 193
1

I've compiled these two contracts using solidity online compiler. I've changed only one line.

  • AbstractB(addressB).getX.gas(0); @BokkyPooBah solution

  • AbstractB(addressB).getX.gas(0)(); @xavier-leprêtre solution

And got massively different bytecodes:

6060604052601e8060106000396000f3606060405260e060020a60003504637ff76d728114601a575b005b601856

vs

606060405260848060106000396000f3606060405260e060020a60003504637ff76d728114601a575b005b60186004357f5197c7aa00000000000000000000000000000000000000000000000000000000606090815273ffffffffffffffffffffffffffffffffffffffff821690635197c7aa906000906064906020906004818588803b1560025787f115600257505050505056


contract AbstractB {
    function getX() returns(uint);
}

contract A {
    function makeCall(address addressB){
         AbstractB(addressB).getX.gas(0);
    }
}

contract AbstractB {
    function getX() returns(uint);
}

contract A {
    function makeCall(address addressB){
         AbstractB(addressB).getX.gas(0)();
    }
}

I don't mind the difference in bytecode size, what's scary is that these contracts might have some behaviour differences. What's going on there?

manidos
  • 4,298
  • 3
  • 31
  • 55
  • 3
    The extra () is needed to make the actual call and obtain return a value. (Example in my edited answer.) – eth Aug 22 '16 at 10:01