1

Hi I have a proxy contract A which delegates function execution to implementation contract B using the standard OpenZeppelin code:

assembly {
            calldatacopy(0, 0, calldatasize())


            let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }

when I tried to call a function getter for a result which is supposed to be [10, 100] I got the string 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000064. What is this encoding and which library I can use to decode it. At first I thought it was RLP encoding but I checked with some RLP decoders but it didn't check out. Thanks

1 Answer 1

2

This is the ABI encoding format used by Solidity, which is documented in the Contract ABI Specification. Basically, static values (e.g., numbers, booleans, bytes1..32) are encoded into 32 bytes (64 hexadecimal characters), and dynamic values are encoded at the end, where a pointer to the location is encoded in place instead.

Using your result as an example, first you split it up into groups of 32 bytes.

0000000000000000000000000000000000000000000000000000000000000020
0000000000000000000000000000000000000000000000000000000000000002
000000000000000000000000000000000000000000000000000000000000000a
0000000000000000000000000000000000000000000000000000000000000064

Since the output is an array, the first 32 bytes (0x000...020) are the pointer to the array, in this case 0x20 or 32, meaning that the array is at position 32 in the output (which is in this case the next 32 bytes). This second group of 32 bytes specify the length of the array, in this case 0x2 or simply 2, meaning that the next two groups of 32 bytes are part of the array.

As expected, the last two groups, 0x0a and 0x64 are 10 and 100 respectively, so decoding the output results in [10, 100] as expected.

Of course doing this by hand isn't very efficient, and there are libraries out there that can parse the output for you automatically. Assuming you're using JavaScript/TypeScript:

There are also some online tools which you can use to encode and decode:

5
  • The output depends on the function return type. For example in this case it can also be interpreted as a tuple of four uint8.
    – Ismael
    Commented Apr 29, 2021 at 0:43
  • I tried to use ethers.js as follows ``` ethers.utils.defaultAbiCoder.decode([uint256, uint256], output) ``` and got [32,2] instead of [10, 100] Commented Apr 30, 2021 at 9:05
  • web3.eth.abi.encodeParameters(['uint256','uint256'],[10,100]) gives the same result [32,2] Commented Apr 30, 2021 at 9:42
  • The array specifies the type for each parameter, so since the first parameter type is uint256[], you want to specify it like encodeParameters(['uint256[]'], ...).
    – Morten
    Commented Apr 30, 2021 at 10:04
  • I managed to solve it. My mistake was in type definition. I should have put ['uint256[]'] instead of ['uint256', 'uint256']. Commented Apr 30, 2021 at 10:05

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.