Skip to content

Commit 7189539

Browse files
authored
Merge pull request #358 from opentensor/fix/stake-transfer-selection
Improves stake transfer, adds interactive selection of delegates
2 parents 2e074ab + e9496a5 commit 7189539

File tree

2 files changed

+66
-138
lines changed

2 files changed

+66
-138
lines changed

bittensor_cli/cli.py

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3528,6 +3528,9 @@ def stake_transfer(
35283528
"-a",
35293529
help="Amount of stake to transfer",
35303530
),
3531+
stake_all: bool = typer.Option(
3532+
False, "--stake-all", "--all", help="Stake all", prompt=False
3533+
),
35313534
prompt: bool = Options.prompt,
35323535
quiet: bool = Options.quiet,
35333536
verbose: bool = Options.verbose,
@@ -3545,6 +3548,8 @@ def stake_transfer(
35453548
- The destination subnet (--dest-netuid)
35463549
- The destination wallet/address (--dest)
35473550
- The amount to transfer (--amount)
3551+
- The origin wallet (--wallet-name)
3552+
- The origin hotkey wallet/address (--wallet-hotkey)
35483553
35493554
If no arguments are provided, an interactive selection menu will be shown.
35503555
@@ -3553,14 +3558,37 @@ def stake_transfer(
35533558
Transfer 100 TAO from subnet 1 to subnet 2:
35543559
[green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest wallet2 --amount 100
35553560
3556-
Using SS58 address:
3561+
Using Destination SS58 address:
35573562
[green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest 5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngEP9H7qjkKgHLcK --amount 100
3563+
3564+
Using Origin hotkey SS58 address (useful when transferring stake from a delegate):
3565+
[green]$[/green] btcli stake transfer --wallet-hotkey 5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngEP9H7qjkKgHLcK --wallet-name sample_wallet
3566+
3567+
Transfer all available stake from origin hotkey:
3568+
[green]$[/green] btcli stake transfer --all --origin-netuid 1 --dest-netuid 2
35583569
"""
35593570
console.print(
35603571
"[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]"
35613572
)
35623573
self.verbosity_handler(quiet, verbose)
35633574

3575+
if not dest_ss58:
3576+
dest_ss58 = Prompt.ask(
3577+
"Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
3578+
)
3579+
3580+
if is_valid_ss58_address(dest_ss58):
3581+
dest_ss58 = dest_ss58
3582+
else:
3583+
dest_wallet = self.wallet_ask(
3584+
dest_ss58,
3585+
wallet_path,
3586+
None,
3587+
ask_for=[WO.NAME, WO.PATH],
3588+
validate=WV.WALLET,
3589+
)
3590+
dest_ss58 = dest_wallet.coldkeypub.ss58_address
3591+
35643592
if not wallet_name:
35653593
wallet_name = Prompt.ask(
35663594
"Enter the [blue]origin wallet name[/blue]",
@@ -3570,13 +3598,16 @@ def stake_transfer(
35703598
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME]
35713599
)
35723600

3601+
interactive_selection = False
35733602
if not wallet_hotkey:
35743603
origin_hotkey = Prompt.ask(
3575-
"Enter the [blue]origin hotkey[/blue] name or "
3576-
"[blue]ss58 address[/blue] where the stake will be moved from",
3577-
default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
3604+
"Enter the [blue]origin hotkey[/blue] name or ss58 address [bold](stake will be transferred FROM here)[/bold] "
3605+
"[dim](or press Enter to select from existing stakes)[/dim]"
35783606
)
3579-
if is_valid_ss58_address(origin_hotkey):
3607+
if origin_hotkey == "":
3608+
interactive_selection = True
3609+
3610+
elif is_valid_ss58_address(origin_hotkey):
35803611
origin_hotkey = origin_hotkey
35813612
else:
35823613
wallet = self.wallet_ask(
@@ -3600,33 +3631,11 @@ def stake_transfer(
36003631
)
36013632
origin_hotkey = wallet.hotkey.ss58_address
36023633

3603-
if not dest_ss58:
3604-
dest_ss58 = Prompt.ask(
3605-
"Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
3606-
)
3607-
3608-
if is_valid_ss58_address(dest_ss58):
3609-
dest_ss58 = dest_ss58
3610-
else:
3611-
dest_wallet = self.wallet_ask(
3612-
dest_ss58,
3613-
wallet_path,
3614-
None,
3615-
ask_for=[WO.NAME, WO.PATH],
3616-
validate=WV.WALLET,
3617-
)
3618-
dest_ss58 = dest_wallet.coldkeypub.ss58_address
3619-
3620-
interactive_selection = False
3621-
if origin_netuid is None and dest_netuid is None and not amount:
3622-
interactive_selection = True
3623-
else:
3634+
if not interactive_selection:
36243635
if origin_netuid is None:
36253636
origin_netuid = IntPrompt.ask(
36263637
"Enter the [blue]origin subnet[/blue] (netuid)"
36273638
)
3628-
if not amount:
3629-
amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to transfer")
36303639

36313640
if dest_netuid is None:
36323641
dest_netuid = IntPrompt.ask(
@@ -3643,6 +3652,7 @@ def stake_transfer(
36433652
dest_coldkey_ss58=dest_ss58,
36443653
amount=amount,
36453654
interactive_selection=interactive_selection,
3655+
stake_all=stake_all,
36463656
prompt=prompt,
36473657
)
36483658
)

bittensor_cli/src/commands/stake/move.py

Lines changed: 28 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def prompt_stake_amount(
207207
console.print("[red]Please enter a valid number or 'all'[/red]")
208208

209209

210-
async def stake_move_selection(
210+
async def stake_move_transfer_selection(
211211
subtensor: "SubtensorInterface",
212212
wallet: Wallet,
213213
):
@@ -293,25 +293,24 @@ async def stake_move_selection(
293293
title_justify="center",
294294
width=len(origin_hotkey_ss58) + 20,
295295
)
296-
table.add_column("Index", justify="right")
297296
table.add_column("Netuid", style="cyan")
298297
table.add_column("Stake Amount", style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"])
299298

300299
available_netuids = []
301-
for idx, netuid in enumerate(origin_hotkey_info["netuids"]):
300+
for netuid in origin_hotkey_info["netuids"]:
302301
stake = origin_hotkey_info["stakes"][netuid]
303302
if stake.tao > 0:
304303
available_netuids.append(netuid)
305-
table.add_row(str(idx), str(netuid), str(stake))
304+
table.add_row(str(netuid), str(stake))
306305

307306
console.print("\n", table)
308307

309308
# Select origin netuid
310-
netuid_idx = Prompt.ask(
311-
"\nEnter the index of the subnet you want to move stake from",
312-
choices=[str(i) for i in range(len(available_netuids))],
309+
origin_netuid = Prompt.ask(
310+
"\nEnter the netuid you want to move stake from",
311+
choices=[str(netuid) for netuid in available_netuids],
313312
)
314-
origin_netuid = available_netuids[int(netuid_idx)]
313+
origin_netuid = int(origin_netuid)
315314
origin_stake = origin_hotkey_info["stakes"][origin_netuid]
316315

317316
# Ask for amount to move
@@ -334,104 +333,6 @@ async def stake_move_selection(
334333
}
335334

336335

337-
async def stake_transfer_selection(
338-
wallet: Wallet, subtensor: "SubtensorInterface", origin_hotkey: str
339-
):
340-
"""Selection interface for transferring stakes."""
341-
(
342-
stakes,
343-
all_netuids,
344-
all_subnets,
345-
) = await asyncio.gather(
346-
subtensor.get_stake_for_coldkey(coldkey_ss58=wallet.coldkeypub.ss58_address),
347-
subtensor.get_all_subnet_netuids(),
348-
subtensor.all_subnets(),
349-
)
350-
all_netuids = sorted(all_netuids)
351-
all_subnets = {di.netuid: di for di in all_subnets}
352-
353-
available_stakes = {}
354-
for stake in stakes:
355-
if stake.stake.tao > 0 and stake.hotkey_ss58 == origin_hotkey:
356-
available_stakes[stake.netuid] = {
357-
"hotkey_ss58": stake.hotkey_ss58,
358-
"stake": stake.stake,
359-
"is_registered": stake.is_registered,
360-
}
361-
362-
if not available_stakes:
363-
console.print("[red]No stakes available to transfer.[/red]")
364-
return None
365-
366-
table = Table(
367-
title=(
368-
f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]"
369-
f"Available Stakes to Transfer\n"
370-
f"for wallet hotkey:\n"
371-
f"[{COLOR_PALETTE['GENERAL']['HOTKEY']}]{wallet.hotkey_str}: {wallet.hotkey.ss58_address}"
372-
f"[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n"
373-
),
374-
show_edge=False,
375-
header_style="bold white",
376-
border_style="bright_black",
377-
title_justify="center",
378-
width=len(wallet.hotkey_str + wallet.hotkey.ss58_address) + 10,
379-
)
380-
381-
table.add_column("Index", justify="right", style="cyan")
382-
table.add_column("Netuid")
383-
table.add_column("Name", style="cyan", justify="left")
384-
table.add_column("Stake Amount", style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"])
385-
table.add_column("Registered", justify="center")
386-
387-
for idx, (netuid, stake_info) in enumerate(available_stakes.items()):
388-
subnet_name_cell = (
389-
f"[{COLOR_PALETTE['GENERAL']['SYMBOL']}]{all_subnets[netuid].symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE['GENERAL']['SYMBOL']}]"
390-
f" {get_subnet_name(all_subnets[netuid])}"
391-
)
392-
table.add_row(
393-
str(idx),
394-
str(netuid),
395-
subnet_name_cell,
396-
str(stake_info["stake"]),
397-
"[dark_sea_green3]YES"
398-
if stake_info["is_registered"]
399-
else f"[{COLOR_PALETTE['STAKE']['NOT_REGISTERED']}]NO",
400-
)
401-
402-
console.print(table)
403-
404-
if not available_stakes:
405-
console.print("[red]No stakes available to transfer.[/red]")
406-
return None
407-
408-
# Prompt to select index of stake to transfer
409-
selection = Prompt.ask(
410-
"\nEnter the index of the stake you want to transfer",
411-
choices=[str(i) for i in range(len(available_stakes))],
412-
)
413-
selected_netuid = list(available_stakes.keys())[int(selection)]
414-
selected_stake = available_stakes[selected_netuid]
415-
416-
# Prompt for amount
417-
stake_balance = selected_stake["stake"]
418-
amount, _ = prompt_stake_amount(stake_balance, selected_netuid, "transfer")
419-
420-
# Prompt for destination subnet
421-
destination_netuid = Prompt.ask(
422-
"\nEnter the netuid of the subnet you want to move stake to"
423-
+ f" ([dim]{group_subnets(all_netuids)}[/dim])",
424-
choices=[str(netuid) for netuid in all_netuids],
425-
show_choices=False,
426-
)
427-
428-
return {
429-
"origin_netuid": selected_netuid,
430-
"amount": amount.tao,
431-
"destination_netuid": int(destination_netuid),
432-
}
433-
434-
435336
async def stake_swap_selection(
436337
subtensor: "SubtensorInterface",
437338
wallet: Wallet,
@@ -540,7 +441,7 @@ async def move_stake(
540441
prompt: bool = True,
541442
):
542443
if interactive_selection:
543-
selection = await stake_move_selection(subtensor, wallet)
444+
selection = await stake_move_transfer_selection(subtensor, wallet)
544445
origin_hotkey = selection["origin_hotkey"]
545446
origin_netuid = selection["origin_netuid"]
546447
amount = selection["amount"]
@@ -699,6 +600,7 @@ async def transfer_stake(
699600
dest_netuid: int,
700601
dest_coldkey_ss58: str,
701602
interactive_selection: bool = False,
603+
stake_all: bool = False,
702604
prompt: bool = True,
703605
) -> bool:
704606
"""Transfers stake from one network to another.
@@ -717,12 +619,13 @@ async def transfer_stake(
717619
Returns:
718620
bool: True if transfer was successful, False otherwise.
719621
"""
720-
origin_hotkey = origin_hotkey or wallet.hotkey.ss58_address
721622
if interactive_selection:
722-
selection = await stake_transfer_selection(wallet, subtensor, origin_hotkey)
623+
selection = await stake_move_transfer_selection(subtensor, wallet)
723624
origin_netuid = selection["origin_netuid"]
724625
amount = selection["amount"]
725626
dest_netuid = selection["destination_netuid"]
627+
stake_all = selection["stake_all"]
628+
origin_hotkey = selection["origin_hotkey"]
726629

727630
# Check if both subnets exist
728631
block_hash = await subtensor.substrate.get_chain_head()
@@ -750,7 +653,22 @@ async def transfer_stake(
750653
hotkey_ss58=origin_hotkey,
751654
netuid=dest_netuid,
752655
)
753-
amount_to_transfer = Balance.from_tao(amount).set_unit(origin_netuid)
656+
657+
if current_stake.tao == 0:
658+
err_console.print(
659+
f"[red]No stake found for hotkey: {origin_hotkey} on netuid: {origin_netuid}[/red]"
660+
)
661+
return False
662+
663+
amount_to_transfer = None
664+
if amount:
665+
amount_to_transfer = Balance.from_tao(amount).set_unit(origin_netuid)
666+
elif stake_all:
667+
amount_to_transfer = current_stake
668+
else:
669+
amount_to_transfer, _ = prompt_stake_amount(
670+
current_stake, origin_netuid, "transfer"
671+
)
754672

755673
# Check if enough stake to transfer
756674
if amount_to_transfer > current_stake:

0 commit comments

Comments
 (0)