code: def prepare_transaction(
          address,
          web3,
          fn_identifier,
          contract_abi=None,
          fn_abi=None,
          transaction=None,
          fn_args=None,
          fn_kwargs=None):
      
      if fn_abi is None:
          fn_abi = find_matching_fn_abi(contract_abi, fn_identifier, fn_args, fn_kwargs)
  
      validate_payable(transaction, fn_abi)
  
      if transaction is None:
          prepared_transaction = {}
      else:
          prepared_transaction = dict(**transaction)
  
      if 'data' in prepared_transaction:
          raise ValueError("Transaction parameter may not contain a 'data' key")
  
      if address:
          prepared_transaction.setdefault('to', address)
  
      prepared_transaction['data'] = encode_transaction_data(
          web3,
          fn_identifier,
          contract_abi,
          fn_abi,
          fn_args,
          fn_kwargs,
      )
      return prepared_transaction
docs: :parameter `is_function_abi` is used to distinguish  function abi from contract abi
      Returns a dictionary of the transaction that could be used to call this
      TODO: make this a public API
      TODO: add new prepare_deploy_transaction API