From 0227cce2f56f7c65a7057fd016904bb3a5d2b9a0 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 15:57:28 +0200 Subject: [PATCH 1/9] Changed bool to enum in hyperparams which allows us to use a third type for complicated extrinsics --- bittensor_cli/src/__init__.py | 83 ++++++++++++--------- bittensor_cli/src/commands/sudo.py | 111 +++++++++++++++++------------ 2 files changed, 113 insertions(+), 81 deletions(-) diff --git a/bittensor_cli/src/__init__.py b/bittensor_cli/src/__init__.py index bc46bd485..1151a2c45 100644 --- a/bittensor_cli/src/__init__.py +++ b/bittensor_cli/src/__init__.py @@ -626,47 +626,62 @@ class WalletValidationTypes(Enum): } +class RootSudoOnly(Enum): + FALSE = 0 + TRUE = 1 + COMPLICATED = 2 + + HYPERPARAMS = { - # btcli name: (subtensor method, root-only bool) - "rho": ("sudo_set_rho", False), - "kappa": ("sudo_set_kappa", False), - "immunity_period": ("sudo_set_immunity_period", False), - "min_allowed_weights": ("sudo_set_min_allowed_weights", False), - "max_weights_limit": ("sudo_set_max_weight_limit", False), - "tempo": ("sudo_set_tempo", True), - "min_difficulty": ("sudo_set_min_difficulty", True), - "max_difficulty": ("sudo_set_max_difficulty", False), - "weights_version": ("sudo_set_weights_version_key", False), - "weights_rate_limit": ("sudo_set_weights_set_rate_limit", True), - "adjustment_interval": ("sudo_set_adjustment_interval", True), - "activity_cutoff": ("sudo_set_activity_cutoff", False), - "target_regs_per_interval": ("sudo_set_target_registrations_per_interval", True), - "min_burn": ("sudo_set_min_burn", False), - "max_burn": ("sudo_set_max_burn", True), - "bonds_moving_avg": ("sudo_set_bonds_moving_average", False), - "max_regs_per_block": ("sudo_set_max_registrations_per_block", True), - "serving_rate_limit": ("sudo_set_serving_rate_limit", False), - "max_validators": ("sudo_set_max_allowed_validators", True), - "adjustment_alpha": ("sudo_set_adjustment_alpha", False), - "difficulty": ("sudo_set_difficulty", True), + # btcli name: (subtensor method, root-only enum) + "rho": ("sudo_set_rho", RootSudoOnly.FALSE), + "kappa": ("sudo_set_kappa", RootSudoOnly.FALSE), + "immunity_period": ("sudo_set_immunity_period", RootSudoOnly.FALSE), + "min_allowed_weights": ("sudo_set_min_allowed_weights", RootSudoOnly.FALSE), + "max_weights_limit": ("sudo_set_max_weight_limit", RootSudoOnly.FALSE), + "tempo": ("sudo_set_tempo", RootSudoOnly.TRUE), + "min_difficulty": ("sudo_set_min_difficulty", RootSudoOnly.TRUE), + "max_difficulty": ("sudo_set_max_difficulty", RootSudoOnly.FALSE), + "weights_version": ("sudo_set_weights_version_key", RootSudoOnly.FALSE), + "weights_rate_limit": ("sudo_set_weights_set_rate_limit", RootSudoOnly.TRUE), + "adjustment_interval": ("sudo_set_adjustment_interval", RootSudoOnly.TRUE), + "activity_cutoff": ("sudo_set_activity_cutoff", RootSudoOnly.FALSE), + "target_regs_per_interval": ( + "sudo_set_target_registrations_per_interval", + RootSudoOnly.TRUE, + ), + "min_burn": ("sudo_set_min_burn", RootSudoOnly.FALSE), + "max_burn": ("sudo_set_max_burn", RootSudoOnly.TRUE), + "bonds_moving_avg": ("sudo_set_bonds_moving_average", RootSudoOnly.FALSE), + "max_regs_per_block": ("sudo_set_max_registrations_per_block", RootSudoOnly.TRUE), + "serving_rate_limit": ("sudo_set_serving_rate_limit", RootSudoOnly.FALSE), + "max_validators": ("sudo_set_max_allowed_validators", RootSudoOnly.TRUE), + "adjustment_alpha": ("sudo_set_adjustment_alpha", RootSudoOnly.FALSE), + "difficulty": ("sudo_set_difficulty", RootSudoOnly.TRUE), "commit_reveal_period": ( "sudo_set_commit_reveal_weights_interval", - False, + RootSudoOnly.FALSE, + ), + "commit_reveal_weights_enabled": ( + "sudo_set_commit_reveal_weights_enabled", + RootSudoOnly.FALSE, + ), + "alpha_values": ("sudo_set_alpha_values", RootSudoOnly.FALSE), + "liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", RootSudoOnly.FALSE), + "registration_allowed": ( + "sudo_set_network_registration_allowed", + RootSudoOnly.TRUE, ), - "commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", False), - "alpha_values": ("sudo_set_alpha_values", False), - "liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", False), - "registration_allowed": ("sudo_set_network_registration_allowed", True), "network_pow_registration_allowed": ( "sudo_set_network_pow_registration_allowed", - False, + RootSudoOnly.FALSE, ), - "yuma3_enabled": ("sudo_set_yuma3_enabled", False), - "alpha_sigmoid_steepness": ("sudo_set_alpha_sigmoid_steepness", True), - "user_liquidity_enabled": ("toggle_user_liquidity", True), - "bonds_reset_enabled": ("sudo_set_bonds_reset_enabled", False), - "transfers_enabled": ("sudo_set_toggle_transfer", False), - "min_allowed_uids": ("sudo_set_min_allowed_uids", True), + "yuma3_enabled": ("sudo_set_yuma3_enabled", RootSudoOnly.FALSE), + "alpha_sigmoid_steepness": ("sudo_set_alpha_sigmoid_steepness", RootSudoOnly.TRUE), + "user_liquidity_enabled": ("toggle_user_liquidity", RootSudoOnly.COMPLICATED), + "bonds_reset_enabled": ("sudo_set_bonds_reset_enabled", RootSudoOnly.FALSE), + "transfers_enabled": ("sudo_set_toggle_transfer", RootSudoOnly.FALSE), + "min_allowed_uids": ("sudo_set_min_allowed_uids", RootSudoOnly.TRUE), } HYPERPARAMS_MODULE = { diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 955f52435..023cf39c9 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -12,6 +12,7 @@ from bittensor_cli.src import ( HYPERPARAMS, HYPERPARAMS_MODULE, + RootSudoOnly, DelegatesDetails, COLOR_PALETTE, ) @@ -295,7 +296,7 @@ async def set_hyperparameter_extrinsic( arbitrary_extrinsic = False - extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", False)) + extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", RootSudoOnly.FALSE)) call_params = {"netuid": netuid} if not extrinsic: arbitrary_extrinsic, call_params = search_metadata( @@ -305,8 +306,8 @@ async def set_hyperparameter_extrinsic( if not arbitrary_extrinsic: err_msg = ":cross_mark: [red]Invalid hyperparameter specified.[/red]" err_console.print(err_msg) - return False, err_msg - if sudo_ and prompt: + return False, err_msg, None + if sudo_ is RootSudoOnly.TRUE and prompt: if not Confirm.ask( "This hyperparam is only settable by root sudo users. If you are not, this will fail. Please confirm" ): @@ -316,63 +317,77 @@ async def set_hyperparameter_extrinsic( msg_value = value if not arbitrary_extrinsic else call_params pallet = HYPERPARAMS_MODULE.get(parameter) or DEFAULT_PALLET - with console.status( - f":satellite: Setting hyperparameter [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{parameter}" - f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] to [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{msg_value}" - f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] on subnet: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]" - f"{netuid}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] ...", - spinner="earth", - ): - if not arbitrary_extrinsic: - extrinsic_params = await substrate.get_metadata_call_function( - module_name=pallet, call_function_name=extrinsic - ) - - # if input value is a list, iterate through the list and assign values - if isinstance(value, list): - # Ensure that there are enough values for all non-netuid parameters - non_netuid_fields = [ - pn_str - for param in extrinsic_params["fields"] - if "netuid" not in (pn_str := str(param["name"])) - ] - - if len(value) < len(non_netuid_fields): - err_msg = ( - "Not enough values provided in the list for all parameters" - ) - err_console.print(err_msg) - return False, err_msg, None - - call_params.update( - {name: val for name, val in zip(non_netuid_fields, value)} - ) + if not arbitrary_extrinsic: + extrinsic_params = await substrate.get_metadata_call_function( + module_name=pallet, call_function_name=extrinsic + ) - else: - if requires_bool( - substrate.metadata, param_name=extrinsic, pallet=pallet - ) and isinstance(value, str): - value = string_to_bool(value) - value_argument = extrinsic_params["fields"][ - len(extrinsic_params["fields"]) - 1 - ] - call_params[str(value_argument["name"])] = value + # if input value is a list, iterate through the list and assign values + if isinstance(value, list): + # Ensure that there are enough values for all non-netuid parameters + non_netuid_fields = [ + pn_str + for param in extrinsic_params["fields"] + if "netuid" not in (pn_str := str(param["name"])) + ] + + if len(value) < len(non_netuid_fields): + err_msg = "Not enough values provided in the list for all parameters" + err_console.print(err_msg) + return False, err_msg, None + + call_params.update( + {name: val for name, val in zip(non_netuid_fields, value)} + ) + else: + if requires_bool( + substrate.metadata, param_name=extrinsic, pallet=pallet + ) and isinstance(value, str): + value = string_to_bool(value) + value_argument = extrinsic_params["fields"][ + len(extrinsic_params["fields"]) - 1 + ] + call_params[str(value_argument["name"])] = value # create extrinsic call call_ = await substrate.compose_call( call_module=pallet, call_function=extrinsic, call_params=call_params, ) - if sudo_: + if sudo_ is RootSudoOnly.TRUE: call = await substrate.compose_call( call_module="Sudo", call_function="sudo", call_params={"call": call_} ) + elif sudo_ is RootSudoOnly.COMPLICATED: + if not prompt: + return ( + False, + "This hyperparam requires interactivity to set, and cannot be run with --no-prompt", + None, + ) + to_sudo_or_not_to_sudo = Confirm.ask( + f"This hyperparam can be executed as sudo or not. Do you want to execute as sudo [y] or not [n]?" + ) + if to_sudo_or_not_to_sudo: + call = await substrate.compose_call( + call_module="Sudo", + call_function="sudo", + call_params={"call": call_}, + ) + else: + call = call_ else: call = call_ - success, err_msg, ext_receipt = await subtensor.sign_and_send_extrinsic( - call, wallet, wait_for_inclusion, wait_for_finalization - ) + with console.status( + f":satellite: Setting hyperparameter [{COLOR_PALETTE.G.SUBHEAD}]{parameter}[/{COLOR_PALETTE.G.SUBHEAD}]" + f" to [{COLOR_PALETTE.G.SUBHEAD}]{msg_value}[/{COLOR_PALETTE.G.SUBHEAD}]" + f" on subnet: [{COLOR_PALETTE.G.SUBHEAD}]{netuid}[/{COLOR_PALETTE.G.SUBHEAD}] ...", + spinner="earth", + ): + success, err_msg, ext_receipt = await subtensor.sign_and_send_extrinsic( + call, wallet, wait_for_inclusion, wait_for_finalization + ) if not success: err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}") return False, err_msg, None @@ -725,6 +740,8 @@ async def sudo_set_hyperparameter( ) err_console.print(err_msg) return False, err_msg, None + if json_output: + prompt = False success, err_msg, ext_id = await set_hyperparameter_extrinsic( subtensor, wallet, netuid, param_name, value, prompt=prompt ) From b1d972871b523907efbc8df3887c8758729cef7e Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 16:18:39 +0200 Subject: [PATCH 2/9] Default for no prompt --- bittensor_cli/src/commands/sudo.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 023cf39c9..870d7ed5a 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -132,6 +132,7 @@ def type_converter_with_retry(type_, val, arg_name): pallet = metadata.get_metadata_pallet(pallet_name) for call in pallet.calls: if call.name == param_name: + print(call.name) if "netuid" not in [x.name for x in call.args]: return False, None call_args = [arg for arg in call.args if arg.value["name"] != "netuid"] @@ -361,14 +362,13 @@ async def set_hyperparameter_extrinsic( ) elif sudo_ is RootSudoOnly.COMPLICATED: if not prompt: - return ( - False, - "This hyperparam requires interactivity to set, and cannot be run with --no-prompt", - None, + to_sudo_or_not_to_sudo = ( + True # default to sudo true when no-prompt is set + ) + else: + to_sudo_or_not_to_sudo = Confirm.ask( + f"This hyperparam can be executed as sudo or not. Do you want to execute as sudo [y] or not [n]?" ) - to_sudo_or_not_to_sudo = Confirm.ask( - f"This hyperparam can be executed as sudo or not. Do you want to execute as sudo [y] or not [n]?" - ) if to_sudo_or_not_to_sudo: call = await substrate.compose_call( call_module="Sudo", From 5e230bb6393256dd8168ba252738842511f27324 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 16:37:50 +0200 Subject: [PATCH 3/9] Missed indent + typing fixes --- .../src/bittensor/subtensor_interface.py | 2 +- bittensor_cli/src/commands/sudo.py | 105 +++++++++--------- 2 files changed, 53 insertions(+), 54 deletions(-) diff --git a/bittensor_cli/src/bittensor/subtensor_interface.py b/bittensor_cli/src/bittensor/subtensor_interface.py index bb841d9f3..fe5e7af2e 100644 --- a/bittensor_cli/src/bittensor/subtensor_interface.py +++ b/bittensor_cli/src/bittensor/subtensor_interface.py @@ -500,7 +500,7 @@ async def get_total_stake_for_hotkey( async def current_take( self, - hotkey_ss58: int, + hotkey_ss58: str, block_hash: Optional[str] = None, reuse_block: bool = False, ) -> Optional[float]: diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 870d7ed5a..e305299ac 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -1,6 +1,6 @@ import asyncio import json -from typing import TYPE_CHECKING, Union, Optional +from typing import TYPE_CHECKING, Union, Optional, Type from async_substrate_interface import AsyncExtrinsicReceipt from bittensor_wallet import Wallet @@ -84,7 +84,7 @@ def allowed_value( return True, value -def string_to_bool(val) -> bool: +def string_to_bool(val) -> Union[bool, Type[ValueError]]: try: return {"true": True, "1": True, "0": False, "false": False}[val.lower()] except KeyError: @@ -160,7 +160,7 @@ def requires_bool(metadata, param_name, pallet: str = DEFAULT_PALLET) -> bool: for call in pallet.calls: if call.name == param_name: if "netuid" not in [x.name for x in call.args]: - return False, None + return False call_args = [arg for arg in call.args if arg.value["name"] != "netuid"] if len(call_args) != 1: return False @@ -272,6 +272,7 @@ async def set_hyperparameter_extrinsic( `False` if the extrinsic fails to enter the block within the timeout. :param wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`, or returns `False` if the extrinsic fails to be finalized within the timeout. + :param prompt: If set to False, will not prompt the user. :return: tuple including: success: `True` if extrinsic was finalized or included in the block. If we did not wait for @@ -350,63 +351,61 @@ async def set_hyperparameter_extrinsic( len(extrinsic_params["fields"]) - 1 ] call_params[str(value_argument["name"])] = value - # create extrinsic call - call_ = await substrate.compose_call( - call_module=pallet, - call_function=extrinsic, - call_params=call_params, + # create extrinsic call + call_ = await substrate.compose_call( + call_module=pallet, + call_function=extrinsic, + call_params=call_params, + ) + if sudo_ is RootSudoOnly.TRUE: + call = await substrate.compose_call( + call_module="Sudo", call_function="sudo", call_params={"call": call_} ) - if sudo_ is RootSudoOnly.TRUE: + elif sudo_ is RootSudoOnly.COMPLICATED: + if not prompt: + to_sudo_or_not_to_sudo = True # default to sudo true when no-prompt is set + else: + to_sudo_or_not_to_sudo = Confirm.ask( + f"This hyperparam can be executed as sudo or not. Do you want to execute as sudo [y] or not [n]?" + ) + if to_sudo_or_not_to_sudo: call = await substrate.compose_call( - call_module="Sudo", call_function="sudo", call_params={"call": call_} + call_module="Sudo", + call_function="sudo", + call_params={"call": call_}, ) - elif sudo_ is RootSudoOnly.COMPLICATED: - if not prompt: - to_sudo_or_not_to_sudo = ( - True # default to sudo true when no-prompt is set - ) - else: - to_sudo_or_not_to_sudo = Confirm.ask( - f"This hyperparam can be executed as sudo or not. Do you want to execute as sudo [y] or not [n]?" - ) - if to_sudo_or_not_to_sudo: - call = await substrate.compose_call( - call_module="Sudo", - call_function="sudo", - call_params={"call": call_}, - ) - else: - call = call_ else: call = call_ - with console.status( - f":satellite: Setting hyperparameter [{COLOR_PALETTE.G.SUBHEAD}]{parameter}[/{COLOR_PALETTE.G.SUBHEAD}]" - f" to [{COLOR_PALETTE.G.SUBHEAD}]{msg_value}[/{COLOR_PALETTE.G.SUBHEAD}]" - f" on subnet: [{COLOR_PALETTE.G.SUBHEAD}]{netuid}[/{COLOR_PALETTE.G.SUBHEAD}] ...", - spinner="earth", - ): - success, err_msg, ext_receipt = await subtensor.sign_and_send_extrinsic( - call, wallet, wait_for_inclusion, wait_for_finalization + else: + call = call_ + with console.status( + f":satellite: Setting hyperparameter [{COLOR_PALETTE.G.SUBHEAD}]{parameter}[/{COLOR_PALETTE.G.SUBHEAD}]" + f" to [{COLOR_PALETTE.G.SUBHEAD}]{msg_value}[/{COLOR_PALETTE.G.SUBHEAD}]" + f" on subnet: [{COLOR_PALETTE.G.SUBHEAD}]{netuid}[/{COLOR_PALETTE.G.SUBHEAD}] ...", + spinner="earth", + ): + success, err_msg, ext_receipt = await subtensor.sign_and_send_extrinsic( + call, wallet, wait_for_inclusion, wait_for_finalization + ) + if not success: + err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}") + return False, err_msg, None + else: + ext_id = await ext_receipt.get_extrinsic_identifier() + await print_extrinsic_id(ext_receipt) + if arbitrary_extrinsic: + console.print( + f":white_heavy_check_mark: " + f"[dark_sea_green3]Hyperparameter {parameter} values changed to {call_params}[/dark_sea_green3]" ) - if not success: - err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}") - return False, err_msg, None + return True, "", ext_id + # Successful registration, final check for membership else: - ext_id = await ext_receipt.get_extrinsic_identifier() - await print_extrinsic_id(ext_receipt) - if arbitrary_extrinsic: - console.print( - f":white_heavy_check_mark: " - f"[dark_sea_green3]Hyperparameter {parameter} values changed to {call_params}[/dark_sea_green3]" - ) - return True, "", ext_id - # Successful registration, final check for membership - else: - console.print( - f":white_heavy_check_mark: " - f"[dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]" - ) - return True, "", ext_id + console.print( + f":white_heavy_check_mark: " + f"[dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]" + ) + return True, "", ext_id async def _get_senate_members( From 03b6b8378aef7d74ac689cfbf27f013d70db7078 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 16:45:24 +0200 Subject: [PATCH 4/9] Debug removed --- bittensor_cli/src/commands/sudo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index e305299ac..76cc0addd 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -132,7 +132,6 @@ def type_converter_with_retry(type_, val, arg_name): pallet = metadata.get_metadata_pallet(pallet_name) for call in pallet.calls: if call.name == param_name: - print(call.name) if "netuid" not in [x.name for x in call.args]: return False, None call_args = [arg for arg in call.args if arg.value["name"] != "netuid"] From f908df7ae0e98fc4b7bb865a6eef657cdab6b5a5 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 16:55:56 +0200 Subject: [PATCH 5/9] tf? From 3c903951fe1cb267b03acb158c2586ad80581d50 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 17:10:39 +0200 Subject: [PATCH 6/9] test --- bittensor_cli/src/commands/sudo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 76cc0addd..263cb44b2 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -318,6 +318,7 @@ async def set_hyperparameter_extrinsic( msg_value = value if not arbitrary_extrinsic else call_params pallet = HYPERPARAMS_MODULE.get(parameter) or DEFAULT_PALLET + if not arbitrary_extrinsic: extrinsic_params = await substrate.get_metadata_call_function( module_name=pallet, call_function_name=extrinsic From 3d46c83ad69c85a490f7fd5febaf085f6e2a0779 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 17:14:24 +0200 Subject: [PATCH 7/9] Ruff --- bittensor_cli/src/commands/sudo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 263cb44b2..76cc0addd 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -318,7 +318,6 @@ async def set_hyperparameter_extrinsic( msg_value = value if not arbitrary_extrinsic else call_params pallet = HYPERPARAMS_MODULE.get(parameter) or DEFAULT_PALLET - if not arbitrary_extrinsic: extrinsic_params = await substrate.get_metadata_call_function( module_name=pallet, call_function_name=extrinsic From 33e6dcd3f5c25947fb2f00461227f81d73f3149e Mon Sep 17 00:00:00 2001 From: bdhimes Date: Thu, 9 Oct 2025 17:32:57 +0200 Subject: [PATCH 8/9] Fixes a number of type annotations --- bittensor_cli/cli.py | 1 - bittensor_cli/src/commands/liquidity/liquidity.py | 15 ++++++++------- bittensor_cli/src/commands/liquidity/utils.py | 2 ++ bittensor_cli/src/commands/stake/add.py | 9 +++++---- bittensor_cli/src/commands/stake/auto_staking.py | 1 - bittensor_cli/src/commands/stake/move.py | 8 ++++++-- bittensor_cli/src/commands/stake/remove.py | 10 +++++----- bittensor_cli/src/commands/wallets.py | 4 ++-- 8 files changed, 28 insertions(+), 22 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 718c2f7ff..a73aa2e81 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -3658,7 +3658,6 @@ def get_auto_stake( self.initialize_chain(network), coldkey_ss58=coldkey_ss58, json_output=json_output, - verbose=verbose, ) ) diff --git a/bittensor_cli/src/commands/liquidity/liquidity.py b/bittensor_cli/src/commands/liquidity/liquidity.py index cc25ff1e9..47f0141f3 100644 --- a/bittensor_cli/src/commands/liquidity/liquidity.py +++ b/bittensor_cli/src/commands/liquidity/liquidity.py @@ -458,7 +458,7 @@ async def show_liquidity_list( wallet: "Wallet", netuid: int, json_output: bool = False, -): +) -> None: current_price_, (success, err_msg, positions) = await asyncio.gather( subtensor.subnet(netuid=netuid), get_liquidity_list(subtensor, wallet, netuid) ) @@ -467,10 +467,10 @@ async def show_liquidity_list( json_console.print( json.dumps({"success": success, "err_msg": err_msg, "positions": []}) ) - return False + return else: err_console.print(f"Error: {err_msg}") - return False + return liquidity_table = Table( Column("ID", justify="center"), Column("Liquidity", justify="center"), @@ -535,10 +535,10 @@ async def remove_liquidity( prompt: Optional[bool] = None, all_liquidity_ids: Optional[bool] = None, json_output: bool = False, -) -> tuple[bool, str]: +) -> None: """Remove liquidity position from provided subnet.""" if not await subtensor.subnet_exists(netuid=netuid): - return False, f"Subnet with netuid: {netuid} does not exist in {subtensor}." + return None if all_liquidity_ids: success, msg, positions = await get_liquidity_list(subtensor, wallet, netuid) @@ -549,7 +549,7 @@ async def remove_liquidity( ) else: return err_console.print(f"Error: {msg}") - return False, msg + return None else: position_ids = [p.id for p in positions] else: @@ -563,7 +563,7 @@ async def remove_liquidity( console.print(f"\tPosition id: {pos}") if not Confirm.ask("Would you like to continue?"): - return False, "User cancelled operation." + return None results = await asyncio.gather( *[ @@ -593,6 +593,7 @@ async def remove_liquidity( "extrinsic_identifier": await ext_receipt.get_extrinsic_identifier(), } json_console.print_json(data=json_table) + return None async def modify_liquidity( diff --git a/bittensor_cli/src/commands/liquidity/utils.py b/bittensor_cli/src/commands/liquidity/utils.py index 76f7ea8a7..f364a64e4 100644 --- a/bittensor_cli/src/commands/liquidity/utils.py +++ b/bittensor_cli/src/commands/liquidity/utils.py @@ -198,3 +198,5 @@ def prompt_position_id() -> int: return position_id except ValueError: console.print("[red]Please enter a valid number[/red].") + # will never return this, but fixes the type checker + return 0 diff --git a/bittensor_cli/src/commands/stake/add.py b/bittensor_cli/src/commands/stake/add.py index 9f3ffc0d0..5b980af08 100644 --- a/bittensor_cli/src/commands/stake/add.py +++ b/bittensor_cli/src/commands/stake/add.py @@ -1,5 +1,4 @@ import asyncio -import json from collections import defaultdict from functools import partial @@ -349,7 +348,7 @@ async def stake_extrinsic( f"[red]Not enough stake[/red]:[bold white]\n wallet balance:{remaining_wallet_balance} < " f"staking amount: {amount_to_stake}[/bold white]" ) - return False + return remaining_wallet_balance -= amount_to_stake # Calculate slippage @@ -432,9 +431,9 @@ async def stake_extrinsic( if prompt: if not Confirm.ask("Would you like to continue?"): - return False + return if not unlock_key(wallet).success: - return False + return if safe_staking: stake_coroutines = {} @@ -537,6 +536,8 @@ def _prompt_stake_amount( return Balance.from_tao(amount), False except ValueError: console.print("[red]Please enter a valid number or 'all'[/red]") + # will never return this, but fixes the type checker + return Balance(0), False def _get_hotkeys_to_stake_to( diff --git a/bittensor_cli/src/commands/stake/auto_staking.py b/bittensor_cli/src/commands/stake/auto_staking.py index d697df8d4..6e8bf3632 100644 --- a/bittensor_cli/src/commands/stake/auto_staking.py +++ b/bittensor_cli/src/commands/stake/auto_staking.py @@ -28,7 +28,6 @@ async def show_auto_stake_destinations( subtensor: "SubtensorInterface", coldkey_ss58: Optional[str] = None, json_output: bool = False, - verbose: bool = False, ) -> Optional[dict[int, dict[str, Optional[str]]]]: """Display auto-stake destinations for the supplied wallet.""" diff --git a/bittensor_cli/src/commands/stake/move.py b/bittensor_cli/src/commands/stake/move.py index 1443d611e..53587a577 100644 --- a/bittensor_cli/src/commands/stake/move.py +++ b/bittensor_cli/src/commands/stake/move.py @@ -201,6 +201,8 @@ def prompt_stake_amount( return Balance.from_tao(amount), False except ValueError: console.print("[red]Please enter a valid number or 'all'[/red]") + # can never return this, but fixes the type checker + return Balance(0), False async def stake_move_transfer_selection( @@ -818,14 +820,16 @@ async def swap_stake( wait_for_finalization (bool): If true, waits for the transaction to be finalized. Returns: - bool: True if the swap was successful, False otherwise. + (success, extrinsic_identifier): + success is True if the swap was successful, False otherwise. + extrinsic_identifier if the extrinsic was successfully included """ hotkey_ss58 = get_hotkey_pub_ss58(wallet) if interactive_selection: try: selection = await stake_swap_selection(subtensor, wallet) except ValueError: - return False + return False, "" origin_netuid = selection["origin_netuid"] amount = selection["amount"] destination_netuid = selection["destination_netuid"] diff --git a/bittensor_cli/src/commands/stake/remove.py b/bittensor_cli/src/commands/stake/remove.py index b4b6bbeb1..5c1033cb2 100644 --- a/bittensor_cli/src/commands/stake/remove.py +++ b/bittensor_cli/src/commands/stake/remove.py @@ -370,7 +370,7 @@ async def unstake_all( era: int = 3, prompt: bool = True, json_output: bool = False, -) -> bool: +) -> None: """Unstakes all stakes from all hotkeys in all subnets.""" include_hotkeys = include_hotkeys or [] exclude_hotkeys = exclude_hotkeys or [] @@ -419,7 +419,7 @@ async def unstake_all( if not stake_info: console.print("[red]No stakes found to unstake[/red]") - return False + return all_sn_dynamic_info = {info.netuid: info for info in all_sn_dynamic_info_} @@ -531,10 +531,10 @@ async def unstake_all( if prompt and not Confirm.ask( "\nDo you want to proceed with unstaking everything?" ): - return False + return if not unlock_key(wallet).success: - return False + return successes = {} with console.status("Unstaking all stakes...") as status: for hotkey_ss58 in hotkey_ss58s: @@ -553,7 +553,7 @@ async def unstake_all( "extrinsic_identifier": ext_id, } if json_output: - return json_console.print(json.dumps({"success": successes})) + json_console.print(json.dumps({"success": successes})) # Extrinsics diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 63edd7ef3..4d74773c5 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -594,8 +594,8 @@ async def wallet_balance( subtensor.get_total_stake_for_coldkey(*coldkeys, block_hash=block_hash), ) - total_free_balance = sum(free_balances.values()) - total_staked_balance = sum(stake[0] for stake in staked_balances.values()) + total_free_balance: Balance = sum(free_balances.values()) + total_staked_balance: Balance = sum(stake[0] for stake in staked_balances.values()) balances = { name: ( From 9e01a84796fd38f754bb7ce62e4eb0b56a998952 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Tue, 14 Oct 2025 22:09:35 +0200 Subject: [PATCH 9/9] changelog + version --- CHANGELOG.md | 6 ++++++ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca36a9767..3d32aab89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +# 9.13.1 /2025-10-14 +* Fix for complicated (user_liquidity_enabled) hyperparams by @thewhaleking in https://github.com/opentensor/btcli/pull/652 +* Fixes a number of type annotations by @thewhaleking in https://github.com/opentensor/btcli/pull/653 + +**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.13.0...v9.13.1 + ## 9.13.0 /2025-10-09 ## What's Changed diff --git a/pyproject.toml b/pyproject.toml index d7e6150f9..a5705e289 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "bittensor-cli" -version = "9.13.0" +version = "9.13.1" description = "Bittensor CLI" readme = "README.md" authors = [