diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 220de3d40..eae4d0fed 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -4573,9 +4573,17 @@ def stake_move( [green]$[/green] btcli stake move """ self.verbosity_handler(quiet, verbose, json_output) - console.print( - "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]" - ) + if prompt: + if not Confirm.ask( + "This transaction will [bold]move stake[/bold] to another hotkey while keeping the same " + "coldkey ownership. Do you wish to continue? ", + default=False, + ): + raise typer.Exit() + else: + console.print( + "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]" + ) if not destination_hotkey: dest_wallet_or_ss58 = Prompt.ask( "Enter the [blue]destination wallet[/blue] where destination hotkey is located or " @@ -4770,9 +4778,18 @@ def stake_transfer( [green]$[/green] btcli stake transfer --all --origin-netuid 1 --dest-netuid 2 """ self.verbosity_handler(quiet, verbose, json_output) - console.print( - "[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]" - ) + if prompt: + if not Confirm.ask( + "This transaction will [bold]transfer ownership[/bold] from one coldkey to another, in subnets " + "which have enabled it. You should ensure that the destination coldkey is " + "[bold]not a validator hotkey[/bold] before continuing. Do you wish to continue?", + default=False, + ): + raise typer.Exit() + else: + console.print( + "[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]" + ) if not dest_ss58: dest_ss58 = Prompt.ask( diff --git a/bittensor_cli/src/bittensor/extrinsics/transfer.py b/bittensor_cli/src/bittensor/extrinsics/transfer.py index 720e8d356..6886fb41a 100644 --- a/bittensor_cli/src/bittensor/extrinsics/transfer.py +++ b/bittensor_cli/src/bittensor/extrinsics/transfer.py @@ -116,9 +116,6 @@ async def do_transfer() -> tuple[bool, str, str, AsyncExtrinsicReceipt]: ) return False, None console.print(f"[dark_orange]Initiating transfer on network: {subtensor.network}") - # Unlock wallet coldkey. - if not unlock_key(wallet).success: - return False, None call_params: dict[str, Optional[Union[str, int]]] = {"dest": destination} if transfer_all: @@ -175,11 +172,20 @@ async def do_transfer() -> tuple[bool, str, str, AsyncExtrinsicReceipt]: # Ask before moving on. if prompt: + hk_owner = await subtensor.get_hotkey_owner(destination, check_exists=False) + if hk_owner and hk_owner != destination: + if not Confirm.ask( + f"The destination appears to be a hotkey, owned by [bright_magenta]{hk_owner}[/bright_magenta]. " + f"Only proceed if you are absolutely sure that [bright_magenta]{destination}[/bright_magenta] is the " + f"correct destination.", + default=False, + ): + return False, None if not Confirm.ask( "Do you want to transfer:[bold white]\n" f" amount: [bright_cyan]{amount if not transfer_all else account_balance}[/bright_cyan]\n" f" from: [light_goldenrod2]{wallet.name}[/light_goldenrod2] : " - f"[bright_magenta]{wallet.coldkey.ss58_address}\n[/bright_magenta]" + f"[bright_magenta]{wallet.coldkeypub.ss58_address}\n[/bright_magenta]" f" to: [bright_magenta]{destination}[/bright_magenta]\n for fee: [bright_cyan]{fee}[/bright_cyan]\n" f"[bright_yellow]Transferring is not the same as staking. To instead stake, use " f"[dark_orange]btcli stake add[/dark_orange] instead[/bright_yellow].\n" @@ -187,6 +193,10 @@ async def do_transfer() -> tuple[bool, str, str, AsyncExtrinsicReceipt]: ): return False, None + # Unlock wallet coldkey. + if not unlock_key(wallet).success: + return False, None + with console.status(":satellite: Transferring...", spinner="earth"): success, block_hash, err_msg, ext_receipt = await do_transfer() diff --git a/bittensor_cli/src/bittensor/subtensor_interface.py b/bittensor_cli/src/bittensor/subtensor_interface.py index a0d6dd6ee..2ef90d284 100644 --- a/bittensor_cli/src/bittensor/subtensor_interface.py +++ b/bittensor_cli/src/bittensor/subtensor_interface.py @@ -1123,6 +1123,7 @@ async def get_hotkey_owner( self, hotkey_ss58: str, block_hash: Optional[str] = None, + check_exists: bool = True, ) -> Optional[str]: val = await self.query( module="SubtensorModule", @@ -1130,10 +1131,15 @@ async def get_hotkey_owner( params=[hotkey_ss58], block_hash=block_hash, ) - if val: - exists = await self.does_hotkey_exist(hotkey_ss58, block_hash=block_hash) + if check_exists: + if val: + exists = await self.does_hotkey_exist( + hotkey_ss58, block_hash=block_hash + ) + else: + exists = False else: - exists = False + exists = True hotkey_owner = val if exists else None return hotkey_owner