@@ -247,6 +247,47 @@ import bittensor as bt
247
247
import bittensor_wallet
248
248
from bittensor import tao
249
249
250
+ <<<<<< < HEAD
251
+ ====== =
252
+ # Load environmental variables
253
+ wallet_name = os.environ.get(' WALLET' )
254
+ total_to_unstake = os.environ.get(' TOTAL_TAO_TO_UNSTAKE' )
255
+ max_stakes_to_unstake = os.environ.get(' MAX_STAKES_TO_UNSTAKE' )
256
+
257
+ # Basic input validation for wallet and TAO amount
258
+ if wallet_name is None :
259
+ sys.exit(" wallet name not specified. Usage: `TOTAL_TAO_TO_UNSTAKE=1 MAX_STAKES_TO_UNSTAKE=10 WALLET=my-wallet-name ./unstakerscript.py`" )
260
+
261
+ if total_to_unstake is None :
262
+ print (" Unstaking total not specified, defaulting to 1 TAO." )
263
+ total_to_unstake = 1
264
+ else :
265
+ try :
266
+ total_to_unstake = float (total_to_unstake)
267
+ except :
268
+ sys.exit(" invalid TAO amount!" )
269
+
270
+ if max_stakes_to_unstake is None :
271
+ max_stakes_to_unstake = 10
272
+ else :
273
+ try :
274
+ max_stakes_to_unstake = int (max_stakes_to_unstake)
275
+ except :
276
+ sys.exit(" invalid number for MAX_STAKES_TO_UNSTAKE" )
277
+
278
+ # Print summary for configuration
279
+ print (f " 🔍 Using wallet: { wallet_name} " )
280
+ print (f " 🧮 Unstaking a total of { total_to_unstake} TAO across up to { max_stakes_to_unstake} lowest-emission validators " )
281
+
282
+ # Initialize Bittensor wallet and balamce object
283
+ total_to_unstake = bt.Balance.from_tao(total_to_unstake)
284
+ wallet = bt.wallet(wallet_name)
285
+ wallet_ck = wallet.coldkeypub.ss58_address
286
+
287
+ unstake_minimum = 0.0005 # TAO
288
+
289
+ # Async helper to perform the actual unstake call
290
+ >>>>>> > 84a50fd (Added commnets throughtout unstaking script)
250
291
async def perform_unstake (subtensor , stake , amount ):
251
292
try :
252
293
print (f " ⏳ Attempting to unstake { amount} from { stake.hotkey_ss58} on subnet { stake.netuid} " )
@@ -255,6 +296,8 @@ async def perform_unstake(subtensor, stake, amount):
255
296
wallet, hotkey_ss58 = stake.hotkey_ss58, netuid = stake.netuid, amount = amount
256
297
)
257
298
elapsed = time.time() - start
299
+
300
+ # Check result object and log outcome
258
301
if result:
259
302
print (f " ✅ Successfully unstaked { amount} from { stake.hotkey_ss58} on subnet { stake.netuid} in { elapsed:.2f } s " )
260
303
return True
@@ -265,38 +308,50 @@ async def perform_unstake(subtensor, stake, amount):
265
308
print (f " ❌ Error during unstake from { stake.hotkey_ss58} on subnet { stake.netuid} : { e} " )
266
309
return False
267
310
268
-
311
+ # Main async workflow
269
312
async def main ():
313
+ # Use the async_subtensor context manager to interact with the chain
270
314
async with bt.async_subtensor(network = ' test' ) as subtensor:
271
315
try :
316
+ # Retrive all active active stakes asscociated with the coldkey
272
317
stakes = await subtensor.get_stake_for_coldkey(wallet_ck)
273
318
except Exception as e:
274
319
sys.exit(f " ❌ Failed to get stake info: { e} " )
275
320
276
- # Filter and sort
321
+ # Filter: Remove small stakes that are under the minimum threshold
277
322
stakes = list (filter (lambda s : float (s.stake.tao) > unstake_minimum, stakes))
323
+
324
+ # Sort by emission rate (lowest emission first)
278
325
stakes = sorted (stakes, key = lambda s : s.emission.tao)
326
+
327
+ # Limit to the N lowest emission validators
279
328
stakes = stakes[:max_stakes_to_unstake]
280
329
281
330
if not stakes:
282
331
sys.exit(" ❌ No eligible stakes found to unstake." )
283
332
333
+ # Print a summary of selected stakes before executint
284
334
print (f " \n 📊 Preparing to unstake from { len (stakes)} validators: \n " )
285
335
for s in stakes:
286
336
print (f " Validator: { s.hotkey_ss58} \n NetUID: { s.netuid} \n Stake: { s.stake} \n Emission: { s.emission} \n ----------- " )
287
337
288
- # Prepare concurrent unstake tasks
338
+ # Determine how much TAO to unstake per validator
289
339
amount_per_stake = total_to_unstake / len (stakes)
340
+
341
+ # Prepare all unstake calls to run concurrently
290
342
tasks = [
291
343
perform_unstake(subtensor, stake, min (amount_per_stake, stake.stake))
292
344
for stake in stakes
293
345
]
294
346
347
+ # Execute unstatke tasks concurrently using ayncio
295
348
results = await asyncio.gather(* tasks)
296
- success_count = sum (results)
297
349
350
+ # Count successes and print final report
351
+ success_count = sum (results)
298
352
print (f " \n 🎯 Unstake complete. Success: { success_count} / { len (stakes)} " )
299
353
354
+ <<<<<< < HEAD
300
355
wallet_name = os.environ.get(' WALLET' )
301
356
total_to_unstake = os.environ.get(' TOTAL_TAO_TO_UNSTAKE' )
302
357
max_stakes_to_unstake = os.environ.get(' MAX_STAKES_TO_UNSTAKE' )
@@ -331,6 +386,9 @@ wallet_ck = wallet.coldkeypub.ss58_address
331
386
# There is a global on-chain minimum balanced allowed for unstaking operations.
332
387
unstake_minimum = 0.0005
333
388
389
+ ====== =
390
+ # Run the async workflow
391
+ >>>>>> > 84a50fd (Added commnets throughtout unstaking script)
334
392
asyncio.run(main())
335
393
336
394
```
0 commit comments