Having the common app options as a decorator facilitates reuse.

def options(func):
    """Having the common app options as a decorator facilitates reuse."""

    # Until https://github.com/pallets/click/issues/926 is fixed the options need to be re-defined
    # for every use
    options_ = [
        option(
            '--datadir',
            help='Directory for storing raiden data.',
            default=lambda: os.path.join(os.path.expanduser('~'), '.raiden'),
            type=click.Path(
                exists=False,
                dir_okay=True,
                file_okay=False,
                writable=True,
                resolve_path=True,
                allow_dash=False,
            ),
            show_default=True,
        ),
        option(
            '--config-file',
            help='Configuration file (TOML)',
            default=os.path.join('${datadir}', 'config.toml'),
            type=PathRelativePath(
                file_okay=True,
                dir_okay=False,
                exists=False,
                readable=True,
                resolve_path=True,
            ),
            show_default=True,
        ),
        option(
            '--keystore-path',
            help=(
                'If you have a non-standard path for the ethereum keystore directory'
                ' provide it using this argument.'
            ),
            default=None,
            type=click.Path(exists=True),
            show_default=True,
        ),
        option(
            '--address',
            help=(
                'The ethereum address you would like raiden to use and for which '
                'a keystore file exists in your local system.'
            ),
            default=None,
            type=ADDRESS_TYPE,
            show_default=True,
        ),
        option(
            '--password-file',
            help='Text file containing the password for the provided account',
            default=None,
            type=click.File(lazy=True),
            show_default=True,
        ),
        option(
            '--tokennetwork-registry-contract-address',
            help='hex encoded address of the Token Network Registry contract.',
            type=ADDRESS_TYPE,
            show_default=True,
        ),
        option(
            '--secret-registry-contract-address',
            help='hex encoded address of the Secret Registry contract.',
            type=ADDRESS_TYPE,
            show_default=True,
        ),
        option(
            '--service-registry-contract-address',
            help='hex encoded address of the Service Registry contract.',
            type=ADDRESS_TYPE,
        ),
        option(
            '--endpoint-registry-contract-address',
            help='hex encoded address of the Endpoint Registry contract.',
            type=ADDRESS_TYPE,
            show_default=True,
        ),
        option(
            '--user-deposit-contract-address',
            help='hex encoded address of the User Deposit contract.',
            type=ADDRESS_TYPE,
        ),
        option(
            '--console',
            help='Start the interactive raiden console',
            is_flag=True,
        ),
        option(
            '--transport',
            help='Transport system to use. UDP is not recommended',
            type=click.Choice(['udp', 'matrix']),
            default='matrix',
            show_default=True,
        ),
        option(
            '--network-id',
            help=(
                'Specify the network name/id of the Ethereum network to run Raiden on.\n'
                'Available networks:\n'
                '"mainnet" - network id: 1\n'
                '"ropsten" - network id: 3\n'
                '"rinkeby" - network id: 4\n'
                '"goerli" - network id: 5\n'
                '"kovan" - network id: 42\n'
                '"<NETWORK_ID>": use the given network id directly\n'
            ),
            type=NetworkChoiceType([
                'mainnet',
                'ropsten',
                'rinkeby',
                'goerli',
                'kovan',
                '<NETWORK_ID>',
            ]),
            default='mainnet',
            show_default=True,
        ),
        option(
            '--environment-type',
            help=(
                'Specify the environment (production or development).\n'
                'The "production" setting adds some safety measures and is mainly intended '
                'for running Raiden on the mainnet.\n'
            ),
            type=EnumChoiceType(Environment),
            default=Environment.PRODUCTION.value,
            show_default=True,
        ),
        option(
            '--accept-disclaimer',
            help='Bypass the experimental software disclaimer prompt',
            is_flag=True,
        ),
        option(
            '--showconfig',
            help='Show all configuration values used to control Raiden\'s behavior',
            is_flag=True,
        ),
        option_group(
            'Ethereum Node Options',
            option(
                '--sync-check/--no-sync-check',
                help='Checks if the ethereum node is synchronized against etherscan.',
                default=True,
                show_default=True,
            ),
            option(
                '--gas-price',
                help=(
                    'Set the gas price for ethereum transactions. If not provided '
                    'the normal gas price startegy is used.\n'
                    'Available options:\n'
                    '"fast" - transactions are usually mined within 60 seconds\n'
                    '"normal" - transactions are usually mined within 5 minutes\n'
                    '<GAS_PRICE> - use given gas price\n'
                ),
                type=GasPriceChoiceType(['normal', 'fast']),
                default='fast',
                show_default=True,
            ),
            option(
                '--eth-rpc-endpoint',
                help=(
                    '"host:port" address of ethereum JSON-RPC server.\n'
                    'Also accepts a protocol prefix (http:// or https://) with optional port'
                ),
                default='http://127.0.0.1:8545',  # geth default jsonrpc port
                type=str,
                show_default=True,
            ),
        ),
        option_group(
            'Raiden Services Options',
            option(
                '--routing-mode',
                help=(
                    'Specify the routing mode to be used.\n'
                    '"basic": use local routing\n'
                    '"pfs": use the path finding service\n'
                ),
                type=EnumChoiceType(RoutingMode),
                default=RoutingMode.BASIC.value,
                show_default=True,
            ),
            option(
                '--pathfinding-service-address',
                help=(
                    'URL to the Raiden path finding service to request paths from.\n'
                    'Example: https://pfs-ropsten.services-dev.raiden.network\n'
                    'Can also be given the "auto" value so that raiden chooses a '
                    'PFS randomly from the service registry contract'
                ),
                default='auto',
                type=str,
                show_default=True,
            ),
            option(
                '--pathfinding-eth-address',
                help=(
                    'Ethereum address to which to pay the fees of the path finding service.\n'
                    'If the path finding service is chosen from the service registry contract, '
                    'this option will be ignored. If the path finding service is configured '
                    'manually, i. e. "--pathfinding-service-address" set to a value other than '
                    '"auto", this argument must be set to a valid EIP55 address.'
                ),
                type=str,
            ),
            option(
                '--pathfinding-max-paths',
                help='Set maximum number of paths to be requested from the path finding service.',
                default=DEFAULT_PATHFINDING_MAX_PATHS,
                type=int,
                show_default=True,
            ),
            option(
                '--pathfinding-max-fee',
                help='Set max fee per request paid to the path finding service.',
                default=DEFAULT_PATHFINDING_MAX_FEE,
                type=int,
                show_default=True,
            ),
            option(
                '--pathfinding-iou-timeout',
                help='Number of blocks before a new IOU to the path finding service expires.',
                default=DEFAULT_PATHFINDING_IOU_TIMEOUT,
                type=int,
                show_default=True,
            ),
            option(
                '--enable-monitoring',
                help='Enable broadcasting of balance proofs to the monitoring services.',
                is_flag=True,
            ),
        ),
        option_group(
            'UDP Transport Options',
            option(
                '--listen-address',
                help='"host:port" for the raiden service to listen on.',
                default='0.0.0.0:{}'.format(INITIAL_PORT),
                type=str,
                show_default=True,
            ),
            option(
                '--max-unresponsive-time',
                help=(
                    'Max time in seconds for which an address can send no packets and '
                    'still be considered healthy.'
                ),
                default=30,
                type=int,
                show_default=True,
            ),
            option(
                '--send-ping-time',
                help=(
                    'Time in seconds after which if we have received no message from a '
                    'node we have a connection with, we are going to send a PING message'
                ),
                default=60,
                type=int,
                show_default=True,
            ),
            option(
                '--nat',
                help=(
                    'Manually specify method to use for determining public IP / NAT traversal.\n'
                    'Available methods:\n'
                    '"auto" - Try UPnP, then STUN, fallback to none\n'
                    '"upnp" - Try UPnP, fallback to none\n'
                    '"stun" - Try STUN, fallback to none\n'
                    '"none" - Use the local interface address '
                    '(this will likely cause connectivity issues)\n'
                    '"ext:<IP>[:<PORT>]" - manually specify the external IP (and optionally port '
                    'number)'
                ),
                type=NATChoiceType(['auto', 'upnp', 'stun', 'none', 'ext:<IP>[:<PORT>]']),
                default='auto',
                show_default=True,
                option_group='udp_transport',
            ),
        ),
        option_group(
            'Matrix Transport Options',
            option(
                '--matrix-server',
                help=(
                    'Matrix homeserver to use for communication.\n'
                    'Valid values:\n'
                    '"auto" - automatically select a suitable homeserver\n'
                    'A URL pointing to a Raiden matrix homeserver'
                ),
                default='auto',
                type=MatrixServerType(['auto', '<url>']),
                show_default=True,
            ),
        ),
        option_group(
            'Logging Options',
            option(
                '--log-config',
                help='Log level configuration.\n'
                     'Format: [<logger-name-1>]:<level>[,<logger-name-2>:level][,...]',
                type=LOG_LEVEL_CONFIG_TYPE,
                default=':info',
                show_default=True,
            ),
            option(
                '--log-file',
                help='file path for logging to file',
                default=None,
                type=str,
                show_default=True,
            ),
            option(
                '--log-json',
                help='Output log lines in JSON format',
                is_flag=True,
            ),
            option(
                '--disable-debug-logfile',
                help=(
                    'Disable the debug logfile feature. This is independent of '
                    'the normal logging setup'
                ),
                is_flag=True,
            ),
        ),
        option_group(
            'RPC Options',
            option(
                '--rpc/--no-rpc',
                help='Start with or without the RPC server.',
                default=True,
                show_default=True,
            ),
            option(
                '--rpccorsdomain',
                help='Comma separated list of domains to accept cross origin requests.',
                default='http://localhost:*/*',
                type=str,
                show_default=True,
            ),
            option(
                '--api-address',
                help='"host:port" for the RPC server to listen on.',
                default='127.0.0.1:5001',
                type=str,
                show_default=True,
            ),
            option(
                '--web-ui/--no-web-ui',
                help=(
                    'Start with or without the web interface. Requires --rpc. '
                    'It will be accessible at http://<api-address>. '
                ),
                default=True,
                show_default=True,
            ),
        ),
        option_group(
            'Debugging options',
            option(
                '--unrecoverable-error-should-crash',
                help=(
                    'DO NOT use, unless you know what you are doing. If provided '
                    'along with a production environment setting then all '
                    'unrecoverable errors will lead to a crash and not simply get logged.'
                ),
                is_flag=True,
                default=False,
            ),
        ),
        option_group(
            'Hash Resolver options',
            option(
                '--resolver-endpoint',
                help=(
                    'URL of the resolver server that is used to resolve '
                    'a payment hash to a secret. '
                    'Accepts a protocol prefix (http:// or https://) with optional port'
                ),
                default=None,
                type=str,
                show_default=True,
            ),
        ),
    ]

    for option_ in reversed(options_):
        func = option_(func)
    return func