4

When using the lower-level address.call(data) to call an external contract, can you retrieve an exception that the external contract throws? Is it part of the return data that’s returned with the success boolean?

1 Answer 1

3

Yes, in solidity the revert reason is passed as the return data of the call.

So, if the call failed with:

revert CustomError(uint256(100))

the return data will be abi.encodeWithSelector(CustomError.selector, uint256(100)). If the revert reason is a string, the return data will be the string abi-encoded.

I've made this example on how to get data out of a custom error.

pragma solidity ^0.8.0;

contract TestError {
    error TimeError(uint256 time);

    event LogTime(uint256 time);

    function getTimestampAsError() external {
        revert TimeError(block.timestamp);
    }

    function main() external {
        // make external call to this contract
        bytes memory data = abi.encodeWithSelector(this.getTimestampAsError.selector);
        (bool success, bytes memory returndata) = address(this).call(data);

        // call failed
        if (!success) {
            // decode returndata
            // we need assembly cause there's no 'decodeWithSelector'
            uint256 time;
            assembly {
                // mload(returndata) -> length of bytes
                // mload(returndata + 0x20) -> start of body
                //    first 4 bytes are TimeError.selector
                time := mload(add(returndata,0x24))
            }

            // return time using logs
            emit LogTime(time);
        }
    }
}
2

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.