7373from bittensor .core .extrinsics .asyncex .staking import (
7474 add_stake_extrinsic ,
7575 add_stake_multiple_extrinsic ,
76+ set_auto_stake_extrinsic ,
7677)
7778from bittensor .core .extrinsics .asyncex .start_call import start_call_extrinsic
7879from bittensor .core .extrinsics .asyncex .mechanism import (
@@ -307,7 +308,7 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):
307308
308309 async def determine_block_hash (
309310 self ,
310- block : Optional [int ],
311+ block : Optional [int ] = None ,
311312 block_hash : Optional [str ] = None ,
312313 reuse_block : bool = False ,
313314 ) -> Optional [str ]:
@@ -317,31 +318,41 @@ async def determine_block_hash(
317318 for blockchain queries.
318319
319320 Arguments:
320- block: The block number to get the hash for. Do not specify if using block_hash or reuse_block.
321- block_hash: The hash of the blockchain block. Do not specify if using block or reuse_block.
322- reuse_block: Whether to reuse the last-used block hash. Do not set if using block or reuse_block.
321+ block: The block number to get the hash for. If specifying along with `block_hash`, the hash of `block` will
322+ be checked and compared with the supplied block hash, raising a ValueError if the two do not match.
323+ block_hash: The hash of the blockchain block. If specifying along with `block`, the hash of `block` will be
324+ checked and compared with the supplied block hash, raising a ValueError if the two do not match.
325+ reuse_block: Whether to reuse the last-used block hash. Do not set if using block or block_hash.
323326
324327 Returns:
325328 Optional[str]: The block hash if one can be determined, None otherwise.
326329
327330 Raises:
328- ValueError: If more than one of block, block_hash, or reuse_block is specified.
331+ ValueError: If reuse_block is set, while also supplying a block/block_hash, or if supplying a block and
332+ block_hash, but the hash of the block does not match the supplied block hash.
329333
330334 Example:
331335 # Get hash for specific block
332336 block_hash = await subtensor.determine_block_hash(block=1000000)
333337
334338 # Use provided block hash
335- hash = await subtensor.determine_block_hash(block_hash="0x1234...")
339+ block_hash = await subtensor.determine_block_hash(block_hash="0x1234...")
336340
337341 # Reuse last block hash
338- hash = await subtensor.determine_block_hash(reuse_block=True)
339- """
340- # Ensure that only one of the parameters is specified.
341- if sum (bool (x ) for x in [block , block_hash , reuse_block ]) > 1 :
342- raise ValueError (
343- "Only one of ``block``, ``block_hash``, or ``reuse_block`` can be specified."
344- )
342+ block_hash = await subtensor.determine_block_hash(reuse_block=True)
343+ """
344+ if reuse_block and any ([block , block_hash ]):
345+ raise ValueError ("Cannot specify both reuse_block and block_hash/block" )
346+ if block and block_hash :
347+ retrieved_block_hash = await self .get_block_hash (block )
348+ if retrieved_block_hash != block_hash :
349+ raise ValueError (
350+ "You have supplied a `block_hash` and a `block`, but the block does not map to the same hash as "
351+ f"the one you supplied. You supplied `block_hash={ block_hash } ` for `block={ block } `, but this block"
352+ f"maps to the block hash { retrieved_block_hash } ."
353+ )
354+ else :
355+ return retrieved_block_hash
345356
346357 # Return the appropriate value.
347358 if block_hash :
@@ -1201,6 +1212,42 @@ async def get_all_subnets_info(
12011212
12021213 return SubnetInfo .list_from_dicts (result )
12031214
1215+ async def get_auto_stakes (
1216+ self ,
1217+ coldkey_ss58 : str ,
1218+ block : Optional [int ] = None ,
1219+ block_hash : Optional [str ] = None ,
1220+ reuse_block : bool = False ,
1221+ ) -> dict [int , str ]:
1222+ """Fetches auto stake destinations for a given wallet across all subnets.
1223+
1224+ Parameters:
1225+ coldkey_ss58: Coldkey ss58 address.
1226+ block: The block number for the query.
1227+ block_hash: The block hash for the query.
1228+ reuse_block: Whether to reuse the last-used block hash.
1229+
1230+ Returns:
1231+ dict[int, str]:
1232+ - netuid: The unique identifier of the subnet.
1233+ - hotkey: The hotkey of the wallet.
1234+ """
1235+ block_hash = await self .determine_block_hash (block , block_hash , reuse_block )
1236+ query = await self .substrate .query_map (
1237+ module = "SubtensorModule" ,
1238+ storage_function = "AutoStakeDestination" ,
1239+ params = [coldkey_ss58 ],
1240+ block_hash = block_hash ,
1241+ )
1242+
1243+ pairs = {}
1244+ async for netuid , destination in query :
1245+ hotkey_ss58 = decode_account_id (destination .value [0 ])
1246+ if hotkey_ss58 :
1247+ pairs [int (netuid )] = hotkey_ss58
1248+
1249+ return pairs
1250+
12041251 async def get_balance (
12051252 self ,
12061253 address : str ,
@@ -2530,7 +2577,6 @@ async def get_neuron_for_pubkey_and_subnet(
25302577 return await self .neuron_for_uid (
25312578 uid = uid ,
25322579 netuid = netuid ,
2533- block = block ,
25342580 block_hash = block_hash ,
25352581 reuse_block = reuse_block ,
25362582 )
@@ -5170,6 +5216,46 @@ async def root_set_weights(
51705216 period = period ,
51715217 )
51725218
5219+ async def set_auto_stake (
5220+ self ,
5221+ wallet : "Wallet" ,
5222+ netuid : int ,
5223+ hotkey_ss58 : str ,
5224+ period : Optional [int ] = None ,
5225+ raise_error : bool = False ,
5226+ wait_for_inclusion : bool = True ,
5227+ wait_for_finalization : bool = True ,
5228+ ) -> tuple [bool , str ]:
5229+ """Sets the coldkey to automatically stake to the hotkey within specific subnet mechanism.
5230+
5231+ Parameters:
5232+ wallet: Bittensor Wallet instance.
5233+ netuid: The subnet unique identifier.
5234+ hotkey_ss58: The SS58 address of the validator's hotkey to which the miner automatically stakes all rewards
5235+ received from the specified subnet immediately upon receipt.
5236+ period: The number of blocks during which the transaction will remain valid after it's submitted. If the
5237+ transaction is not included in a block within that number of blocks, it will expire and be rejected. You
5238+ can think of it as an expiration date for the transaction.
5239+ raise_error: Raises a relevant exception rather than returning `False` if unsuccessful.
5240+ wait_for_inclusion: Whether to wait for the inclusion of the transaction.
5241+ wait_for_finalization: Whether to wait for the finalization of the transaction.
5242+
5243+ Returns:
5244+ tuple[bool, str]:
5245+ `True` if the extrinsic executed successfully, `False` otherwise.
5246+ `message` is a string value describing the success or potential error.
5247+ """
5248+ return await set_auto_stake_extrinsic (
5249+ subtensor = self ,
5250+ wallet = wallet ,
5251+ netuid = netuid ,
5252+ hotkey_ss58 = hotkey_ss58 ,
5253+ period = period ,
5254+ raise_error = raise_error ,
5255+ wait_for_inclusion = wait_for_inclusion ,
5256+ wait_for_finalization = wait_for_finalization ,
5257+ )
5258+
51735259 async def set_children (
51745260 self ,
51755261 wallet : "Wallet" ,
0 commit comments