6

I am trying to understand different methods of invoking functions of another smart contract (which is already deployed on the blockchain).

Please see example below (call data/bytecode based on using 5 as lucky number).

pragma solidity ^0.4.17;

contract DeployedContract {
    uint public result = 0;

    function add(uint input) {
        result = result + input;
    }
}


contract Proxy {    
    address deployed_contract = 0x123;

    function call1(uint lucky_number) { 
        deployed_contract.call(bytes4(sha3("add(uint)")),lucky_number);
        // fails
    }

    function call2(uint lucky_number) { 
        deployed_contract.call(bytes4(sha3("add(uint256)")),lucky_number);
        // success
    }

    function call3(uint lucky_number) {
        deployed_contract.call(0x1003e2d2,lucky_number);
        // success
        // when debugging in remix, call data is 0x1003e2d20000000000000000000000000000000000000000000000000000000000000005
    }

    function call4() {
        deployed_contract.call(0x1003e2d20000000000000000000000000000000000000000000000000000000000000005);
        // does not compile: TypeError: Invalid rational number
    }

    function call5(bytes32 data) {
        // using call data from above (see call3), when using bytes32 as type, data is truncated to 0x1003e2d200000000000000000000000000000000000000000000000000000000
        deployed_contract.call(data); 
        // fails, since bytes32 truncates data  
    }

}

Questions:

  • Why is uint256 as parameter necessary (see call2), even though the function definition is add(uint)?

  • call4(): uses the exact call data as is generated with call3(), not sure how this could be done otherwise?

  • call5(): any ideas on how to achieve this?

Looking forward to understand this better, appreciate if somebody could give me some pointers. Cheers!

3

You should consider the following also.

pragma solidity ^0.4.17;

contract DeployedContract {
    uint public result = 0;

    function add(uint input) {
        result = result + input;
    }
}

contract Proxy {    
    address deployed_contract = 0x123;

    function directCall() public {
        DeployedContract(deployed_contract).add(123);
    }
}

Just assume the contract from the address.

Also, uint is an alias of uint256

Bytes32 is an array of bytes of length 32. Bytes first 32 bytes is a uint256 which contains the length of the bytes

call4 can be fixed with:

function call4() {
    deployed_contract.call("0x1003e2d20000000000000000000000000000000000000000000000000000000000000005");
    // does not compile: TypeError: Invalid rational number
}

As it takes bytes and bytes need to be enclosed in quotes, assuming that the data being passed is correct.

call5 needs to be passed an array with remix or simply just do the following:

function call5(bytes data) {
    // using call data from above (see call3), when using bytes32 as type, data is truncated to 0x1003e2d200000000000000000000000000000000000000000000000000000000
    deployed_contract.call(data); 
    // fails, since bytes32 truncates data  
}

And again, call it with

"0x1003e2d20000000000000000000000000000000000000000000000000000000000000005"
  • 1
    Great pointers, thank you very much! Regarding call5(), having to pass an array in remix is quite the gotcha (also this question, and this issue). – trommor Oct 10 '17 at 15:57
  • However, I couldn't get your solution for call4() to work, neither in remix nor on private chain for testing. – trommor Oct 10 '17 at 16:06
  • What error is it giving you? If you recompiled it then you might need to check what the new byte data is. I believe part of it is the instruction reference so if your code has changed then the instruction order will have changed too and the byte code is now invalid. – James Lockhart Oct 10 '17 at 16:30
0

Better use uint256 instead of uint

https://github.com/OpenZeppelin/zeppelin-solidity/issues/226

... uint, int: synonyms for uint256, int256 respectively (not to be used for computing the function selector).

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

0
0

I had trouble getting call to work with bytes as well. The problem was that the call function was expecting bytecode, but our string was being interpreted as ASCII then converted character-by-character into a byte array. The solidity docs mention hexadecimal literals and it solves the problem.

function call4() {
  deployed_contract.call( 
 hex"1003e2d20000000000000000000000000000000000000000000000000000000000000005");
}

Also, just in case you're writing a function that accepts bytes through Remix, you can use this format to pass the raw byte data: ["0x10", "0x03", "0xe2", ...]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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