library RevertMsgExtractor {
    /// @dev Helper function to extract a useful revert message from a failed call.
    /// If the returned data is malformed or not correctly abi encoded then this call can fail itself.
    function getRevertMsg(bytes memory returnData)
        internal pure
        returns (string memory)
    {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (returnData.length < 68) return "Transaction reverted silently";

        assembly {
            // Slice the sighash.
            returnData := add(returnData, 0x04)
        }
        return abi.decode(returnData, (string)); // All that remains is the revert string
    }
}
function getRevertMsg(bytes memory returnData)
    internal pure
    returns (string memory)
{
    // If the _res length is less than 68, then the transaction failed silently (without a revert message)
    if (returnData.length < 68) return "Transaction reverted silently";

    assembly {
        // Slice the sighash.
        returnData := add(returnData, 0x04)
    }
    return abi.decode(returnData, (string)); // All that remains is the revert string
}

/// @dev Helper function to extract a useful revert message from a failed call.
/// If the returned data is malformed or not correctly abi encoded then this call can fail itself.