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_by_coin_id(coin.name()) if coin_record is None: continue result[coin_record.name()] = coin_record return result
def update_coin_store_for_spend_bundle(self, spend_bundle: SpendBundle, now: CoinTimestamp): err = self.validate_spend_bundle(spend_bundle, now) if err != 0: raise BadSpendBundleError(f"validation failure {err}") for spent_coin in spend_bundle.removals(): coin_name = spent_coin.name() coin_record = self._db[coin_name] self._db[coin_name] = replace(coin_record, spent_block_index=now.height, spent=True) for new_coin in spend_bundle.additions(): self._add_coin_entry(new_coin, now)
async def add_pending_transaction(self, spend_bundle: SpendBundle, wallet_id): """ Called from wallet_node before new transaction is sent to the full_node """ now = uint64(int(time.time())) add_list: List[Coin] = [] rem_list: List[Coin] = [] total_removed = 0 total_added = 0 outgoing_amount = 0 for add in spend_bundle.additions(): total_added += add.amount add_list.append(add) for rem in spend_bundle.removals(): total_removed += rem.amount rem_list.append(rem) fee_amount = total_removed - total_added # Figure out if we are sending to ourself or someone else. to_puzzle_hash: Optional[bytes32] = None for add in add_list: if not await self.puzzle_store.puzzle_hash_exists(add.puzzle_hash): to_puzzle_hash = add.puzzle_hash outgoing_amount += add.amount break # If there is no addition for outside puzzlehash we are sending tx to ourself if to_puzzle_hash is None: to_puzzle_hash = add_list[0].puzzle_hash outgoing_amount += total_added tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=now, to_puzzle_hash=to_puzzle_hash, amount=uint64(outgoing_amount), fee_amount=uint64(fee_amount), incoming=False, confirmed=False, sent=uint32(0), spend_bundle=spend_bundle, additions=add_list, removals=rem_list, wallet_id=wallet_id, sent_to=[], ) # Wallet node will use this queue to retry sending this transaction until full nodes receives it await self.tx_store.add_transaction_record(tx_record) self.state_changed("pending_transaction") self.tx_pending_changed()
async def generate_signed_transaction( self, amount: uint64, to_address: bytes32, fee: uint64 = uint64(0), origin_id: bytes32 = None, coins: Set[Coin] = None, ) -> Optional[TransactionRecord]: sigs: List[G2Element] = [] # Get coins and calculate amount of change required if coins is None: selected_coins: Optional[Set[Coin]] = await self.select_coins( amount) else: selected_coins = coins if selected_coins is None: return None total_amount = sum([x.amount for x in selected_coins]) change = total_amount - amount # first coin becomes the auditor special case auditor = selected_coins.pop() puzzle_hash = auditor.puzzle_hash inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle( puzzle_hash) auditor_info = ( auditor.parent_coin_info, inner_puzzle.get_tree_hash(), auditor.amount, ) list_of_solutions = [] # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) auditees = [( auditor.parent_coin_info, inner_puzzle.get_tree_hash(), auditor.amount, total_amount, )] for coin in selected_coins: coin_inner_puzzle: Program = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) auditees.append(( coin.parent_coin_info, coin_inner_puzzle[coin], coin.amount, 0, )) primaries = [{"puzzlehash": to_address, "amount": amount}] if change > 0: changepuzzlehash = await self.get_new_inner_hash() primaries.append({ "puzzlehash": changepuzzlehash, "amount": change }) innersol = self.standard_wallet.make_solution(primaries=primaries) sigs = sigs + await self.get_sigs(inner_puzzle, innersol) parent_info = await self.get_parent_for_coin(auditor) assert parent_info is not None assert self.cc_info.my_core is not None solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), auditor.amount, binutils.disassemble(inner_puzzle), binutils.disassemble(innersol), auditor_info, auditees, False, ) main_coin_solution = CoinSolution( auditor, Program.to([ cc_wallet_puzzles.cc_make_puzzle( inner_puzzle.get_tree_hash(), self.cc_info.my_core, ), solution, ]), ) list_of_solutions.append(main_coin_solution) # main = SpendBundle([main_coin_solution], ZERO96) ephemeral_coin_solution = create_spend_for_ephemeral( auditor, auditor, total_amount) list_of_solutions.append(ephemeral_coin_solution) # eph = SpendBundle([ephemeral_coin_solution], ZERO96) auditor_coin_colution = create_spend_for_auditor(auditor, auditor) list_of_solutions.append(auditor_coin_colution) # aud = SpendBundle([auditor_coin_colution], ZERO96) # loop through remaining spends, treating them as aggregatees for coin in selected_coins: coin_inner_puzzle = await self.inner_puzzle_for_cc_puzzle( coin.puzzle_hash) innersol = self.standard_wallet.make_solution() parent_info = await self.get_parent_for_coin(coin) assert parent_info is not None sigs = sigs + await self.get_sigs(coin_inner_puzzle, innersol) solution = cc_wallet_puzzles.cc_make_solution( self.cc_info.my_core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coin.amount, binutils.disassemble(coin_inner_puzzle), binutils.disassemble(innersol), auditor_info, None, ) list_of_solutions.append( CoinSolution( coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( coin_inner_puzzle.get_tree_hash(), self.cc_info.my_core, ), solution, ]), )) list_of_solutions.append( create_spend_for_ephemeral(coin, auditor, 0)) list_of_solutions.append(create_spend_for_auditor(auditor, coin)) aggsig = AugSchemeMPL.aggregate(sigs) spend_bundle = SpendBundle(list_of_solutions, aggsig) tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=to_address, amount=uint64(amount), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(0), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=self.wallet_info.id, sent_to=[], trade_id=None, ) return tx_record
def debug_spend_bundle(spend_bundle: SpendBundle) -> None: """ Print a lot of useful information about a `SpendBundle` that might help with debugging its clvm. """ assert_consumed_set = set() print("=" * 80) for coin_solution in spend_bundle.coin_solutions: coin, solution_pair = coin_solution.coin, coin_solution.solution puzzle_reveal = solution_pair.first() solution = solution_pair.rest().first() print(f"consuming coin {dump_coin(coin)}") print(f" with id {coin.name()}") print() print( f"\nbrun -y main.sym '{bu_disassemble(puzzle_reveal)}' '{bu_disassemble(solution)}'" ) error, conditions, cost = conditions_dict_for_solution( Program.to([puzzle_reveal, solution])) if error: print(f"*** error {error}") else: print() cost, r = run_program(puzzle_reveal, solution) print(disassemble(r)) print() if conditions and len(conditions) > 0: print("grouped conditions:") for condition_programs in conditions.values(): print() for c in condition_programs: as_prog = Program.to([c.opcode, c.var1, c.var2]) print(f" {disassemble(as_prog)}") print() for _ in conditions.get(ConditionOpcode.ASSERT_COIN_CONSUMED, []): assert_consumed_set.add(bytes32(_.var1)) else: print("(no output conditions generated)") print() print("-------") created = set(spend_bundle.additions()) spent = set(spend_bundle.removals()) zero_coin_set = set(coin.name() for coin in created if coin.amount == 0) ephemeral = created.intersection(spent) created.difference_update(ephemeral) spent.difference_update(ephemeral) print() print("spent coins") for coin in sorted(spent, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => spent coin id {coin.name()}") print() print("created coins") for coin in sorted(created, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => created coin id {coin.name()}") if ephemeral: print() print("ephemeral coins") for coin in sorted(ephemeral, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => created coin id {coin.name()}") print() print(f"assert_consumed_set = {sorted(assert_consumed_set)}") print() print(f"zero_coin_set = {sorted(zero_coin_set)}") print() set_difference = zero_coin_set ^ assert_consumed_set print(f"zero_coin_set ^ assert_consumed_set = {sorted(set_difference)}") if len(set_difference): print( "not all zero coins asserted consumed or vice versa, entering debugger" ) breakpoint() print() print("=" * 80)
def debug_spend_bundle(spend_bundle: SpendBundle) -> None: """ Print a lot of useful information about a `SpendBundle` that might help with debugging its clvm. """ assert_consumed_set = set() pks = [] msgs = [] print("=" * 80) for coin_solution in spend_bundle.coin_solutions: coin, solution_pair = coin_solution.coin, Program.to( coin_solution.solution) puzzle_reveal = solution_pair.first() solution = solution_pair.rest().first() print(f"consuming coin {dump_coin(coin)}") print(f" with id {coin.name()}") print() print( f"\nbrun -y main.sym '{bu_disassemble(puzzle_reveal)}' '{bu_disassemble(solution)}'" ) error, conditions, cost = conditions_dict_for_solution( Program.to([puzzle_reveal, solution])) if error: print(f"*** error {error}") elif conditions is not None: for pk, m in pkm_pairs_for_conditions_dict(conditions, coin.name()): pks.append(pk) msgs.append(m) print() r = puzzle_reveal.run(solution) print(disassemble(r)) print() if conditions and len(conditions) > 0: print("grouped conditions:") for condition_programs in conditions.values(): print() for c in condition_programs: as_prog = Program.to([c.opcode, c.vars[0], c.vars[1]]) print(f" {disassemble(as_prog)}") print() for _ in conditions.get(ConditionOpcode.ASSERT_COIN_CONSUMED, []): assert_consumed_set.add(bytes32(c.vars[0])) else: print("(no output conditions generated)") print() print("-------") created = set(spend_bundle.additions()) spent = set(spend_bundle.removals()) zero_coin_set = set(coin.name() for coin in created if coin.amount == 0) ephemeral = created.intersection(spent) created.difference_update(ephemeral) spent.difference_update(ephemeral) print() print("spent coins") for coin in sorted(spent, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => spent coin id {coin.name()}") print() print("created coins") for coin in sorted(created, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => created coin id {coin.name()}") if ephemeral: print() print("ephemeral coins") for coin in sorted(ephemeral, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => created coin id {coin.name()}") print() print(f"assert_consumed_set = {sorted(assert_consumed_set)}") print() print(f"zero_coin_set = {sorted(zero_coin_set)}") print() set_difference = zero_coin_set ^ assert_consumed_set print(f"zero_coin_set ^ assert_consumed_set = {sorted(set_difference)}") if len(set_difference): print("not all zero coins asserted consumed or vice versa") print() print("=" * 80) print() if len(msgs) > 0: validates = AugSchemeMPL.aggregate_verify( pks, msgs, spend_bundle.aggregated_signature) print(f"aggregated signature check pass: {validates}")
def debug_spend_bundle(spend_bundle: SpendBundle) -> None: """ Print a lot of useful information about a `SpendBundle` that might help with debugging its clvm. """ pks = [] msgs = [] created_announcements: List[List[bytes]] = [] asserted_annoucements = [] print("=" * 80) for coin_solution in spend_bundle.coin_solutions: coin = coin_solution.coin puzzle_reveal = coin_solution.puzzle_reveal solution = coin_solution.solution coin_name = coin.name() print(f"consuming coin {dump_coin(coin)}") print(f" with id {coin_name}") print() print(f"\nbrun -y main.sym '{bu_disassemble(puzzle_reveal)}' '{bu_disassemble(solution)}'") error, conditions, cost = conditions_dict_for_solution(puzzle_reveal, solution) if error: print(f"*** error {error}") elif conditions is not None: for pk, m in pkm_pairs_for_conditions_dict(conditions, coin_name): pks.append(pk) msgs.append(m) print() r = puzzle_reveal.run(solution) print(disassemble(r)) print() if conditions and len(conditions) > 0: print("grouped conditions:") for condition_programs in conditions.values(): print() for c in condition_programs: if len(c.vars) == 1: as_prog = Program.to([c.opcode, c.vars[0]]) if len(c.vars) == 2: as_prog = Program.to([c.opcode, c.vars[0], c.vars[1]]) print(f" {disassemble(as_prog)}") created_announcements.extend( [coin_name] + _.vars for _ in conditions.get(ConditionOpcode.CREATE_ANNOUNCEMENT, []) ) asserted_annoucements.extend( [_.vars[0].hex() for _ in conditions.get(ConditionOpcode.ASSERT_ANNOUNCEMENT, [])] ) print() else: print("(no output conditions generated)") print() print("-------") created = set(spend_bundle.additions()) spent = set(spend_bundle.removals()) zero_coin_set = set(coin.name() for coin in created if coin.amount == 0) ephemeral = created.intersection(spent) created.difference_update(ephemeral) spent.difference_update(ephemeral) print() print("spent coins") for coin in sorted(spent, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => spent coin id {coin.name()}") print() print("created coins") for coin in sorted(created, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => created coin id {coin.name()}") if ephemeral: print() print("ephemeral coins") for coin in sorted(ephemeral, key=lambda _: _.name()): print(f" {dump_coin(coin)}") print(f" => created coin id {coin.name()}") created_announcement_pairs = [(_, std_hash(b"".join(_)).hex()) for _ in created_announcements] if created_announcements: print("created announcements") for announcement, hashed in sorted(created_announcement_pairs, key=lambda _: _[-1]): as_hex = [f"0x{_.hex()}" for _ in announcement] print(f" {as_hex} =>\n {hashed}") eor_announcements = sorted(set(_[-1] for _ in created_announcement_pairs) ^ set(asserted_annoucements)) print() print() print(f"zero_coin_set = {sorted(zero_coin_set)}") print() print(f"created announcements = {sorted([_[-1] for _ in created_announcement_pairs])}") print() print(f"asserted announcements = {sorted(asserted_annoucements)}") print() print(f"symdiff of announcements = {sorted(eor_announcements)}") print() print() print("=" * 80) print() validates = AugSchemeMPL.aggregate_verify(pks, msgs, spend_bundle.aggregated_signature) print(f"aggregated signature check pass: {validates}")
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_hex = file_path.read_text() trade_offer: TradeRecord = TradeRecord.from_bytes( hexstr_to_bytes(trade_offer_hex)) offer_spend_bundle = trade_offer.spend_bundle coinsols = [] # [] of CoinSolutions cc_coinsol_outamounts: Dict[bytes32, List[Tuple[Any, int]]] = dict() # Used for generating auditor solution, key is colour auditees: Dict[bytes32, List[Tuple[bytes32, bytes32, Any, int]]] = dict() aggsig = offer_spend_bundle.aggregated_signature cc_discrepancies: Dict[bytes32, int] = dict() chia_discrepancy = None wallets: Dict[bytes32, Any] = dict() # colour to wallet dict for coinsol in offer_spend_bundle.coin_solutions: puzzle = coinsol.solution.first() solution = coinsol.solution.rest().first() # work out the deficits between coin amount and expected output for each if cc_wallet_puzzles.check_is_cc_puzzle(puzzle): if not cc_wallet_puzzles.is_ephemeral_solution(solution): # Calculate output amounts colour = cc_wallet_puzzles.get_genesis_from_puzzle(puzzle) 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].wallet_info.id) if coinsol.coin in [record.coin for record in unspent]: return False, None, "can't respond to own offer" innerpuzzlereveal = cc_wallet_puzzles.inner_puzzle( solution) innersol = cc_wallet_puzzles.inner_puzzle_solution( solution) out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution( innerpuzzlereveal, innersol) if colour in cc_discrepancies: cc_discrepancies[ colour] += coinsol.coin.amount - out_amount else: cc_discrepancies[ colour] = coinsol.coin.amount - out_amount # Store coinsol and output amount for later if colour in cc_coinsol_outamounts: cc_coinsol_outamounts[colour].append( (coinsol, out_amount)) else: cc_coinsol_outamounts[colour] = [(coinsol, out_amount)] # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) if colour in auditees: auditees[colour].append(( coinsol.coin.parent_coin_info, Program(innerpuzzlereveal).get_tree_hash(), coinsol.coin.amount, out_amount, )) else: auditees[colour] = [( coinsol.coin.parent_coin_info, Program(innerpuzzlereveal).get_tree_hash(), coinsol.coin.amount, out_amount, )] else: coinsols.append(coinsol) else: # standard chia 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 chia_discrepancy is None: chia_discrepancy = cc_wallet_puzzles.get_output_discrepancy_for_puzzle_and_solution( coinsol.coin, puzzle, solution) else: chia_discrepancy += cc_wallet_puzzles.get_output_discrepancy_for_puzzle_and_solution( coinsol.coin, puzzle, solution) coinsols.append(coinsol) chia_spend_bundle: Optional[SpendBundle] = None if chia_discrepancy is not None: chia_spend_bundle = await self.wallet_state_manager.main_wallet.create_spend_bundle_relative_chia( chia_discrepancy, []) zero_spend_list: List[SpendBundle] = [] # 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 chia_spend_bundle is None: to_exclude: List = [] else: to_exclude = chia_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 chia 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" auditor = my_cc_spends.pop() auditor_inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash( auditor.puzzle_hash) assert auditor_inner_puzzle is not None inner_hash = auditor_inner_puzzle.get_tree_hash() auditor_info = ( auditor.parent_coin_info, inner_hash, auditor.amount, ) core = cc_wallet_puzzles.cc_make_core(colour) parent_info = await wallets[colour].get_parent_for_coin(auditor) for coloured_coin in my_cc_spends: inner_solution = self.wallet_state_manager.main_wallet.make_solution( consumed=[auditor.name()]) sig = await wallets[ colour].get_sigs_for_innerpuz_with_innersol( await self.get_inner_puzzle_for_puzzle_hash( coloured_coin.puzzle_hash), inner_solution, ) aggsig = AugSchemeMPL.aggregate([sig, aggsig]) inner_puzzle = await self.get_inner_puzzle_for_puzzle_hash( coloured_coin.puzzle_hash) assert inner_puzzle is not None # auditees should be (primary_input, innerpuzhash, coin_amount, output_amount) auditees[colour].append(( coloured_coin.parent_coin_info, inner_puzzle.get_tree_hash(), coloured_coin.amount, 0, )) solution = cc_wallet_puzzles.cc_make_solution( core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), coloured_coin.amount, binutils.disassemble(inner_puzzle), binutils.disassemble(inner_solution), auditor_info, None, ) coin_spend = CoinSolution( coloured_coin, Program.to([ cc_wallet_puzzles.cc_make_puzzle( inner_puzzle.get_tree_hash(), core, ), solution, ]), ) coinsols.append(coin_spend) ephemeral = cc_wallet_puzzles.create_spend_for_ephemeral( coloured_coin, auditor, 0) coinsols.append(ephemeral) auditor = cc_wallet_puzzles.create_spend_for_auditor( auditor, coloured_coin) coinsols.append(auditor) # Tweak the offer's solution to include the new auditor for cc_coinsol_out in cc_coinsol_outamounts[colour]: cc_coinsol = cc_coinsol_out[0] new_solution = cc_wallet_puzzles.update_auditors_in_solution( cc_coinsol.solution, auditor_info) new_coinsol = CoinSolution(cc_coinsol.coin, new_solution) coinsols.append(new_coinsol) eph = cc_wallet_puzzles.create_spend_for_ephemeral( cc_coinsol.coin, auditor, cc_coinsol_out[1]) coinsols.append(eph) aud = cc_wallet_puzzles.create_spend_for_auditor( auditor, cc_coinsol.coin) coinsols.append(aud) # Finish the auditor CoinSolution with new information newinnerpuzhash = await wallets[colour].get_new_inner_hash() outputamount = (sum([c.amount for c in my_cc_spends]) + cc_discrepancies[colour] + auditor.amount) innersol = self.wallet_state_manager.main_wallet.make_solution( primaries=[{ "puzzlehash": newinnerpuzhash, "amount": outputamount }]) parent_info = await wallets[colour].get_parent_for_coin(auditor) auditees[colour].append(( auditor.parent_coin_info, auditor_inner_puzzle.get_tree_hash(), auditor.amount, outputamount, )) sigs: List[G2Element] = await wallets[colour].get_sigs( auditor_inner_puzzle, innersol) aggsig = AugSchemeMPL.aggregate(sigs + [aggsig]) solution = cc_wallet_puzzles.cc_make_solution( core, ( parent_info.parent_name, parent_info.inner_puzzle_hash, parent_info.amount, ), auditor.amount, binutils.disassemble(auditor_inner_puzzle), binutils.disassemble(innersol), auditor_info, auditees[colour], ) cs = CoinSolution( auditor, Program.to([ cc_wallet_puzzles.cc_make_puzzle( auditor_inner_puzzle.get_tree_hash(), core), solution, ]), ) coinsols.append(cs) cs_eph = create_spend_for_ephemeral(auditor, auditor, outputamount) coinsols.append(cs_eph) cs_aud = create_spend_for_auditor(auditor, auditor) coinsols.append(cs_aud) spend_bundle = SpendBundle(coinsols, aggsig) my_tx_records = [] if zero_spend_list is not None: zero_spend_list.append(spend_bundle) spend_bundle = SpendBundle.aggregate(zero_spend_list) # Add transaction history hor this trade now = uint64(int(time.time())) if chia_spend_bundle is not None: spend_bundle = SpendBundle.aggregate( [spend_bundle, chia_spend_bundle]) if chia_discrepancy < 0: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=now, to_puzzle_hash=token_bytes(), amount=uint64(abs(chia_discrepancy)), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(10), spend_bundle=chia_spend_bundle, additions=chia_spend_bundle.additions(), removals=chia_spend_bundle.removals(), wallet_id=uint32(1), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) else: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(chia_discrepancy)), fee_amount=uint64(0), incoming=True, confirmed=False, sent=uint32(10), spend_bundle=chia_spend_bundle, additions=chia_spend_bundle.additions(), removals=chia_spend_bundle.removals(), wallet_id=uint32(1), sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) my_tx_records.append(tx_record) for colour, amount in cc_discrepancies.items(): wallet = wallets[colour] if chia_discrepancy > 0: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(amount)), fee_amount=uint64(0), incoming=False, confirmed=False, sent=uint32(10), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=wallet.wallet_info.id, sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) else: tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(abs(amount)), fee_amount=uint64(0), incoming=True, confirmed=False, sent=uint32(10), spend_bundle=spend_bundle, additions=spend_bundle.additions(), removals=spend_bundle.removals(), wallet_id=wallet.wallet_info.id, sent_to=[], trade_id=std_hash(spend_bundle.name() + bytes(now)), ) my_tx_records.append(tx_record) tx_record = TransactionRecord( confirmed_at_index=uint32(0), created_at_time=uint64(int(time.time())), to_puzzle_hash=token_bytes(), amount=uint64(0), fee_amount=uint64(0), incoming=False, 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)), ) 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