Skip to content

Commit 8e52652

Browse files
authored
Merge pull request #632 from opentensor/feat/auto-staking
Feat/auto staking
2 parents 3e56841 + c705a0f commit 8e52652

File tree

3 files changed

+460
-0
lines changed

3 files changed

+460
-0
lines changed

bittensor_cli/cli.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
prompt_position_id,
7373
)
7474
from bittensor_cli.src.commands.stake import (
75+
auto_staking as auto_stake,
7576
children_hotkeys,
7677
list as list_stake,
7778
move as move_stake,
@@ -935,6 +936,12 @@ def __init__(self):
935936
self.stake_app.command(
936937
"add", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
937938
)(self.stake_add)
939+
self.stake_app.command(
940+
"auto", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
941+
)(self.get_auto_stake)
942+
self.stake_app.command(
943+
"set-auto", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
944+
)(self.set_auto_stake)
938945
self.stake_app.command(
939946
"remove", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
940947
)(self.stake_remove)
@@ -3596,6 +3603,137 @@ def wallet_swap_coldkey(
35963603
)
35973604
)
35983605

3606+
def get_auto_stake(
3607+
self,
3608+
network: Optional[list[str]] = Options.network,
3609+
wallet_name: Optional[str] = Options.wallet_name,
3610+
wallet_path: Optional[str] = Options.wallet_path,
3611+
coldkey_ss58=typer.Option(
3612+
None,
3613+
"--ss58",
3614+
"--coldkey_ss58",
3615+
"--coldkey.ss58_address",
3616+
"--coldkey.ss58",
3617+
help="Coldkey address of the wallet",
3618+
),
3619+
quiet: bool = Options.quiet,
3620+
verbose: bool = Options.verbose,
3621+
json_output: bool = Options.json_output,
3622+
):
3623+
"""Display auto-stake destinations for a wallet across all subnets."""
3624+
3625+
self.verbosity_handler(quiet, verbose, json_output)
3626+
3627+
wallet = None
3628+
if coldkey_ss58:
3629+
if not is_valid_ss58_address(coldkey_ss58):
3630+
print_error("You entered an invalid ss58 address")
3631+
raise typer.Exit()
3632+
else:
3633+
if wallet_name:
3634+
coldkey_or_ss58 = wallet_name
3635+
else:
3636+
coldkey_or_ss58 = Prompt.ask(
3637+
"Enter the [blue]wallet name[/blue] or [blue]coldkey ss58 address[/blue]",
3638+
default=self.config.get("wallet_name") or defaults.wallet.name,
3639+
)
3640+
if is_valid_ss58_address(coldkey_or_ss58):
3641+
coldkey_ss58 = coldkey_or_ss58
3642+
else:
3643+
wallet_name = coldkey_or_ss58 if coldkey_or_ss58 else wallet_name
3644+
wallet = self.wallet_ask(
3645+
wallet_name,
3646+
wallet_path,
3647+
None,
3648+
ask_for=[WO.NAME, WO.PATH],
3649+
validate=WV.WALLET,
3650+
)
3651+
3652+
return self._run_command(
3653+
auto_stake.show_auto_stake_destinations(
3654+
wallet,
3655+
self.initialize_chain(network),
3656+
coldkey_ss58=coldkey_ss58,
3657+
json_output=json_output,
3658+
verbose=verbose,
3659+
)
3660+
)
3661+
3662+
def set_auto_stake(
3663+
self,
3664+
network: Optional[list[str]] = Options.network,
3665+
wallet_name: Optional[str] = Options.wallet_name,
3666+
wallet_path: Optional[str] = Options.wallet_path,
3667+
netuid: Optional[int] = Options.netuid_not_req,
3668+
quiet: bool = Options.quiet,
3669+
verbose: bool = Options.verbose,
3670+
prompt: bool = Options.prompt,
3671+
wait_for_inclusion: bool = Options.wait_for_inclusion,
3672+
wait_for_finalization: bool = Options.wait_for_finalization,
3673+
json_output: bool = Options.json_output,
3674+
):
3675+
"""Set the auto-stake destination hotkey for a coldkey."""
3676+
3677+
self.verbosity_handler(quiet, verbose, json_output)
3678+
3679+
wallet = self.wallet_ask(
3680+
wallet_name,
3681+
wallet_path,
3682+
None,
3683+
ask_for=[WO.NAME, WO.PATH],
3684+
validate=WV.WALLET,
3685+
)
3686+
3687+
if netuid is None:
3688+
netuid = IntPrompt.ask(
3689+
"Enter the [blue]netuid[/blue] to configure",
3690+
default=defaults.netuid,
3691+
)
3692+
validate_netuid(netuid)
3693+
3694+
hotkey_prompt = Prompt.ask(
3695+
"Enter the [blue]hotkey ss58 address[/blue] to auto-stake to "
3696+
"[dim](Press Enter to view delegates)[/dim]",
3697+
default="",
3698+
show_default=False,
3699+
).strip()
3700+
3701+
if not hotkey_prompt:
3702+
selected_hotkey = self._run_command(
3703+
subnets.show(
3704+
subtensor=self.initialize_chain(network),
3705+
netuid=netuid,
3706+
sort=False,
3707+
max_rows=20,
3708+
prompt=False,
3709+
delegate_selection=True,
3710+
),
3711+
exit_early=False,
3712+
)
3713+
if not selected_hotkey:
3714+
print_error("No delegate selected. Exiting.")
3715+
return
3716+
hotkey_ss58 = selected_hotkey
3717+
else:
3718+
hotkey_ss58 = hotkey_prompt
3719+
3720+
if not is_valid_ss58_address(hotkey_ss58):
3721+
print_error("You entered an invalid hotkey ss58 address")
3722+
return
3723+
3724+
return self._run_command(
3725+
auto_stake.set_auto_stake_destination(
3726+
wallet,
3727+
self.initialize_chain(network),
3728+
netuid,
3729+
hotkey_ss58,
3730+
wait_for_inclusion=wait_for_inclusion,
3731+
wait_for_finalization=wait_for_finalization,
3732+
prompt_user=prompt,
3733+
json_output=json_output,
3734+
)
3735+
)
3736+
35993737
def stake_list(
36003738
self,
36013739
network: Optional[list[str]] = Options.network,

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,30 @@ async def get_stake_for_coldkey(
225225
stakes: list[StakeInfo] = StakeInfo.list_from_any(result)
226226
return [stake for stake in stakes if stake.stake > 0]
227227

228+
async def get_auto_stake_destinations(
229+
self,
230+
coldkey_ss58: str,
231+
block_hash: Optional[str] = None,
232+
reuse_block: bool = False,
233+
) -> dict[int, str]:
234+
"""Retrieve auto-stake destinations configured for a coldkey."""
235+
236+
query = await self.substrate.query_map(
237+
module="SubtensorModule",
238+
storage_function="AutoStakeDestination",
239+
params=[coldkey_ss58],
240+
block_hash=block_hash,
241+
reuse_block_hash=reuse_block,
242+
)
243+
244+
destinations: dict[int, str] = {}
245+
async for netuid, destination in query:
246+
hotkey_ss58 = decode_account_id(destination.value[0])
247+
if hotkey_ss58:
248+
destinations[int(netuid)] = hotkey_ss58
249+
250+
return destinations
251+
228252
async def get_stake_for_coldkey_and_hotkey(
229253
self,
230254
hotkey_ss58: str,

0 commit comments

Comments
 (0)