text: import logging
  import time
  import traceback
  from pathlib import Path
  from secrets import token_bytes
  from typing import Any, Dict, List, Optional, Tuple
  
  from blspy import AugSchemeMPL
  
  from skynet.types.blockchain_format.coin import Coin
  from skynet.types.blockchain_format.program import Program
  from skynet.types.blockchain_format.sized_bytes import bytes32
  from skynet.types.spend_bundle import SpendBundle
  from skynet.types.coin_spend import CoinSpend
  from skynet.util.byte_types import hexstr_to_bytes
  from skynet.util.db_wrapper import DBWrapper
  from skynet.util.hash import std_hash
  from skynet.util.ints import uint32, uint64
  from skynet.wallet.cc_wallet import cc_utils
  from skynet.wallet.cc_wallet.cc_utils import CC_MOD, SpendableCC, spend_bundle_for_spendable_ccs, uncurry_cc
  from skynet.wallet.cc_wallet.cc_wallet import CCWallet
  from skynet.wallet.puzzles.genesis_by_coin_id_with_0 import genesis_coin_id_for_genesis_coin_checker
  from skynet.wallet.trade_record import TradeRecord
  from skynet.wallet.trading.trade_status import TradeStatus
  from skynet.wallet.trading.trade_store import TradeStore
  from skynet.wallet.transaction_record import TransactionRecord
  from skynet.wallet.util.trade_utils import (
      get_discrepancies_for_spend_bundle,
      get_output_amount_for_puzzle_and_solution,
      get_output_discrepancy_for_puzzle_and_solution,
  )
  from skynet.wallet.util.transaction_type import TransactionType
  from skynet.wallet.util.wallet_types import WalletType
  from skynet.wallet.wallet import Wallet
  from skynet.wallet.wallet_coin_record import WalletCoinRecord
  
  
  class TradeManager:
      wallet_state_manager: Any
      log: logging.Logger
      trade_store: TradeStore
  
      @staticmethod
      async def create(
          wallet_state_manager: Any,
          db_wrapper: DBWrapper,
          name: str = None,
      ):
          self = TradeManager()
          if name:
              self.log = logging.getLogger(name)
          else:
              self.log = logging.getLogger(__name__)
  
          self.wallet_state_manager = wallet_state_manager
          self.trade_store = await TradeStore.create(db_wrapper)
          return self
  
      async def get_offers_with_status(self, status: TradeStatus) -> List[TradeRecord]:
          records = await self.trade_store.get_trade_record_with_status(status)
          return records
  
      async def get_coins_of_interest(
          self,
      ) -> Tuple[Dict[bytes32, Coin], Dict[bytes32, Coin]]:
          """
          Returns list of coins we want to check if they are included in filter,
          These will include coins that belong to us and coins that that on other side of treade
          """
          all_pending = []
          pending_accept = await self.get_offers_with_status(TradeStatus.PENDING_ACCEPT)
          pending_confirm = await self.get_offers_with_status(TradeStatus.PENDING_CONFIRM)
          pending_cancel = await self.get_offers_with_status(TradeStatus.PENDING_CANCEL)
          all_pending.extend(pending_accept)
          all_pending.extend(pending_confirm)
          all_pending.extend(pending_cancel)
          removals = {}
          additions = {}
  
          for trade in all_pending:
              for coin in trade.removals:
                  removals[coin.name()] = coin
              for coin in trade.additions:
                  additions[coin.name()] = coin
  
          return removals, additions
  
      async def get_trade_by_coin(self, coin: Coin) -> Optional[TradeRecord]:
          all_trades = await self.get_all_trades()
          for trade in all_trades:
              if trade.status == TradeStatus.CANCELED.value:
                  continue
              if coin in trade.removals:
                  return trade
              if coin in trade.additions:
                  return trade
          return None
  
      async def coins_of_interest_farmed(self, removals: List[Coin], additions: List[Coin], height: uint32):
          """
          If both our coins and other coins in trade got removed that means that trade was successfully executed
          If coins from other side of trade got farmed without ours, that means that trade failed because either someone
          else completed trade or other side of trade canceled the trade by doing a spend.
          If our coins got farmed but coins from other side didn't, we successfully canceled trade by spending inputs.
          """
          removal_dict = {}
          addition_dict = {}
          checked: Dict[bytes32, Coin] = {}
          for coin in removals:
              removal_dict[coin.name()] = coin
          for coin in additions:
              addition_dict[coin.name()] = coin
  
          all_coins = []
          all_coins.extend(removals)
          all_coins.extend(additions)
  
          for coin in all_coins:
              if coin.name() in checked:
                  continue
              trade = await self.get_trade_by_coin(coin)
              if trade is None:
                  self.log.error(f"Coin: {Coin}, not in any trade")
                  continue
  
              # Check if all coins that are part of the trade got farmed
              # If coin is missing, trade failed
              failed = False
              for removed_coin in trade.removals:
                  if removed_coin.name() not in removal_dict:
                      self.log.error(f"{removed_coin} from trade not removed")
                      failed = True
                  checked[removed_coin.name()] = removed_coin
              for added_coin in trade.additions:
                  if added_coin.name() not in addition_dict:
                      self.log.error(f"{added_coin} from trade not added")
                      failed = True
                  checked[coin.name()] = coin
  
              if failed is False:
                  # Mark this trade as successful
                  await self.trade_store.set_status(trade.trade_id, TradeStatus.CONFIRMED, True, height)
                  self.log.info(f"Trade with id: {trade.trade_id} confirmed at height: {height}")
              else:
                  # Either we canceled this trade or this trade failed
                  if trade.status == TradeStatus.PENDING_CANCEL.value:
                      await self.trade_store.set_status(trade.trade_id, TradeStatus.CANCELED, True)
                      self.log.info(f"Trade with id: {trade.trade_id} canceled at height: {height}")
                  elif trade.status == TradeStatus.PENDING_CONFIRM.value:
                      await self.trade_store.set_status(trade.trade_id, TradeStatus.FAILED, True)
                      self.log.warning(f"Trade with id: {trade.trade_id} failed at height: {height}")
  
      async def get_locked_coins(self, wallet_id: int = None) -> Dict[bytes32, WalletCoinRecord]:
          """Returns a dictionary of confirmed coins that are locked by a trade."""
          all_pending = []
          pending_accept = await self.get_offers_with_status(TradeStatus.PENDING_ACCEPT)
          pending_confirm = await self.get_offers_with_status(TradeStatus.PENDING_CONFIRM)
          pending_cancel = await self.get_offers_with_status(TradeStatus.PENDING_CANCEL)
          all_pending.extend(pending_accept)
          all_pending.extend(pending_confirm)
          all_pending.extend(pending_cancel)
          if len(all_pending) == 0:
              return {}
  
          result = {}
          for trade_offer in all_pending:
              if trade_offer.tx_spend_bundle is None:
                  locked = await self.get_locked_coins_in_spend_bundle(trade_offer.spend_bundle)
              else:
                  locked = await self.get_locked_coins_in_spend_bundle(trade_offer.tx_spend_bundle)
              for name, record in locked.items():
                  if wallet_id is None or record.wallet_id == wallet_id:
                      result[name] = record
  
          return result
  
      async def get_all_trades(self):
          all: List[TradeRecord] = await self.trade_store.get_all_trades()
          return all
  
      async def get_trade_by_id(self, trade_id: bytes) -> Optional[TradeRecord]:
          record = await self.trade_store.get_trade_record(trade_id)
          return record
  
      async def get_locked_coins_in_spend_bundle(self, bundle: SpendBundle) -> Dict[bytes32, WalletCoinRecord]:
          """Returns a list of coin records that are used in this SpendBundle"""
          result = {}
          removals = bundle.removals()
          for coin in removals:
              coin_record = await self.wallet_state_manager.coin_store.get_coin_record(coin.name())
              if coin_record is None:
                  continue
              result[coin_record.name()] = coin_record
          return result
  
      async def cancel_pending_offer(self, trade_id: bytes32):
          await self.trade_store.set_status(trade_id, TradeStatus.CANCELED, False)
  
      async def cancel_pending_offer_safely(self, trade_id: bytes32):
          """This will create a transaction that includes coins that were offered"""
          self.log.info(f"Secure-Cancel pending offer with id trade_id {trade_id.hex()}")
          trade = await self.trade_store.get_trade_record(trade_id)
          if trade is None:
              return None
  
          all_coins = trade.removals
  
          for coin in all_coins:
              wallet = await self.wallet_state_manager.get_wallet_for_coin(coin.name())
  
              if wallet is None:
                  continue
              new_ph = await wallet.get_new_puzzlehash()
              if wallet.type() == WalletType.COLOURED_COIN.value:
                  tx = await wallet.generate_signed_transaction(
                      [coin.amount], [new_ph], 0, coins={coin}, ignore_max_send_amount=True
                  )
              else:
                  tx = await wallet.generate_signed_transaction(
                      coin.amount, new_ph, 0, coins={coin}, ignore_max_send_amount=True
                  )
              await self.wallet_state_manager.add_pending_transaction(tx_record=tx)
  
          await self.trade_store.set_status(trade_id, TradeStatus.PENDING_CANCEL, False)
          return None
  
      async def save_trade(self, trade: TradeRecord):
          await self.trade_store.add_trade_record(trade, False)
  
      async def create_offer_for_ids(
          self, offer: Dict[int, int], file_name: str
      ) -> Tuple[bool, Optional[TradeRecord], Optional[str]]:
          success, trade_offer, error = await self._create_offer_for_ids(offer)
  
          if success is True and trade_offer is not None:
              self.write_offer_to_disk(Path(file_name), trade_offer)
              await self.save_trade(trade_offer)
  
          return success, trade_offer, error
  
      async def _create_offer_for_ids(self, offer: Dict[int, int]) -> Tuple[bool, Optional[TradeRecord], Optional[str]]:
          """
          Offer is dictionary of wallet ids and amount
          """
          spend_bundle = None
          try:
              for id in offer.keys():
                  amount = offer[id]
                  wallet_id = uint32(int(id))
                  wallet = self.wallet_state_manager.wallets[wallet_id]
                  if isinstance(wallet, CCWallet):
                      balance = await wallet.get_confirmed_balance()
                      if balance < abs(amount) and amount < 0:
                          raise Exception(f"insufficient funds in wallet {wallet_id}")
                      if amount > 0:
                          if spend_bundle is None:
                              to_exclude: List[Coin] = []
                          else:
                              to_exclude = spend_bundle.removals()
                          zero_spend_bundle: SpendBundle = await wallet.generate_zero_val_coin(False, to_exclude)
  
                          if spend_bundle is None:
                              spend_bundle = zero_spend_bundle
                          else:
                              spend_bundle = SpendBundle.aggregate([spend_bundle, zero_spend_bundle])
  
                          additions = zero_spend_bundle.additions()
                          removals = zero_spend_bundle.removals()
                          zero_val_coin: Optional[Coin] = None
                          for add in additions:
                              if add not in removals and add.amount == 0:
                                  zero_val_coin = add
                          new_spend_bundle = await wallet.create_spend_bundle_relative_amount(amount, zero_val_coin)
                      else:
                          new_spend_bundle = await wallet.create_spend_bundle_relative_amount(amount)
                  elif isinstance(wallet, Wallet):
                      if spend_bundle is None:
                          to_exclude = []
                      else:
                          to_exclude = spend_bundle.removals()
                      new_spend_bundle = await wallet.create_spend_bundle_relative_skynet(amount, to_exclude)
                  else:
                      return False, None, "unsupported wallet type"
                  if new_spend_bundle is None or new_spend_bundle.removals() == []:
                      raise Exception(f"Wallet {id} was unable to create offer.")
                  if spend_bundle is None:
                      spend_bundle = new_spend_bundle
                  else:
                      spend_bundle = SpendBundle.aggregate([spend_bundle, new_spend_bundle])
  
              if spend_bundle is None:
                  return False, None, None
  
              now = uint64(int(time.time()))
              trade_offer: TradeRecord = TradeRecord(
                  confirmed_at_index=uint32(0),
                  accepted_at_time=None,
                  created_at_time=now,
                  my_offer=True,
                  sent=uint32(0),
                  spend_bundle=spend_bundle,
                  tx_spend_bundle=None,
                  additions=spend_bundle.additions(),
                  removals=spend_bundle.removals(),
                  trade_id=std_hash(spend_bundle.name() + bytes(now)),
                  status=uint32(TradeStatus.PENDING_ACCEPT.value),
                  sent_to=[],
              )
              return True, trade_offer, None
          except Exception as e:
              tb = traceback.format_exc()
              self.log.error(f"Error with creating trade offer: {type(e)}{tb}")
              return False, None, str(e)
  
      def write_offer_to_disk(self, file_path: Path, offer: TradeRecord):
          if offer is not None:
              file_path.write_text(bytes(offer).hex())
  
      async def get_discrepancies_for_offer(self, file_path: Path) -> Tuple[bool, Optional[Dict], Optional[Exception]]:
          self.log.info(f"trade offer: {file_path}")
          trade_offer_hex = file_path.read_text()
          trade_offer = TradeRecord.from_bytes(bytes.fromhex(trade_offer_hex))
          return get_discrepancies_for_spend_bundle(trade_offer.spend_bundle)
  
      async def get_inner_puzzle_for_puzzle_hash(self, puzzle_hash) -> Program:
          info = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(puzzle_hash.hex())
          assert info is not None
          puzzle = self.wallet_state_manager.main_wallet.puzzle_for_pk(bytes(info.pubkey))
          return puzzle
  
      async def maybe_create_wallets_for_offer(self, file_path: Path) -> bool:
          success, result, error = await self.get_discrepancies_for_offer(file_path)
          if not success or result is None:
              return False
  
          for key, value in result.items():
              wsm = self.wallet_state_manager
              wallet: Wallet = wsm.main_wallet
              if key == "skynet":
                  continue
              self.log.info(f"value is {key}")
              exists = await wsm.get_wallet_for_colour(key)
              if exists is not None:
                  continue
  
              await CCWallet.create_wallet_for_cc(wsm, wallet, key)
  
          return True
  
      async def respond_to_offer(self, file_path: Path) -> Tuple[bool, Optional[TradeRecord], Optional[str]]:
          has_wallets = await self.maybe_create_wallets_for_offer(file_path)
          if not has_wallets:
              return False, None, "Unknown Error"
          trade_offer = None
          try:
              trade_offer_hex = file_path.read_text()
              trade_offer = TradeRecord.from_bytes(hexstr_to_bytes(trade_offer_hex))
          except Exception as e:
              return False, None, f"Error: {e}"
          if trade_offer is not None:
              offer_spend_bundle: SpendBundle = trade_offer.spend_bundle
  
          coinsols: List[CoinSpend] = []  # [] of CoinSpends
          cc_coinsol_outamounts: Dict[bytes32, List[Tuple[CoinSpend, int]]] = dict()
          aggsig = offer_spend_bundle.aggregated_signature
          cc_discrepancies: Dict[bytes32, int] = dict()
          skynet_discrepancy = None
          wallets: Dict[bytes32, Any] = dict()  # colour to wallet dict
  
          for coinsol in offer_spend_bundle.coin_spends:
              puzzle: Program = Program.from_bytes(bytes(coinsol.puzzle_reveal))
              solution: Program = Program.from_bytes(bytes(coinsol.solution))
  
              # work out the deficits between coin amount and expected output for each
              r = cc_utils.uncurry_cc(puzzle)
              if r:
                  # Calculate output amounts
                  mod_hash, genesis_checker, inner_puzzle = r
                  colour = bytes(genesis_checker).hex()
                  if colour not in wallets:
                      wallets[colour] = await self.wallet_state_manager.get_wallet_for_colour(colour)
                  unspent = await self.wallet_state_manager.get_spendable_coins_for_wallet(wallets[colour].id())
                  if coinsol.coin in [record.coin for record in unspent]:
                      return False, None, "can't respond to own offer"
  
                  innersol = solution.first()
  
                  total = get_output_amount_for_puzzle_and_solution(inner_puzzle, innersol)
                  if colour in cc_discrepancies:
                      cc_discrepancies[colour] += coinsol.coin.amount - total
                  else:
                      cc_discrepancies[colour] = coinsol.coin.amount - total
                  # Store coinsol and output amount for later
                  if colour in cc_coinsol_outamounts:
                      cc_coinsol_outamounts[colour].append((coinsol, total))
                  else:
                      cc_coinsol_outamounts[colour] = [(coinsol, total)]
  
              else:
                  # standard skynet coin
                  unspent = await self.wallet_state_manager.get_spendable_coins_for_wallet(1)
                  if coinsol.coin in [record.coin for record in unspent]:
                      return False, None, "can't respond to own offer"
                  if skynet_discrepancy is None:
                      skynet_discrepancy = get_output_discrepancy_for_puzzle_and_solution(coinsol.coin, puzzle, solution)
                  else:
                      skynet_discrepancy += get_output_discrepancy_for_puzzle_and_solution(coinsol.coin, puzzle, solution)
                  coinsols.append(coinsol)
  
          skynet_spend_bundle: Optional[SpendBundle] = None
          if skynet_discrepancy is not None:
              skynet_spend_bundle = await self.wallet_state_manager.main_wallet.create_spend_bundle_relative_skynet(
                  skynet_discrepancy, []
              )
              if skynet_spend_bundle is not None:
                  for coinsol in coinsols:
                      skynet_spend_bundle.coin_spends.append(coinsol)
  
          zero_spend_list: List[SpendBundle] = []
          spend_bundle = None
          # create coloured coin
          self.log.info(cc_discrepancies)
          for colour in cc_discrepancies.keys():
              if cc_discrepancies[colour] < 0:
                  my_cc_spends = await wallets[colour].select_coins(abs(cc_discrepancies[colour]))
              else:
                  if skynet_spend_bundle is None:
                      to_exclude: List = []
                  else:
                      to_exclude = skynet_spend_bundle.removals()
                  my_cc_spends = await wallets[colour].select_coins(0)
                  if my_cc_spends is None or my_cc_spends == set():
                      zero_spend_bundle: SpendBundle = await wallets[colour].generate_zero_val_coin(False, to_exclude)
                      if zero_spend_bundle is None:
                          return (
                              False,
                              None,
                              "Unable to generate zero value coin. Confirm that you have skynet available",
                          )
                      zero_spend_list.append(zero_spend_bundle)
  
                      additions = zero_spend_bundle.additions()
                      removals = zero_spend_bundle.removals()
                      my_cc_spends = set()
                      for add in additions:
                          if add not in removals and add.amount == 0:
                              my_cc_spends.add(add)
  
              if my_cc_spends == set() or my_cc_spends is None:
                  return False, None, "insufficient funds"
  
              # Create SpendableCC list and innersol_list with both my coins and the offered coins
              # Firstly get the output coin
              my_output_coin = my_cc_spends.pop()
              spendable_cc_list = []
              innersol_list = []
              genesis_id = genesis_coin_id_for_genesis_coin_checker(Program.from_bytes(bytes.fromhex(colour)))
              # Make the rest of the coins assert the output coin is consumed
              for coloured_coin in my_cc_spends:
                  inner_solution = self.wallet_state_manager.main_wallet.make_solution(consumed=[my_output_coin.name()])
                  inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash(coloured_coin.puzzle_hash)
                  assert inner_puzzle is not None
  
                  sigs = await wallets[colour].get_sigs(inner_puzzle, inner_solution, coloured_coin.name())
                  sigs.append(aggsig)
                  aggsig = AugSchemeMPL.aggregate(sigs)
  
                  lineage_proof = await wallets[colour].get_lineage_proof_for_coin(coloured_coin)
                  spendable_cc_list.append(SpendableCC(coloured_coin, genesis_id, inner_puzzle, lineage_proof))
                  innersol_list.append(inner_solution)
  
              # Create SpendableCC for each of the coloured coins received
              for cc_coinsol_out in cc_coinsol_outamounts[colour]:
                  cc_coinsol = cc_coinsol_out[0]
                  puzzle = Program.from_bytes(bytes(cc_coinsol.puzzle_reveal))
                  solution = Program.from_bytes(bytes(cc_coinsol.solution))
  
                  r = uncurry_cc(puzzle)
                  if r:
                      mod_hash, genesis_coin_checker, inner_puzzle = r
                      inner_solution = solution.first()
                      lineage_proof = solution.rest().rest().first()
                      spendable_cc_list.append(SpendableCC(cc_coinsol.coin, genesis_id, inner_puzzle, lineage_proof))
                      innersol_list.append(inner_solution)
  
              # Finish the output coin SpendableCC with new information
              newinnerpuzhash = await wallets[colour].get_new_inner_hash()
              outputamount = sum([c.amount for c in my_cc_spends]) + cc_discrepancies[colour] + my_output_coin.amount
              inner_solution = self.wallet_state_manager.main_wallet.make_solution(
                  primaries=[{"puzzlehash": newinnerpuzhash, "amount": outputamount}]
              )
              inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash(my_output_coin.puzzle_hash)
              assert inner_puzzle is not None
  
              lineage_proof = await wallets[colour].get_lineage_proof_for_coin(my_output_coin)
              spendable_cc_list.append(SpendableCC(my_output_coin, genesis_id, inner_puzzle, lineage_proof))
              innersol_list.append(inner_solution)
  
              sigs = await wallets[colour].get_sigs(inner_puzzle, inner_solution, my_output_coin.name())
              sigs.append(aggsig)
              aggsig = AugSchemeMPL.aggregate(sigs)
              if spend_bundle is None:
                  spend_bundle = spend_bundle_for_spendable_ccs(
                      CC_MOD,
                      Program.from_bytes(bytes.fromhex(colour)),
                      spendable_cc_list,
                      innersol_list,
                      [aggsig],
                  )
              else:
                  new_spend_bundle = spend_bundle_for_spendable_ccs(
                      CC_MOD,
                      Program.from_bytes(bytes.fromhex(colour)),
                      spendable_cc_list,
                      innersol_list,
                      [aggsig],
                  )
                  spend_bundle = SpendBundle.aggregate([spend_bundle, new_spend_bundle])
              # reset sigs and aggsig so that they aren't included next time around
              sigs = []
              aggsig = AugSchemeMPL.aggregate(sigs)
          my_tx_records = []
          if zero_spend_list is not None and spend_bundle is not None:
              zero_spend_list.append(spend_bundle)
              spend_bundle = SpendBundle.aggregate(zero_spend_list)
  
          if spend_bundle is None:
              return False, None, "spend_bundle missing"
  
          # Add transaction history for this trade
          now = uint64(int(time.time()))
          if skynet_spend_bundle is not None:
              spend_bundle = SpendBundle.aggregate([spend_bundle, skynet_spend_bundle])
              if skynet_discrepancy < 0:
                  tx_record = TransactionRecord(
                      confirmed_at_height=uint32(0),
                      created_at_time=now,
                      to_puzzle_hash=token_bytes(),
                      amount=uint64(abs(skynet_discrepancy)),
                      fee_amount=uint64(0),
                      confirmed=False,
                      sent=uint32(10),
                      spend_bundle=skynet_spend_bundle,
                      additions=skynet_spend_bundle.additions(),
                      removals=skynet_spend_bundle.removals(),
                      wallet_id=uint32(1),
                      sent_to=[],
                      trade_id=std_hash(spend_bundle.name() + bytes(now)),
                      type=uint32(TransactionType.OUTGOING_TRADE.value),
                      name=skynet_spend_bundle.name(),
                  )
              else:
                  tx_record = TransactionRecord(
                      confirmed_at_height=uint32(0),
                      created_at_time=uint64(int(time.time())),
                      to_puzzle_hash=token_bytes(),
                      amount=uint64(abs(skynet_discrepancy)),
                      fee_amount=uint64(0),
                      confirmed=False,
                      sent=uint32(10),
                      spend_bundle=skynet_spend_bundle,
                      additions=skynet_spend_bundle.additions(),
                      removals=skynet_spend_bundle.removals(),
                      wallet_id=uint32(1),
                      sent_to=[],
                      trade_id=std_hash(spend_bundle.name() + bytes(now)),
                      type=uint32(TransactionType.INCOMING_TRADE.value),
                      name=skynet_spend_bundle.name(),
                  )
              my_tx_records.append(tx_record)
  
          for colour, amount in cc_discrepancies.items():
              wallet = wallets[colour]
              if skynet_discrepancy > 0:
                  tx_record = TransactionRecord(
                      confirmed_at_height=uint32(0),
                      created_at_time=uint64(int(time.time())),
                      to_puzzle_hash=token_bytes(),
                      amount=uint64(abs(amount)),
                      fee_amount=uint64(0),
                      confirmed=False,
                      sent=uint32(10),
                      spend_bundle=spend_bundle,
                      additions=spend_bundle.additions(),
                      removals=spend_bundle.removals(),
                      wallet_id=wallet.id(),
                      sent_to=[],
                      trade_id=std_hash(spend_bundle.name() + bytes(now)),
                      type=uint32(TransactionType.OUTGOING_TRADE.value),
                      name=spend_bundle.name(),
                  )
              else:
                  tx_record = TransactionRecord(
                      confirmed_at_height=uint32(0),
                      created_at_time=uint64(int(time.time())),
                      to_puzzle_hash=token_bytes(),
                      amount=uint64(abs(amount)),
                      fee_amount=uint64(0),
                      confirmed=False,
                      sent=uint32(10),
                      spend_bundle=spend_bundle,
                      additions=spend_bundle.additions(),
                      removals=spend_bundle.removals(),
                      wallet_id=wallet.id(),
                      sent_to=[],
                      trade_id=std_hash(spend_bundle.name() + bytes(now)),
                      type=uint32(TransactionType.INCOMING_TRADE.value),
                      name=token_bytes(),
                  )
              my_tx_records.append(tx_record)
  
          tx_record = TransactionRecord(
              confirmed_at_height=uint32(0),
              created_at_time=uint64(int(time.time())),
              to_puzzle_hash=token_bytes(),
              amount=uint64(0),
              fee_amount=uint64(0),
              confirmed=False,
              sent=uint32(0),
              spend_bundle=spend_bundle,
              additions=spend_bundle.additions(),
              removals=spend_bundle.removals(),
              wallet_id=uint32(0),
              sent_to=[],
              trade_id=std_hash(spend_bundle.name() + bytes(now)),
              type=uint32(TransactionType.OUTGOING_TRADE.value),
              name=spend_bundle.name(),
          )
  
          now = uint64(int(time.time()))
          trade_record: TradeRecord = TradeRecord(
              confirmed_at_index=uint32(0),
              accepted_at_time=now,
              created_at_time=now,
              my_offer=False,
              sent=uint32(0),
              spend_bundle=offer_spend_bundle,
              tx_spend_bundle=spend_bundle,
              additions=spend_bundle.additions(),
              removals=spend_bundle.removals(),
              trade_id=std_hash(spend_bundle.name() + bytes(now)),
              status=uint32(TradeStatus.PENDING_CONFIRM.value),
              sent_to=[],
          )
  
          await self.save_trade(trade_record)
          await self.wallet_state_manager.add_pending_transaction(tx_record)
          for tx in my_tx_records:
              await self.wallet_state_manager.add_transaction(tx)
  
          return True, trade_record, None
  