content: from typing import (
      TYPE_CHECKING,
      Any,
      Sequence,
      cast,
  )
  
  from toolz import (
      merge,
  )
  
  from web3._utils.normalizers import (
      abi_ens_resolver,
      async_abi_ens_resolver,
  )
  from web3._utils.rpc_abi import (
      RPC_ABIS,
      abi_request_formatters,
  )
  from web3.types import (
      RPCEndpoint,
  )
  
  from .._utils.abi import (
      abi_data_tree,
      async_data_tree_map,
      strip_abi_type,
  )
  from .._utils.formatters import (
      recursive_map,
  )
  from ..exceptions import (
      Web3TypeError,
  )
  from .base import (
      Web3Middleware,
  )
  from .formatting import (
      FormattingMiddlewareBuilder,
  )
  
  if TYPE_CHECKING:
      from web3 import (  # noqa: F401
          AsyncWeb3,
          Web3,
      )
  
  
  def _is_logs_subscription_with_optional_args(method: RPCEndpoint, params: Any) -> bool:
      return method == "eth_subscribe" and len(params) == 2 and params[0] == "logs"
  
  
  async def async_format_all_ens_names_to_address(
      async_web3: "AsyncWeb3[Any]",
      abi_types_for_method: Sequence[Any],
      data: Sequence[Any],
  ) -> Sequence[Any]:
      # provide a stepwise version of what the curried formatters do
      abi_typed_params = abi_data_tree(abi_types_for_method, data)
      formatted_data_tree = await async_data_tree_map(
          async_web3,
          async_abi_ens_resolver,
          abi_typed_params,
      )
      formatted_params = recursive_map(strip_abi_type, formatted_data_tree)
      return formatted_params
  
  
  async def async_apply_ens_to_address_conversion(
      async_web3: "AsyncWeb3[Any]",
      params: Any,
      abi_types_for_method: Sequence[str] | dict[str, str],
  ) -> Any:
      if isinstance(abi_types_for_method, Sequence):
          formatted_params = await async_format_all_ens_names_to_address(
              async_web3, abi_types_for_method, params
          )
          return formatted_params
  
      elif isinstance(abi_types_for_method, dict):
          # first arg is a dict but other args may be preset
          # e.g. eth_call({...}, "latest")
          # this is similar to applying a dict formatter at index 0 of the args
          param_dict = params[0]
          fields = list(abi_types_for_method.keys() & param_dict.keys())
          formatted_params = await async_format_all_ens_names_to_address(
              async_web3,
              [abi_types_for_method[field] for field in fields],
              [param_dict[field] for field in fields],
          )
          formatted_dict = dict(zip(fields, formatted_params))
          formatted_params_dict = merge(param_dict, formatted_dict)
          return (formatted_params_dict, *params[1:])
  
      else:
          raise Web3TypeError(
              f"ABI definitions must be a list or dictionary, "
              f"got {abi_types_for_method!r}"
          )
  
  
  class ENSNameToAddressMiddleware(Web3Middleware):
      _formatting_middleware = None
  
      def request_processor(self, method: "RPCEndpoint", params: Any) -> Any:
          if self._formatting_middleware is None:
              normalizers = [
                  abi_ens_resolver(self._w3),
              ]
              self._formatting_middleware = FormattingMiddlewareBuilder.build(
                  request_formatters=abi_request_formatters(normalizers, RPC_ABIS)
              )
  
          return self._formatting_middleware(self._w3).request_processor(method, params)
  
      # -- async -- #
  
      async def async_request_processor(self, method: "RPCEndpoint", params: Any) -> Any:
          abi_types_for_method = RPC_ABIS.get(method, None)
  
          if abi_types_for_method is not None:
              if _is_logs_subscription_with_optional_args(method, params):
                  # eth_subscribe optional logs params are unique.
                  # Handle them separately here.
                  (formatted_dict,) = await async_apply_ens_to_address_conversion(
                      cast("AsyncWeb3[Any]", self._w3),
                      (params[1],),
                      {
                          "address": "address",
                          "topics": "bytes32[]",
                      },
                  )
                  params = (params[0], formatted_dict)
  
              else:
                  params = await async_apply_ens_to_address_conversion(
                      cast("AsyncWeb3[Any]", self._w3),
                      params,
                      abi_types_for_method,
                  )
  
          return method, params
  