diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 2407bce4..b185dd83 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -2163,6 +2163,9 @@ def wallet_transfer( [green]$[/green] btcli wallet transfer --dest 5Dp8... --amount 100 [bold]NOTE[/bold]: This command is used for executing token transfers within the Bittensor network. Users should verify the destination address and the TAO amount before confirming the transaction to avoid errors or loss of funds. + + JSON OUTPUT SCHEMA + {success: bool, message: Optional[str], extrinsic_identifier: Optional[str]} """ if not is_valid_ss58_address(destination_ss58_address): print_error("You have entered an incorrect ss58 address. Please try again.") @@ -2240,6 +2243,9 @@ def wallet_swap_hotkey( EXAMPLE [green]$[/green] btcli wallet swap_hotkey destination_hotkey_name --wallet-name your_wallet_name --wallet-hotkey original_hotkey --netuid 1 + + JSON OUTPUT SCHEMA + {success: bool, message: Optional[str], extrinsic_identifier: Optional[str]} """ netuid = get_optional_netuid(netuid, all_netuids) self.verbosity_handler(quiet, verbose, json_output) @@ -5867,6 +5873,9 @@ def sudo_trim( EXAMPLE [green]$[/green] btcli sudo trim --netuid 95 --wallet-name my_wallet --wallet-hotkey my_hotkey --max 64 + + JSON OUTPUT SCHEMA + {success: bool, message: Optional[str], extrinsic_identifier: Optional[str]} """ self.verbosity_handler(quiet, verbose, json_output) @@ -7106,7 +7115,12 @@ def liquidity_remove( verbose: bool = Options.verbose, json_output: bool = Options.json_output, ): - """Remove liquidity from the swap (as a combination of TAO + Alpha).""" + """ + Remove liquidity from the swap (as a combination of TAO + Alpha). + + JSON OUTPUT SCHEMA + {position_id: {success: bool, message: Optional[str], extrinsic_identifier: Optional[str]}} + """ self.verbosity_handler(quiet, verbose, json_output) @@ -7177,7 +7191,12 @@ def liquidity_modify( verbose: bool = Options.verbose, json_output: bool = Options.json_output, ): - """Modifies the liquidity position for the given subnet.""" + """ + Modifies the liquidity position for the given subnet. + + JSON OUTPUT SCHEMA + {success: bool, message: Optional[str], extrinsic_identifier: Optional[str]} + """ self.verbosity_handler(quiet, verbose, json_output) if not netuid: netuid = IntPrompt.ask( diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index c8be3356..3429fb63 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -1512,3 +1512,39 @@ async def print_extrinsic_id( f":white_heavy_check_mark:Your extrinsic has been included as {ext_id}" ) return + + +class SingleTransactionJsonOutput: + def __init__( + self, + success: bool, + message: Optional[str] = None, + extrinsic_identifier: Optional[str] = None, + ): + self.success = success + self.message = message + self.extrinsic_identifier = extrinsic_identifier + + def print(self) -> None: + json_console.print_json(data=self.as_dict()) + + def as_dict(self) -> dict: + return { + "success": self.success, + "message": self.message, + "extrinsic_identifier": self.extrinsic_identifier, + } + + +class MultiTransactionJsonOutput: + def __init__(self): + self.dict = {} + + def add_item(self, key: str, value: SingleTransactionJsonOutput) -> None: + self.dict[key] = value + + def print(self) -> None: + json_console.print_json(data=self.as_dict()) + + def as_dict(self) -> dict: + return {k: v.as_dict() for k, v in self.dict.items()} diff --git a/bittensor_cli/src/commands/liquidity/liquidity.py b/bittensor_cli/src/commands/liquidity/liquidity.py index cc25ff1e..378b15d2 100644 --- a/bittensor_cli/src/commands/liquidity/liquidity.py +++ b/bittensor_cli/src/commands/liquidity/liquidity.py @@ -13,6 +13,8 @@ err_console, json_console, print_extrinsic_id, + SingleTransactionJsonOutput, + MultiTransactionJsonOutput, ) from bittensor_cli.src.bittensor.balances import Balance, fixed_to_float from bittensor_cli.src.commands.liquidity.utils import ( @@ -274,11 +276,7 @@ async def add_liquidity( await print_extrinsic_id(ext_receipt) ext_id = await ext_receipt.get_extrinsic_identifier() if json_output: - json_console.print( - json.dumps( - {"success": success, "message": message, "extrinsic_identifier": ext_id} - ) - ) + SingleTransactionJsonOutput(success, message, ext_id).print() else: if success: console.print( @@ -537,16 +535,26 @@ async def remove_liquidity( json_output: bool = False, ) -> tuple[bool, str]: """Remove liquidity position from provided subnet.""" + json_response = MultiTransactionJsonOutput() if not await subtensor.subnet_exists(netuid=netuid): - return False, f"Subnet with netuid: {netuid} does not exist in {subtensor}." + err_msg = f"Subnet with netuid: {netuid} does not exist in {subtensor}." + if json_output: + json_response.add_item("0", SingleTransactionJsonOutput(False, err_msg)) + json_response.print() + return False, err_msg if all_liquidity_ids: success, msg, positions = await get_liquidity_list(subtensor, wallet, netuid) if not success: if json_output: - json_console.print_json( - data={"success": False, "err_msg": msg, "positions": positions} - ) + if len(positions) == 0: + json_response.add_item("0", SingleTransactionJsonOutput(False, msg)) + else: + for position in positions: + json_response.add_item( + str(position.id), SingleTransactionJsonOutput(False, msg) + ) + json_response.print() else: return err_console.print(f"Error: {msg}") return False, msg @@ -556,11 +564,12 @@ async def remove_liquidity( position_ids = [position_id] if prompt: - console.print("You are about to remove LiquidityPositions with:") - console.print(f"\tSubnet: {netuid}") - console.print(f"\tWallet name: {wallet.name}") - for pos in position_ids: - console.print(f"\tPosition id: {pos}") + console.print( + "You are about to remove LiquidityPositions with:\n" + f"\tSubnet: {netuid}\n" + f"\tWallet name: {wallet.name}" + + "\n".join(f"\tPosition id: {pos}" for pos in position_ids) + ) if not Confirm.ask("Would you like to continue?"): return False, "User cancelled operation." @@ -585,14 +594,14 @@ async def remove_liquidity( else: err_console.print(f"[red] Error removing {posid}: {msg}") else: - json_table = {} - for (success, msg, ext_receipt), posid in zip(results, position_ids): - json_table[posid] = { - "success": success, - "err_msg": msg, - "extrinsic_identifier": await ext_receipt.get_extrinsic_identifier(), - } - json_console.print_json(data=json_table) + ext_ids = await asyncio.gather( + *[ext_receipt.get_extrinsic_identifier() for _, _, ext_receipt in results] + ) + for (success, msg, _), posid, ext_id in zip(results, position_ids, ext_ids): + json_response.add_item( + str(posid), SingleTransactionJsonOutput(success, msg, ext_id) + ) + json_response.print() async def modify_liquidity( @@ -609,7 +618,7 @@ async def modify_liquidity( if not await subtensor.subnet_exists(netuid=netuid): err_msg = f"Subnet with netuid: {netuid} does not exist in {subtensor}." if json_output: - json_console.print(json.dumps({"success": False, "err_msg": err_msg})) + SingleTransactionJsonOutput(False, err_msg).print() else: err_console.print(err_msg) return False @@ -636,9 +645,7 @@ async def modify_liquidity( ) if json_output: ext_id = await ext_receipt.get_extrinsic_identifier() if success else None - json_console.print_json( - data={"success": success, "err_msg": msg, "extrinsic_identifier": ext_id} - ) + SingleTransactionJsonOutput(success, msg, ext_id).print() else: if success: await print_extrinsic_id(ext_receipt) diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 955f5243..110bb55a 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -29,6 +29,7 @@ string_to_u64, get_hotkey_pub_ss58, print_extrinsic_id, + SingleTransactionJsonOutput, ) if TYPE_CHECKING: @@ -1071,7 +1072,7 @@ async def trim( if subnet_owner != wallet.coldkeypub.ss58_address: err_msg = "This wallet doesn't own the specified subnet." if json_output: - json_console.print_json(data={"success": False, "message": err_msg}) + SingleTransactionJsonOutput(False, err_msg).print() else: err_console.print(f":cross_mark: [red]{err_msg}[/red]") return False @@ -1091,13 +1092,7 @@ async def trim( ) if not success: if json_output: - json_console.print_json( - data={ - "success": False, - "message": err_msg, - "extrinsic_identifier": None, - } - ) + SingleTransactionJsonOutput(False, err_msg, None).print() else: err_console.print(f":cross_mark: [red]{err_msg}[/red]") return False @@ -1105,9 +1100,7 @@ async def trim( ext_id = await ext_receipt.get_extrinsic_identifier() msg = f"Successfully trimmed UIDs on SN{netuid} to {max_n}" if json_output: - json_console.print_json( - data={"success": True, "message": msg, "extrinsic_identifier": ext_id} - ) + SingleTransactionJsonOutput(True, msg, ext_id).print() else: await print_extrinsic_id(ext_receipt) console.print( diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 63edd7ef..c311b46c 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -50,6 +50,7 @@ decode_account_id, get_hotkey_pub_ss58, print_extrinsic_id, + SingleTransactionJsonOutput, ) @@ -1509,9 +1510,7 @@ async def transfer( ) ext_id = (await ext_receipt.get_extrinsic_identifier()) if result else None if json_output: - json_console.print( - json.dumps({"success": result, "extrinsic_identifier": ext_id}) - ) + SingleTransactionJsonOutput(result, extrinsic_identifier=ext_id).print() else: await print_extrinsic_id(ext_receipt) return result @@ -1715,9 +1714,7 @@ async def swap_hotkey( else: ext_id = None if json_output: - json_console.print( - json.dumps({"success": result, "extrinsic_identifier": ext_id}) - ) + SingleTransactionJsonOutput(result, extrinsic_identifier=ext_id).print() else: await print_extrinsic_id(ext_receipt) return result