1
1
#!/usr/bin/env python3
2
2
import asyncio
3
3
import curses
4
+ import copy
4
5
import importlib
5
6
import json
6
7
import os .path
10
11
import traceback
11
12
import warnings
12
13
from pathlib import Path
13
- from typing import Coroutine , Optional
14
+ from typing import Coroutine , Optional , Union
14
15
from dataclasses import fields
15
16
16
17
import rich
@@ -89,6 +90,23 @@ class Options:
89
90
Re-usable typer args
90
91
"""
91
92
93
+ @classmethod
94
+ def edit_help (cls , option_name : str , help_text : str ):
95
+ """
96
+ Edits the `help` attribute of a copied given Typer option in this class, returning
97
+ the modified Typer option.
98
+
99
+ Args:
100
+ option_name: the name of the option (e.g. "wallet_name")
101
+ help_text: New help text to be used (e.g. "Wallet's name")
102
+
103
+ Returns:
104
+ Modified Typer Option with new help text.
105
+ """
106
+ copied_attr = copy .copy (getattr (cls , option_name ))
107
+ setattr (copied_attr , "help" , help_text )
108
+ return copied_attr
109
+
92
110
wallet_name = typer .Option (
93
111
None ,
94
112
"--wallet-name" ,
@@ -3202,7 +3220,11 @@ def stake_add(
3202
3220
help = "When set, this command stakes to all hotkeys associated with the wallet. Do not use if specifying "
3203
3221
"hotkeys in `--include-hotkeys`." ,
3204
3222
),
3205
- netuid : Optional [int ] = Options .netuid_not_req ,
3223
+ netuids : Optional [str ] = Options .edit_help (
3224
+ "netuids" ,
3225
+ "Netuid(s) to for which to add stake. Specify multiple netuids by separating with a comma, e.g."
3226
+ "`btcli st add -n 1,2,3" ,
3227
+ ),
3206
3228
all_netuids : bool = Options .all_netuids ,
3207
3229
wallet_name : str = Options .wallet_name ,
3208
3230
wallet_path : str = Options .wallet_path ,
@@ -3242,52 +3264,76 @@ def stake_add(
3242
3264
6. Stake all balance to a subnet:
3243
3265
[green]$[/green] btcli stake add --all --netuid 3
3244
3266
3267
+ 7. Stake the same amount to multiple subnets:
3268
+ [green]$[/green] btcli stake add --amount 100 --netuids 4,5,6
3269
+
3245
3270
[bold]Safe Staking Parameters:[/bold]
3246
3271
• [blue]--safe[/blue]: Enables rate tolerance checks
3247
3272
• [blue]--tolerance[/blue]: Maximum % rate change allowed (0.05 = 5%)
3248
3273
• [blue]--partial[/blue]: Complete partial stake if rates exceed tolerance
3249
3274
3250
3275
"""
3276
+ netuids = netuids or []
3251
3277
self .verbosity_handler (quiet , verbose , json_output )
3252
3278
safe_staking = self .ask_safe_staking (safe_staking )
3253
3279
if safe_staking :
3254
3280
rate_tolerance = self .ask_rate_tolerance (rate_tolerance )
3255
3281
allow_partial_stake = self .ask_partial_stake (allow_partial_stake )
3256
3282
console .print ("\n " )
3257
- netuid = get_optional_netuid (netuid , all_netuids )
3283
+
3284
+ if netuids :
3285
+ netuids = parse_to_list (
3286
+ netuids , int , "Netuids must be ints separated by commas" , False
3287
+ )
3288
+ else :
3289
+ netuid_ = get_optional_netuid (None , all_netuids )
3290
+ netuids = [netuid_ ] if netuid_ else None
3291
+ if netuids :
3292
+ for netuid_ in netuids :
3293
+ # ensure no negative netuids make it into our list
3294
+ validate_netuid (netuid_ )
3258
3295
3259
3296
if stake_all and amount :
3260
3297
print_error (
3261
3298
"Cannot specify an amount and 'stake-all'. Choose one or the other."
3262
3299
)
3263
- raise typer . Exit ()
3300
+ return
3264
3301
3265
3302
if stake_all and not amount :
3266
3303
if not Confirm .ask ("Stake all the available TAO tokens?" , default = False ):
3267
- raise typer .Exit ()
3304
+ return
3305
+
3306
+ if (
3307
+ stake_all
3308
+ and (isinstance (netuids , list ) and len (netuids ) > 1 )
3309
+ or (netuids is None )
3310
+ ):
3311
+ print_error ("Cannot stake all to multiple subnets." )
3312
+ return
3268
3313
3269
3314
if all_hotkeys and include_hotkeys :
3270
3315
print_error (
3271
3316
"You have specified hotkeys to include and also the `--all-hotkeys` flag. The flag"
3272
3317
"should only be used standalone (to use all hotkeys) or with `--exclude-hotkeys`."
3273
3318
)
3274
- raise typer . Exit ()
3319
+ return
3275
3320
3276
3321
if include_hotkeys and exclude_hotkeys :
3277
3322
print_error (
3278
3323
"You have specified options for both including and excluding hotkeys. Select one or the other."
3279
3324
)
3280
- raise typer . Exit ()
3325
+ return
3281
3326
3282
3327
if not wallet_hotkey and not all_hotkeys and not include_hotkeys :
3283
3328
if not wallet_name :
3284
3329
wallet_name = Prompt .ask (
3285
3330
"Enter the [blue]wallet name[/blue]" ,
3286
3331
default = self .config .get ("wallet_name" ) or defaults .wallet .name ,
3287
3332
)
3288
- if netuid is not None :
3333
+ if netuids is not None :
3289
3334
hotkey_or_ss58 = Prompt .ask (
3290
- "Enter the [blue]wallet hotkey[/blue] name or [blue]ss58 address[/blue] to stake to [dim](or Press Enter to view delegates)[/dim]" ,
3335
+ "Enter the [blue]wallet hotkey[/blue] name or [blue]ss58 address[/blue] to stake to [dim]"
3336
+ "(or Press Enter to view delegates)[/dim]" ,
3291
3337
)
3292
3338
else :
3293
3339
hotkey_or_ss58 = Prompt .ask (
@@ -3299,10 +3345,18 @@ def stake_add(
3299
3345
wallet = self .wallet_ask (
3300
3346
wallet_name , wallet_path , wallet_hotkey , ask_for = [WO .NAME , WO .PATH ]
3301
3347
)
3348
+ if len (netuids ) > 1 :
3349
+ netuid_ = IntPrompt .ask (
3350
+ "Enter the netuid for which to show delegates" ,
3351
+ choices = [str (x ) for x in netuids ],
3352
+ )
3353
+ else :
3354
+ netuid_ = netuids [0 ]
3355
+
3302
3356
selected_hotkey = self ._run_command (
3303
3357
subnets .show (
3304
3358
subtensor = self .initialize_chain (network ),
3305
- netuid = netuid ,
3359
+ netuid = netuid_ ,
3306
3360
sort = False ,
3307
3361
max_rows = 12 ,
3308
3362
prompt = False ,
@@ -3312,7 +3366,7 @@ def stake_add(
3312
3366
)
3313
3367
if not selected_hotkey :
3314
3368
print_error ("No delegate selected. Exiting." )
3315
- raise typer . Exit ()
3369
+ return
3316
3370
include_hotkeys = selected_hotkey
3317
3371
elif is_valid_ss58_address (hotkey_or_ss58 ):
3318
3372
wallet = self .wallet_ask (
@@ -3373,8 +3427,8 @@ def stake_add(
3373
3427
)
3374
3428
if free_balance == Balance .from_tao (0 ):
3375
3429
print_error ("You dont have any balance to stake." )
3376
- raise typer . Exit ()
3377
- if netuid is not None :
3430
+ return
3431
+ if netuids :
3378
3432
amount = FloatPrompt .ask (
3379
3433
f"Amount to [{ COLORS .G .SUBHEAD_MAIN } ]stake (TAO τ)"
3380
3434
)
@@ -3396,7 +3450,7 @@ def stake_add(
3396
3450
add_stake .stake_add (
3397
3451
wallet ,
3398
3452
self .initialize_chain (network ),
3399
- netuid ,
3453
+ netuids ,
3400
3454
stake_all ,
3401
3455
amount ,
3402
3456
prompt ,
@@ -4796,12 +4850,9 @@ def subnets_list(
4796
4850
def subnets_price (
4797
4851
self ,
4798
4852
network : Optional [list [str ]] = Options .network ,
4799
- netuids : str = typer .Option (
4800
- None ,
4801
- "--netuids" ,
4802
- "--netuid" ,
4803
- "-n" ,
4804
- help = "Netuid(s) to show the price for." ,
4853
+ netuids : str = Options .edit_help (
4854
+ "netuids" ,
4855
+ "Netuids to show the price for. Separate multiple netuids with a comma, for example: `-n 0,1,2`." ,
4805
4856
),
4806
4857
interval_hours : int = typer .Option (
4807
4858
24 ,
0 commit comments