def load_pool_config(root_path: Path) -> List[PoolWalletConfig]: config = load_config(root_path, "config.yaml") ret_list: List[PoolWalletConfig] = [] if "pool_list" in config["pool"]: for pool_config_dict in config["pool"]["pool_list"]: try: pool_config = PoolWalletConfig( bytes32.from_hexstr(pool_config_dict["launcher_id"]), pool_config_dict["pool_url"], pool_config_dict["payout_instructions"], bytes32.from_hexstr( pool_config_dict["target_puzzle_hash"]), bytes32.from_hexstr( pool_config_dict["p2_singleton_puzzle_hash"]), G1Element.from_bytes( hexstr_to_bytes(pool_config_dict["owner_public_key"])), G1Element.from_bytes( hexstr_to_bytes( pool_config_dict["authentication_public_key"])), ) ret_list.append(pool_config) except Exception as e: log.error(f"Exception loading config: {pool_config_dict} {e}") return ret_list
async def get_transaction(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: wallet_id = args["id"] transaction_id = bytes32.from_hexstr(args["tx_id"]) config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) name = config["network_overrides"]["config"][config["selected_network"]]["address_prefix"] tx: TransactionRecord = await wallet_client.get_transaction(wallet_id, transaction_id=transaction_id) print_transaction(tx, verbose=(args["verbose"] > 0), name=name)
async def get_transaction(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: transaction_id = bytes32.from_hexstr(args["tx_id"]) config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) address_prefix = config["network_overrides"]["config"][ config["selected_network"]]["address_prefix"] tx: TransactionRecord = await wallet_client.get_transaction( "this is unused", transaction_id=transaction_id) try: wallet_type = await get_wallet_type(wallet_id=tx.wallet_id, wallet_client=wallet_client) mojo_per_unit = get_mojo_per_unit(wallet_type=wallet_type) name = await get_name_for_wallet_id( config=config, wallet_type=wallet_type, wallet_id=tx.wallet_id, wallet_client=wallet_client, ) except LookupError as e: print(e.args[0]) return print_transaction( tx, verbose=(args["verbose"] > 0), name=name, address_prefix=address_prefix, mojo_per_unit=mojo_per_unit, )
async def add_token(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: asset_id = args["asset_id"] token_name = args["token_name"] try: asset_id_bytes: bytes32 = bytes32.from_hexstr(asset_id) existing_info: Optional[Tuple[ Optional[uint32], str]] = await wallet_client.cat_asset_id_to_name(asset_id_bytes) if existing_info is None or existing_info[0] is None: response = await wallet_client.create_wallet_for_existing_cat( asset_id_bytes) wallet_id = response["wallet_id"] await wallet_client.set_cat_name(wallet_id, token_name) print( f"Successfully added {token_name} with wallet id {wallet_id} on key {fingerprint}" ) else: wallet_id, old_name = existing_info await wallet_client.set_cat_name(wallet_id, token_name) print( f"Successfully renamed {old_name} with wallet_id {wallet_id} on key {fingerprint} to {token_name}" ) except ValueError as e: if "fromhex()" in str(e): print(f"{asset_id} is not a valid Asset ID") else: raise e
async def get_login_link(launcher_id_str: str) -> None: launcher_id: bytes32 = bytes32.from_hexstr(launcher_id_str) config = load_config(DEFAULT_ROOT_PATH, "config.yaml") self_hostname = config["self_hostname"] farmer_rpc_port = config["farmer"]["rpc_port"] farmer_client = await FarmerRpcClient.create(self_hostname, uint16(farmer_rpc_port), DEFAULT_ROOT_PATH, config) try: login_link: Optional[str] = await farmer_client.get_pool_login_link( launcher_id) if login_link is None: print("Was not able to get login link.") else: print(login_link) except Exception as e: if isinstance(e, aiohttp.ClientConnectorError): print( f"Connection error. Check if farmer is running at {farmer_rpc_port}." f" You can run the farmer by:\n chia start farmer-only") else: print(f"Exception from 'farmer' {e}") finally: farmer_client.close() await farmer_client.await_closed()
async def get_additions_and_removals(self, request: Dict) -> Optional[Dict]: if "header_hash" not in request: raise ValueError("No header_hash in request") header_hash = bytes32.from_hexstr(request["header_hash"]) block: Optional[ FullBlock] = await self.service.block_store.get_full_block( header_hash) if block is None: raise ValueError(f"Block {header_hash.hex()} not found") async with self.service._blockchain_lock_low_priority: if self.service.blockchain.height_to_hash( block.height) != header_hash: raise ValueError( f"Block at {header_hash.hex()} is no longer in the blockchain (it's in a fork)" ) additions: List[ CoinRecord] = await self.service.coin_store.get_coins_added_at_height( block.height) removals: List[ CoinRecord] = await self.service.coin_store.get_coins_removed_at_height( block.height) return {"additions": additions, "removals": removals}
async def get_puzzle_and_solution(self, request: Dict) -> Optional[Dict]: coin_name: bytes32 = bytes32.from_hexstr(request["coin_id"]) height = request["height"] coin_record = await self.service.coin_store.get_coin_record(coin_name) if coin_record is None or not coin_record.spent or coin_record.spent_block_index != height: raise ValueError( f"Invalid height {height}. coin record {coin_record}") header_hash = self.service.blockchain.height_to_hash(height) assert header_hash is not None block: Optional[ FullBlock] = await self.service.block_store.get_full_block( header_hash) if block is None or block.transactions_generator is None: raise ValueError("Invalid block or block generator") block_generator: Optional[ BlockGenerator] = await self.service.blockchain.get_block_generator( block) assert block_generator is not None error, puzzle, solution = get_puzzle_and_solution_for_coin( block_generator, coin_name, self.service.constants.MAX_BLOCK_COST_CLVM) if error is not None: raise ValueError(f"Error: {error}") puzzle_ser: SerializedProgram = SerializedProgram.from_program( Program.to(puzzle)) solution_ser: SerializedProgram = SerializedProgram.from_program( Program.to(solution)) return { "coin_solution": CoinSpend(coin_record.coin, puzzle_ser, solution_ser) }
async def get_mempool_item_by_tx_id(self, request: Dict) -> Optional[Dict]: if "tx_id" not in request: raise ValueError("No tx_id in request") tx_id: bytes32 = bytes32.from_hexstr(request["tx_id"]) item = self.service.mempool_manager.get_mempool_item(tx_id) if item is None: raise ValueError(f"Tx id 0x{tx_id.hex()} not in the mempool") return {"mempool_item": item}
async def get_block(self, request: Dict) -> Optional[Dict]: if "header_hash" not in request: raise ValueError("No header_hash in request") header_hash = bytes32.from_hexstr(request["header_hash"]) block: Optional[ FullBlock] = await self.service.block_store.get_full_block( header_hash) if block is None: raise ValueError(f"Block {header_hash.hex()} not found") return {"block": block}
async def get_network_space(self, request: Dict) -> Optional[Dict]: """ Retrieves an estimate of total space validating the chain between two block header hashes. """ if "newer_block_header_hash" not in request or "older_block_header_hash" not in request: raise ValueError( "Invalid request. newer_block_header_hash and older_block_header_hash required" ) newer_block_hex = request["newer_block_header_hash"] older_block_hex = request["older_block_header_hash"] if newer_block_hex == older_block_hex: raise ValueError("New and old must not be the same") newer_block_bytes = bytes32.from_hexstr(newer_block_hex) older_block_bytes = bytes32.from_hexstr(older_block_hex) newer_block = await self.service.block_store.get_block_record( newer_block_bytes) if newer_block is None: raise ValueError("Newer block not found") older_block = await self.service.block_store.get_block_record( older_block_bytes) if older_block is None: raise ValueError("Newer block not found") delta_weight = newer_block.weight - older_block.weight delta_iters = newer_block.total_iters - older_block.total_iters weight_div_iters = delta_weight / delta_iters additional_difficulty_constant = self.service.constants.DIFFICULTY_CONSTANT_FACTOR eligible_plots_filter_multiplier = 2**self.service.constants.NUMBER_ZERO_BITS_PLOT_FILTER network_space_bytes_estimate = (UI_ACTUAL_SPACE_CONSTANT_FACTOR * weight_div_iters * additional_difficulty_constant * eligible_plots_filter_multiplier) return {"space": uint128(int(network_space_bytes_estimate))}
async def get_coin_record_by_name(self, request: Dict) -> Optional[Dict]: """ Retrieves a coin record by it's name. """ if "name" not in request: raise ValueError("Name not in request") name = bytes32.from_hexstr(request["name"]) coin_record: Optional[ CoinRecord] = await self.service.blockchain.coin_store.get_coin_record( name) if coin_record is None: raise ValueError(f"Coin record 0x{name.hex()} not found") return {"coin_record": coin_record}
async def get_offers(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: id: Optional[str] = args.get("id", None) filepath: Optional[str] = args.get("filepath", None) exclude_my_offers: bool = args.get("exclude_my_offers", False) exclude_taken_offers: bool = args.get("exclude_taken_offers", False) include_completed: bool = args.get("include_completed", False) summaries: bool = args.get("summaries", False) reverse: bool = args.get("reverse", False) file_contents: bool = (filepath is not None) or summaries records: List[TradeRecord] = [] if id is None: batch_size: int = 10 start: int = 0 end: int = start + batch_size # Traverse offers page by page while True: new_records: List[ TradeRecord] = await wallet_client.get_all_offers( start, end, reverse=reverse, file_contents=file_contents, exclude_my_offers=exclude_my_offers, exclude_taken_offers=exclude_taken_offers, include_completed=include_completed, ) records.extend(new_records) # If fewer records were returned than requested, we're done if len(new_records) < batch_size: break start = end end += batch_size else: records = [ await wallet_client.get_offer(bytes32.from_hexstr(id), file_contents) ] if filepath is not None: with open(pathlib.Path(filepath), "w") as file: file.write(Offer.from_bytes(records[0].offer).to_bech32()) file.close() for record in records: await print_trade_record(record, wallet_client, summaries=summaries)
async def get_block_record(self, request: Dict): if "header_hash" not in request: raise ValueError("header_hash not in request") header_hash_str = request["header_hash"] header_hash = bytes32.from_hexstr(header_hash_str) record: Optional[ BlockRecord] = self.service.blockchain.try_block_record( header_hash) if record is None: # Fetch from DB record = await self.service.blockchain.block_store.get_block_record( header_hash) if record is None: raise ValueError(f"Block {header_hash.hex()} does not exist") return {"block_record": record}
async def print_offer_summary(wallet_client: WalletRpcClient, sum_dict: dict): for asset_id, amount in sum_dict.items(): if asset_id == "xch": wid: str = "1" name: str = "XCH" unit: int = units["chia"] else: result = await wallet_client.cat_asset_id_to_name( bytes32.from_hexstr(asset_id)) wid = "Unknown" name = asset_id unit = units["cat"] if result is not None: wid = str(result[0]) name = result[1] print( f" - {name} (Wallet ID: {wid}): {Decimal(int(amount)) / unit} ({int(Decimal(amount))} mojos)" )
async def cancel_offer(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: id = bytes32.from_hexstr(args["id"]) secure: bool = not args["insecure"] fee: int = int(Decimal(args["fee"]) * units["chia"]) trade_record = await wallet_client.get_offer(id, file_contents=True) await print_trade_record(trade_record, wallet_client, summaries=True) confirmation = input( f"Are you sure you wish to cancel offer with ID: {trade_record.trade_id}? (y/n): " ) if confirmation in ["y", "yes"]: await wallet_client.cancel_offer(id, secure=secure, fee=fee) print(f"Cancelled offer with ID {trade_record.trade_id}") if secure: print( f"Use chia wallet get_offers --id {trade_record.trade_id} -f {fingerprint} to view cancel status" )
async def _messages_to_resend(self) -> List[Tuple[Message, Set[bytes32]]]: if self.wallet_state_manager is None or self.backup_initialized is False or self._shut_down: return [] messages: List[Tuple[Message, Set[bytes32]]] = [] records: List[ TransactionRecord] = await self.wallet_state_manager.tx_store.get_not_sent( ) for record in records: if record.spend_bundle is None: continue msg = make_msg( ProtocolMessageTypes.send_transaction, wallet_protocol.SendTransaction(record.spend_bundle), ) already_sent = set() for peer, status, _ in record.sent_to: if status == MempoolInclusionStatus.SUCCESS.value: already_sent.add(bytes32.from_hexstr(peer)) messages.append((msg, already_sent)) return messages
async def get_puzzle_and_solution(self, request: Dict) -> Optional[Dict]: coin_name: bytes32 = bytes32.from_hexstr(request["coin_id"]) height = request["height"] coin_record = await self.service.coin_store.get_coin_record(coin_name) if coin_record is None or not coin_record.spent or coin_record.spent_block_index != height: raise ValueError( f"Invalid height {height}. coin record {coin_record}") header_hash = self.service.blockchain.height_to_hash(height) # TODO: address hint error and remove ignore # error: Argument 1 to "get_full_block" of "BlockStore" has incompatible type "Optional[bytes32]"; # expected "bytes32" [arg-type] block: Optional[ FullBlock] = await self.service.block_store.get_full_block( header_hash) # type: ignore[arg-type] # noqa: E501 if block is None or block.transactions_generator is None: raise ValueError("Invalid block or block generator") block_generator: Optional[ BlockGenerator] = await self.service.blockchain.get_block_generator( block) assert block_generator is not None error, puzzle, solution = get_puzzle_and_solution_for_coin( block_generator, coin_name, self.service.constants.MAX_BLOCK_COST_CLVM) if error is not None: raise ValueError(f"Error: {error}") puzzle_ser: SerializedProgram = SerializedProgram.from_program( Program.to(puzzle)) solution_ser: SerializedProgram = SerializedProgram.from_program( Program.to(solution)) return { "coin_solution": CoinSpend(coin_record.coin, puzzle_ser, solution_ser) }
async def show(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: config = load_config(DEFAULT_ROOT_PATH, "config.yaml") self_hostname = config["self_hostname"] farmer_rpc_port = config["farmer"]["rpc_port"] farmer_client = await FarmerRpcClient.create(self_hostname, uint16(farmer_rpc_port), DEFAULT_ROOT_PATH, config) address_prefix = config["network_overrides"]["config"][ config["selected_network"]]["address_prefix"] summaries_response = await wallet_client.get_wallets() wallet_id_passed_in = args.get("id", None) plot_counts: Counter = Counter() try: pool_state_list: List = (await farmer_client.get_pool_state())["pool_state"] harvesters = await farmer_client.get_harvesters() for d in harvesters["harvesters"]: for plot in d["plots"]: if plot.get("pool_contract_puzzle_hash", None) is not None: # Non pooled plots will have a None pool_contract_puzzle_hash plot_counts[hexstr_to_bytes( plot["pool_contract_puzzle_hash"])] += 1 except Exception as e: if isinstance(e, aiohttp.ClientConnectorError): print( f"Connection error. Check if farmer is running at {farmer_rpc_port}." f" You can run the farmer by:\n chia start farmer-only") else: print(f"Exception from 'wallet' {e}") farmer_client.close() await farmer_client.await_closed() return pool_state_dict: Dict[bytes32, Dict] = { bytes32.from_hexstr(pool_state_item["pool_config"]["launcher_id"]): pool_state_item for pool_state_item in pool_state_list } if wallet_id_passed_in is not None: for summary in summaries_response: typ = WalletType(int(summary["type"])) if summary[ "id"] == wallet_id_passed_in and typ != WalletType.POOLING_WALLET: print( f"Wallet with id: {wallet_id_passed_in} is not a pooling wallet. Please provide a different id." ) return pool_wallet_info, _ = await wallet_client.pw_status(wallet_id_passed_in ) await pprint_pool_wallet_state( wallet_client, wallet_id_passed_in, pool_wallet_info, address_prefix, pool_state_dict, plot_counts, ) else: print(f"Wallet height: {await wallet_client.get_height_info()}") print( f"Sync status: {'Synced' if (await wallet_client.get_synced()) else 'Not synced'}" ) for summary in summaries_response: wallet_id = summary["id"] typ = WalletType(int(summary["type"])) if typ == WalletType.POOLING_WALLET: print(f"Wallet id {wallet_id}: ") pool_wallet_info, _ = await wallet_client.pw_status(wallet_id) await pprint_pool_wallet_state( wallet_client, wallet_id, pool_wallet_info, address_prefix, pool_state_dict, plot_counts, ) print("") farmer_client.close() await farmer_client.await_closed()
async def get_recent_signage_point_or_eos(self, request: Dict): if "sp_hash" not in request: challenge_hash: bytes32 = bytes32.from_hexstr( request["challenge_hash"]) # This is the case of getting an end of slot eos_tuple = self.service.full_node_store.recent_eos.get( challenge_hash) if not eos_tuple: raise ValueError( f"Did not find eos {challenge_hash.hex()} in cache") eos, time_received = eos_tuple # If it's still in the full node store, it's not reverted if self.service.full_node_store.get_sub_slot( eos.challenge_chain.get_hash()): return { "eos": eos, "time_received": time_received, "reverted": False } # Otherwise we can backtrack from peak to find it in the blockchain curr: Optional[BlockRecord] = self.service.blockchain.get_peak() if curr is None: raise ValueError("No blocks in the chain") number_of_slots_searched = 0 while number_of_slots_searched < 10: if curr.first_in_sub_slot: assert curr.finished_challenge_slot_hashes is not None if curr.finished_challenge_slot_hashes[ -1] == eos.challenge_chain.get_hash(): # Found this slot in the blockchain return { "eos": eos, "time_received": time_received, "reverted": False } number_of_slots_searched += len( curr.finished_challenge_slot_hashes) curr = self.service.blockchain.try_block_record(curr.prev_hash) if curr is None: # Got to the beginning of the blockchain without finding the slot return { "eos": eos, "time_received": time_received, "reverted": True } # Backtracked through 10 slots but still did not find it return { "eos": eos, "time_received": time_received, "reverted": True } # Now we handle the case of getting a signage point sp_hash: bytes32 = bytes32.from_hexstr(request["sp_hash"]) sp_tuple = self.service.full_node_store.recent_signage_points.get( sp_hash) if sp_tuple is None: raise ValueError(f"Did not find sp {sp_hash.hex()} in cache") sp, time_received = sp_tuple # If it's still in the full node store, it's not reverted if self.service.full_node_store.get_signage_point(sp_hash): return { "signage_point": sp, "time_received": time_received, "reverted": False } # Otherwise we can backtrack from peak to find it in the blockchain rc_challenge: bytes32 = sp.rc_vdf.challenge next_b: Optional[BlockRecord] = None curr_b_optional: Optional[ BlockRecord] = self.service.blockchain.get_peak() assert curr_b_optional is not None curr_b: BlockRecord = curr_b_optional for _ in range(200): sp_total_iters = sp.cc_vdf.number_of_iterations + curr_b.ip_sub_slot_total_iters( self.service.constants) if curr_b.reward_infusion_new_challenge == rc_challenge: if next_b is None: return { "signage_point": sp, "time_received": time_received, "reverted": False } next_b_total_iters = next_b.ip_sub_slot_total_iters( self.service.constants) + next_b.ip_iters( self.service.constants) return { "signage_point": sp, "time_received": time_received, "reverted": sp_total_iters > next_b_total_iters, } if curr_b.finished_reward_slot_hashes is not None: assert curr_b.finished_challenge_slot_hashes is not None for eos_rc in curr_b.finished_challenge_slot_hashes: if eos_rc == rc_challenge: if next_b is None: return { "signage_point": sp, "time_received": time_received, "reverted": False } next_b_total_iters = next_b.ip_sub_slot_total_iters( self.service.constants) + next_b.ip_iters( self.service.constants) return { "signage_point": sp, "time_received": time_received, "reverted": sp_total_iters > next_b_total_iters, } next_b = curr_b curr_b_optional = self.service.blockchain.try_block_record( curr_b.prev_hash) if curr_b_optional is None: break curr_b = curr_b_optional return { "signage_point": sp, "time_received": time_received, "reverted": True }
async def create(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: state = args["state"] prompt = not args.get("yes", False) fee = Decimal(args.get("fee", 0)) fee_mojos = uint64(int(fee * units["chia"])) target_puzzle_hash: Optional[bytes32] # Could use initial_pool_state_from_dict to simplify if state == "SELF_POOLING": pool_url: Optional[str] = None relative_lock_height = uint32(0) target_puzzle_hash = None # wallet will fill this in elif state == "FARMING_TO_POOL": config = load_config(DEFAULT_ROOT_PATH, "config.yaml") enforce_https = config["full_node"]["selected_network"] == "mainnet" pool_url = str(args["pool_url"]) if enforce_https and not pool_url.startswith("https://"): print(f"Pool URLs must be HTTPS on mainnet {pool_url}. Aborting.") return json_dict = await create_pool_args(pool_url) relative_lock_height = json_dict["relative_lock_height"] target_puzzle_hash = bytes32.from_hexstr( json_dict["target_puzzle_hash"]) else: raise ValueError( "Plot NFT must be created in SELF_POOLING or FARMING_TO_POOL state." ) pool_msg = f" and join pool: {pool_url}" if pool_url else "" print(f"Will create a plot NFT{pool_msg}.") if prompt: user_input: str = input("Confirm [n]/y: ") else: user_input = "yes" if user_input.lower() == "y" or user_input.lower() == "yes": try: tx_record: TransactionRecord = await wallet_client.create_new_pool_wallet( target_puzzle_hash, pool_url, relative_lock_height, "localhost:5000", "new", state, fee_mojos, ) start = time.time() while time.time() - start < 10: await asyncio.sleep(0.1) tx = await wallet_client.get_transaction( str(1), tx_record.name) if len(tx.sent_to) > 0: print(f"Transaction submitted to nodes: {tx.sent_to}") print( f"Do chia wallet get_transaction -f {fingerprint} -tx 0x{tx_record.name} to get status" ) return None except Exception as e: print(f"Error creating plot NFT: {e}") return print("Aborting.")
async def set_payout_instructions(self, request: Dict) -> Dict: launcher_id: bytes32 = bytes32.from_hexstr(request["launcher_id"]) await self.service.set_payout_instructions( launcher_id, request["payout_instructions"]) return {}
async def set_user_info( self, interval: uint64, limit: uint64, origin_parent_id: str, origin_puzzle_hash: str, origin_amount: uint64, admin_pubkey: str, ) -> None: admin_pubkey_bytes = hexstr_to_bytes(admin_pubkey) assert self.rl_info.user_pubkey is not None origin = Coin( bytes32.from_hexstr(origin_parent_id), bytes32.from_hexstr(origin_puzzle_hash), origin_amount, ) rl_puzzle = rl_puzzle_for_pk( pubkey=self.rl_info.user_pubkey, rate_amount=limit, interval_time=interval, origin_id=origin.name(), clawback_pk=admin_pubkey_bytes, ) rl_puzzle_hash = rl_puzzle.get_tree_hash() new_rl_info = RLInfo( "user", admin_pubkey_bytes, self.rl_info.user_pubkey, limit, interval, origin, origin.name(), rl_puzzle_hash, True, ) rl_puzzle_hash = rl_puzzle.get_tree_hash() if await self.wallet_state_manager.puzzle_store.puzzle_hash_exists( rl_puzzle_hash): raise ValueError( "Cannot create multiple Rate Limited wallets under the same keys. This will change in a future release." ) user_pubkey: G1Element = G1Element.from_bytes(self.rl_info.user_pubkey) index = await self.wallet_state_manager.puzzle_store.index_for_pubkey( user_pubkey) assert index is not None record = DerivationRecord( index, rl_puzzle_hash, user_pubkey, WalletType.RATE_LIMITED, self.id(), ) aggregation_puzzlehash = self.rl_get_aggregation_puzzlehash( new_rl_info.rl_puzzle_hash) record2 = DerivationRecord( index + 1, aggregation_puzzlehash, user_pubkey, WalletType.RATE_LIMITED, self.id(), ) await self.wallet_state_manager.puzzle_store.add_derivation_paths( [record, record2]) self.wallet_state_manager.set_coin_with_puzzlehash_created_callback( aggregation_puzzlehash, self.aggregate_this_coin) data_str = json.dumps(new_rl_info.to_json_dict()) new_wallet_info = WalletInfo(self.id(), self.wallet_info.name, self.type(), data_str) await self.wallet_state_manager.user_store.update_wallet( new_wallet_info, False) await self.wallet_state_manager.add_new_wallet(self, self.id()) self.wallet_info = new_wallet_info self.rl_info = new_rl_info