content: from functools import (
      singledispatch,
  )
  import operator
  from typing import (
      TYPE_CHECKING,
      Any,
      Collection,
      Iterable,
      TypeVar,
      Union,
      cast,
  )
  
  from eth_account import (
      Account,
  )
  from eth_account.signers.local import (
      LocalAccount,
  )
  from eth_account.types import (
      TransactionDictType as EthAccountTxParams,
  )
  from eth_keys.datatypes import (
      PrivateKey,
  )
  from eth_typing import (
      ChecksumAddress,
      HexStr,
  )
  from eth_utils import (
      to_checksum_address,
      to_dict,
  )
  from eth_utils.curried import (
      apply_formatter_if,
  )
  from eth_utils.toolz import (
      compose,
  )
  from toolz import (
      curry,
  )
  
  from web3._utils.async_transactions import (
      async_fill_nonce,
      async_fill_transaction_defaults,
  )
  from web3._utils.method_formatters import (
      STANDARD_NORMALIZERS,
  )
  from web3._utils.rpc_abi import (
      TRANSACTION_PARAMS_ABIS,
      apply_abi_formatters_to_dict,
  )
  from web3._utils.transactions import (
      fill_nonce,
      fill_transaction_defaults,
  )
  from web3.exceptions import (
      Web3TypeError,
  )
  from web3.middleware.base import (
      Web3MiddlewareBuilder,
  )
  from web3.types import (
      RPCEndpoint,
      TxParams,
  )
  
  if TYPE_CHECKING:
      from web3 import (  # noqa: F401
          AsyncWeb3,
          Web3,
      )
  
  T = TypeVar("T")
  
  to_hexstr_from_eth_key = operator.methodcaller("to_hex")
  
  
  def is_eth_key(value: Any) -> bool:
      return isinstance(value, PrivateKey)
  
  
  key_normalizer = compose(
      apply_formatter_if(is_eth_key, to_hexstr_from_eth_key),
  )
  
  _PrivateKey = Union[LocalAccount, PrivateKey, HexStr, bytes]
  
  
  @to_dict
  def gen_normalized_accounts(
      val: _PrivateKey | Collection[_PrivateKey],
  ) -> Iterable[tuple[ChecksumAddress, LocalAccount]]:
      if isinstance(
          val,
          (
              list,
              tuple,
              set,
          ),
      ):
          for i in val:
              account: LocalAccount = to_account(i)
              yield account.address, account
      else:
          account = to_account(val)
          yield account.address, account
          return
  
  
  @singledispatch
  def to_account(val: Any) -> LocalAccount:
      raise Web3TypeError(
          "key must be one of the types: "
          "eth_keys.datatype.PrivateKey, eth_account.signers.local.LocalAccount, "
          "or raw private key as a hex string or byte string. "
          f"Was of type {type(val)}"
      )
  
  
  @to_account.register(LocalAccount)
  def _(val: T) -> T:
      return val
  
  
  def private_key_to_account(val: _PrivateKey) -> LocalAccount:
      normalized_key = key_normalizer(val)
      return Account.from_key(normalized_key)
  
  
  to_account.register(PrivateKey, private_key_to_account)
  to_account.register(str, private_key_to_account)
  to_account.register(bytes, private_key_to_account)
  
  
  def format_transaction(transaction: TxParams) -> TxParams:
      """
      Format transaction so that it can be used correctly in the signing middleware.
  
      Converts bytes to hex strings and other types that can be passed to
      the underlying layers. Also has the effect of normalizing 'from' for
      easier comparisons.
      """
      return apply_abi_formatters_to_dict(
          STANDARD_NORMALIZERS, TRANSACTION_PARAMS_ABIS, transaction
      )
  
  
  class SignAndSendRawMiddlewareBuilder(Web3MiddlewareBuilder):
      _accounts = None
      format_and_fill_tx = None
  
      @staticmethod
      @curry
      def build(
          private_key_or_account: _PrivateKey | Collection[_PrivateKey],
          w3: Union["Web3", "AsyncWeb3[Any]"],
      ) -> "SignAndSendRawMiddlewareBuilder":
          middleware = SignAndSendRawMiddlewareBuilder(w3)
          middleware._accounts = gen_normalized_accounts(private_key_or_account)
          return middleware
  
      def request_processor(self, method: "RPCEndpoint", params: Any) -> Any:
          if method != "eth_sendTransaction":
              return method, params
          else:
              w3 = cast("Web3", self._w3)
              if self.format_and_fill_tx is None:
                  self.format_and_fill_tx = compose(
                      format_transaction,
                      fill_transaction_defaults(w3),
                      fill_nonce(w3),
                  )
  
              filled_transaction = self.format_and_fill_tx(params[0])
              tx_from = filled_transaction.get("from", None)
  
              if tx_from is None or (
                  tx_from is not None and tx_from not in self._accounts
              ):
                  return method, params
              else:
                  account = self._accounts[to_checksum_address(tx_from)]
                  raw_tx = account.sign_transaction(filled_transaction).raw_transaction
  
                  return (
                      RPCEndpoint("eth_sendRawTransaction"),
                      [raw_tx.to_0x_hex()],
                  )
  
      # -- async -- #
  
      async def async_request_processor(self, method: "RPCEndpoint", params: Any) -> Any:
          if method != "eth_sendTransaction":
              return method, params
  
          else:
              w3 = cast("AsyncWeb3[Any]", self._w3)
  
              formatted_transaction = format_transaction(params[0])
              filled_transaction = await async_fill_transaction_defaults(
                  w3, formatted_transaction
              )
              filled_transaction = await async_fill_nonce(w3, filled_transaction)
              tx_from = filled_transaction.get("from", None)
  
              if tx_from is None or (
                  tx_from is not None and tx_from not in self._accounts
              ):
                  return method, params
              else:
                  account = self._accounts[to_checksum_address(tx_from)]
                  raw_tx = account.sign_transaction(
                      cast(EthAccountTxParams, filled_transaction)
                  ).raw_transaction
  
                  return (
                      RPCEndpoint("eth_sendRawTransaction"),
                      [raw_tx.to_0x_hex()],
                  )
  