From da471d0af5bfb5351e39fcb385018d3fe65e7b63 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:39:01 +0200 Subject: [PATCH 01/20] Basic implementation --- bittensor_cli/cli.py | 66 ++++++++++++++++++++++++++- bittensor_cli/src/commands/wallets.py | 44 ++++++++++++++++++ pyproject.toml | 2 +- 3 files changed, 109 insertions(+), 3 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 961a1f0f2..d7c7df6e4 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -2285,7 +2285,7 @@ def wallet_regen_coldkey_pub( EXAMPLE - [green]$[/green] btcli wallet regen_coldkeypub --ss58_address 5DkQ4... + [green]$[/green] btcli wallet regen-coldkeypub --ss58_address 5DkQ4... [bold]Note[/bold]: This command is particularly useful for users who need to regenerate their coldkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old coldkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities. """ @@ -2317,7 +2317,7 @@ def wallet_regen_coldkey_pub( address=ss58_address if ss58_address else public_key_hex ): rich.print("[red]Error: Invalid SS58 address or public key![/red]") - raise typer.Exit() + return return self._run_command( wallets.regen_coldkey_pub( wallet, ss58_address, public_key_hex, overwrite, json_output @@ -2383,6 +2383,68 @@ def wallet_regen_hotkey( ) ) + def wallet_regen_hotkey_pub( + self, + wallet_name: Optional[str] = Options.wallet_name, + wallet_path: Optional[str] = Options.wallet_path, + wallet_hotkey: Optional[str] = Options.wallet_hotkey, + public_key_hex: Optional[str] = Options.public_hex_key, + ss58_address: Optional[str] = Options.ss58_address, + overwrite: bool = Options.overwrite, + quiet: bool = Options.quiet, + verbose: bool = Options.verbose, + json_output: bool = Options.json_output, + ): + """ + Regenerates the public part of a hotkey (hotkeypub.txt) for a wallet. + + Use this command when you need to move machine for subnet mining. Use the public key or SS58 address from your hotkeypub.txt that you have on another machine to regenerate the hotkeypub.txt on this new machine. + + USAGE + + The command requires either a public key in hexadecimal format or an ``SS58`` address from the existing hotkeypub.txt from old machine to regenerate the coldkeypub on the new machine. + + EXAMPLE + + [green]$[/green] btcli wallet regen-hotkeypub --ss58_address 5DkQ4... + + [bold]Note[/bold]: This command is particularly useful for users who need to regenerate their hotkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old hotkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities. + """ + self.verbosity_handler(quiet, verbose, json_output) + + if not wallet_path: + wallet_path = Prompt.ask( + "Enter the path to the wallets directory", + default=self.config.get("wallet_path") or defaults.wallet.path, + ) + wallet_path = os.path.expanduser(wallet_path) + + if not wallet_name: + wallet_name = Prompt.ask( + f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)", + default=defaults.wallet.name, + ) + wallet = Wallet(wallet_name, wallet_hotkey, wallet_path) + + if not ss58_address and not public_key_hex: + prompt_answer = typer.prompt( + "Enter the ss58_address or the public key in hex" + ) + if prompt_answer.startswith("0x"): + public_key_hex = prompt_answer + else: + ss58_address = prompt_answer + if not utils.is_valid_bittensor_address_or_public_key( + address=ss58_address if ss58_address else public_key_hex + ): + rich.print("[red]Error: Invalid SS58 address or public key![/red]") + return False + return self._run_command( + wallets.regen_hotkey_pub( + wallet, ss58_address, public_key_hex, overwrite, json_output + ) + ) + def wallet_new_hotkey( self, wallet_name: Optional[str] = Options.wallet_name, diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 61efa696c..237a48494 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -287,6 +287,50 @@ async def regen_hotkey( ) +async def regen_hotkey_pub( +wallet: Wallet, + ss58_address: str, + public_key_hex: str, + overwrite: Optional[bool] = False, + json_output: bool = False, +): + """Creates a new hotkeypub under this wallet.""" + try: + new_hotkeypub = wallet.regenerate_hotkeypub( + ss58_address=ss58_address, + public_key=public_key_hex, + overwrite=overwrite, + ) + if isinstance(new_hotkeypub, Wallet): + console.print( + "\n✅ [dark_sea_green]Regenerated coldkeypub successfully!\n", + f"[dark_sea_green]Wallet name: ({new_hotkeypub.name}), path: ({new_hotkeypub.path}), " + f"coldkey ss58: ({new_hotkeypub.coldkeypub.ss58_address})", + ) + if json_output: + json_console.print( + json.dumps( + { + "success": True, + "data": { + "name": new_hotkeypub.name, + "path": new_hotkeypub.path, + "hotkey": new_hotkeypub.hotkey_str, + "hotkey_ss58": new_hotkeypub.hotkey.ss58_address, + "coldkey_ss58": new_hotkeypub.coldkeypub.ss58_address, + }, + "error": "", + } + ) + ) + except KeyFileError: + print_error("KeyFileError: File is not writable") + if json_output: + json_console.print( + '{"success": false, "error": "Keyfile is not writable", "data": null}' + ) + + async def new_hotkey( wallet: Wallet, n_words: int, diff --git a/pyproject.toml b/pyproject.toml index 42ea0367d..426b15322 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ dependencies = [ "rich>=13.7,<15.0", "scalecodec==1.2.11", "typer>=0.16", - "bittensor-wallet>=3.0.7", + "bittensor-wallet>=3.1.0", "plotille>=5.0.0", "plotly>=6.0.0", ] From b8e6d79fc3af7ba2265e2607f8c6f4c4dc1413d2 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:39:09 +0200 Subject: [PATCH 02/20] Ruff --- bittensor_cli/src/commands/wallets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 237a48494..da9dde9fd 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -288,7 +288,7 @@ async def regen_hotkey( async def regen_hotkey_pub( -wallet: Wallet, + wallet: Wallet, ss58_address: str, public_key_hex: str, overwrite: Optional[bool] = False, From 580b8a74278095c06467536c3728d58d7234e1fb Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:40:53 +0200 Subject: [PATCH 03/20] Added commands --- bittensor_cli/cli.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index d7c7df6e4..e9d1a0e28 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -791,6 +791,9 @@ def __init__(self): self.wallet_app.command( "regen-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"] )(self.wallet_regen_hotkey) + self.wallet_app.command( + "regen-hotkey-pub", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"] + )(self.wallet_regen_hotkey_pub) self.wallet_app.command( "new-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"] )(self.wallet_new_hotkey) @@ -973,6 +976,10 @@ def __init__(self): "regen_hotkey", hidden=True, )(self.wallet_regen_hotkey) + self.wallet_app.command( + "regen_hotkey_pub", + hidden=True, + )(self.wallet_regen_hotkey_pub) self.wallet_app.command( "new_hotkey", hidden=True, From b959fe35d9754800264069420bbc46714a7e1020 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:44:25 +0200 Subject: [PATCH 04/20] Added commands --- bittensor_cli/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index e9d1a0e28..7106529d6 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -792,7 +792,7 @@ def __init__(self): "regen-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"] )(self.wallet_regen_hotkey) self.wallet_app.command( - "regen-hotkey-pub", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"] + "regen-hotkeypub", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"] )(self.wallet_regen_hotkey_pub) self.wallet_app.command( "new-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"] @@ -977,7 +977,7 @@ def __init__(self): hidden=True, )(self.wallet_regen_hotkey) self.wallet_app.command( - "regen_hotkey_pub", + "regen_hotkeypub", hidden=True, )(self.wallet_regen_hotkey_pub) self.wallet_app.command( From 6d975c3b737895e82b107f69931edcab5d331d95 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:48:14 +0200 Subject: [PATCH 05/20] Error handling --- bittensor_cli/cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 7106529d6..7f5056a82 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -1150,7 +1150,8 @@ async def _run(): exit_early is True ): # temporarily to handle multiple run commands in one session try: - await self.subtensor.substrate.close() + if self.subtensor: + await self.subtensor.substrate.close() raise typer.Exit() except Exception as e: # ensures we always exit cleanly if not isinstance(e, (typer.Exit, RuntimeError)): From 75501bb05d7fedb24dd43db91712657e0ae79899 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:52:08 +0200 Subject: [PATCH 06/20] Improved text --- bittensor_cli/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 7f5056a82..8a9194f97 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -2308,7 +2308,7 @@ def wallet_regen_coldkey_pub( if not wallet_name: wallet_name = Prompt.ask( - f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)", + f"Enter the name of the [{COLORS.G.CK}]wallet for the new coldkeypub", default=defaults.wallet.name, ) wallet = Wallet(wallet_name, wallet_hotkey, wallet_path) @@ -2429,7 +2429,7 @@ def wallet_regen_hotkey_pub( if not wallet_name: wallet_name = Prompt.ask( - f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)", + f"Enter the name of the [{COLORS.G.CK}]wallet for the new hotkeypub", default=defaults.wallet.name, ) wallet = Wallet(wallet_name, wallet_hotkey, wallet_path) From 9aacee83c5eb7f37cb7d4614511445b476f11bfb Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 17:59:10 +0200 Subject: [PATCH 07/20] Add test --- tests/e2e_tests/test_wallet_creations.py | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/e2e_tests/test_wallet_creations.py b/tests/e2e_tests/test_wallet_creations.py index 019cad6b5..b2478f537 100644 --- a/tests/e2e_tests/test_wallet_creations.py +++ b/tests/e2e_tests/test_wallet_creations.py @@ -16,6 +16,7 @@ * btcli w regen_coldkey * btcli w regen_coldkeypub * btcli w regen_hotkey +* btcli w regen_hotkeypub """ @@ -542,6 +543,34 @@ def test_wallet_regen(wallet_setup, capfd): ) print("Passed wallet regen_hotkey command ✅") + hotkeypub_path = os.path.join(wallet_path, "new_wallet", "hotkeypub.txt") + initial_hotkeypub_mod_time = os.path.getmtime(hotkeypub_path) + result = exec_command( + command="wallet", + sub_command="regen-hotkeypub", + extra_args=[ + "--wallet-name", + "new_wallet", + "--hotkey", + "new_hotkey", + "--wallet-path", + wallet_path, + "--ss58-address", + ss58_address, + "--overwrite", + ], + ) + + # Wait a bit to ensure file system updates modification time + time.sleep(2) + + new_hotkeypub_mod_time = os.path.getmtime(hotkey_path) + + assert initial_hotkeypub_mod_time != new_hotkeypub_mod_time, ( + "Hotkey file was not regenerated as expected" + ) + print("Passed wallet regen_hotkeypub command ✅") + def test_wallet_balance_all(local_chain, wallet_setup, capfd): """ From ed21df78aae9b01b86dd6e712a7a626ebb7589ff Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 18:39:39 +0200 Subject: [PATCH 08/20] Updated reqs. Will need to be fixed upstream first. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 426b15322..4238ae4f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ dependencies = [ "rich>=13.7,<15.0", "scalecodec==1.2.11", "typer>=0.16", - "bittensor-wallet>=3.1.0", + "bittensor-wallet>=3.1.1", "plotille>=5.0.0", "plotly>=6.0.0", ] From 8dc3a8f5103feffdd521363a3194ee04aefcfda6 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 18:40:51 +0200 Subject: [PATCH 09/20] Update test --- tests/e2e_tests/test_wallet_creations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e_tests/test_wallet_creations.py b/tests/e2e_tests/test_wallet_creations.py index b2478f537..692405d0a 100644 --- a/tests/e2e_tests/test_wallet_creations.py +++ b/tests/e2e_tests/test_wallet_creations.py @@ -543,7 +543,7 @@ def test_wallet_regen(wallet_setup, capfd): ) print("Passed wallet regen_hotkey command ✅") - hotkeypub_path = os.path.join(wallet_path, "new_wallet", "hotkeypub.txt") + hotkeypub_path = os.path.join(wallet_path, "new_wallet", "hotkeys", "new_hotkeypub.txt") initial_hotkeypub_mod_time = os.path.getmtime(hotkeypub_path) result = exec_command( command="wallet", From 1c19e0fd5bda79ecc9130ac822b16b7bfae818e4 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 18:40:58 +0200 Subject: [PATCH 10/20] Ruff --- tests/e2e_tests/test_wallet_creations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/e2e_tests/test_wallet_creations.py b/tests/e2e_tests/test_wallet_creations.py index 692405d0a..7dcbc5970 100644 --- a/tests/e2e_tests/test_wallet_creations.py +++ b/tests/e2e_tests/test_wallet_creations.py @@ -543,7 +543,9 @@ def test_wallet_regen(wallet_setup, capfd): ) print("Passed wallet regen_hotkey command ✅") - hotkeypub_path = os.path.join(wallet_path, "new_wallet", "hotkeys", "new_hotkeypub.txt") + hotkeypub_path = os.path.join( + wallet_path, "new_wallet", "hotkeys", "new_hotkeypub.txt" + ) initial_hotkeypub_mod_time = os.path.getmtime(hotkeypub_path) result = exec_command( command="wallet", From 714cafb97dd90a20396ec2171e82356205931cd4 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:03:18 +0200 Subject: [PATCH 11/20] New fn to retrieve wallet hotkey ss58 --- bittensor_cli/src/bittensor/utils.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index ef5f2e4b1..735abe524 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -1431,3 +1431,15 @@ def blocks_to_duration(blocks: int) -> str: results.append(f"{unit_count}{unit}") # Return only the first two non-zero units return " ".join(results[:2]) or "0s" + + +def get_hotkey_pub_ss58(wallet: Wallet) -> str: + """ + Helper fn to retrieve the hotkeypub ss58 of a wallet that may have been created before + bt-wallet 3.1.1 and thus not have a wallet hotkeypub. In this case, it will return the hotkey + SS58. + """ + try: + return wallet.hotkeypub.ss58_address + except KeyFileError: + return wallet.hotkey.ss58_address From aa70fb3ac4daf30a20820c4a63b197403d59e16e Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:16:59 +0200 Subject: [PATCH 12/20] Update some commands. --- bittensor_cli/src/commands/sudo.py | 24 ++++++++------- bittensor_cli/src/commands/wallets.py | 42 ++++++++++++++++----------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 8004dc90f..1046c28cf 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -26,6 +26,7 @@ json_console, string_to_u16, string_to_u64, + get_hotkey_pub_ss58, ) if TYPE_CHECKING: @@ -497,7 +498,7 @@ async def vote_senate_extrinsic( call_module="SubtensorModule", call_function="vote", call_params={ - "hotkey": wallet.hotkey.ss58_address, + "hotkey": get_hotkey_pub_ss58(wallet), "proposal": proposal_hash, "index": proposal_idx, "approve": vote, @@ -513,9 +514,10 @@ async def vote_senate_extrinsic( # Successful vote, final check for data else: if vote_data := await subtensor.get_vote_data(proposal_hash): + hotkey_ss58 = get_hotkey_pub_ss58(wallet) if ( - vote_data.ayes.count(wallet.hotkey.ss58_address) > 0 - or vote_data.nays.count(wallet.hotkey.ss58_address) > 0 + vote_data.ayes.count(hotkey_ss58) > 0 + or vote_data.nays.count(hotkey_ss58) > 0 ): console.print(":white_heavy_check_mark: [green]Vote cast.[/green]") return True @@ -859,10 +861,9 @@ async def senate_vote( return False print_verbose(f"Fetching senate status of {wallet.hotkey_str}") - if not await _is_senate_member(subtensor, hotkey_ss58=wallet.hotkey.ss58_address): - err_console.print( - f"Aborting: Hotkey {wallet.hotkey.ss58_address} isn't a senate member." - ) + hotkey_ss58 = get_hotkey_pub_ss58(wallet) + if not await _is_senate_member(subtensor, hotkey_ss58=hotkey_ss58): + err_console.print(f"Aborting: Hotkey {hotkey_ss58} isn't a senate member.") return False # Unlock the wallet. @@ -890,7 +891,7 @@ async def senate_vote( async def get_current_take(subtensor: "SubtensorInterface", wallet: Wallet): - current_take = await subtensor.current_take(wallet.hotkey.ss58_address) + current_take = await subtensor.current_take(get_hotkey_pub_ss58(wallet)) return current_take @@ -912,12 +913,13 @@ async def _do_set_take() -> bool: return False block_hash = await subtensor.substrate.get_chain_head() + hotkey_ss58 = get_hotkey_pub_ss58(wallet) netuids_registered = await subtensor.get_netuids_for_hotkey( - wallet.hotkey.ss58_address, block_hash=block_hash + hotkey_ss58, block_hash=block_hash ) if not len(netuids_registered) > 0: err_console.print( - f"Hotkey [{COLOR_PALETTE.G.HK}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}] is not registered to" + f"Hotkey [{COLOR_PALETTE.G.HK}]{hotkey_ss58}[/{COLOR_PALETTE.G.HK}] is not registered to" f" any subnet. Please register using [{COLOR_PALETTE.G.SUBHEAD}]`btcli subnets register`" f"[{COLOR_PALETTE.G.SUBHEAD}] and try again." ) @@ -926,7 +928,7 @@ async def _do_set_take() -> bool: result: bool = await set_take_extrinsic( subtensor=subtensor, wallet=wallet, - delegate_ss58=wallet.hotkey.ss58_address, + delegate_ss58=hotkey_ss58, take=take, ) diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index da9dde9fd..00132d3d9 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -3,7 +3,7 @@ import json import os from collections import defaultdict -from typing import Generator, Optional +from typing import Generator, Optional, Union import aiohttp from bittensor_wallet import Wallet, Keypair @@ -48,6 +48,7 @@ WalletLike, blocks_to_duration, decode_account_id, + get_hotkey_pub_ss58, ) @@ -159,7 +160,7 @@ async def regen_coldkey( "name": new_wallet.name, "path": new_wallet.path, "hotkey": new_wallet.hotkey_str, - "hotkey_ss58": new_wallet.hotkey.ss58_address, + "hotkey_ss58": get_hotkey_pub_ss58(new_wallet), "coldkey_ss58": new_wallet.coldkeypub.ss58_address, }, "error": "", @@ -209,7 +210,7 @@ async def regen_coldkey_pub( "name": new_coldkeypub.name, "path": new_coldkeypub.path, "hotkey": new_coldkeypub.hotkey_str, - "hotkey_ss58": new_coldkeypub.hotkey.ss58_address, + "hotkey_ss58": get_hotkey_pub_ss58(new_coldkeypub), "coldkey_ss58": new_coldkeypub.coldkeypub.ss58_address, }, "error": "", @@ -255,7 +256,7 @@ async def regen_hotkey( console.print( "\n✅ [dark_sea_green]Regenerated hotkey successfully!\n", f"[dark_sea_green]Wallet name: ({new_hotkey_.name}), path: ({new_hotkey_.path}), " - f"hotkey ss58: ({new_hotkey_.hotkey.ss58_address})", + f"hotkey ss58: ({new_hotkey_.hotkeypub.ss58_address})", ) if json_output: json_console.print( @@ -266,7 +267,7 @@ async def regen_hotkey( "name": new_hotkey_.name, "path": new_hotkey_.path, "hotkey": new_hotkey_.hotkey_str, - "hotkey_ss58": new_hotkey_.hotkey.ss58_address, + "hotkey_ss58": new_hotkey_.hotkeypub.ss58_address, "coldkey_ss58": new_hotkey_.coldkeypub.ss58_address, }, "error": "", @@ -316,7 +317,7 @@ async def regen_hotkey_pub( "name": new_hotkeypub.name, "path": new_hotkeypub.path, "hotkey": new_hotkeypub.hotkey_str, - "hotkey_ss58": new_hotkeypub.hotkey.ss58_address, + "hotkey_ss58": new_hotkeypub.hotkeypub.ss58_address, "coldkey_ss58": new_hotkeypub.coldkeypub.ss58_address, }, "error": "", @@ -367,7 +368,7 @@ async def new_hotkey( "name": wallet.name, "path": wallet.path, "hotkey": wallet.hotkey_str, - "hotkey_ss58": wallet.hotkey.ss58_address, + "hotkey_ss58": get_hotkey_pub_ss58(wallet), "coldkey_ss58": wallet.coldkeypub.ss58_address, }, "error": "", @@ -446,19 +447,24 @@ async def wallet_create( json_output: bool = False, ): """Creates a new wallet.""" - output_dict = {"success": False, "error": "", "data": None} + output_dict: dict[str, Optional[Union[bool, str, dict]]] = { + "success": False, + "error": "", + "data": None, + } if uri: try: keypair = Keypair.create_from_uri(uri) wallet.set_coldkey(keypair=keypair, encrypt=False, overwrite=False) wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=False) wallet.set_hotkey(keypair=keypair, encrypt=False, overwrite=False) + wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=False) output_dict["success"] = True output_dict["data"] = { "name": wallet.name, "path": wallet.path, "hotkey": wallet.hotkey_str, - "hotkey_ss58": wallet.hotkey.ss58_address, + "hotkey_ss58": wallet.hotkeypub.ss58_address, "coldkey_ss58": wallet.coldkeypub.ss58_address, } except Exception as e: @@ -499,7 +505,7 @@ async def wallet_create( "name": wallet.name, "path": wallet.path, "hotkey": wallet.hotkey_str, - "hotkey_ss58": wallet.hotkey.ss58_address, + "hotkey_ss58": wallet.hotkeypub.ss58_address, } except KeyFileError as error: err = str(error) @@ -838,13 +844,14 @@ async def wallet_list(wallet_path: str, json_output: bool): data = f"[bold red]Hotkey[/bold red][green] {hkey}[/green] (?)" hk_data = {"name": hkey.name, "ss58_address": "?"} if hkey: + hkey_ss58 = get_hotkey_pub_ss58(hkey) try: data = ( f"[bold red]Hotkey[/bold red] [green]{hkey.hotkey_str}[/green] " - f"ss58_address [green]{hkey.hotkey.ss58_address}[/green]\n" + f"ss58_address [green]{hkey_ss58}[/green]\n" ) hk_data["name"] = hkey.hotkey_str - hk_data["ss58_address"] = hkey.hotkey.ss58_address + hk_data["ss58_address"] = hkey_ss58 except UnicodeDecodeError: pass wallet_tree.add(data) @@ -1297,7 +1304,7 @@ def _get_hotkeys( def is_hotkey_matched(wallet: Wallet, item: str) -> bool: if is_valid_ss58_address(item): - return wallet.hotkey.ss58_address == item + return get_hotkey_pub_ss58(wallet) == item else: return wallet.hotkey_str == item @@ -1329,9 +1336,10 @@ def _get_key_address(all_hotkeys: list[Wallet]) -> tuple[list[str], dict[str, Wa hotkey_coldkey_to_hotkey_wallet = {} for hotkey_wallet in all_hotkeys: if hotkey_wallet.coldkeypub: - if hotkey_wallet.hotkey.ss58_address not in hotkey_coldkey_to_hotkey_wallet: - hotkey_coldkey_to_hotkey_wallet[hotkey_wallet.hotkey.ss58_address] = {} - hotkey_coldkey_to_hotkey_wallet[hotkey_wallet.hotkey.ss58_address][ + hotkey_ss58 = get_hotkey_pub_ss58(hotkey_wallet) + if hotkey_ss58 not in hotkey_coldkey_to_hotkey_wallet: + hotkey_coldkey_to_hotkey_wallet[hotkey_ss58] = {} + hotkey_coldkey_to_hotkey_wallet[hotkey_ss58][ hotkey_wallet.coldkeypub.ss58_address ] = hotkey_wallet else: @@ -1515,7 +1523,7 @@ def neuron_row_maker( if hotkey_names := [ w.hotkey_str for w in hotkeys - if w.hotkey.ss58_address == n.hotkey + if get_hotkey_pub_ss58(w) == n.hotkey ]: hotkey_name = f"{hotkey_names[0]}-" yield [""] * 5 + [ From b6c587603a07f0f99414ef61322075baeab65313 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:19:24 +0200 Subject: [PATCH 13/20] More commands. --- bittensor_cli/src/commands/stake/move.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bittensor_cli/src/commands/stake/move.py b/bittensor_cli/src/commands/stake/move.py index b4efbd127..c72bbb41e 100644 --- a/bittensor_cli/src/commands/stake/move.py +++ b/bittensor_cli/src/commands/stake/move.py @@ -16,6 +16,7 @@ group_subnets, get_subnet_name, unlock_key, + get_hotkey_pub_ss58, ) if TYPE_CHECKING: @@ -343,8 +344,9 @@ async def stake_swap_selection( # Filter stakes for this hotkey hotkey_stakes = {} + hotkey_ss58 = get_hotkey_pub_ss58(wallet) for stake in stakes: - if stake.hotkey_ss58 == wallet.hotkey.ss58_address and stake.stake.tao > 0: + if stake.hotkey_ss58 == hotkey_ss58 and stake.stake.tao > 0: hotkey_stakes[stake.netuid] = { "stake": stake.stake, "is_registered": stake.is_registered, @@ -357,12 +359,12 @@ async def stake_swap_selection( # Display available stakes table = Table( title=f"\n[{COLOR_PALETTE.G.HEADER}]Available Stakes for Hotkey\n[/{COLOR_PALETTE.G.HEADER}]" - f"[{COLOR_PALETTE.G.HK}]{wallet.hotkey_str}: {wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}]\n", + f"[{COLOR_PALETTE.G.HK}]{wallet.hotkey_str}: {hotkey_ss58}[/{COLOR_PALETTE.G.HK}]\n", show_edge=False, header_style="bold white", border_style="bright_black", title_justify="center", - width=len(wallet.hotkey.ss58_address) + 20, + width=len(hotkey_ss58) + 20, ) table.add_column("Index", justify="right", style="cyan") @@ -817,7 +819,7 @@ async def swap_stake( Returns: bool: True if the swap was successful, False otherwise. """ - hotkey_ss58 = wallet.hotkey.ss58_address + hotkey_ss58 = get_hotkey_pub_ss58(wallet) if interactive_selection: try: selection = await stake_swap_selection(subtensor, wallet) From 68e5afc62fb0a3973c6bec1c31007d57f3a6620e Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:27:31 +0200 Subject: [PATCH 14/20] More commands. --- bittensor_cli/cli.py | 17 +++++++++-------- .../src/bittensor/subtensor_interface.py | 3 ++- bittensor_cli/src/bittensor/utils.py | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 8a9194f97..65230eda6 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -58,6 +58,7 @@ validate_uri, prompt_for_subnet_identity, validate_rate_tolerance, + get_hotkey_pub_ss58, ) from bittensor_cli.src.commands import sudo, wallets, view from bittensor_cli.src.commands import weights as weights_cmds @@ -1734,7 +1735,7 @@ def wallet_ask( if return_wallet_and_hotkey: valid = utils.is_valid_wallet(wallet) if valid[1]: - return wallet, wallet.hotkey.ss58_address + return wallet, get_hotkey_pub_ss58(wallet) else: if wallet_hotkey and is_valid_ss58_address(wallet_hotkey): return wallet, wallet_hotkey @@ -2572,7 +2573,7 @@ def wallet_associate_hotkey( ask_for=[WO.NAME, WO.PATH, WO.HOTKEY], validate=WV.WALLET_AND_HOTKEY, ) - hotkey_ss58 = wallet.hotkey.ss58_address + hotkey_ss58 = get_hotkey_pub_ss58(wallet) hotkey_display = ( f"hotkey [blue]{wallet_hotkey}[/blue] " f"[{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]" @@ -3588,7 +3589,7 @@ def stake_add( ask_for=[WO.NAME, WO.HOTKEY, WO.PATH], validate=WV.WALLET_AND_HOTKEY, ) - include_hotkeys = wallet.hotkey.ss58_address + include_hotkeys = get_hotkey_pub_ss58(wallet) elif all_hotkeys or include_hotkeys or exclude_hotkeys: wallet = self.wallet_ask( @@ -4052,7 +4053,7 @@ def stake_move( ask_for=[WO.NAME, WO.PATH, WO.HOTKEY], validate=WV.WALLET_AND_HOTKEY, ) - destination_hotkey = destination_wallet.hotkey.ss58_address + destination_hotkey = get_hotkey_pub_ss58(destination_wallet) else: if is_valid_ss58_address(destination_hotkey): destination_hotkey = destination_hotkey @@ -4091,7 +4092,7 @@ def stake_move( ask_for=[WO.NAME, WO.PATH, WO.HOTKEY], validate=WV.WALLET_AND_HOTKEY, ) - origin_hotkey = wallet.hotkey.ss58_address + origin_hotkey = get_hotkey_pub_ss58(wallet) else: if is_valid_ss58_address(wallet_hotkey): origin_hotkey = wallet_hotkey @@ -4103,7 +4104,7 @@ def stake_move( ask_for=[], validate=WV.WALLET_AND_HOTKEY, ) - origin_hotkey = wallet.hotkey.ss58_address + origin_hotkey = get_hotkey_pub_ss58(wallet) if not interactive_selection: if origin_netuid is None: @@ -4256,7 +4257,7 @@ def stake_transfer( ask_for=[WO.NAME, WO.PATH, WO.HOTKEY], validate=WV.WALLET_AND_HOTKEY, ) - origin_hotkey = wallet.hotkey.ss58_address + origin_hotkey = get_hotkey_pub_ss58(wallet) else: if is_valid_ss58_address(wallet_hotkey): origin_hotkey = wallet_hotkey @@ -4268,7 +4269,7 @@ def stake_transfer( ask_for=[], validate=WV.WALLET_AND_HOTKEY, ) - origin_hotkey = wallet.hotkey.ss58_address + origin_hotkey = get_hotkey_pub_ss58(wallet) if not interactive_selection: if origin_netuid is None: diff --git a/bittensor_cli/src/bittensor/subtensor_interface.py b/bittensor_cli/src/bittensor/subtensor_interface.py index 3d8a632d5..0684b31ef 100644 --- a/bittensor_cli/src/bittensor/subtensor_interface.py +++ b/bittensor_cli/src/bittensor/subtensor_interface.py @@ -39,6 +39,7 @@ validate_chain_endpoint, u16_normalized_float, U16_MAX, + get_hotkey_pub_ss58, ) SubstrateClass = ( @@ -666,7 +667,7 @@ async def filter_netuids_by_registered_hotkeys( for sublist in await asyncio.gather( *[ self.get_netuids_for_hotkey( - wallet.hotkey.ss58_address, + get_hotkey_pub_ss58(wallet), reuse_block=reuse_block, block_hash=block_hash, ) diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index 735abe524..d7ffa6e4a 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -275,7 +275,7 @@ def get_hotkey_wallets_for_wallet( (exists := hotkey_for_name.hotkey_file.exists_on_device()) and not hotkey_for_name.hotkey_file.is_encrypted() # and hotkey_for_name.coldkeypub.ss58_address - and hotkey_for_name.hotkey.ss58_address + and get_hotkey_pub_ss58(hotkey_for_name) ): hotkey_wallets.append(hotkey_for_name) elif ( From f40e8b56e12043629b460834d7069d411fb8e32b Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:40:02 +0200 Subject: [PATCH 15/20] More commands. --- .../src/bittensor/extrinsics/root.py | 12 +++---- bittensor_cli/src/commands/stake/add.py | 8 ++--- .../src/commands/stake/children_hotkeys.py | 31 ++++++++++--------- bittensor_cli/src/commands/stake/remove.py | 10 +++--- bittensor_cli/src/commands/subnets/subnets.py | 6 ++-- bittensor_cli/src/commands/weights.py | 4 +-- 6 files changed, 36 insertions(+), 35 deletions(-) diff --git a/bittensor_cli/src/bittensor/extrinsics/root.py b/bittensor_cli/src/bittensor/extrinsics/root.py index d8d4900aa..3f3c4f039 100644 --- a/bittensor_cli/src/bittensor/extrinsics/root.py +++ b/bittensor_cli/src/bittensor/extrinsics/root.py @@ -36,7 +36,7 @@ u16_normalized_float, print_verbose, format_error_message, - unlock_key, + unlock_key, get_hotkey_pub_ss58, ) if TYPE_CHECKING: @@ -310,7 +310,7 @@ async def root_register_extrinsic( print_verbose(f"Checking if hotkey ({wallet.hotkey_str}) is registered on root") is_registered = await is_hotkey_registered( - subtensor, netuid=0, hotkey_ss58=wallet.hotkey.ss58_address + subtensor, netuid=0, hotkey_ss58=get_hotkey_pub_ss58(wallet) ) if is_registered: console.print( @@ -322,7 +322,7 @@ async def root_register_extrinsic( call = await subtensor.substrate.compose_call( call_module="SubtensorModule", call_function="root_register", - call_params={"hotkey": wallet.hotkey.ss58_address}, + call_params={"hotkey": get_hotkey_pub_ss58(wallet)}, ) success, err_msg = await subtensor.sign_and_send_extrinsic( call, @@ -341,7 +341,7 @@ async def root_register_extrinsic( uid = await subtensor.query( module="SubtensorModule", storage_function="Uids", - params=[0, wallet.hotkey.ss58_address], + params=[0, get_hotkey_pub_ss58(wallet)], ) if uid is not None: console.print( @@ -391,7 +391,7 @@ async def _do_set_weights(): "weights": weight_vals, "netuid": 0, "version_key": version_key, - "hotkey": wallet.hotkey.ss58_address, + "hotkey": get_hotkey_pub_ss58(wallet), }, ) # Period dictates how long the extrinsic will stay as part of waiting pool @@ -415,7 +415,7 @@ async def _do_set_weights(): return False, await response.error_message my_uid = await subtensor.query( - "SubtensorModule", "Uids", [0, wallet.hotkey.ss58_address] + "SubtensorModule", "Uids", [0, get_hotkey_pub_ss58(wallet)] ) if my_uid is None: diff --git a/bittensor_cli/src/commands/stake/add.py b/bittensor_cli/src/commands/stake/add.py index b223eaf2e..e80efe457 100644 --- a/bittensor_cli/src/commands/stake/add.py +++ b/bittensor_cli/src/commands/stake/add.py @@ -19,7 +19,7 @@ print_error, print_verbose, unlock_key, - json_console, + json_console, get_hotkey_pub_ss58, ) from bittensor_wallet import Wallet @@ -552,7 +552,7 @@ def _get_hotkeys_to_stake_to( # Stake to all hotkeys except excluded ones all_hotkeys_: list[Wallet] = get_hotkey_wallets_for_wallet(wallet=wallet) return [ - (wallet.hotkey_str, wallet.hotkey.ss58_address) + (wallet.hotkey_str, get_hotkey_pub_ss58(wallet)) for wallet in all_hotkeys_ if wallet.hotkey_str not in (exclude_hotkeys or []) ] @@ -572,7 +572,7 @@ def _get_hotkeys_to_stake_to( name=wallet.name, hotkey=hotkey_ss58_or_hotkey_name, ) - hotkeys.append((wallet_.hotkey_str, wallet_.hotkey.ss58_address)) + hotkeys.append((wallet_.hotkey_str, get_hotkey_pub_ss58(wallet_))) return hotkeys @@ -581,7 +581,7 @@ def _get_hotkeys_to_stake_to( f"Staking to hotkey: ({wallet.hotkey_str}) in wallet: ({wallet.name})" ) assert wallet.hotkey is not None - return [(None, wallet.hotkey.ss58_address)] + return [(None, get_hotkey_pub_ss58(wallet))] def _define_stake_table( diff --git a/bittensor_cli/src/commands/stake/children_hotkeys.py b/bittensor_cli/src/commands/stake/children_hotkeys.py index ef16823e4..82e1271d1 100644 --- a/bittensor_cli/src/commands/stake/children_hotkeys.py +++ b/bittensor_cli/src/commands/stake/children_hotkeys.py @@ -20,7 +20,7 @@ is_valid_ss58_address, format_error_message, unlock_key, - json_console, + json_console, get_hotkey_pub_ss58, ) @@ -464,7 +464,7 @@ async def _render_table( netuid_children_tuples = [] for netuid_ in netuids: success, children, err_mg = await subtensor.get_children( - wallet.hotkey.ss58_address, netuid_ + get_hotkey_pub_ss58(wallet), netuid_ ) if children: netuid_children_tuples.append((netuid_, children)) @@ -472,16 +472,16 @@ async def _render_table( err_console.print( f"Failed to get children from subtensor {netuid_}: {err_mg}" ) - await _render_table(wallet.hotkey.ss58_address, netuid_children_tuples) + await _render_table(get_hotkey_pub_ss58(wallet), netuid_children_tuples) else: success, children, err_mg = await subtensor.get_children( - wallet.hotkey.ss58_address, netuid + get_hotkey_pub_ss58(wallet), netuid ) if not success: err_console.print(f"Failed to get children from subtensor: {err_mg}") if children: netuid_children_tuples = [(netuid, children)] - await _render_table(wallet.hotkey.ss58_address, netuid_children_tuples) + await _render_table(get_hotkey_pub_ss58(wallet), netuid_children_tuples) return children @@ -500,12 +500,12 @@ async def set_children( """Set children hotkeys.""" # Validate children SS58 addresses # TODO check to see if this should be allowed to be specified by user instead of pulling from wallet - hotkey = wallet.hotkey.ss58_address + hotkey = get_hotkey_pub_ss58(wallet) for child in children: if not is_valid_ss58_address(child): err_console.print(f":cross_mark:[red] Invalid SS58 address: {child}[/red]") return - if child == wallet.hotkey.ss58_address: + if child == hotkey: err_console.print(":cross_mark:[red] Cannot set yourself as a child.[/red]") return @@ -608,7 +608,7 @@ async def revoke_children( subtensor=subtensor, wallet=wallet, netuid=netuid, - hotkey=wallet.hotkey.ss58_address, + hotkey=get_hotkey_pub_ss58(wallet), children_with_proportions=[], prompt=prompt, wait_for_inclusion=wait_for_inclusion, @@ -647,7 +647,7 @@ async def revoke_children( subtensor=subtensor, wallet=wallet, netuid=netuid, - hotkey=wallet.hotkey.ss58_address, + hotkey=get_hotkey_pub_ss58(wallet), children_with_proportions=[], prompt=prompt, wait_for_inclusion=True, @@ -746,7 +746,7 @@ async def set_chk_take_subnet(subnet: int, chk_take: float) -> bool: subtensor=subtensor, wallet=wallet, netuid=subnet, - hotkey=wallet.hotkey.ss58_address, + hotkey=get_hotkey_pub_ss58(wallet), take=chk_take, prompt=prompt, wait_for_inclusion=wait_for_inclusion, @@ -756,7 +756,7 @@ async def set_chk_take_subnet(subnet: int, chk_take: float) -> bool: if success: console.print(":white_heavy_check_mark: [green]Set childkey take.[/green]") console.print( - f"The childkey take for {wallet.hotkey.ss58_address} is now set to {take * 100:.2f}%." + f"The childkey take for {get_hotkey_pub_ss58(wallet)} is now set to {take * 100:.2f}%." ) return True else: @@ -766,9 +766,10 @@ async def set_chk_take_subnet(subnet: int, chk_take: float) -> bool: return False # Print childkey take for other user and return (dont offer to change take rate) - if not hotkey or hotkey == wallet.hotkey.ss58_address: - hotkey = wallet.hotkey.ss58_address - if hotkey != wallet.hotkey.ss58_address or not take: + wallet_hk = get_hotkey_pub_ss58(wallet) + if not hotkey or hotkey == wallet_hk: + hotkey = wallet_hk + if hotkey != wallet_hk or not take: # display childkey take for other users if netuid: await display_chk_take(hotkey, netuid) @@ -826,7 +827,7 @@ async def set_chk_take_subnet(subnet: int, chk_take: float) -> bool: subtensor=subtensor, wallet=wallet, netuid=netuid_, - hotkey=wallet.hotkey.ss58_address, + hotkey=wallet_hk, take=take, prompt=prompt, wait_for_inclusion=True, diff --git a/bittensor_cli/src/commands/stake/remove.py b/bittensor_cli/src/commands/stake/remove.py index a28254e32..1125770a1 100644 --- a/bittensor_cli/src/commands/stake/remove.py +++ b/bittensor_cli/src/commands/stake/remove.py @@ -21,7 +21,7 @@ format_error_message, group_subnets, unlock_key, - json_console, + json_console, get_hotkey_pub_ss58, ) if TYPE_CHECKING: @@ -407,7 +407,7 @@ async def unstake_all( old_identities=old_identities, ) elif not hotkey_ss58_address: - hotkeys = [(wallet.hotkey_str, wallet.hotkey.ss58_address, None)] + hotkeys = [(wallet.hotkey_str, get_hotkey_pub_ss58(wallet), None)] else: hotkeys = [(None, hotkey_ss58_address, None)] @@ -1198,7 +1198,7 @@ def _get_hotkeys_to_unstake( print_verbose("Unstaking from all hotkeys") all_hotkeys_ = get_hotkey_wallets_for_wallet(wallet=wallet) wallet_hotkeys = [ - (wallet.hotkey_str, wallet.hotkey.ss58_address, None) + (wallet.hotkey_str, get_hotkey_pub_ss58(wallet), None) for wallet in all_hotkeys_ if wallet.hotkey_str not in exclude_hotkeys ] @@ -1230,7 +1230,7 @@ def _get_hotkeys_to_unstake( path=wallet.path, hotkey=hotkey_identifier, ) - result.append((wallet_.hotkey_str, wallet_.hotkey.ss58_address, None)) + result.append((wallet_.hotkey_str, get_hotkey_pub_ss58(wallet_), None)) return result # Only cli.config.wallet.hotkey is specified @@ -1238,7 +1238,7 @@ def _get_hotkeys_to_unstake( f"Unstaking from wallet: ({wallet.name}) from hotkey: ({wallet.hotkey_str})" ) assert wallet.hotkey is not None - return [(wallet.hotkey_str, wallet.hotkey.ss58_address, None)] + return [(wallet.hotkey_str, get_hotkey_pub_ss58(wallet), None)] def _create_unstake_table( diff --git a/bittensor_cli/src/commands/subnets/subnets.py b/bittensor_cli/src/commands/subnets/subnets.py index 62a20b63b..1e546d094 100644 --- a/bittensor_cli/src/commands/subnets/subnets.py +++ b/bittensor_cli/src/commands/subnets/subnets.py @@ -35,7 +35,7 @@ get_subnet_name, unlock_key, blocks_to_duration, - json_console, + json_console, get_hotkey_pub_ss58, ) if TYPE_CHECKING: @@ -114,7 +114,7 @@ async def _find_event_attributes_in_extrinsic_receipt( return False, None call_params = { - "hotkey": wallet.hotkey.ss58_address, + "hotkey": get_hotkey_pub_ss58(wallet), "mechid": 1, } call_function = "register_network" @@ -1654,7 +1654,7 @@ async def register( str(netuid), f"{Balance.get_unit(netuid)}", f"τ {current_recycle.tao:.4f}", - f"{wallet.hotkey.ss58_address}", + f"{get_hotkey_pub_ss58(wallet)}", f"{wallet.coldkeypub.ss58_address}", ) console.print(table) diff --git a/bittensor_cli/src/commands/weights.py b/bittensor_cli/src/commands/weights.py index 68ec0308f..685398666 100644 --- a/bittensor_cli/src/commands/weights.py +++ b/bittensor_cli/src/commands/weights.py @@ -14,7 +14,7 @@ err_console, console, format_error_message, - json_console, + json_console, get_hotkey_pub_ss58, ) from bittensor_cli.src.bittensor.extrinsics.root import ( convert_weights_and_uids_for_emit, @@ -128,7 +128,7 @@ async def commit_weights( # Generate the hash of the weights commit_hash = generate_weight_hash( - address=self.wallet.hotkey.ss58_address, + address=get_hotkey_pub_ss58(self.wallet), netuid=self.netuid, uids=uids, values=weights, From edfac733c9693ed4a3537f868b6a411e84025dd5 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:40:12 +0200 Subject: [PATCH 16/20] Ruff --- bittensor_cli/src/commands/stake/add.py | 3 ++- bittensor_cli/src/commands/stake/children_hotkeys.py | 3 ++- bittensor_cli/src/commands/stake/remove.py | 3 ++- bittensor_cli/src/commands/subnets/subnets.py | 3 ++- bittensor_cli/src/commands/weights.py | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/bittensor_cli/src/commands/stake/add.py b/bittensor_cli/src/commands/stake/add.py index e80efe457..6579d9767 100644 --- a/bittensor_cli/src/commands/stake/add.py +++ b/bittensor_cli/src/commands/stake/add.py @@ -19,7 +19,8 @@ print_error, print_verbose, unlock_key, - json_console, get_hotkey_pub_ss58, + json_console, + get_hotkey_pub_ss58, ) from bittensor_wallet import Wallet diff --git a/bittensor_cli/src/commands/stake/children_hotkeys.py b/bittensor_cli/src/commands/stake/children_hotkeys.py index 82e1271d1..d01e8d147 100644 --- a/bittensor_cli/src/commands/stake/children_hotkeys.py +++ b/bittensor_cli/src/commands/stake/children_hotkeys.py @@ -20,7 +20,8 @@ is_valid_ss58_address, format_error_message, unlock_key, - json_console, get_hotkey_pub_ss58, + json_console, + get_hotkey_pub_ss58, ) diff --git a/bittensor_cli/src/commands/stake/remove.py b/bittensor_cli/src/commands/stake/remove.py index 1125770a1..67f0109f6 100644 --- a/bittensor_cli/src/commands/stake/remove.py +++ b/bittensor_cli/src/commands/stake/remove.py @@ -21,7 +21,8 @@ format_error_message, group_subnets, unlock_key, - json_console, get_hotkey_pub_ss58, + json_console, + get_hotkey_pub_ss58, ) if TYPE_CHECKING: diff --git a/bittensor_cli/src/commands/subnets/subnets.py b/bittensor_cli/src/commands/subnets/subnets.py index 1e546d094..bb42132c9 100644 --- a/bittensor_cli/src/commands/subnets/subnets.py +++ b/bittensor_cli/src/commands/subnets/subnets.py @@ -35,7 +35,8 @@ get_subnet_name, unlock_key, blocks_to_duration, - json_console, get_hotkey_pub_ss58, + json_console, + get_hotkey_pub_ss58, ) if TYPE_CHECKING: diff --git a/bittensor_cli/src/commands/weights.py b/bittensor_cli/src/commands/weights.py index 685398666..63e3b72f3 100644 --- a/bittensor_cli/src/commands/weights.py +++ b/bittensor_cli/src/commands/weights.py @@ -14,7 +14,8 @@ err_console, console, format_error_message, - json_console, get_hotkey_pub_ss58, + json_console, + get_hotkey_pub_ss58, ) from bittensor_cli.src.bittensor.extrinsics.root import ( convert_weights_and_uids_for_emit, From 95a4af5ef9c864f89f0b169775a545b1c0b6891d Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:45:39 +0200 Subject: [PATCH 17/20] Think this is it --- .../src/bittensor/extrinsics/registration.py | 55 ++++++++++--------- .../src/bittensor/extrinsics/root.py | 3 +- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/bittensor_cli/src/bittensor/extrinsics/registration.py b/bittensor_cli/src/bittensor/extrinsics/registration.py index 8bbc8064f..d1800e1a2 100644 --- a/bittensor_cli/src/bittensor/extrinsics/registration.py +++ b/bittensor_cli/src/bittensor/extrinsics/registration.py @@ -38,7 +38,7 @@ print_verbose, print_error, unlock_key, - hex_to_bytes, + hex_to_bytes, get_hotkey_pub_ss58, ) if typing.TYPE_CHECKING: @@ -490,7 +490,7 @@ async def register_extrinsic( async def get_neuron_for_pubkey_and_subnet(): uid = await subtensor.query( - "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address] + "SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)] ) if uid is None: return NeuronInfo.get_null_neuron() @@ -525,7 +525,7 @@ async def get_neuron_for_pubkey_and_subnet(): if not Confirm.ask( f"Continue Registration?\n" f" hotkey [{COLOR_PALETTE.G.HK}]({wallet.hotkey_str})[/{COLOR_PALETTE.G.HK}]:" - f"\t[{COLOR_PALETTE.G.HK}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}]\n" + f"\t[{COLOR_PALETTE.G.HK}]{get_hotkey_pub_ss58(wallet)}[/{COLOR_PALETTE.G.HK}]\n" f" coldkey [{COLOR_PALETTE.G.CK}]({wallet.name})[/{COLOR_PALETTE.G.CK}]:" f"\t[{COLOR_PALETTE.G.CK}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE.G.CK}]\n" f" network:\t\t[{COLOR_PALETTE.G.LINKS}]{subtensor.network}[/{COLOR_PALETTE.G.LINKS}]\n" @@ -577,7 +577,7 @@ async def get_neuron_for_pubkey_and_subnet(): if not pow_result: # might be registered already on this subnet is_registered = await is_hotkey_registered( - subtensor, netuid=netuid, hotkey_ss58=wallet.hotkey.ss58_address + subtensor, netuid=netuid, hotkey_ss58=get_hotkey_pub_ss58(wallet) ) if is_registered: err_console.print( @@ -598,7 +598,7 @@ async def get_neuron_for_pubkey_and_subnet(): "block_number": pow_result.block_number, "nonce": pow_result.nonce, "work": [int(byte_) for byte_ in pow_result.seal], - "hotkey": wallet.hotkey.ss58_address, + "hotkey": get_hotkey_pub_ss58(wallet), "coldkey": wallet.coldkeypub.ss58_address, }, ) @@ -639,7 +639,7 @@ async def get_neuron_for_pubkey_and_subnet(): is_registered = await is_hotkey_registered( subtensor, netuid=netuid, - hotkey_ss58=wallet.hotkey.ss58_address, + hotkey_ss58=get_hotkey_pub_ss58(wallet), ) if is_registered: console.print( @@ -704,7 +704,7 @@ async def burned_register_extrinsic( spinner="aesthetic", ) as status: my_uid = await subtensor.query( - "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address] + "SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)] ) block_hash = await subtensor.substrate.get_chain_head() @@ -751,7 +751,7 @@ async def burned_register_extrinsic( call_function="burned_register", call_params={ "netuid": netuid, - "hotkey": wallet.hotkey.ss58_address, + "hotkey": get_hotkey_pub_ss58(wallet), }, ) success, err_msg = await subtensor.sign_and_send_extrinsic( @@ -773,10 +773,10 @@ async def burned_register_extrinsic( reuse_block=False, ), subtensor.get_netuids_for_hotkey( - wallet.hotkey.ss58_address, block_hash=block_hash + get_hotkey_pub_ss58(wallet), block_hash=block_hash ), subtensor.query( - "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address] + "SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)] ), ) @@ -1146,7 +1146,7 @@ async def _block_solver( timeout = 0.15 if cuda else 0.15 while netuid == -1 or not await is_hotkey_registered( - subtensor, netuid, wallet.hotkey.ss58_address + subtensor, netuid, get_hotkey_pub_ss58(wallet) ): # Wait until a solver finds a solution try: @@ -1755,37 +1755,39 @@ async def swap_hotkey_extrinsic( :return: Success """ block_hash = await subtensor.substrate.get_chain_head() + hk_ss58 = get_hotkey_pub_ss58(wallet) netuids_registered = await subtensor.get_netuids_for_hotkey( - wallet.hotkey.ss58_address, block_hash=block_hash + hk_ss58, block_hash=block_hash ) netuids_registered_new_hotkey = await subtensor.get_netuids_for_hotkey( - new_wallet.hotkey.ss58_address, block_hash=block_hash + hk_ss58, block_hash=block_hash ) if netuid is not None and netuid not in netuids_registered: err_console.print( - f":cross_mark: [red]Failed[/red]: Original hotkey {wallet.hotkey.ss58_address} is not registered on subnet {netuid}" + f":cross_mark: [red]Failed[/red]: Original hotkey {hk_ss58} is not registered on subnet {netuid}" ) return False elif not len(netuids_registered) > 0: err_console.print( - f"Original hotkey [dark_orange]{wallet.hotkey.ss58_address}[/dark_orange] is not registered on any subnet. " + f"Original hotkey [dark_orange]{hk_ss58}[/dark_orange] is not registered on any subnet. " f"Please register and try again" ) return False + new_hk_ss58 = get_hotkey_pub_ss58(new_wallet) if netuid is not None: if netuid in netuids_registered_new_hotkey: err_console.print( - f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} " + f":cross_mark: [red]Failed[/red]: New hotkey {new_hk_ss58} " f"is already registered on subnet {netuid}" ) return False else: if len(netuids_registered_new_hotkey) > 0: err_console.print( - f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} " + f":cross_mark: [red]Failed[/red]: New hotkey {new_hk_ss58} " f"is already registered on subnet(s) {netuids_registered_new_hotkey}" ) return False @@ -1798,28 +1800,28 @@ async def swap_hotkey_extrinsic( if netuid is not None: confirm_message = ( f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t" - f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t" - f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n" + f"[dark_orange]{hk_ss58} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t" + f"[dark_orange]{new_hk_ss58} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n" "This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]" ) else: confirm_message = ( f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t" - f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t" - f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n" + f"[dark_orange]{hk_ss58} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t" + f"[dark_orange]{new_hk_ss58} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n" "This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]" ) if not Confirm.ask(confirm_message): return False print_verbose( - f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address} - {wallet.hotkey_str}) with " - f"{new_wallet.name}'s hotkey ({new_wallet.hotkey.ss58_address} - {new_wallet.hotkey_str})" + f"Swapping {wallet.name}'s hotkey ({hk_ss58} - {wallet.hotkey_str}) with " + f"{new_wallet.name}'s hotkey ({new_hk_ss58} - {new_wallet.hotkey_str})" ) with console.status(":satellite: Swapping hotkeys...", spinner="aesthetic"): call_params = { - "hotkey": wallet.hotkey.ss58_address, - "new_hotkey": new_wallet.hotkey.ss58_address, + "hotkey": hk_ss58, + "new_hotkey": new_hk_ss58, "netuid": netuid, } @@ -1832,7 +1834,8 @@ async def swap_hotkey_extrinsic( if success: console.print( - f"Hotkey {wallet.hotkey.ss58_address} ({wallet.hotkey_str}) swapped for new hotkey: {new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})" + f"Hotkey {hk_ss58} ({wallet.hotkey_str}) swapped for new hotkey: " + f"{new_hk_ss58} ({new_wallet.hotkey_str})" ) return True else: diff --git a/bittensor_cli/src/bittensor/extrinsics/root.py b/bittensor_cli/src/bittensor/extrinsics/root.py index 3f3c4f039..207fb8642 100644 --- a/bittensor_cli/src/bittensor/extrinsics/root.py +++ b/bittensor_cli/src/bittensor/extrinsics/root.py @@ -36,7 +36,8 @@ u16_normalized_float, print_verbose, format_error_message, - unlock_key, get_hotkey_pub_ss58, + unlock_key, + get_hotkey_pub_ss58, ) if TYPE_CHECKING: From 411fadd1ca2937f01b9ebc0217baad88da464233 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 20:45:58 +0200 Subject: [PATCH 18/20] =?UTF-8?q?Ruff=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bittensor_cli/src/bittensor/extrinsics/registration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bittensor_cli/src/bittensor/extrinsics/registration.py b/bittensor_cli/src/bittensor/extrinsics/registration.py index d1800e1a2..b2461d897 100644 --- a/bittensor_cli/src/bittensor/extrinsics/registration.py +++ b/bittensor_cli/src/bittensor/extrinsics/registration.py @@ -38,7 +38,8 @@ print_verbose, print_error, unlock_key, - hex_to_bytes, get_hotkey_pub_ss58, + hex_to_bytes, + get_hotkey_pub_ss58, ) if typing.TYPE_CHECKING: From 29cb6b9516214822f236e806f1a47df7c78634d5 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 21:19:48 +0200 Subject: [PATCH 19/20] Req --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8e29fb202..95709532a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ dependencies = [ "rich>=13.7,<15.0", "scalecodec==1.2.11", "typer>=0.16", - "bittensor-wallet>=3.1.1", + "bittensor-wallet>=4.0.0", "packaging", "plotille>=5.0.0", "plotly>=6.0.0", From 8d4819887fa9a945809874061b2868f6510e3b91 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 6 Aug 2025 22:36:18 +0200 Subject: [PATCH 20/20] Typo --- tests/e2e_tests/test_wallet_creations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e_tests/test_wallet_creations.py b/tests/e2e_tests/test_wallet_creations.py index 7dcbc5970..1e7020671 100644 --- a/tests/e2e_tests/test_wallet_creations.py +++ b/tests/e2e_tests/test_wallet_creations.py @@ -566,7 +566,7 @@ def test_wallet_regen(wallet_setup, capfd): # Wait a bit to ensure file system updates modification time time.sleep(2) - new_hotkeypub_mod_time = os.path.getmtime(hotkey_path) + new_hotkeypub_mod_time = os.path.getmtime(hotkeypub_path) assert initial_hotkeypub_mod_time != new_hotkeypub_mod_time, ( "Hotkey file was not regenerated as expected"