11import asyncio
2+ import json
3+ from collections import defaultdict
24from functools import partial
35
46from typing import TYPE_CHECKING , Optional
1719 print_error ,
1820 print_verbose ,
1921 unlock_key ,
22+ json_console ,
2023)
2124from bittensor_wallet import Wallet
2225
@@ -38,6 +41,7 @@ async def stake_add(
3841 safe_staking : bool ,
3942 rate_tolerance : float ,
4043 allow_partial_stake : bool ,
44+ json_output : bool ,
4145 era : int ,
4246):
4347 """
@@ -54,6 +58,7 @@ async def stake_add(
5458 safe_staking: whether to use safe staking
5559 rate_tolerance: rate tolerance percentage for stake operations
5660 allow_partial_stake: whether to allow partial stake
61+ json_output: whether to output stake info in JSON format
5762 era: Blocks for which the transaction should be valid.
5863
5964 Returns:
@@ -67,25 +72,25 @@ async def safe_stake_extrinsic(
6772 hotkey_ss58_ : str ,
6873 price_limit : Balance ,
6974 status = None ,
70- ) -> None :
75+ ) -> bool :
7176 err_out = partial (print_error , status = status )
7277 failure_prelude = (
7378 f":cross_mark: [red]Failed[/red] to stake { amount_ } on Netuid { netuid_ } "
7479 )
75- current_balance = await subtensor . get_balance ( wallet . coldkeypub . ss58_address )
76- next_nonce = await subtensor .substrate . get_account_next_index (
77- wallet .coldkeypub .ss58_address
78- )
79- call = await subtensor . substrate . compose_call (
80- call_module = "SubtensorModule " ,
81- call_function = "add_stake_limit" ,
82- call_params = {
83- "hotkey " : hotkey_ss58_ ,
84- "netuid " : netuid_ ,
85- "amount_staked " : amount_ . rao ,
86- "limit_price " : price_limit ,
87- "allow_partial" : allow_partial_stake ,
88- } ,
80+ current_balance , next_nonce , call = await asyncio . gather (
81+ subtensor .get_balance ( wallet . coldkeypub . ss58_address ),
82+ subtensor . substrate . get_account_next_index ( wallet .coldkeypub .ss58_address ),
83+ subtensor . substrate . compose_call (
84+ call_module = "SubtensorModule" ,
85+ call_function = "add_stake_limit " ,
86+ call_params = {
87+ "hotkey" : hotkey_ss58_ ,
88+ "netuid " : netuid_ ,
89+ "amount_staked " : amount_ . rao ,
90+ "limit_price " : price_limit ,
91+ "allow_partial " : allow_partial_stake ,
92+ } ,
93+ ) ,
8994 )
9095 extrinsic = await subtensor .substrate .create_signed_extrinsic (
9196 call = call ,
@@ -105,70 +110,78 @@ async def safe_stake_extrinsic(
105110 f"Either increase price tolerance or enable partial staking." ,
106111 status = status ,
107112 )
108- return
113+ return False
109114 else :
110115 err_out (f"\n { failure_prelude } with error: { format_error_message (e )} " )
111- return
116+ return False
117+ if not await response .is_success :
118+ err_out (
119+ f"\n { failure_prelude } with error: { format_error_message (await response .error_message )} "
120+ )
121+ return False
112122 else :
113- if not await response .is_success :
114- err_out (
115- f"\n { failure_prelude } with error: { format_error_message (await response .error_message )} "
116- )
117- else :
118- block_hash = await subtensor .substrate .get_chain_head ()
119- new_balance , new_stake = await asyncio .gather (
120- subtensor .get_balance (wallet .coldkeypub .ss58_address , block_hash ),
121- subtensor .get_stake (
122- hotkey_ss58 = hotkey_ss58_ ,
123- coldkey_ss58 = wallet .coldkeypub .ss58_address ,
124- netuid = netuid_ ,
125- block_hash = block_hash ,
126- ),
127- )
128- console .print (
129- f":white_heavy_check_mark: [dark_sea_green3]Finalized. Stake added to netuid: { netuid_ } [/dark_sea_green3]"
130- )
131- console .print (
132- f"Balance:\n [blue]{ current_balance } [/blue] :arrow_right: [{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ new_balance } "
133- )
134-
135- amount_staked = current_balance - new_balance
136- if allow_partial_stake and (amount_staked != amount_ ):
137- console .print (
138- "Partial stake transaction. Staked:\n "
139- f" [{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ amount_staked } [/{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ] "
140- f"instead of "
141- f"[blue]{ amount_ } [/blue]"
142- )
123+ if json_output :
124+ # the rest of this checking is not necessary if using json_output
125+ return True
126+ block_hash = await subtensor .substrate .get_chain_head ()
127+ new_balance , new_stake = await asyncio .gather (
128+ subtensor .get_balance (wallet .coldkeypub .ss58_address , block_hash ),
129+ subtensor .get_stake (
130+ hotkey_ss58 = hotkey_ss58_ ,
131+ coldkey_ss58 = wallet .coldkeypub .ss58_address ,
132+ netuid = netuid_ ,
133+ block_hash = block_hash ,
134+ ),
135+ )
136+ console .print (
137+ f":white_heavy_check_mark: [dark_sea_green3]Finalized. "
138+ f"Stake added to netuid: { netuid_ } [/dark_sea_green3]"
139+ )
140+ console .print (
141+ f"Balance:\n [blue]{ current_balance } [/blue] :arrow_right: "
142+ f"[{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ new_balance } "
143+ )
143144
145+ amount_staked = current_balance - new_balance
146+ if allow_partial_stake and (amount_staked != amount_ ):
144147 console .print (
145- f"Subnet: [ { COLOR_PALETTE [ 'GENERAL' ][ 'SUBHEADING' ] } ] { netuid_ } [/ { COLOR_PALETTE [ 'GENERAL' ][ 'SUBHEADING' ] } ] "
146- f"Stake: \n "
147- f" [blue] { current_stake } [/blue ] "
148- f":arrow_right: "
149- f"[{ COLOR_PALETTE [ 'STAKE' ][ 'STAKE_AMOUNT' ] } ] { new_stake } \n "
148+ "Partial stake transaction. Staked: \n "
149+ f" [ { COLOR_PALETTE [ 'STAKE' ][ 'STAKE_AMOUNT' ] } ] { amount_staked } "
150+ f"[/ { COLOR_PALETTE [ 'STAKE' ][ 'STAKE_AMOUNT' ] } ] "
151+ f"instead of "
152+ f"[blue] { amount_ } [/blue] "
150153 )
151154
155+ console .print (
156+ f"Subnet: [{ COLOR_PALETTE ['GENERAL' ]['SUBHEADING' ]} ]"
157+ f"{ netuid_ } [/{ COLOR_PALETTE ['GENERAL' ]['SUBHEADING' ]} ] "
158+ f"Stake:\n "
159+ f" [blue]{ current_stake } [/blue] "
160+ f":arrow_right: "
161+ f"[{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ new_stake } \n "
162+ )
163+ return True
164+
152165 async def stake_extrinsic (
153166 netuid_i , amount_ , current , staking_address_ss58 , status = None
154- ):
167+ ) -> bool :
155168 err_out = partial (print_error , status = status )
156- current_balance = await subtensor .get_balance (wallet .coldkeypub .ss58_address )
169+ current_balance , next_nonce , call = await asyncio .gather (
170+ subtensor .get_balance (wallet .coldkeypub .ss58_address ),
171+ subtensor .substrate .get_account_next_index (wallet .coldkeypub .ss58_address ),
172+ subtensor .substrate .compose_call (
173+ call_module = "SubtensorModule" ,
174+ call_function = "add_stake" ,
175+ call_params = {
176+ "hotkey" : staking_address_ss58 ,
177+ "netuid" : netuid_i ,
178+ "amount_staked" : amount_ .rao ,
179+ },
180+ ),
181+ )
157182 failure_prelude = (
158183 f":cross_mark: [red]Failed[/red] to stake { amount } on Netuid { netuid_i } "
159184 )
160- next_nonce = await subtensor .substrate .get_account_next_index (
161- wallet .coldkeypub .ss58_address
162- )
163- call = await subtensor .substrate .compose_call (
164- call_module = "SubtensorModule" ,
165- call_function = "add_stake" ,
166- call_params = {
167- "hotkey" : staking_address_ss58 ,
168- "netuid" : netuid_i ,
169- "amount_staked" : amount_ .rao ,
170- },
171- )
172185 extrinsic = await subtensor .substrate .create_signed_extrinsic (
173186 call = call , keypair = wallet .coldkey , nonce = next_nonce , era = {"period" : era }
174187 )
@@ -178,35 +191,46 @@ async def stake_extrinsic(
178191 )
179192 except SubstrateRequestException as e :
180193 err_out (f"\n { failure_prelude } with error: { format_error_message (e )} " )
181- return
194+ return False
182195 else :
183- await response .process_events ()
184196 if not await response .is_success :
185197 err_out (
186198 f"\n { failure_prelude } with error: { format_error_message (await response .error_message )} "
187199 )
200+ return False
188201 else :
202+ if json_output :
203+ # the rest of this is not necessary if using json_output
204+ return True
205+ new_block_hash = await subtensor .substrate .get_chain_head ()
189206 new_balance , new_stake = await asyncio .gather (
190- subtensor .get_balance (wallet .coldkeypub .ss58_address ),
207+ subtensor .get_balance (
208+ wallet .coldkeypub .ss58_address , block_hash = new_block_hash
209+ ),
191210 subtensor .get_stake (
192211 hotkey_ss58 = staking_address_ss58 ,
193212 coldkey_ss58 = wallet .coldkeypub .ss58_address ,
194213 netuid = netuid_i ,
214+ block_hash = new_block_hash ,
195215 ),
196216 )
197217 console .print (
198- f":white_heavy_check_mark: [dark_sea_green3]Finalized. Stake added to netuid: { netuid_i } [/dark_sea_green3]"
218+ f":white_heavy_check_mark: "
219+ f"[dark_sea_green3]Finalized. Stake added to netuid: { netuid_i } [/dark_sea_green3]"
199220 )
200221 console .print (
201- f"Balance:\n [blue]{ current_balance } [/blue] :arrow_right: [{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ new_balance } "
222+ f"Balance:\n [blue]{ current_balance } [/blue] :arrow_right: "
223+ f"[{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ new_balance } "
202224 )
203225 console .print (
204- f"Subnet: [{ COLOR_PALETTE ['GENERAL' ]['SUBHEADING' ]} ]{ netuid_i } [/{ COLOR_PALETTE ['GENERAL' ]['SUBHEADING' ]} ] "
226+ f"Subnet: [{ COLOR_PALETTE ['GENERAL' ]['SUBHEADING' ]} ]"
227+ f"{ netuid_i } [/{ COLOR_PALETTE ['GENERAL' ]['SUBHEADING' ]} ] "
205228 f"Stake:\n "
206229 f" [blue]{ current } [/blue] "
207230 f":arrow_right: "
208231 f"[{ COLOR_PALETTE ['STAKE' ]['STAKE_AMOUNT' ]} ]{ new_stake } \n "
209232 )
233+ return True
210234
211235 netuids = (
212236 [int (netuid )]
@@ -337,7 +361,9 @@ async def stake_extrinsic(
337361 base_row .extend (
338362 [
339363 f"{ rate_with_tolerance } { Balance .get_unit (netuid )} /{ Balance .get_unit (0 )} " ,
340- f"[{ 'dark_sea_green3' if allow_partial_stake else 'red' } ]{ allow_partial_stake } [/{ 'dark_sea_green3' if allow_partial_stake else 'red' } ]" , # safe staking
364+ f"[{ 'dark_sea_green3' if allow_partial_stake else 'red' } ]"
365+ # safe staking
366+ f"{ allow_partial_stake } [/{ 'dark_sea_green3' if allow_partial_stake else 'red' } ]" ,
341367 ]
342368 )
343369
@@ -356,7 +382,7 @@ async def stake_extrinsic(
356382 return False
357383
358384 if safe_staking :
359- stake_coroutines = []
385+ stake_coroutines = {}
360386 for i , (ni , am , curr , price_with_tolerance ) in enumerate (
361387 zip (
362388 netuids , amounts_to_stake , current_stake_balances , prices_with_tolerance
@@ -365,27 +391,23 @@ async def stake_extrinsic(
365391 for _ , staking_address in hotkeys_to_stake_to :
366392 # Regular extrinsic for root subnet
367393 if ni == 0 :
368- stake_coroutines .append (
369- stake_extrinsic (
370- netuid_i = ni ,
371- amount_ = am ,
372- current = curr ,
373- staking_address_ss58 = staking_address ,
374- )
394+ stake_coroutines [(ni , staking_address )] = stake_extrinsic (
395+ netuid_i = ni ,
396+ amount_ = am ,
397+ current = curr ,
398+ staking_address_ss58 = staking_address ,
375399 )
376400 else :
377- stake_coroutines .append (
378- safe_stake_extrinsic (
379- netuid_ = ni ,
380- amount_ = am ,
381- current_stake = curr ,
382- hotkey_ss58_ = staking_address ,
383- price_limit = price_with_tolerance ,
384- )
401+ stake_coroutines [(ni , staking_address )] = safe_stake_extrinsic (
402+ netuid_ = ni ,
403+ amount_ = am ,
404+ current_stake = curr ,
405+ hotkey_ss58_ = staking_address ,
406+ price_limit = price_with_tolerance ,
385407 )
386408 else :
387- stake_coroutines = [
388- stake_extrinsic (
409+ stake_coroutines = {
410+ ( ni , staking_address ): stake_extrinsic (
389411 netuid_i = ni ,
390412 amount_ = am ,
391413 current = curr ,
@@ -395,12 +417,15 @@ async def stake_extrinsic(
395417 zip (netuids , amounts_to_stake , current_stake_balances )
396418 )
397419 for _ , staking_address in hotkeys_to_stake_to
398- ]
399-
420+ }
421+ successes = defaultdict ( dict )
400422 with console .status (f"\n :satellite: Staking on netuid(s): { netuids } ..." ):
401423 # We can gather them all at once but balance reporting will be in race-condition.
402- for coroutine in stake_coroutines :
403- await coroutine
424+ for (ni , staking_address ), coroutine in stake_coroutines .items ():
425+ success = await coroutine
426+ successes [ni ][staking_address ] = success
427+ if json_output :
428+ json_console .print (json .dumps ({"staking_success" : successes }))
404429
405430
406431# Helper functions
0 commit comments