Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f02fbe8
Add get_auto_stake_destinations
ibraheem-abe Sep 19, 2025
1321ab4
add cmd get_auto_stake
ibraheem-abe Sep 19, 2025
9e6503b
add set-auto
ibraheem-abe Sep 19, 2025
b65de60
show_auto_stake
ibraheem-abe Sep 19, 2025
8b40ff2
set_auto_stake_destination
ibraheem-abe Sep 19, 2025
dbaffe3
cleanup
ibraheem-abe Sep 19, 2025
1ec2912
Merge branch 'staging' into feat/auto-staking
thewhaleking Sep 23, 2025
c705a0f
Update to include extrinsic identifiers
thewhaleking Sep 23, 2025
b84ed9e
Updates wording in transfer confirm
thewhaleking Sep 30, 2025
08fb41f
Merge pull request #642 from opentensor/fix/thewhaleking/update-wordi…
thewhaleking Sep 30, 2025
74a0514
fix mechanism labelling
ibraheem-abe Sep 30, 2025
4bd8bd3
update cmd and create alias
ibraheem-abe Sep 30, 2025
3e56841
Merge pull request #643 from opentensor/update/split-emissions
ibraheem-abe Sep 30, 2025
8e52652
Merge pull request #632 from opentensor/feat/auto-staking
ibraheem-abe Oct 3, 2025
cfeed27
Updates wording on origin/destination hotkey in `st move`
thewhaleking Oct 6, 2025
9842fd9
Ensures no error at the end of `btcli --commands`
thewhaleking Oct 6, 2025
b1f2a22
Hides the associate_hotkey alias
thewhaleking Oct 6, 2025
244087b
Ruff
thewhaleking Oct 6, 2025
278e9e8
Merge pull request #647 from opentensor/fix/thewhaleking/update-st-mo…
thewhaleking Oct 6, 2025
2ad0eb1
Merge branch 'staging' into fix/thewhaleking/commands-list
thewhaleking Oct 6, 2025
e4174e2
Indent
thewhaleking Oct 6, 2025
fb278ea
Merge pull request #648 from opentensor/fix/thewhaleking/commands-list
thewhaleking Oct 7, 2025
dd4c9b4
bumps version and changelog
ibraheem-abe Oct 8, 2025
fa5f3d3
Merge pull request #650 from opentensor/changelog/9130
ibraheem-abe Oct 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## 9.13.0 /2025-10-09

## What's Changed
* Updates wording in transfer confirm by @thewhaleking in https://github.com/opentensor/btcli/pull/642
* Update/split emissions by @ibraheem-abe in https://github.com/opentensor/btcli/pull/643
* Feat/auto staking by @ibraheem-abe in https://github.com/opentensor/btcli/pull/632
* Updates wording on origin/destination hotkey in `st move` by @thewhaleking in https://github.com/opentensor/btcli/pull/647
* commands list fixes by @thewhaleking in https://github.com/opentensor/btcli/pull/648

**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.12.0...v9.13.0

## 9.12.0 /2025-09-25
* Removes warning icon in transfer by @ibraheem-abe in https://github.com/opentensor/btcli/pull/634
* Add Extrinsic Identifier Output by @thewhaleking in https://github.com/opentensor/btcli/pull/633
Expand Down
169 changes: 165 additions & 4 deletions bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
prompt_position_id,
)
from bittensor_cli.src.commands.stake import (
auto_staking as auto_stake,
children_hotkeys,
list as list_stake,
move as move_stake,
Expand Down Expand Up @@ -617,6 +618,7 @@ def commands_callback(value: bool):
if value:
cli = CLIManager()
console.print(cli.generate_command_tree())
raise typer.Exit()


def debug_callback(value: bool):
Expand Down Expand Up @@ -935,6 +937,12 @@ def __init__(self):
self.stake_app.command(
"add", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
)(self.stake_add)
self.stake_app.command(
"auto", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
)(self.get_auto_stake)
self.stake_app.command(
"set-auto", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
)(self.set_auto_stake)
self.stake_app.command(
"remove", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
)(self.stake_remove)
Expand Down Expand Up @@ -979,7 +987,7 @@ def __init__(self):
"emissions", rich_help_panel=HELP_PANELS["MECHANISMS"]["EMISSION"]
)(self.mechanism_emission_get)
self.subnet_mechanisms_app.command(
"emissions-split", rich_help_panel=HELP_PANELS["MECHANISMS"]["EMISSION"]
"split-emissions", rich_help_panel=HELP_PANELS["MECHANISMS"]["EMISSION"]
)(self.mechanism_emission_set)

# sudo commands
Expand Down Expand Up @@ -1105,14 +1113,19 @@ def __init__(self):
"get_identity",
hidden=True,
)(self.wallet_get_id)
self.wallet_app.command("associate_hotkey")(self.wallet_associate_hotkey)
self.wallet_app.command("associate_hotkey", hidden=True)(
self.wallet_associate_hotkey
)

# Subnets
self.subnets_app.command("burn_cost", hidden=True)(self.subnets_burn_cost)
self.subnets_app.command("pow_register", hidden=True)(self.subnets_pow_register)
self.subnets_app.command("set_identity", hidden=True)(self.subnets_set_identity)
self.subnets_app.command("get_identity", hidden=True)(self.subnets_get_identity)
self.subnets_app.command("check_start", hidden=True)(self.subnets_check_start)
self.subnet_mechanisms_app.command("emissions-split", hidden=True)(
self.mechanism_emission_set
)

# Sudo
self.sudo_app.command("senate_vote", hidden=True)(self.sudo_senate_vote)
Expand Down Expand Up @@ -3593,6 +3606,137 @@ def wallet_swap_coldkey(
)
)

def get_auto_stake(
self,
network: Optional[list[str]] = Options.network,
wallet_name: Optional[str] = Options.wallet_name,
wallet_path: Optional[str] = Options.wallet_path,
coldkey_ss58=typer.Option(
None,
"--ss58",
"--coldkey_ss58",
"--coldkey.ss58_address",
"--coldkey.ss58",
help="Coldkey address of the wallet",
),
quiet: bool = Options.quiet,
verbose: bool = Options.verbose,
json_output: bool = Options.json_output,
):
"""Display auto-stake destinations for a wallet across all subnets."""

self.verbosity_handler(quiet, verbose, json_output)

wallet = None
if coldkey_ss58:
if not is_valid_ss58_address(coldkey_ss58):
print_error("You entered an invalid ss58 address")
raise typer.Exit()
else:
if wallet_name:
coldkey_or_ss58 = wallet_name
else:
coldkey_or_ss58 = Prompt.ask(
"Enter the [blue]wallet name[/blue] or [blue]coldkey ss58 address[/blue]",
default=self.config.get("wallet_name") or defaults.wallet.name,
)
if is_valid_ss58_address(coldkey_or_ss58):
coldkey_ss58 = coldkey_or_ss58
else:
wallet_name = coldkey_or_ss58 if coldkey_or_ss58 else wallet_name
wallet = self.wallet_ask(
wallet_name,
wallet_path,
None,
ask_for=[WO.NAME, WO.PATH],
validate=WV.WALLET,
)

return self._run_command(
auto_stake.show_auto_stake_destinations(
wallet,
self.initialize_chain(network),
coldkey_ss58=coldkey_ss58,
json_output=json_output,
verbose=verbose,
)
)

def set_auto_stake(
self,
network: Optional[list[str]] = Options.network,
wallet_name: Optional[str] = Options.wallet_name,
wallet_path: Optional[str] = Options.wallet_path,
netuid: Optional[int] = Options.netuid_not_req,
quiet: bool = Options.quiet,
verbose: bool = Options.verbose,
prompt: bool = Options.prompt,
wait_for_inclusion: bool = Options.wait_for_inclusion,
wait_for_finalization: bool = Options.wait_for_finalization,
json_output: bool = Options.json_output,
):
"""Set the auto-stake destination hotkey for a coldkey."""

self.verbosity_handler(quiet, verbose, json_output)

wallet = self.wallet_ask(
wallet_name,
wallet_path,
None,
ask_for=[WO.NAME, WO.PATH],
validate=WV.WALLET,
)

if netuid is None:
netuid = IntPrompt.ask(
"Enter the [blue]netuid[/blue] to configure",
default=defaults.netuid,
)
validate_netuid(netuid)

hotkey_prompt = Prompt.ask(
"Enter the [blue]hotkey ss58 address[/blue] to auto-stake to "
"[dim](Press Enter to view delegates)[/dim]",
default="",
show_default=False,
).strip()

if not hotkey_prompt:
selected_hotkey = self._run_command(
subnets.show(
subtensor=self.initialize_chain(network),
netuid=netuid,
sort=False,
max_rows=20,
prompt=False,
delegate_selection=True,
),
exit_early=False,
)
if not selected_hotkey:
print_error("No delegate selected. Exiting.")
return
hotkey_ss58 = selected_hotkey
else:
hotkey_ss58 = hotkey_prompt

if not is_valid_ss58_address(hotkey_ss58):
print_error("You entered an invalid hotkey ss58 address")
return

return self._run_command(
auto_stake.set_auto_stake_destination(
wallet,
self.initialize_chain(network),
netuid,
hotkey_ss58,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
prompt_user=prompt,
json_output=json_output,
)
)

def stake_list(
self,
network: Optional[list[str]] = Options.network,
Expand Down Expand Up @@ -4318,15 +4462,32 @@ def stake_move(
network: Optional[list[str]] = Options.network,
wallet_name: Optional[str] = Options.wallet_name,
wallet_path: Optional[str] = Options.wallet_path,
wallet_hotkey: Optional[str] = Options.wallet_hotkey_ss58,
wallet_hotkey: Optional[str] = typer.Option(
None,
"--from",
"--hotkey",
"--hotkey-ss58",
"-H",
"--wallet_hotkey",
"--wallet_hotkey_ss58",
"--wallet-hotkey",
"--wallet-hotkey-ss58",
"--wallet.hotkey",
help="Validator hotkey or SS58 where the stake is currently located.",
),
origin_netuid: Optional[int] = typer.Option(
None, "--origin-netuid", help="Origin netuid"
),
destination_netuid: Optional[int] = typer.Option(
None, "--dest-netuid", help="Destination netuid"
),
destination_hotkey: Optional[str] = typer.Option(
None, "--dest-ss58", "--dest", help="Destination hotkey", prompt=False
None,
"--to",
"--dest-ss58",
"--dest",
help="Destination validator hotkey SS58",
prompt=False,
),
amount: float = typer.Option(
None,
Expand Down
3 changes: 2 additions & 1 deletion bittensor_cli/src/bittensor/extrinsics/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ async def do_transfer() -> tuple[bool, str, str, AsyncExtrinsicReceipt]:
f"[bright_magenta]{wallet.coldkey.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]"
f"[dark_orange]btcli stake add[/dark_orange] instead[/bright_yellow].\n"
f"Proceed with transfer?"
):
return False, None

Expand Down
24 changes: 24 additions & 0 deletions bittensor_cli/src/bittensor/subtensor_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,30 @@ async def get_stake_for_coldkey(
stakes: list[StakeInfo] = StakeInfo.list_from_any(result)
return [stake for stake in stakes if stake.stake > 0]

async def get_auto_stake_destinations(
self,
coldkey_ss58: str,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> dict[int, str]:
"""Retrieve auto-stake destinations configured for a coldkey."""

query = await self.substrate.query_map(
module="SubtensorModule",
storage_function="AutoStakeDestination",
params=[coldkey_ss58],
block_hash=block_hash,
reuse_block_hash=reuse_block,
)

destinations: dict[int, str] = {}
async for netuid, destination in query:
hotkey_ss58 = decode_account_id(destination.value[0])
if hotkey_ss58:
destinations[int(netuid)] = hotkey_ss58

return destinations

async def get_stake_for_coldkey_and_hotkey(
self,
hotkey_ss58: str,
Expand Down
Loading
Loading