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

    abi: ABI = {{contract_name | lower}}_abi
    {%- if has_bytecode %}
    bytecode: bytes | None = try_bytecode_hexbytes({{contract_name | lower}}_bytecode, "{{contract_name | lower}}")
    {%- 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 %}

    @classmethod
    def constructor(cls{{', ' + constructor.input_names_and_types|join(', ') if has_constructor_args 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.

      """

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


    @classmethod
    def deploy(cls, w3: Web3, account: LocalAccount | ChecksumAddress{{', constructorArgs: ConstructorArgs' if has_constructor_args 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({{ '*constructorArgs' if has_constructor_args 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)
        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.raw_transaction)
        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

