Solidity Contract Invocation – Calling External Functions with Bytecode

contract-developmentcontract-invocationsolidity

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!

Best Answer

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"