content: from typing import (
      TYPE_CHECKING,
      Any,
      cast,
  )
  
  from eth_utils.toolz import (
      assoc,
  )
  
  from web3._utils.method_formatters import (
      to_hex_if_integer,
  )
  from web3._utils.utility_methods import (
      all_in_dict,
      any_in_dict,
      none_in_dict,
  )
  from web3.constants import (
      DYNAMIC_FEE_TXN_PARAMS,
  )
  from web3.exceptions import (
      InvalidTransaction,
      TransactionTypeMismatch,
  )
  from web3.middleware.base import (
      Web3Middleware,
  )
  from web3.types import (
      BlockData,
      RPCEndpoint,
      TxParams,
      Wei,
  )
  
  if TYPE_CHECKING:
      from web3 import (  # noqa: F401
          AsyncWeb3,
          Web3,
      )
  
  
  def validate_transaction_params(
      transaction: TxParams, latest_block: BlockData, strategy_based_gas_price: Wei
  ) -> TxParams:
      # gas price strategy explicitly set:
      if (
          strategy_based_gas_price is not None
          and "gasPrice" not in transaction
          and none_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction)
      ):
          transaction = assoc(
              transaction, "gasPrice", to_hex_if_integer(strategy_based_gas_price)
          )
  
      # legacy and dynamic fee tx variables used:
      if "gasPrice" in transaction and any_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction):
          raise TransactionTypeMismatch()
      # dynamic fee transaction - canonical case:
      elif all_in_dict(DYNAMIC_FEE_TXN_PARAMS, transaction):
          if int(str(transaction["maxFeePerGas"]), 16) < int(
              str(transaction["maxPriorityFeePerGas"]), 16
          ):
              raise InvalidTransaction("maxFeePerGas must be >= maxPriorityFeePerGas")
      # dynamic fee txn - no max fee:
      elif "maxFeePerGas" not in transaction and "maxPriorityFeePerGas" in transaction:
          base_fee = latest_block["baseFeePerGas"]
          priority_fee = int(str(transaction["maxPriorityFeePerGas"]), 16)
          max_fee_per_gas = priority_fee + 2 * base_fee
          transaction = assoc(transaction, "maxFeePerGas", hex(max_fee_per_gas))
      # dynamic fee transaction - no priority fee:
      elif "maxFeePerGas" in transaction and "maxPriorityFeePerGas" not in transaction:
          raise InvalidTransaction(
              "maxPriorityFeePerGas must be defined in a 1559 transaction."
          )
  
      # should be a fully formed (legacy or dynamic fee) tx
      # or no fee values were specified
      return transaction
  
  
  class GasPriceStrategyMiddleware(Web3Middleware):
      """
      - Uses a gas price strategy if one is set. This is only supported for
        legacy transactions. It is recommended to send dynamic fee transactions
        (EIP-1559) whenever possible.
  
      - Validates transaction params against legacy and dynamic fee txn values.
      """
  
      def request_processor(self, method: RPCEndpoint, params: Any) -> Any:
          if method == "eth_sendTransaction":
              transaction = params[0]
              generated_gas_price = self._w3.eth.generate_gas_price(transaction)
              w3 = cast("Web3", self._w3)
              latest_block = w3.eth.get_block("latest")
              transaction = validate_transaction_params(
                  transaction, latest_block, generated_gas_price
              )
              params = (transaction,)
  
          return method, params
  
      # -- async -- #
  
      async def async_request_processor(self, method: RPCEndpoint, params: Any) -> Any:
          if method == "eth_sendTransaction":
              transaction = params[0]
              w3 = cast("AsyncWeb3[Any]", self._w3)
              generated_gas_price = w3.eth.generate_gas_price(transaction)
              latest_block = await w3.eth.get_block("latest")
              transaction = validate_transaction_params(
                  transaction, latest_block, generated_gas_price
              )
              params = (transaction,)
          return method, params
  