Solidity – How to Decode Return Bytes from Solidity `address.call`

evmsolidity

If I call method x, which returns an address, in the Ethereum contract with address addr:

(bool success, bytes memory returnVal) = addr.call(abi.encodeWithSignature("x()"));
require(success, "Could not call x()");

I then need to decode the result in returnBytes to get an address. Is this the correct way to do it?

(address returnedAddr) = abi.decode(returnVal, (address));

Best Answer

No.

The call data must be composed of a function identifier (4 first bytes of keccak256 of your function signature) followed by the encoded parameters if any. addr.call(abi.encodePacked("x()")) is incorrect. The best way is to use the provided abi functions, such as encodeWithSignature, it's just more readable.

Like in the following example. I just changed call to staticcall to be able to keep the test function view. You can change it to call if that's a better fit for your use case.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A {
    function getAddress() public pure returns (address) {
        return 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
    }
}
contract B {
    address addr;
    constructor(address _addr) {
        addr = _addr;
    }

    function test() public view returns (address returnValue) {
        (bool success, bytes memory returnBytes) = addr.staticcall(abi.encodeWithSignature("getAddress()"));
        require(success == true, "Call to getAddress() failed");
        returnValue = abi.decode(returnBytes, (address));
    }

}