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?

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)));
}
  • As a note, abi.encode was implemented in 0.4.22 if I am not wrong? – Eli Drion Apr 30 '18 at 21:28
  • @EliDrion I have no reason to doubt that. :-) – smarx Apr 30 '18 at 23:13
  • Not a note for you, but for people who might use older versions and wonder why it doesn't work. :) – Eli Drion Apr 30 '18 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.

  • Thanks for pointing that out, it is true. Any way I could do this with strings? – Florian Castelain Apr 30 '18 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. – Eli Drion Apr 30 '18 at 20:19
  • Well, my purpose in long terme is to not having to use the abstract contract ^^ – Florian Castelain Apr 30 '18 at 20:20
  • 1
    But why tho? There is literally no downside of using the abstract contract. – mafrasi2 Apr 30 '18 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 '18 at 16:14

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.