content: from typing import (
      TYPE_CHECKING,
      Any,
      Callable,
      Coroutine,
      Sequence,
      TypeVar,
      Union,
      cast,
  )
  
  from eth_abi.codec import (
      ABICodec,
  )
  from eth_utils.toolz import (
      curry,
      pipe,
  )
  
  from web3._utils.filters import (
      AsyncLogFilter,
      LogFilter,
      _UseExistingFilter,
  )
  from web3.method import (
      Method,
  )
  from web3.providers.persistent import (
      PersistentConnectionProvider,
  )
  from web3.types import (
      FormattedEthSubscriptionResponse,
      RPCEndpoint,
      RPCResponse,
  )
  
  if TYPE_CHECKING:
      from web3.main import (  # noqa: F401
          AsyncWeb3,
          Web3,
      )
  
  
  @curry
  def apply_result_formatters(
      result_formatters: Callable[..., Any], result: RPCResponse
  ) -> RPCResponse:
      if result_formatters:
          formatted_result = pipe(result, result_formatters)
          return formatted_result
      else:
          return result
  
  
  TReturn = TypeVar("TReturn")
  
  
  @curry
  def retrieve_request_information_for_batching(
      w3: Union["AsyncWeb3[Any]", "Web3"],
      module: "Module",
      method: Method[Callable[..., Any]],
  ) -> (
      Callable[..., tuple[tuple[RPCEndpoint, Any], Sequence[Any]]]
      | Callable[..., Coroutine[Any, Any, tuple[tuple[RPCEndpoint, Any], Sequence[Any]]]]
  ):
      async def async_inner(
          *args: Any, **kwargs: Any
      ) -> tuple[tuple[RPCEndpoint, Any], Sequence[Any]]:
          (method_str, params), response_formatters = method.process_params(
              module, *args, **kwargs
          )
          if isinstance(w3.provider, PersistentConnectionProvider):
              w3.provider._request_processor.cache_request_information(
                  None, cast(RPCEndpoint, method_str), params, response_formatters
              )
          return (cast(RPCEndpoint, method_str), params), response_formatters
  
      def inner(
          *args: Any, **kwargs: Any
      ) -> tuple[tuple[RPCEndpoint, Any], Sequence[Any]]:
          (method_str, params), response_formatters = method.process_params(
              module, *args, **kwargs
          )
          return (cast(RPCEndpoint, method_str), params), response_formatters
  
      return async_inner if module.is_async else inner
  
  
  @curry
  def retrieve_blocking_method_call_fn(
      w3: "Web3",
      module: "Module",
      method: Method[Callable[..., TReturn]],
  ) -> Callable[..., TReturn | LogFilter]:
      def caller(*args: Any, **kwargs: Any) -> TReturn | LogFilter:
          try:
              (method_str, params), response_formatters = method.process_params(
                  module, *args, **kwargs
              )
          except _UseExistingFilter as err:
              return LogFilter(eth_module=module, filter_id=err.filter_id)
  
          (
              result_formatters,
              error_formatters,
              null_result_formatters,
          ) = response_formatters
          result = w3.manager.request_blocking(
              method_str, params, error_formatters, null_result_formatters
          )
          return apply_result_formatters(result_formatters, result)
  
      return caller
  
  
  @curry
  def retrieve_async_method_call_fn(
      async_w3: "AsyncWeb3[Any]",
      module: "Module",
      method: Method[Callable[..., Any]],
  ) -> Callable[
      ...,
      Coroutine[
          Any,
          Any,
          RPCResponse | FormattedEthSubscriptionResponse | AsyncLogFilter | None,
      ],
  ]:
      async def caller(
          *args: Any, **kwargs: Any
      ) -> RPCResponse | FormattedEthSubscriptionResponse | AsyncLogFilter:
          try:
              (method_str, params), response_formatters = method.process_params(
                  module, *args, **kwargs
              )
          except _UseExistingFilter as err:
              return AsyncLogFilter(eth_module=module, filter_id=err.filter_id)
  
          if isinstance(async_w3.provider, PersistentConnectionProvider):
              return await async_w3.manager.socket_request(
                  cast(RPCEndpoint, method_str),
                  params,
                  response_formatters=response_formatters,
              )
          else:
              (
                  result_formatters,
                  error_formatters,
                  null_result_formatters,
              ) = response_formatters
              result = await async_w3.manager.coro_request(
                  method_str, params, error_formatters, null_result_formatters
              )
              return apply_result_formatters(result_formatters, result)
  
      return caller
  
  
  #  Module should no longer have access to the full web3 api.
  #  Only the calling functions need access to the request methods.
  #  Any "re-entrant" shenanigans can go in the middleware, which do
  #  have web3 access.
  class Module:
      is_async = False
  
      def __init__(self, w3: Union["AsyncWeb3[Any]", "Web3"]) -> None:
          if self.is_async:
              self.retrieve_caller_fn = retrieve_async_method_call_fn(w3, self)
          else:
              self.retrieve_caller_fn = retrieve_blocking_method_call_fn(w3, self)
          self.retrieve_request_information = retrieve_request_information_for_batching(
              w3, self
          )
          self.w3 = w3
  
      @property
      def codec(self) -> ABICodec:
          # use codec set on the Web3 instance
          return self.w3.codec
  
      def attach_methods(
          self,
          methods: dict[str, Method[Callable[..., Any]]],
      ) -> None:
          for method_name, method_class in methods.items():
              klass = (
                  method_class.__get__(module=self)()
                  if method_class.is_property
                  else method_class.__get__(module=self)
              )
              setattr(self, method_name, klass)
  