Skip to content

Commit 7d1589b

Browse files
committed
Stake movement
1 parent 990912f commit 7d1589b

File tree

4 files changed

+217
-89
lines changed

4 files changed

+217
-89
lines changed

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import aiohttp
66
from async_substrate_interface.utils.storage import StorageKey
77
from bittensor_wallet import Wallet
8+
from bittensor_wallet.bittensor_wallet import Keypair
89
from bittensor_wallet.utils import SS58_FORMAT
910
from scalecodec import GenericCall
1011
from async_substrate_interface.errors import SubstrateRequestException
@@ -1488,7 +1489,7 @@ async def get_owned_hotkeys(
14881489

14891490
return [decode_account_id(hotkey[0]) for hotkey in owned_hotkeys or []]
14901491

1491-
async def get_extrinsic_fee(self, call, keypair) -> Balance:
1492+
async def get_extrinsic_fee(self, call: GenericCall, keypair: Keypair) -> Balance:
14921493
fee_dict = await self.substrate.get_payment_info(call, keypair)
14931494
return Balance.from_rao(fee_dict["partial_fee"])
14941495

bittensor_cli/src/commands/stake/add.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ def _define_stake_table(
629629
table.add_column(
630630
"Extrinsic Fee (τ)",
631631
justify="center",
632-
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
632+
style=COLOR_PALETTE.STAKE.TAO,
633633
)
634634
# TODO: Uncomment when slippage is reimplemented for v3
635635
# table.add_column(

bittensor_cli/src/commands/stake/move.py

Lines changed: 101 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ async def display_stake_movement_cross_subnets(
3333
destination_hotkey: str,
3434
amount_to_move: Balance,
3535
stake_fee: Balance,
36+
extrinsic_fee: Balance,
3637
) -> tuple[Balance, str]:
3738
"""Calculate and display stake movement information"""
3839

3940
if origin_netuid == destination_netuid:
4041
subnet = await subtensor.subnet(origin_netuid)
41-
received_amount_tao = subnet.alpha_to_tao(amount_to_move - stake_fee)
42+
received_amount_tao = (
43+
subnet.alpha_to_tao(amount_to_move - stake_fee) - extrinsic_fee
44+
)
4245
received_amount = subnet.tao_to_alpha(received_amount_tao)
4346

4447
if received_amount < Balance.from_tao(0).set_unit(destination_netuid):
@@ -62,7 +65,9 @@ async def display_stake_movement_cross_subnets(
6265
price_destination = dynamic_destination.price.tao
6366
rate = price_origin / (price_destination or 1)
6467

65-
received_amount_tao = dynamic_origin.alpha_to_tao(amount_to_move - stake_fee)
68+
received_amount_tao = (
69+
dynamic_origin.alpha_to_tao(amount_to_move - stake_fee) - extrinsic_fee
70+
)
6671
received_amount = dynamic_destination.tao_to_alpha(received_amount_tao)
6772
received_amount.set_unit(destination_netuid)
6873

@@ -81,14 +86,14 @@ async def display_stake_movement_cross_subnets(
8186
# Create and display table
8287
table = Table(
8388
title=(
84-
f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]"
89+
f"\n[{COLOR_PALETTE.G.HEADER}]"
8590
f"Moving stake from: "
86-
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{Balance.get_unit(origin_netuid)}(Netuid: {origin_netuid})"
87-
f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}] "
91+
f"[{COLOR_PALETTE.G.SUBHEAD}]{Balance.get_unit(origin_netuid)}(Netuid: {origin_netuid})"
92+
f"[/{COLOR_PALETTE.G.SUBHEAD}] "
8893
f"to: "
89-
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{Balance.get_unit(destination_netuid)}(Netuid: {destination_netuid})"
90-
f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]\nNetwork: {subtensor.network}\n"
91-
f"[/{COLOR_PALETTE['GENERAL']['HEADER']}]"
94+
f"[{COLOR_PALETTE.G.SUBHEAD}]{Balance.get_unit(destination_netuid)}(Netuid: {destination_netuid})"
95+
f"[/{COLOR_PALETTE.G.SUBHEAD}]\nNetwork: {subtensor.network}\n"
96+
f"[/{COLOR_PALETTE.G.HEADER}]"
9297
),
9398
show_footer=True,
9499
show_edge=False,
@@ -132,6 +137,9 @@ async def display_stake_movement_cross_subnets(
132137
justify="center",
133138
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
134139
)
140+
table.add_column(
141+
"Extrinsic Fee (τ)", justify="center", style=COLOR_PALETTE.STAKE.TAO
142+
)
135143

136144
table.add_row(
137145
f"{Balance.get_unit(origin_netuid)}({origin_netuid})",
@@ -142,6 +150,7 @@ async def display_stake_movement_cross_subnets(
142150
price_str,
143151
str(received_amount),
144152
str(stake_fee.set_unit(origin_netuid)),
153+
str(extrinsic_fee),
145154
)
146155

147156
console.print(table)
@@ -165,10 +174,10 @@ def prompt_stake_amount(
165174
while True:
166175
amount_input = Prompt.ask(
167176
f"\nEnter the amount to {action_name} "
168-
f"[{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{Balance.get_unit(netuid)}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}] "
169-
f"[{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}](max: {current_balance})[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}] "
177+
f"[{COLOR_PALETTE.S.STAKE_AMOUNT}]{Balance.get_unit(netuid)}[/{COLOR_PALETTE.S.STAKE_AMOUNT}] "
178+
f"[{COLOR_PALETTE.S.STAKE_AMOUNT}](max: {current_balance})[/{COLOR_PALETTE.S.STAKE_AMOUNT}] "
170179
f"or "
171-
f"[{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]'all'[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}] "
180+
f"[{COLOR_PALETTE.S.STAKE_AMOUNT}]'all'[/{COLOR_PALETTE.S.STAKE_AMOUNT}] "
172181
f"for entire balance"
173182
)
174183

@@ -183,7 +192,7 @@ def prompt_stake_amount(
183192
if amount > current_balance.tao:
184193
console.print(
185194
f"[red]Amount exceeds available balance of "
186-
f"[{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{current_balance}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]"
195+
f"[{COLOR_PALETTE.S.STAKE_AMOUNT}]{current_balance}[/{COLOR_PALETTE.S.STAKE_AMOUNT}]"
187196
f"[/red]"
188197
)
189198
continue
@@ -270,16 +279,16 @@ async def stake_move_transfer_selection(
270279

271280
# Display available netuids for selected hotkey
272281
table = Table(
273-
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Available Stakes for Hotkey\n[/{COLOR_PALETTE['GENERAL']['HEADER']}]"
274-
f"[{COLOR_PALETTE['GENERAL']['HOTKEY']}]{origin_hotkey_ss58}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n",
282+
title=f"\n[{COLOR_PALETTE.G.HEADER}]Available Stakes for Hotkey\n[/{COLOR_PALETTE.G.HEADER}]"
283+
f"[{COLOR_PALETTE.G.HK}]{origin_hotkey_ss58}[/{COLOR_PALETTE.G.HK}]\n",
275284
show_edge=False,
276285
header_style="bold white",
277286
border_style="bright_black",
278287
title_justify="center",
279288
width=len(origin_hotkey_ss58) + 20,
280289
)
281290
table.add_column("Netuid", style="cyan")
282-
table.add_column("Stake Amount", style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"])
291+
table.add_column("Stake Amount", style=COLOR_PALETTE.STAKE.STAKE_AMOUNT)
283292

284293
available_netuids = []
285294
for netuid in origin_hotkey_info["netuids"]:
@@ -347,8 +356,8 @@ async def stake_swap_selection(
347356

348357
# Display available stakes
349358
table = Table(
350-
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Available Stakes for Hotkey\n[/{COLOR_PALETTE['GENERAL']['HEADER']}]"
351-
f"[{COLOR_PALETTE['GENERAL']['HOTKEY']}]{wallet.hotkey_str}: {wallet.hotkey.ss58_address}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n",
359+
title=f"\n[{COLOR_PALETTE.G.HEADER}]Available Stakes for Hotkey\n[/{COLOR_PALETTE.G.HEADER}]"
360+
f"[{COLOR_PALETTE.G.HK}]{wallet.hotkey_str}: {wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}]\n",
352361
show_edge=False,
353362
header_style="bold white",
354363
border_style="bright_black",
@@ -366,7 +375,7 @@ async def stake_swap_selection(
366375
for idx, (netuid, stake_info) in enumerate(sorted(hotkey_stakes.items())):
367376
subnet_info = subnet_dict[netuid]
368377
subnet_name_cell = (
369-
f"[{COLOR_PALETTE['GENERAL']['SYMBOL']}]{subnet_info.symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE['GENERAL']['SYMBOL']}]"
378+
f"[{COLOR_PALETTE.G.SYM}]{subnet_info.symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE.G.SYM}]"
370379
f" {get_subnet_name(subnet_info)}"
371380
)
372381

@@ -498,14 +507,28 @@ async def move_stake(
498507
)
499508
return False
500509

501-
stake_fee = await subtensor.get_stake_fee(
502-
origin_hotkey_ss58=origin_hotkey,
503-
origin_netuid=origin_netuid,
504-
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
505-
destination_hotkey_ss58=destination_hotkey,
506-
destination_netuid=destination_netuid,
507-
destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
508-
amount=amount_to_move_as_balance.rao,
510+
call = await subtensor.substrate.compose_call(
511+
call_module="SubtensorModule",
512+
call_function="move_stake",
513+
call_params={
514+
"origin_hotkey": origin_hotkey,
515+
"origin_netuid": origin_netuid,
516+
"destination_hotkey": destination_hotkey,
517+
"destination_netuid": destination_netuid,
518+
"alpha_amount": amount_to_move_as_balance.rao,
519+
},
520+
)
521+
stake_fee, extrinsic_fee = await asyncio.gather(
522+
subtensor.get_stake_fee(
523+
origin_hotkey_ss58=origin_hotkey,
524+
origin_netuid=origin_netuid,
525+
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
526+
destination_hotkey_ss58=destination_hotkey,
527+
destination_netuid=destination_netuid,
528+
destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
529+
amount=amount_to_move_as_balance.rao,
530+
),
531+
subtensor.get_extrinsic_fee(call, wallet.coldkeypub),
509532
)
510533

511534
# Display stake movement details
@@ -519,6 +542,7 @@ async def move_stake(
519542
destination_hotkey=destination_hotkey,
520543
amount_to_move=amount_to_move_as_balance,
521544
stake_fee=stake_fee,
545+
extrinsic_fee=extrinsic_fee,
522546
)
523547
except ValueError:
524548
return False
@@ -529,20 +553,10 @@ async def move_stake(
529553
if not unlock_key(wallet).success:
530554
return False
531555
with console.status(
532-
f"\n:satellite: Moving [blue]{amount_to_move_as_balance}[/blue] from [blue]{origin_hotkey}[/blue] on netuid: [blue]{origin_netuid}[/blue] \nto "
556+
f"\n:satellite: Moving [blue]{amount_to_move_as_balance}[/blue] from [blue]{origin_hotkey}[/blue] on netuid: "
557+
f"[blue]{origin_netuid}[/blue] \nto "
533558
f"[blue]{destination_hotkey}[/blue] on netuid: [blue]{destination_netuid}[/blue] ..."
534559
):
535-
call = await subtensor.substrate.compose_call(
536-
call_module="SubtensorModule",
537-
call_function="move_stake",
538-
call_params={
539-
"origin_hotkey": origin_hotkey,
540-
"origin_netuid": origin_netuid,
541-
"destination_hotkey": destination_hotkey,
542-
"destination_netuid": destination_netuid,
543-
"alpha_amount": amount_to_move_as_balance.rao,
544-
},
545-
)
546560
extrinsic = await subtensor.substrate.create_signed_extrinsic(
547561
call=call, keypair=wallet.coldkey, era={"period": era}
548562
)
@@ -677,19 +691,33 @@ async def transfer_stake(
677691
if amount_to_transfer > current_stake:
678692
err_console.print(
679693
f"[red]Not enough stake to transfer[/red]:\n"
680-
f"Stake balance: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{current_stake}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}] < "
681-
f"Transfer amount: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{amount_to_transfer}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]"
694+
f"Stake balance: [{COLOR_PALETTE.S.STAKE_AMOUNT}]{current_stake}[/{COLOR_PALETTE.S.STAKE_AMOUNT}] < "
695+
f"Transfer amount: [{COLOR_PALETTE.S.STAKE_AMOUNT}]{amount_to_transfer}[/{COLOR_PALETTE.S.STAKE_AMOUNT}]"
682696
)
683697
return False
684698

685-
stake_fee = await subtensor.get_stake_fee(
686-
origin_hotkey_ss58=origin_hotkey,
687-
origin_netuid=origin_netuid,
688-
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
689-
destination_hotkey_ss58=origin_hotkey,
690-
destination_netuid=dest_netuid,
691-
destination_coldkey_ss58=dest_coldkey_ss58,
692-
amount=amount_to_transfer.rao,
699+
call = await subtensor.substrate.compose_call(
700+
call_module="SubtensorModule",
701+
call_function="transfer_stake",
702+
call_params={
703+
"destination_coldkey": dest_coldkey_ss58,
704+
"hotkey": origin_hotkey,
705+
"origin_netuid": origin_netuid,
706+
"destination_netuid": dest_netuid,
707+
"alpha_amount": amount_to_transfer.rao,
708+
},
709+
)
710+
stake_fee, extrinsic_fee = await asyncio.gather(
711+
subtensor.get_stake_fee(
712+
origin_hotkey_ss58=origin_hotkey,
713+
origin_netuid=origin_netuid,
714+
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
715+
destination_hotkey_ss58=origin_hotkey,
716+
destination_netuid=dest_netuid,
717+
destination_coldkey_ss58=dest_coldkey_ss58,
718+
amount=amount_to_transfer.rao,
719+
),
720+
subtensor.get_extrinsic_fee(call, wallet.coldkeypub),
693721
)
694722

695723
# Display stake movement details
@@ -703,6 +731,7 @@ async def transfer_stake(
703731
destination_hotkey=origin_hotkey,
704732
amount_to_move=amount_to_transfer,
705733
stake_fee=stake_fee,
734+
extrinsic_fee=extrinsic_fee,
706735
)
707736
except ValueError:
708737
return False
@@ -715,18 +744,6 @@ async def transfer_stake(
715744
return False
716745

717746
with console.status("\n:satellite: Transferring stake ..."):
718-
call = await subtensor.substrate.compose_call(
719-
call_module="SubtensorModule",
720-
call_function="transfer_stake",
721-
call_params={
722-
"destination_coldkey": dest_coldkey_ss58,
723-
"hotkey": origin_hotkey,
724-
"origin_netuid": origin_netuid,
725-
"destination_netuid": dest_netuid,
726-
"alpha_amount": amount_to_transfer.rao,
727-
},
728-
)
729-
730747
extrinsic = await subtensor.substrate.create_signed_extrinsic(
731748
call=call, keypair=wallet.coldkey, era={"period": era}
732749
)
@@ -846,19 +863,32 @@ async def swap_stake(
846863
if amount_to_swap > current_stake:
847864
err_console.print(
848865
f"[red]Not enough stake to swap[/red]:\n"
849-
f"Stake balance: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{current_stake}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}] < "
850-
f"Swap amount: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{amount_to_swap}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]"
866+
f"Stake balance: [{COLOR_PALETTE.S.STAKE_AMOUNT}]{current_stake}[/{COLOR_PALETTE.S.STAKE_AMOUNT}] < "
867+
f"Swap amount: [{COLOR_PALETTE.S.STAKE_AMOUNT}]{amount_to_swap}[/{COLOR_PALETTE.S.STAKE_AMOUNT}]"
851868
)
852869
return False
853870

854-
stake_fee = await subtensor.get_stake_fee(
855-
origin_hotkey_ss58=hotkey_ss58,
856-
origin_netuid=origin_netuid,
857-
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
858-
destination_hotkey_ss58=hotkey_ss58,
859-
destination_netuid=destination_netuid,
860-
destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
861-
amount=amount_to_swap.rao,
871+
call = await subtensor.substrate.compose_call(
872+
call_module="SubtensorModule",
873+
call_function="swap_stake",
874+
call_params={
875+
"hotkey": hotkey_ss58,
876+
"origin_netuid": origin_netuid,
877+
"destination_netuid": destination_netuid,
878+
"alpha_amount": amount_to_swap.rao,
879+
},
880+
)
881+
stake_fee, extrinsic_fee = await asyncio.gather(
882+
subtensor.get_stake_fee(
883+
origin_hotkey_ss58=hotkey_ss58,
884+
origin_netuid=origin_netuid,
885+
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
886+
destination_hotkey_ss58=hotkey_ss58,
887+
destination_netuid=destination_netuid,
888+
destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
889+
amount=amount_to_swap.rao,
890+
),
891+
subtensor.get_extrinsic_fee(call, wallet.coldkeypub),
862892
)
863893

864894
# Display stake movement details
@@ -872,6 +902,7 @@ async def swap_stake(
872902
destination_hotkey=hotkey_ss58,
873903
amount_to_move=amount_to_swap,
874904
stake_fee=stake_fee,
905+
extrinsic_fee=extrinsic_fee,
875906
)
876907
except ValueError:
877908
return False
@@ -887,17 +918,6 @@ async def swap_stake(
887918
f"\n:satellite: Swapping stake from netuid [blue]{origin_netuid}[/blue] "
888919
f"to netuid [blue]{destination_netuid}[/blue]..."
889920
):
890-
call = await subtensor.substrate.compose_call(
891-
call_module="SubtensorModule",
892-
call_function="swap_stake",
893-
call_params={
894-
"hotkey": hotkey_ss58,
895-
"origin_netuid": origin_netuid,
896-
"destination_netuid": destination_netuid,
897-
"alpha_amount": amount_to_swap.rao,
898-
},
899-
)
900-
901921
extrinsic = await subtensor.substrate.create_signed_extrinsic(
902922
call=call, keypair=wallet.coldkey, era={"period": era}
903923
)

0 commit comments

Comments
 (0)