1

For some reason beyond my control, I need to store encoded data in a string variable.

I know abi.encode and abi.decode usually work on bytes memory but I also believe that string memory can be casted to bytes memory.

Here is an example contract I use to debug in remix:

pragma solidity ^0.5.0;

contract Test
{
    function encode(uint256 a, string calldata b) external pure returns(string memory)
    {
        return string(abi.encode(a, b));
    }
    function decode(string calldata a) external pure returns(uint256, string memory)
    {
        return abi.decode(bytes(a), (uint256, string));
    }
}

It works great with some values. For example encode(42, "test") returns

\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000*\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000@\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0004test\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000

which can then be decoded back to 42, "test".

However, for some values, such as 255, "test", then I get a revert when trying to decode the encoded string.

Any idea how to solve that ? Is their no other way then to use bytes instead of string ?

1

I think I would focus on the testing methodology.

The contract looks okay to me.

I fiddled with it a little to test the original two functions and ended up with something that seems to work. It works for both examples, e.g. 255, "test".

I didn't find a case where it doesn't work. Admittedly, did not test very much.

pragma solidity ^0.5.0;

contract Test
{
    function encode(uint a, string memory b) internal pure returns(string memory)
    {
        return string(abi.encode(a, b));
    }
    function decode(string memory a) internal pure returns(uint, string memory)
    {
        return abi.decode(bytes(a), (uint, string));
    }

    function test(uint a, string calldata b) external pure returns(uint, string memory) {
        string memory encoded = encode(a, b);
        return decode(encoded);
    }    
}

Hope it helps.

  • it confirms that there is a possible string representation, but when I try to compute it offchain and pass it to a smart contract I can't manage to make it work. My usecase is trying to decode something that was passed as an argument, stored somewhere in a string and by a contract I don't control, and then read by my contract – Amxx Apr 4 '19 at 20:53
  • Change the two internal functions to public so the client can use them. The advantage here is you are ensuring all clients and all languages will always have a way to convert that matches what the contract expects. Use the contract's pure functions to do offchain computations, and you shouldn't have a problem. – Rob Hitchens - B9lab Apr 4 '19 at 23:10
  • They are external, and I tried ... calling the encode sometimes cause revert (for example with 255, "test") – Amxx Apr 5 '19 at 8:01

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.