class {{contract_name}}Contract(Contract):
    """A web3.py Contract class for the {{contract_name}} contract."""

    abi: ABI = {{contract_name | lower}}_abi
    # We change `bytecode` as needed for linking, but keep
    # `_raw_bytecode` unchanged as an original copy.
    {% if bytecode %}# pylint: disable=line-too-long
    _raw_bytecode : HexStr | None = HexStr("{{bytecode}}")
    {% else %}
    _raw_bytecode : HexStr | None = None
    {%- endif -%}

    def __init__(self, address: ChecksumAddress | None = None) -> None:
        try:
            # Initialize parent Contract class
            super().__init__(address=address)
            self.functions = {{contract_name}}ContractFunctions({{contract_name | lower}}_abi, self.w3, address) # type: ignore
            {% if has_events -%}
            self.events = {{contract_name}}ContractEvents({{contract_name | lower}}_abi, self.w3, address) # type: ignore
            {%- endif %}
            {% if has_errors -%}
            self.errors = {{contract_name}}ContractErrors()
            {%- endif %}

        except FallbackNotFound:
            print("Fallback function not found. Continuing...")

    {% if has_events -%}
    events: {{contract_name}}ContractEvents
    {%- endif %}

    {% if has_errors -%}
    errors: {{contract_name}}ContractErrors = {{contract_name}}ContractErrors()
    {%- endif %}

    functions: {{contract_name}}ContractFunctions

{% set has_constructor_args = constructor.input_names_and_types|length > 0 %}
{% if has_constructor_args %}
    class ConstructorArgs(NamedTuple):
        """Arguments to pass the contract's constructor function."""
{% for name_and_type in constructor.input_names_and_types %}
        {{name_and_type}}
{% endfor %}
{% endif %}

{% set has_link_references = link_references.contract_names|length > 0 %}
{% if has_link_references %}
    class LinkReferences(NamedTuple):
        """Link references required when deploying."""
{% for name_and_type in link_references.contract_names_and_types %}
        {{name_and_type}}
{% endfor %}

    link_references_placeholder_lookup: dict[str, str] = {
{% for lookup in link_references.contract_names_to_placeholder_lookup %}
        {{lookup}},
{% endfor %}
    }
{% endif %}



    @classmethod
    def constructor(cls{{', ' + constructor.input_names_and_types|join(', ') if has_constructor_args else ''}}{{', link_references: LinkReferences' if has_link_references else ''}}) -> ContractConstructor: # type: ignore
        """Creates a transaction with the contract's constructor function.

        Parameters
        ----------

        w3 : Web3
            A web3 instance.
        account : LocalAccount
            The account to use to deploy the contract.

        Returns
        -------
        Self
            A deployed instance of the contract.

        """
        cls.bytecode = cls._raw_bytecode
        if cls.bytecode is not None:
{% if has_link_references %}
{% for contract_name in link_references.contract_names%}
            cls.bytecode = cls.bytecode.replace(
                cls.link_references_placeholder_lookup["{{contract_name}}"], link_references.{{contract_name}}.address[2:].lower()
            )
{% endfor %}
{% endif %}
            # bytecode needs to be in hex for web3
            cls.bytecode = HexBytes(cls.bytecode)


        return super().constructor({{constructor.input_names | wrap_with_dataclass_to_tuple | join(', ')}})


    @classmethod
    def deploy(cls, w3: Web3, account: LocalAccount | ChecksumAddress{{', constructor_args: ConstructorArgs' if has_constructor_args else ''}}{{', link_references: LinkReferences' if has_link_references else ''}}) -> Self:
        """Deploys and instance of the contract.

        Parameters
        ----------
        w3 : Web3
            A web3 instance.
        account : LocalAccount
            The account to use to deploy the contract.

        Returns
        -------
        Self
            A deployed instance of the contract.
        """
        deployer = cls.factory(w3=w3)
        constructor_fn = deployer.constructor({{ '*constructor_args,' if has_constructor_args else ''}}{{'link_references' if has_link_references else ''}})

        # if an address is supplied, try to use a web3 default account
        if isinstance(account, str):
            tx_hash = constructor_fn.transact({"from": account })
            tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

            deployed_contract = deployer(address=tx_receipt.contractAddress) # type: ignore
            return deployed_contract

        # otherwise use the account provided.
        deployment_tx = constructor_fn.build_transaction()
        current_nonce = w3.eth.get_transaction_count(account.address, "pending")
        deployment_tx.update({"nonce": current_nonce})

        # Sign the transaction with local account private key
        signed_tx = account.sign_transaction(deployment_tx)

        # Send the signed transaction and wait for receipt
        tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
        tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

        deployed_contract = deployer(address=tx_receipt.contractAddress) # type: ignore
        return deployed_contract

    @classmethod
    def factory(cls, w3: Web3, class_name: str | None = None, **kwargs: Any) -> Type[Self]:
        """Deploys and instance of the contract.

        Parameters
        ----------
        w3 : Web3
            A web3 instance.
        class_name: str | None
            The instance class name.

        Returns
        -------
        Self
            A deployed instance of the contract.
        """
        contract = super().factory(w3, class_name, **kwargs)
        contract.functions = {{contract_name}}ContractFunctions({{contract_name | lower}}_abi, w3, None)
        {% if has_errors -%}
        contract.errors = {{contract_name}}ContractErrors()
        {%- endif %}

        return contract

