abstract contract DelegateCaller {
    
    function implementation() public view virtual returns (address);

    function delegateToImplementation(bytes memory data) public returns (bytes memory) {
        address impl = implementation();
        require(impl != address(0), "NO implemention");
        return delegateTo(impl, data);
    }
    
    function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returnData) = callee.delegatecall(data);
        assembly {
            if eq(success, 0) {
                revert(add(returnData, 0x20), returndatasize())
            }
        }
        return returnData;
    }

        /**
     * @notice Delegates execution to an implementation contract
     * @dev It returns to the external caller whatever the implementation returns or forwards reverts
     *  There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
     * @param data The raw data to delegatecall
     * @return The returned bytes from the delegatecall
     */
    function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
        (bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
        assembly {
            if eq(success, 0) {
                revert(add(returnData, 0x20), returndatasize())
            }
        }
        return abi.decode(returnData, (bytes));
    }
}
function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
    (bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
    assembly {
        if eq(success, 0) {
            revert(add(returnData, 0x20), returndatasize())
        }
    }
    return abi.decode(returnData, (bytes));
}

/**
 * @notice Delegates execution to an implementation contract
 * @dev It returns to the external caller whatever the implementation returns or forwards reverts
 *  There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
 * @param data The raw data to delegatecall
 * @return The returned bytes from the delegatecall
 */