1

I am playing arround with smart contracts. I have 2 contracts: target and executer (don't mind the name, it's just testing stuff).

target has just a simple function to change a string:

contract target {
    string public value = "lol";
    event SetValue(string);

    function setValue(string v) public {
        value = v;
        emit SetValue(v);
    }
}

From executer, I have a function to execute the setValue of target using an abstract and another function to execute setValue using the function's hash.

contract target {
   function setValue(string v) public;
}


    contract executer {

        target public tc;
        address public ta;
        function exeWithAbi(string value) public {
            tc.setValue(value);
        }

        function setAddress(address a) public {
            tc = target(a);
            ta = a;
        }

        function exeWithoutAbi(string v) public {
            require(ta.call(bytes4(keccak256("setValue(string)")),v));
        }

The function exeWithAbi works fine, but the function exeWithoutAbi does not work properly. It changes the value of the string, but sets it to nothing (empty string I think). According to the information provided by Remix (the details tab), the string I pass (setValue(string)) is correct (it is the correct function hash)

Why is the value of my string not being set properly?

2 Answers 2

3

Using abi.encode should work, although I'm not 100% sure why. (I don't understand why that's not what ta.call is already doing.)

function exeWithoutAbi(string v) public {
    require(ta.call(bytes4(keccak256("setValue(string)")), abi.encode(v)));
}
3
  • As a note, abi.encode was implemented in 0.4.22 if I am not wrong? Apr 30, 2018 at 21:28
  • @EliDrion I have no reason to doubt that. :-)
    – user19510
    Apr 30, 2018 at 23:13
  • Not a note for you, but for people who might use older versions and wonder why it doesn't work. :) Apr 30, 2018 at 23:17
4

It doesn't work because a string is encoded differently than bytes32, so it won't work through using the call method, because you have to the ABI encoding yourself. It will work for other types such as uint or bool.

12
  • Thanks for pointing that out, it is true. Any way I could do this with strings? Apr 30, 2018 at 20:16
  • 1
    For the call, probably, but you will need to search about it. You should stick to using the abstract contract, it's better. Apr 30, 2018 at 20:19
  • Well, my purpose in long terme is to not having to use the abstract contract ^^ Apr 30, 2018 at 20:20
  • 1
    But why tho? There is literally no downside of using the abstract contract.
    – mafrasi2
    Apr 30, 2018 at 20:23
  • 1
    @Andromelus no, definitely not. It's just used for the compilation, but it's gone in the bytecode. I just tested how much gas it needs and it's actually cheaper to use the interface instead of the manual method, since the function selector is already calculated during compilation. In your manual method, it's calculated each time you execute exeWithoutAbi(), which costs gas and needs more instructions.
    – mafrasi2
    May 1, 2018 at 16:14

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.