2

I have a function on contract A for examples :

uint256[] values;
function set(uint256[] _arrayToSet){
    values = _arrayToSet;
}

It works perfectly when called directly, but I would like to call it from contract B, so in B I have something like that :

function set(address _contract, uint256[] _values){
       bool d = _contract.call.gas(50764)( bytes4(sha3("set(uint256[])")),_values);
}

However this does not set values, is there a way to use .call() with array as input ? Thanks in advance.

1 Answer 1

5

The problem here is that Solidity call encoder have troubles in encoding dynamic arrays. Here is the example to illustrate this, assuming you have an instance of your first contract in web3.eth:

console.log(settingContract.set.getData([10]));

0x6ea9bfc5
0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000001
000000000000000000000000000000000000000000000000000000000000000a

This is the correct encoding of set function invocation. Here you can see the function signature 0x6ea9bfc5, a pointer to the length of the array 0x20 (in that case, the size of the pointer itself which is 32 bytes), length of the array 0x1 which is 1 (single 32 bytes word), and 0xa which is the value of the first element 10. Now let's see what call will produce assuming the same input:

Debug(bytes data);
function () {
    Debug(data);
}
function setIt(uint256[] _values) returns(bool) {
    return address(this).call(bytes4(sha3("set(uint256[])")), _values);
}

// Data of Debug event log from receipt of calling contract.setIt([10]);
0x6ea9bfc5
000000000000000000000000000000000000000000000000000000000000000a

This is incorrect encoding, Solidity encodes it as a fixed size uint256[1] array.

In order to overcome this problem, you can put dynamic array prefixes yourself:

function setIt(uint256[] _values) returns(bool) {
    return address(this).call(
        bytes4(sha3("set(uint256[])")),
        uint256(32),             // pointer to the length of the array
        uint256(_values.length), // length of the array
        _values                  // array itself
    );
}

Now it will work as expected. Nevertheless I think this is a compiler bug, so I will report it.

See more details and examples in the ABI specification: http://solidity.readthedocs.io/en/develop/abi-spec.html#use-of-dynamic-types.

1
  • You are right! If anyone is going to use this solution, please mind that it cost a quite lot of gas to use this like that, I needed to use over 100 k gas. Thanks!
    – MeMyself
    Commented May 15, 2017 at 19:17

Your Answer

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

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