[Ethereum] Delegatecall return values solidity 5.0

delegatecallsolidity

With solidity 5.0+ , the delegatecall function can return a boolean and a bytes representing return value. I want to understand how does one convert the returned bytes to various datatypes. ex

If the call is:

bool s, bytes b = delegatecall(....)

How can bytes b be converted to native types like (assuming i as the caller know the return value type):

  • bytes32
  • uint256
  • user defined struct

Thanks!

Best Answer

You can use abi.decode(...):

abi.decode(bytes memory encodedData, (...)) returns (...): ABI-decodes the given data, while the types are given in parentheses as second argument. Example:

(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes)).

Returning structs is not possible with the current ABI. You should add pragma experimental ABIEncoderV2 to your pragma.

Here you have a simple example to test:

pragma solidity ^0.5.0;

contract D {

    function delegatecallSetN(address _e, uint _n) public returns (uint, bytes32, uint, string memory) {
        bytes memory data = abi.encodeWithSelector(bytes4(keccak256("setN(uint256)")), _n);
        (bool success, bytes memory returnedData) = _e.delegatecall(data);
        require(success);
        return abi.decode(returnedData, (uint, bytes32, uint, string));
    }
}

contract E {

    uint public n;
    struct User {
        uint id;
        string name;
    }

    mapping (address => User) users;

    function setN(uint _n) public returns (uint, bytes32, uint, string memory) {
        bytes32 dataBytes = 0x111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFFCCCC;
        n = _n;
        users[msg.sender] = User(123, "mystring");
        return (n, dataBytes, users[msg.sender].id, users[msg.sender].name);
    }
}

Input:

decoded input 
{
    "address _e": "0x5b0C9dC0AFE417858DcC8dB5269E47ABc572AA77",
    "uint256 _n": "2"
}

Output:

decoded output 
{
    "0": "uint256: 2",
    "1": "bytes32: 0x111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFFCCCC",
    "2": "uint256: 123",
    "3": "string: mystring"
}