{# loop over all events and create types for each #}
{%- for event in events -%}

{% set has_event_args = event.inputs|length > 0 %}

class {{contract_name}}{{event.capitalized_name}}ContractEvent(ContractEvent):
    """ContractEvent for {{event.name}}."""
    # super() get_logs and create_filter methods are generic, while our version adds values & types
    # pylint: disable=arguments-differ

    {# TODO: add type-hints for argument_names #}
    {# TODO: remove pylint disable when we add a type-hint for argument_names #}
    # pylint: disable=useless-parent-delegation
    def __init__(self, *argument_names: tuple[str]) -> None:
        super().__init__(*argument_names)

    {# TODO: add type-hints for argument_filters -#}
    @combomethod_typed
    def get_logs_typed(
        self,
        argument_filters: dict[str, Any] | None = None,
        from_block: BlockIdentifier | None = None,
        to_block: BlockIdentifier | None = None,
        block_hash: HexBytes | None = None,
    ) -> Iterable[{{event.capitalized_name}}Event]:
        """Extension of `get_logs` that return a typed dataclass of the event."""
        abi_events = super().get_logs(argument_filters=argument_filters, from_block=from_block, to_block=to_block, block_hash=block_hash)
        # TODO there may be issues with this function if the user uses a middleware that changes event structure.
        return [
            {{event.capitalized_name}}Event(
                log_index = abi_event.logIndex,
                transaction_index = abi_event.transactionIndex,
                transaction_hash = abi_event.transactionHash,
                address = abi_event.address,
                block_hash = abi_event.blockHash,
                block_number = abi_event.blockNumber,
{% if has_event_args %}
                args = {{event.capitalized_name}}Event.{{event.capitalized_name}}EventArgs(
{%- for event_input in event.inputs %}
                    {{event_input.name}} = abi_event.args["{{event_input.name}}"],
{%- endfor %}
                ),
{% else %}
                args = BaseEventArgs(),
{% endif %}
            ) for abi_event in abi_events
        ]
    
    @combomethod_typed
    def process_receipt_typed(
        self, txn_receipt: TxReceipt, errors: EventLogErrorFlags = WARN
    ) -> Iterable[{{event.capitalized_name}}Event]:
        """Extension of `process_receipt` that return a typed dataclass of the event."""
        abi_events = super().process_receipt(txn_receipt, errors)
        # TODO there may be issues with this function if the user uses a middleware that changes event structure.
        return [
            {{event.capitalized_name}}Event(
                log_index = abi_event.logIndex,
                transaction_index = abi_event.transactionIndex,
                transaction_hash = abi_event.transactionHash,
                address = abi_event.address,
                block_hash = abi_event.blockHash,
                block_number = abi_event.blockNumber,
{% if has_event_args %}
                args = {{event.capitalized_name}}Event.{{event.capitalized_name}}EventArgs(
{%- for event_input in event.inputs %}
                    {{event_input.name}} = abi_event.args["{{event_input.name}}"],
{%- endfor %}
                ),
{% else %}
                args = BaseEventArgs(),
{% endif %}
            ) for abi_event in abi_events
        ]

    {# TODO: add type-hints for argument_filters -#}
    @combomethod_typed
    def create_filter( # type: ignore
        self,
        *,  # PEP 3102
        argument_filters: dict[str, Any] | None = None,
        from_block: BlockIdentifier | None = None,
        to_block: BlockIdentifier = "latest",
        address: ChecksumAddress | None = None,
        topics: Sequence[Any] | None = None,
    ) -> LogFilter:
        return cast(LogFilter, super().create_filter(argument_filters=argument_filters, from_block=from_block, to_block=to_block, address=address, topics=topics))

{% endfor %}

class {{contract_name}}ContractEvents(ContractEvents):
    """ContractEvents for the {{contract_name}} contract."""
{% for event in events %}
    {{event.name}}: Type[{{contract_name}}{{event.capitalized_name}}ContractEvent]
{% endfor %}

    def __init__(
        self,
        abi: ABI,
        w3: "Web3",
        address: ChecksumAddress | None = None,
    ) -> None:
        super().__init__(abi, w3, address)
        {% for event in events -%}
        self.{{event.name}} = cast(Type[{{contract_name}}{{event.capitalized_name}}ContractEvent], {{contract_name}}{{event.capitalized_name}}ContractEvent.factory(
            "{{event.name}}",
            w3=w3,
            contract_abi=abi,
            address=address,
            event_name="{{event.name}}"
        ))
        {% endfor %}