communex.client
1import gc 2import hashlib 3import json 4import queue 5import threading 6from concurrent.futures import Future, ThreadPoolExecutor 7from contextlib import contextmanager 8from copy import deepcopy 9from dataclasses import dataclass 10from time import sleep 11from typing import Any, Mapping, TypeVar, cast 12 13import websocket 14from substrateinterface import ExtrinsicReceipt, Keypair, SubstrateInterface 15from substrateinterface.storage import StorageKey 16 17from communex._common import transform_stake_dmap 18from communex.encryption import bytes_from_hex, encrypt_weights 19from communex.errors import ChainTransactionError, NetworkQueryError 20from communex.types import NetworkParams, Ss58Address, SubnetParams 21 22# TODO: InsufficientBalanceError, MismatchedLengthError etc 23 24MAX_REQUEST_SIZE = 9_000_000 25 26 27@dataclass 28class ConnectionContainer: 29 substrate: SubstrateInterface 30 stop_event: threading.Event 31 lock: threading.Lock 32 33 34@dataclass 35class Chunk: 36 batch_requests: list[tuple[Any, Any]] 37 prefix_list: list[list[str]] 38 fun_params: list[tuple[Any, Any, Any, Any, str]] 39 40 41T1 = TypeVar("T1") 42T2 = TypeVar("T2") 43 44 45def send_heartbeat( 46 si: SubstrateInterface, 47 stop: threading.Event, 48 lock: threading.Lock, 49): 50 while not stop.is_set(): 51 # uses substrateinterface wrapper because its very stateful 52 # and we could mess with something by directly using the websocket 53 with lock: 54 _ = si.websocket.pong() # type: ignore 55 sleep(11) # Send heartbeat every 30 seconds 56 57 58def _instantiate_substrateinterface( 59 url: str, ws_options: dict[str, bool | int], lock: threading.Lock 60): 61 ws = websocket.WebSocket() 62 ws.connect(url) # type: ignore 63 stop_event = threading.Event() 64 si = SubstrateInterface(websocket=ws, ws_options=ws_options) 65 heartbeat_thread = threading.Thread( 66 target=send_heartbeat, args=(si, stop_event, lock), daemon=True 67 ) 68 heartbeat_thread.start() 69 70 return ConnectionContainer( 71 si, 72 stop_event, 73 lock, 74 ) 75 76 77class CommuneClient: 78 """ 79 A client for interacting with Commune network nodes, querying storage, 80 submitting transactions, etc. 81 82 Attributes: 83 wait_for_finalization: Whether to wait for transaction finalization. 84 85 Example: 86 ```py 87 client = CommuneClient() 88 client.query(name='function_name', params=['param1', 'param2']) 89 ``` 90 91 Raises: 92 AssertionError: If the maximum connections value is less than or equal 93 to zero. 94 """ 95 96 wait_for_finalization: bool 97 _num_connections: int 98 _connection_queue: queue.Queue[ConnectionContainer] 99 _ws_options: dict[str, int] 100 url: str 101 102 def __init__( 103 self, 104 url: str, 105 num_connections: int = 1, 106 wait_for_finalization: bool = False, 107 timeout: int | None = None, 108 ): 109 """ 110 Args: 111 url: The URL of the network node to connect to. 112 num_connections: The number of websocket connections to be opened. 113 """ 114 assert num_connections > 0 115 self._num_connections = num_connections 116 self.wait_for_finalization = wait_for_finalization 117 self._connection_queue = queue.Queue(num_connections) 118 self.url = url 119 120 for _ in range(num_connections): 121 ws_options: dict[str, int] = {} 122 if timeout is not None: 123 ws_options["timeout"] = timeout 124 self._ws_options = ws_options 125 self._connection_queue.put( 126 _instantiate_substrateinterface( 127 url, ws_options, threading.Lock() 128 ) 129 ) 130 131 @property 132 def connections(self) -> int: 133 """ 134 Gets the maximum allowed number of simultaneous connections to the 135 network node. 136 """ 137 return self._num_connections 138 139 @contextmanager 140 def get_conn(self, timeout: float | None = None, init: bool = False): 141 """ 142 Context manager to get a connection from the pool. 143 144 Tries to get a connection from the pool queue. If the queue is empty, 145 it blocks for `timeout` seconds until a connection is available. If 146 `timeout` is None, it blocks indefinitely. 147 148 Args: 149 timeout: The maximum time in seconds to wait for a connection. 150 151 Yields: 152 The connection object from the pool. 153 154 Raises: 155 QueueEmptyError: If no connection is available within the timeout 156 period. 157 """ 158 conn = self._connection_queue.get(timeout=timeout) 159 if init: 160 conn.substrate.init_runtime() # type: ignore 161 try: 162 gc.collect() 163 if conn.substrate.websocket and conn.substrate.websocket.connected: # type: ignore 164 with conn.lock: 165 yield conn.substrate 166 else: 167 # reconnects 168 conn.stop_event.set() 169 conn = _instantiate_substrateinterface( 170 self.url, self._ws_options, threading.Lock() 171 ) 172 with conn.lock: 173 yield conn.substrate 174 finally: 175 self._connection_queue.put(conn) 176 177 def _get_storage_keys( 178 self, 179 storage: str, 180 queries: list[tuple[str, list[Any]]], 181 block_hash: str | None, 182 ): 183 send: list[tuple[str, list[Any]]] = [] 184 prefix_list: list[Any] = [] 185 186 key_idx = 0 187 with self.get_conn(init=True) as substrate: 188 for function, params in queries: 189 storage_key = StorageKey.create_from_storage_function( # type: ignore 190 storage, 191 function, 192 params, 193 runtime_config=substrate.runtime_config, # type: ignore 194 metadata=substrate.metadata, # type: ignore 195 ) 196 197 prefix = storage_key.to_hex() 198 prefix_list.append(prefix) 199 send.append(("state_getKeys", [prefix, block_hash])) 200 key_idx += 1 201 return send, prefix_list 202 203 def _get_lists( 204 self, 205 storage_module: str, 206 queries: list[tuple[str, list[Any]]], 207 substrate: SubstrateInterface, 208 ) -> list[tuple[Any, Any, Any, Any, str]]: 209 """ 210 Generates a list of tuples containing parameters for each storage function based on the given functions and substrate interface. 211 212 Args: 213 functions (dict[str, list[query_call]]): A dictionary where keys are storage module names and values are lists of tuples. 214 Each tuple consists of a storage function name and its parameters. 215 substrate: An instance of the SubstrateInterface class used to interact with the substrate. 216 217 Returns: 218 A list of tuples in the format `(value_type, param_types, key_hashers, params, storage_function)` for each storage function in the given functions. 219 220 Example: 221 >>> _get_lists( 222 functions={'storage_module': [('storage_function', ['param1', 'param2'])]}, 223 substrate=substrate_instance 224 ) 225 [('value_type', 'param_types', 'key_hashers', ['param1', 'param2'], 'storage_function'), ...] 226 """ 227 228 function_parameters: list[tuple[Any, Any, Any, Any, str]] = [] 229 230 metadata_pallet = substrate.metadata.get_metadata_pallet( # type: ignore 231 storage_module 232 ) 233 for storage_function, params in queries: 234 storage_item = metadata_pallet.get_storage_function( # type: ignore 235 storage_function 236 ) 237 238 value_type = storage_item.get_value_type_string() # type: ignore 239 param_types = storage_item.get_params_type_string() # type: ignore 240 key_hashers = storage_item.get_param_hashers() # type: ignore 241 function_parameters.append( 242 ( 243 value_type, 244 param_types, 245 key_hashers, 246 params, 247 storage_function, 248 ) # type: ignore 249 ) 250 return function_parameters 251 252 def _send_batch( 253 self, 254 batch_payload: list[Any], 255 request_ids: list[int], 256 extract_result: bool = True, 257 ): 258 """ 259 Sends a batch of requests to the substrate and collects the results. 260 261 Args: 262 substrate: An instance of the substrate interface. 263 batch_payload: The payload of the batch request. 264 request_ids: A list of request IDs for tracking responses. 265 results: A list to store the results of the requests. 266 extract_result: Whether to extract the result from the response. 267 268 Raises: 269 NetworkQueryError: If there is an `error` in the response message. 270 271 Note: 272 No explicit return value as results are appended to the provided 'results' list. 273 """ 274 results: list[str | dict[Any, Any]] = [] 275 with self.get_conn(init=True) as substrate: 276 try: 277 substrate.websocket.send( # type: ignore 278 json.dumps(batch_payload) 279 ) 280 except NetworkQueryError: 281 pass 282 while len(results) < len(request_ids): 283 received_messages = json.loads( 284 substrate.websocket.recv() # type: ignore 285 ) 286 if isinstance(received_messages, dict): 287 received_messages: list[dict[Any, Any]] = [ 288 received_messages 289 ] 290 291 for message in received_messages: 292 if message.get("id") in request_ids: 293 if extract_result: 294 try: 295 results.append(message["result"]) 296 except Exception: 297 raise ( 298 RuntimeError( 299 f"Error extracting result from message: {message}" 300 ) 301 ) 302 else: 303 results.append(message) 304 if "error" in message: 305 raise NetworkQueryError(message["error"]) 306 307 return results 308 309 def _make_request_smaller( 310 self, 311 batch_request: list[tuple[T1, T2]], 312 prefix_list: list[list[str]], 313 fun_params: list[tuple[Any, Any, Any, Any, str]], 314 ) -> tuple[list[list[tuple[T1, T2]]], list[Chunk]]: 315 """ 316 Splits a batch of requests into smaller batches, each not exceeding the specified maximum size. 317 318 Args: 319 batch_request: A list of requests to be sent in a batch. 320 max_size: Maximum size of each batch in bytes. 321 322 Returns: 323 A list of smaller request batches. 324 325 Example: 326 >>> _make_request_smaller(batch_request=[('method1', 'params1'), ('method2', 'params2')], max_size=1000) 327 [[('method1', 'params1')], [('method2', 'params2')]] 328 """ 329 assert len(prefix_list) == len(fun_params) == len(batch_request) 330 331 def estimate_size(request: tuple[T1, T2]): 332 """Convert the batch request to a string and measure its length""" 333 return len(json.dumps(request)) 334 335 # Initialize variables 336 result: list[list[tuple[T1, T2]]] = [] 337 current_batch = [] 338 current_prefix_batch = [] 339 current_params_batch = [] 340 current_size = 0 341 342 chunk_list: list[Chunk] = [] 343 344 # Iterate through each request in the batch 345 for request, prefix, params in zip( 346 batch_request, prefix_list, fun_params 347 ): 348 request_size = estimate_size(request) 349 350 # Check if adding this request exceeds the max size 351 if current_size + request_size > MAX_REQUEST_SIZE: 352 # If so, start a new batch 353 354 # Essentiatly checks that it's not the first iteration 355 if current_batch: 356 chunk = Chunk( 357 current_batch, 358 current_prefix_batch, 359 current_params_batch, 360 ) 361 chunk_list.append(chunk) 362 result.append(current_batch) 363 364 current_batch = [request] 365 current_prefix_batch = [prefix] 366 current_params_batch = [params] 367 current_size = request_size 368 else: 369 # Otherwise, add to the current batch 370 current_batch.append(request) 371 current_size += request_size 372 current_prefix_batch.append(prefix) 373 current_params_batch.append(params) 374 375 # Add the last batch if it's not empty 376 if current_batch: 377 result.append(current_batch) 378 chunk = Chunk( 379 current_batch, current_prefix_batch, current_params_batch 380 ) 381 chunk_list.append(chunk) 382 383 return result, chunk_list 384 385 def _are_changes_equal(self, change_a: Any, change_b: Any): 386 for (a, b), (c, d) in zip(change_a, change_b): 387 if a != c or b != d: 388 return False 389 390 def _rpc_request_batch( 391 self, 392 batch_requests: list[tuple[str, list[Any]]], 393 extract_result: bool = True, 394 ) -> list[str]: 395 """ 396 Sends batch requests to the substrate node using multiple threads and collects the results. 397 398 Args: 399 substrate: An instance of the substrate interface. 400 batch_requests : A list of requests to be sent in batches. 401 max_size: Maximum size of each batch in bytes. 402 extract_result: Whether to extract the result from the response message. 403 404 Returns: 405 A list of results from the batch requests. 406 407 Example: 408 >>> _rpc_request_batch(substrate_instance, [('method1', ['param1']), ('method2', ['param2'])]) 409 ['result1', 'result2', ...] 410 """ 411 412 chunk_results: list[Any] = [] 413 # smaller_requests = self._make_request_smaller(batch_requests) 414 request_id = 0 415 with ThreadPoolExecutor() as executor: 416 futures: list[Future[list[str | dict[Any, Any]]]] = [] 417 for chunk in [batch_requests]: 418 request_ids: list[int] = [] 419 batch_payload: list[Any] = [] 420 for method, params in chunk: 421 request_id += 1 422 request_ids.append(request_id) 423 batch_payload.append( 424 { 425 "jsonrpc": "2.0", 426 "method": method, 427 "params": params, 428 "id": request_id, 429 } 430 ) 431 432 futures.append( 433 executor.submit( 434 self._send_batch, 435 batch_payload=batch_payload, 436 request_ids=request_ids, 437 extract_result=extract_result, 438 ) 439 ) 440 for future in futures: 441 resul = future.result() 442 chunk_results.append(resul) 443 return chunk_results 444 445 def _rpc_request_batch_chunked( 446 self, chunk_requests: list[Chunk], extract_result: bool = True 447 ): 448 """ 449 Sends batch requests to the substrate node using multiple threads and collects the results. 450 451 Args: 452 substrate: An instance of the substrate interface. 453 batch_requests : A list of requests to be sent in batches. 454 max_size: Maximum size of each batch in bytes. 455 extract_result: Whether to extract the result from the response message. 456 457 Returns: 458 A list of results from the batch requests. 459 460 Example: 461 >>> _rpc_request_batch(substrate_instance, [('method1', ['param1']), ('method2', ['param2'])]) 462 ['result1', 'result2', ...] 463 """ 464 465 def split_chunks( 466 chunk: Chunk, chunk_info: list[Chunk], chunk_info_idx: int 467 ): 468 manhattam_chunks: list[tuple[Any, Any]] = [] 469 mutaded_chunk_info = deepcopy(chunk_info) 470 max_n_keys = 35000 471 for query in chunk.batch_requests: 472 result_keys = query[1][0] 473 keys_amount = len(result_keys) 474 if keys_amount > max_n_keys: 475 mutaded_chunk_info.pop(chunk_info_idx) 476 for i in range(0, keys_amount, max_n_keys): 477 new_chunk = deepcopy(chunk) 478 splitted_keys = result_keys[i : i + max_n_keys] 479 splitted_query = deepcopy(query) 480 splitted_query[1][0] = splitted_keys 481 new_chunk.batch_requests = [splitted_query] 482 manhattam_chunks.append(splitted_query) 483 mutaded_chunk_info.insert(chunk_info_idx, new_chunk) 484 else: 485 manhattam_chunks.append(query) 486 return manhattam_chunks, mutaded_chunk_info 487 488 assert len(chunk_requests) > 0 489 mutated_chunk_info: list[Chunk] = [] 490 chunk_results: list[Any] = [] 491 # smaller_requests = self._make_request_smaller(batch_requests) 492 request_id = 0 493 494 with ThreadPoolExecutor() as executor: 495 futures: list[Future[list[str | dict[Any, Any]]]] = [] 496 for idx, macro_chunk in enumerate(chunk_requests): 497 _, mutated_chunk_info = split_chunks( 498 macro_chunk, chunk_requests, idx 499 ) 500 for chunk in mutated_chunk_info: 501 request_ids: list[int] = [] 502 batch_payload: list[Any] = [] 503 for method, params in chunk.batch_requests: 504 # for method, params in micro_chunk: 505 request_id += 1 506 request_ids.append(request_id) 507 batch_payload.append( 508 { 509 "jsonrpc": "2.0", 510 "method": method, 511 "params": params, 512 "id": request_id, 513 } 514 ) 515 futures.append( 516 executor.submit( 517 self._send_batch, 518 batch_payload=batch_payload, 519 request_ids=request_ids, 520 extract_result=extract_result, 521 ) 522 ) 523 for future in futures: 524 resul = future.result() 525 chunk_results.append(resul) 526 return chunk_results, mutated_chunk_info 527 528 def _decode_response( 529 self, 530 response: list[str], 531 function_parameters: list[tuple[Any, Any, Any, Any, str]], 532 prefix_list: list[Any], 533 block_hash: str, 534 ) -> dict[str, dict[Any, Any]]: 535 """ 536 Decodes a response from the substrate interface and organizes the data into a dictionary. 537 538 Args: 539 response: A list of encoded responses from a substrate query. 540 function_parameters: A list of tuples containing the parameters for each storage function. 541 last_keys: A list of the last keys used in the substrate query. 542 prefix_list: A list of prefixes used in the substrate query. 543 substrate: An instance of the SubstrateInterface class. 544 block_hash: The hash of the block to be queried. 545 546 Returns: 547 A dictionary where each key is a storage function name and the value is another dictionary. 548 This inner dictionary's key is the decoded key from the response and the value is the corresponding decoded value. 549 550 Raises: 551 ValueError: If an unsupported hash type is encountered in the `concat_hash_len` function. 552 553 Example: 554 >>> _decode_response( 555 response=[...], 556 function_parameters=[...], 557 last_keys=[...], 558 prefix_list=[...], 559 substrate=substrate_instance, 560 block_hash="0x123..." 561 ) 562 {'storage_function_name': {decoded_key: decoded_value, ...}, ...} 563 """ 564 565 def get_item_key_value( 566 item_key: tuple[Any, ...] | Any, 567 ) -> tuple[Any, ...] | Any: 568 if isinstance(item_key, tuple): 569 return tuple(k.value for k in item_key) # type: ignore 570 return item_key.value 571 572 def concat_hash_len(key_hasher: str) -> int: 573 """ 574 Determines the length of the hash based on the given key hasher type. 575 576 Args: 577 key_hasher: The type of key hasher. 578 579 Returns: 580 The length of the hash corresponding to the given key hasher type. 581 582 Raises: 583 ValueError: If the key hasher type is not supported. 584 585 Example: 586 >>> concat_hash_len("Blake2_128Concat") 587 16 588 """ 589 590 if key_hasher == "Blake2_128Concat": 591 return 16 592 elif key_hasher == "Twox64Concat": 593 return 8 594 elif key_hasher == "Identity": 595 return 0 596 else: 597 raise ValueError("Unsupported hash type") 598 599 assert len(response) == len(function_parameters) == len(prefix_list) 600 result_dict: dict[str, dict[Any, Any]] = {} 601 for res, fun_params_tuple, prefix in zip( 602 response, function_parameters, prefix_list 603 ): 604 if not res: 605 continue 606 res = res[0] 607 changes = res["changes"] # type: ignore 608 value_type, param_types, key_hashers, params, storage_function = ( 609 fun_params_tuple 610 ) 611 with self.get_conn(init=True) as substrate: 612 for item in changes: 613 # Determine type string 614 key_type_string: list[Any] = [] 615 for n in range(len(params), len(param_types)): 616 key_type_string.append( 617 f"[u8; {concat_hash_len(key_hashers[n])}]" 618 ) 619 key_type_string.append(param_types[n]) 620 621 item_key_obj = substrate.decode_scale( # type: ignore 622 type_string=f"({', '.join(key_type_string)})", 623 scale_bytes="0x" + item[0][len(prefix) :], 624 return_scale_obj=True, 625 block_hash=block_hash, 626 ) 627 # strip key_hashers to use as item key 628 if len(param_types) - len(params) == 1: 629 item_key = item_key_obj.value_object[1] # type: ignore 630 else: 631 item_key = tuple( # type: ignore 632 item_key_obj.value_object[key + 1] # type: ignore 633 for key in range( # type: ignore 634 len(params), len(param_types) + 1, 2 635 ) 636 ) 637 638 item_value = substrate.decode_scale( # type: ignore 639 type_string=value_type, 640 scale_bytes=item[1], 641 return_scale_obj=True, 642 block_hash=block_hash, 643 ) 644 result_dict.setdefault(storage_function, {}) 645 key = get_item_key_value(item_key) # type: ignore 646 result_dict[storage_function][key] = item_value.value # type: ignore 647 648 return result_dict 649 650 def query_batch( 651 self, functions: dict[str, list[tuple[str, list[Any]]]] 652 ) -> dict[str, str]: 653 """ 654 Executes batch queries on a substrate and returns results in a dictionary format. 655 656 Args: 657 substrate: An instance of SubstrateInterface to interact with the substrate. 658 functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls (function name and parameters). 659 660 Returns: 661 A dictionary where keys are storage function names and values are the query results. 662 663 Raises: 664 Exception: If no result is found from the batch queries. 665 666 Example: 667 >>> query_batch(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) 668 {'function_name': 'query_result', ...} 669 """ 670 671 result: dict[str, str] = {} 672 if not functions: 673 raise Exception("No result") 674 with self.get_conn(init=True) as substrate: 675 for module, queries in functions.items(): 676 storage_keys: list[Any] = [] 677 for fn, params in queries: 678 storage_function = substrate.create_storage_key( # type: ignore 679 pallet=module, storage_function=fn, params=params 680 ) 681 storage_keys.append(storage_function) 682 683 block_hash = substrate.get_block_hash() 684 responses: list[Any] = substrate.query_multi( # type: ignore 685 storage_keys=storage_keys, block_hash=block_hash 686 ) 687 688 for item in responses: 689 fun = item[0] 690 query = item[1] 691 storage_fun = fun.storage_function 692 result[storage_fun] = query.value 693 694 return result 695 696 def query_batch_map( 697 self, 698 functions: dict[str, list[tuple[str, list[Any]]]], 699 block_hash: str | None = None, 700 ) -> dict[str, dict[Any, Any]]: 701 """ 702 Queries multiple storage functions using a map batch approach and returns the combined result. 703 704 Args: 705 substrate: An instance of SubstrateInterface for substrate interaction. 706 functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls. 707 708 Returns: 709 The combined result of the map batch query. 710 711 Example: 712 >>> query_batch_map(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) 713 # Returns the combined result of the map batch query 714 """ 715 multi_result: dict[str, dict[Any, Any]] = {} 716 717 def recursive_update( 718 d: dict[str, dict[T1, T2] | dict[str, Any]], 719 u: Mapping[str, dict[Any, Any] | str], 720 ) -> dict[str, dict[T1, T2]]: 721 for k, v in u.items(): 722 if isinstance(v, dict): 723 d[k] = recursive_update(d.get(k, {}), v) # type: ignore 724 else: 725 d[k] = v # type: ignore 726 return d # type: ignore 727 728 def get_page(): 729 send, prefix_list = self._get_storage_keys( 730 storage, queries, block_hash 731 ) 732 with self.get_conn(init=True) as substrate: 733 function_parameters = self._get_lists( 734 storage, queries, substrate 735 ) 736 responses = self._rpc_request_batch(send) 737 # assumption because send is just the storage_function keys 738 # so it should always be really small regardless of the amount of queries 739 assert len(responses) == 1 740 res = responses[0] 741 built_payload: list[tuple[str, list[Any]]] = [] 742 for result_keys in res: 743 built_payload.append( 744 ("state_queryStorageAt", [result_keys, block_hash]) 745 ) 746 _, chunks_info = self._make_request_smaller( 747 built_payload, prefix_list, function_parameters 748 ) 749 chunks_response, chunks_info = self._rpc_request_batch_chunked( 750 chunks_info 751 ) 752 return chunks_response, chunks_info 753 754 if not block_hash: 755 with self.get_conn(init=True) as substrate: 756 block_hash = substrate.get_block_hash() 757 for storage, queries in functions.items(): 758 chunks, chunks_info = get_page() 759 # if this doesn't happen something is wrong on the code 760 # and we won't be able to decode the data properly 761 assert len(chunks) == len(chunks_info) 762 for chunk_info, response in zip(chunks_info, chunks): 763 storage_result = self._decode_response( 764 response, 765 chunk_info.fun_params, 766 chunk_info.prefix_list, 767 block_hash, 768 ) 769 multi_result = recursive_update(multi_result, storage_result) 770 771 return multi_result 772 773 def query( 774 self, 775 name: str, 776 params: list[Any] = [], 777 module: str = "SubspaceModule", 778 block_hash: str | None = None, 779 ) -> Any: 780 """ 781 Queries a storage function on the network. 782 783 Sends a query to the network and retrieves data from a 784 specified storage function. 785 786 Args: 787 name: The name of the storage function to query. 788 params: The parameters to pass to the storage function. 789 module: The module where the storage function is located. 790 791 Returns: 792 The result of the query from the network. 793 794 Raises: 795 NetworkQueryError: If the query fails or is invalid. 796 """ 797 798 result = self.query_batch({module: [(name, params)]}) 799 800 return result[name] 801 802 def query_map( 803 self, 804 name: str, 805 params: list[Any] = [], 806 module: str = "SubspaceModule", 807 extract_value: bool = True, 808 block_hash: str | None = None, 809 ) -> dict[Any, Any]: 810 """ 811 Queries a storage map from a network node. 812 813 Args: 814 name: The name of the storage map to query. 815 params: A list of parameters for the query. 816 module: The module in which the storage map is located. 817 818 Returns: 819 A dictionary representing the key-value pairs 820 retrieved from the storage map. 821 822 Raises: 823 QueryError: If the query to the network fails or is invalid. 824 """ 825 826 result = self.query_batch_map({module: [(name, params)]}, block_hash) 827 828 if extract_value: 829 return {k.value: v.value for k, v in result} # type: ignore 830 831 return result 832 833 def compose_call( 834 self, 835 fn: str, 836 params: dict[str, Any], 837 key: Keypair | None, 838 module: str = "SubspaceModule", 839 wait_for_inclusion: bool = True, 840 wait_for_finalization: bool | None = None, 841 sudo: bool = False, 842 unsigned: bool = False, 843 ) -> ExtrinsicReceipt: 844 """ 845 Composes and submits a call to the network node. 846 847 Composes and signs a call with the provided keypair, and submits it to 848 the network. The call can be a standard extrinsic or a sudo extrinsic if 849 elevated permissions are required. The method can optionally wait for 850 the call's inclusion in a block and/or its finalization. 851 852 Args: 853 fn: The function name to call on the network. 854 params: A dictionary of parameters for the call. 855 key: The keypair for signing the extrinsic. 856 module: The module containing the function. 857 wait_for_inclusion: Wait for the call's inclusion in a block. 858 wait_for_finalization: Wait for the transaction's finalization. 859 sudo: Execute the call as a sudo (superuser) operation. 860 861 Returns: 862 The receipt of the submitted extrinsic, if 863 `wait_for_inclusion` is True. Otherwise, returns a string 864 identifier of the extrinsic. 865 866 Raises: 867 ChainTransactionError: If the transaction fails. 868 """ 869 870 if key is None and not unsigned: 871 raise ValueError("Key must be provided for signed extrinsics.") 872 873 with self.get_conn() as substrate: 874 if wait_for_finalization is None: 875 wait_for_finalization = self.wait_for_finalization 876 877 call = substrate.compose_call( # type: ignore 878 call_module=module, call_function=fn, call_params=params 879 ) 880 if sudo: 881 call = substrate.compose_call( # type: ignore 882 call_module="Sudo", 883 call_function="sudo", 884 call_params={ 885 "call": call.value, # type: ignore 886 }, 887 ) 888 889 if not unsigned: 890 assert key is not None 891 extrinsic = substrate.create_signed_extrinsic( # type: ignore 892 call=call, 893 keypair=key, 894 ) 895 else: 896 extrinsic = substrate.create_unsigned_extrinsic(call=call) # type: ignore 897 898 response = substrate.submit_extrinsic( 899 extrinsic=extrinsic, 900 wait_for_inclusion=wait_for_inclusion, 901 wait_for_finalization=wait_for_finalization, 902 ) 903 if wait_for_inclusion: 904 if not response.is_success: 905 raise ChainTransactionError( 906 response.error_message, # type: ignore 907 response, # type: ignore 908 ) 909 910 return response 911 912 def compose_call_multisig( 913 self, 914 fn: str, 915 params: dict[str, Any], 916 key: Keypair, 917 signatories: list[Ss58Address], 918 threshold: int, 919 module: str = "SubspaceModule", 920 wait_for_inclusion: bool = True, 921 wait_for_finalization: bool | None = None, 922 sudo: bool = False, 923 era: dict[str, int] | None = None, 924 ) -> ExtrinsicReceipt: 925 """ 926 Composes and submits a multisignature call to the network node. 927 928 This method allows the composition and submission of a call that 929 requires multiple signatures for execution, known as a multisignature 930 call. It supports specifying signatories, a threshold of signatures for 931 the call's execution, and an optional era for the call's mortality. The 932 call can be a standard extrinsic, a sudo extrinsic for elevated 933 permissions, or a multisig extrinsic if multiple signatures are 934 required. Optionally, the method can wait for the call's inclusion in a 935 block and/or its finalization. Make sure to pass all keys, 936 that are part of the multisignature. 937 938 Args: 939 fn: The function name to call on the network. params: A dictionary 940 of parameters for the call. key: The keypair for signing the 941 extrinsic. signatories: List of SS58 addresses of the signatories. 942 Include ALL KEYS that are part of the multisig. threshold: The 943 minimum number of signatories required to execute the extrinsic. 944 module: The module containing the function to call. 945 wait_for_inclusion: Whether to wait for the call's inclusion in a 946 block. wait_for_finalization: Whether to wait for the transaction's 947 finalization. sudo: Execute the call as a sudo (superuser) 948 operation. era: Specifies the call's mortality in terms of blocks in 949 the format 950 {'period': amount_blocks}. If omitted, the extrinsic is 951 immortal. 952 953 Returns: 954 The receipt of the submitted extrinsic if `wait_for_inclusion` is 955 True. Otherwise, returns a string identifier of the extrinsic. 956 957 Raises: 958 ChainTransactionError: If the transaction fails. 959 """ 960 961 # getting the call ready 962 with self.get_conn() as substrate: 963 if wait_for_finalization is None: 964 wait_for_finalization = self.wait_for_finalization 965 966 # prepares the `GenericCall` object 967 call = substrate.compose_call( # type: ignore 968 call_module=module, call_function=fn, call_params=params 969 ) 970 if sudo: 971 call = substrate.compose_call( # type: ignore 972 call_module="Sudo", 973 call_function="sudo", 974 call_params={ 975 "call": call.value, # type: ignore 976 }, 977 ) 978 979 # modify the rpc methods at runtime, to allow for correct payment 980 # fee calculation parity has a bug in this version, 981 # where the method has to be removed 982 rpc_methods = substrate.config.get("rpc_methods") # type: ignore 983 984 if "state_call" in rpc_methods: # type: ignore 985 rpc_methods.remove("state_call") # type: ignore 986 987 # create the multisig account 988 multisig_acc = substrate.generate_multisig_account( # type: ignore 989 signatories, threshold 990 ) 991 992 # send the multisig extrinsic 993 extrinsic = substrate.create_multisig_extrinsic( # type: ignore 994 call=call, # type: ignore 995 keypair=key, 996 multisig_account=multisig_acc, # type: ignore 997 era=era, # type: ignore 998 ) # type: ignore 999 1000 response = substrate.submit_extrinsic( 1001 extrinsic=extrinsic, 1002 wait_for_inclusion=wait_for_inclusion, 1003 wait_for_finalization=wait_for_finalization, 1004 ) 1005 1006 if wait_for_inclusion: 1007 if not response.is_success: 1008 raise ChainTransactionError( 1009 response.error_message, # type: ignore 1010 response, # type: ignore 1011 ) 1012 1013 return response 1014 1015 def transfer( 1016 self, 1017 key: Keypair, 1018 amount: int, 1019 dest: Ss58Address, 1020 ) -> ExtrinsicReceipt: 1021 """ 1022 Transfers a specified amount of tokens from the signer's account to the 1023 specified account. 1024 1025 Args: 1026 key: The keypair associated with the sender's account. 1027 amount: The amount to transfer, in nanotokens. 1028 dest: The SS58 address of the recipient. 1029 1030 Returns: 1031 A receipt of the transaction. 1032 1033 Raises: 1034 InsufficientBalanceError: If the sender's account does not have 1035 enough balance. 1036 ChainTransactionError: If the transaction fails. 1037 """ 1038 1039 params = {"dest": dest, "value": amount} 1040 1041 return self.compose_call( 1042 module="Balances", fn="transfer_keep_alive", params=params, key=key 1043 ) 1044 1045 def transfer_multiple( 1046 self, 1047 key: Keypair, 1048 destinations: list[Ss58Address], 1049 amounts: list[int], 1050 netuid: str | int = 0, 1051 ) -> ExtrinsicReceipt: 1052 """ 1053 Transfers specified amounts of tokens from the signer's account to 1054 multiple target accounts. 1055 1056 The `destinations` and `amounts` lists must be of the same length. 1057 1058 Args: 1059 key: The keypair associated with the sender's account. 1060 destinations: A list of SS58 addresses of the recipients. 1061 amounts: Amount to transfer to each recipient, in nanotokens. 1062 netuid: The network identifier. 1063 1064 Returns: 1065 A receipt of the transaction. 1066 1067 Raises: 1068 InsufficientBalanceError: If the sender's account does not have 1069 enough balance for all transfers. 1070 ChainTransactionError: If the transaction fails. 1071 """ 1072 1073 assert len(destinations) == len(amounts) 1074 1075 # extract existential deposit from amounts 1076 existential_deposit = self.get_existential_deposit() 1077 amounts = [a - existential_deposit for a in amounts] 1078 1079 params = { 1080 "netuid": netuid, 1081 "destinations": destinations, 1082 "amounts": amounts, 1083 } 1084 1085 return self.compose_call( 1086 module="SubspaceModule", 1087 fn="transfer_multiple", 1088 params=params, 1089 key=key, 1090 ) 1091 1092 def stake( 1093 self, 1094 key: Keypair, 1095 amount: int, 1096 dest: Ss58Address, 1097 ) -> ExtrinsicReceipt: 1098 """ 1099 Stakes the specified amount of tokens to a module key address. 1100 1101 Args: 1102 key: The keypair associated with the staker's account. 1103 amount: The amount of tokens to stake, in nanotokens. 1104 dest: The SS58 address of the module key to stake to. 1105 netuid: The network identifier. 1106 1107 Returns: 1108 A receipt of the staking transaction. 1109 1110 Raises: 1111 InsufficientBalanceError: If the staker's account does not have 1112 enough balance. 1113 ChainTransactionError: If the transaction fails. 1114 """ 1115 1116 params = {"amount": amount, "module_key": dest} 1117 1118 return self.compose_call(fn="add_stake", params=params, key=key) 1119 1120 def unstake( 1121 self, 1122 key: Keypair, 1123 amount: int, 1124 dest: Ss58Address, 1125 ) -> ExtrinsicReceipt: 1126 """ 1127 Unstakes the specified amount of tokens from a module key address. 1128 1129 Args: 1130 key: The keypair associated with the unstaker's account. 1131 amount: The amount of tokens to unstake, in nanotokens. 1132 dest: The SS58 address of the module key to unstake from. 1133 netuid: The network identifier. 1134 1135 Returns: 1136 A receipt of the unstaking transaction. 1137 1138 Raises: 1139 InsufficientStakeError: If the staked key does not have enough 1140 staked tokens by the signer key. 1141 ChainTransactionError: If the transaction fails. 1142 """ 1143 1144 params = {"amount": amount, "module_key": dest} 1145 return self.compose_call(fn="remove_stake", params=params, key=key) 1146 1147 def update_module( 1148 self, 1149 key: Keypair, 1150 name: str, 1151 address: str, 1152 metadata: str | None = None, 1153 delegation_fee: int = 20, 1154 weight_setting_delegation_fee: int | None = None, 1155 netuid: int = 0, 1156 ) -> ExtrinsicReceipt: 1157 """ 1158 Updates the parameters of a registered module. 1159 1160 The delegation fee must be an integer between 0 and 100. 1161 1162 Args: 1163 key: The keypair associated with the module's account. 1164 name: The new name for the module. If None, the name is not updated. 1165 address: The new address for the module. 1166 If None, the address is not updated. 1167 delegation_fee: The new delegation fee for the module, 1168 between 0 and 100. 1169 netuid: The network identifier. 1170 1171 Returns: 1172 A receipt of the module update transaction. 1173 1174 Raises: 1175 InvalidParameterError: If the provided parameters are invalid. 1176 ChainTransactionError: If the transaction fails. 1177 """ 1178 1179 assert isinstance(delegation_fee, int) 1180 params = { 1181 "netuid": netuid, 1182 "name": name, 1183 "address": address, 1184 "stake_delegation_fee": delegation_fee, 1185 "validator_weight_fee": weight_setting_delegation_fee, 1186 "metadata": metadata, 1187 } 1188 1189 response = self.compose_call("update_module", params=params, key=key) 1190 1191 return response 1192 1193 def register_module( 1194 self, 1195 key: Keypair, 1196 name: str, 1197 address: str | None = None, 1198 subnet: str = "Rootnet", 1199 metadata: str | None = None, 1200 ) -> ExtrinsicReceipt: 1201 """ 1202 Registers a new module in the network. 1203 1204 Args: 1205 key: The keypair used for registering the module. 1206 name: The name of the module. If None, a default or previously 1207 set name is used. # How does this work? 1208 address: The address of the module. If None, a default or 1209 previously set address is used. # How does this work? 1210 subnet: The network subnet to register the module in. 1211 min_stake: The minimum stake required for the module, in nanotokens. 1212 If None, a default value is used. 1213 1214 Returns: 1215 A receipt of the registration transaction. 1216 1217 Raises: 1218 InvalidParameterError: If the provided parameters are invalid. 1219 ChainTransactionError: If the transaction fails. 1220 """ 1221 1222 key_addr = key.ss58_address 1223 1224 params = { 1225 "network_name": subnet, 1226 "address": address, 1227 "name": name, 1228 "module_key": key_addr, 1229 "metadata": metadata, 1230 } 1231 1232 response = self.compose_call("register", params=params, key=key) 1233 return response 1234 1235 def deregister_module(self, key: Keypair, netuid: int) -> ExtrinsicReceipt: 1236 """ 1237 Deregisters a module from the network. 1238 1239 Args: 1240 key: The keypair associated with the module's account. 1241 netuid: The network identifier. 1242 1243 Returns: 1244 A receipt of the module deregistration transaction. 1245 1246 Raises: 1247 ChainTransactionError: If the transaction fails. 1248 """ 1249 1250 params = {"netuid": netuid} 1251 1252 response = self.compose_call("deregister", params=params, key=key) 1253 1254 return response 1255 1256 def register_subnet( 1257 self, key: Keypair, name: str, metadata: str | None = None 1258 ) -> ExtrinsicReceipt: 1259 """ 1260 Registers a new subnet in the network. 1261 1262 Args: 1263 key (Keypair): The keypair used for registering the subnet. 1264 name (str): The name of the subnet to be registered. 1265 metadata (str | None, optional): Additional metadata for the subnet. Defaults to None. 1266 1267 Returns: 1268 ExtrinsicReceipt: A receipt of the subnet registration transaction. 1269 1270 Raises: 1271 ChainTransactionError: If the transaction fails. 1272 """ 1273 1274 params = { 1275 "name": name, 1276 "metadata": metadata, 1277 } 1278 1279 response = self.compose_call("register_subnet", params=params, key=key) 1280 1281 return response 1282 1283 def vote( 1284 self, 1285 key: Keypair, 1286 uids: list[int], 1287 weights: list[int], 1288 netuid: int = 0, 1289 ) -> ExtrinsicReceipt: 1290 """ 1291 Casts votes on a list of module UIDs with corresponding weights. 1292 1293 The length of the UIDs list and the weights list should be the same. 1294 Each weight corresponds to the UID at the same index. 1295 1296 Args: 1297 key: The keypair used for signing the vote transaction. 1298 uids: A list of module UIDs to vote on. 1299 weights: A list of weights corresponding to each UID. 1300 netuid: The network identifier. 1301 1302 Returns: 1303 A receipt of the voting transaction. 1304 1305 Raises: 1306 InvalidParameterError: If the lengths of UIDs and weights lists 1307 do not match. 1308 ChainTransactionError: If the transaction fails. 1309 """ 1310 1311 assert len(uids) == len(weights) 1312 1313 params = { 1314 "uids": uids, 1315 "weights": weights, 1316 "netuid": netuid, 1317 } 1318 1319 response = self.compose_call( 1320 "set_weights", 1321 params=params, 1322 key=key, 1323 module="SubnetEmissionModule", 1324 ) 1325 1326 return response 1327 1328 def delegate_weight_control( 1329 self, key: Keypair, target: Ss58Address, netuid: int 1330 ): 1331 """ 1332 delegates weight setting control from the current account to the target account. 1333 Both accounts have to be registered and have a valid validator `spec` 1334 """ 1335 1336 params = { 1337 "netuid": netuid, 1338 "target": target, 1339 } 1340 1341 response = self.compose_call( 1342 "delegate_weight_control", 1343 params=params, 1344 key=key, 1345 module="SubnetEmissionModule", 1346 ) 1347 return response 1348 1349 def add_authorities( 1350 self, 1351 key: Keypair, 1352 new_authorities: list[tuple[Ss58Address, tuple[str, str]]], 1353 ): 1354 """ 1355 only for the sudo key 1356 give the authorities as hexadecimal 1357 """ 1358 params = { 1359 "new_authorities": new_authorities, 1360 } 1361 response = self.compose_call( 1362 "add_authorities", 1363 params=params, 1364 key=key, 1365 module="Offworker", 1366 sudo=True, 1367 ) 1368 return response 1369 1370 def vote_encrypted( 1371 self, 1372 key: Keypair, 1373 uids: list[int], 1374 weights: list[int], 1375 netuid: int = 0, 1376 ) -> ExtrinsicReceipt: 1377 """ 1378 Casts encrypted votes for module UIDs with corresponding weights. 1379 1380 Args: 1381 key (Keypair): The keypair used for signing the transaction. 1382 uids (list[int]): List of UIDs to vote for. 1383 weights (list[int]): List of weights corresponding to each UID. 1384 netuid (int, optional): Network UID. Defaults to 0. 1385 1386 Returns: 1387 ExtrinsicReceipt: Receipt of the submitted extrinsic. 1388 1389 Raises: 1390 ValueError: If there's a length mismatch between UIDs and weights, 1391 if subnet data is not found, or if subnet key format is invalid. 1392 """ 1393 if len(uids) != len(weights): 1394 raise ValueError("Length mismatch between UIDs and weights") 1395 1396 subnet_data = self.query( 1397 "SubnetDecryptionData", 1398 module="SubnetEmissionModule", 1399 params=[netuid], 1400 ) 1401 if not subnet_data: 1402 raise ValueError("Subnet data not found") 1403 1404 subnet_key = subnet_data.get("node_public_key") 1405 if not subnet_key or len(subnet_key) < 2: 1406 raise ValueError("Invalid subnet key format") 1407 1408 vote_data = list(zip(uids, weights)) 1409 decryptor = ( 1410 bytes_from_hex(subnet_key[0]), 1411 bytes_from_hex(subnet_key[1]), 1412 ) 1413 validator_key = [int(x) for x in key.public_key] 1414 1415 encrypted_weights = encrypt_weights(decryptor, vote_data, validator_key) 1416 weights_hash = hashlib.sha256(str(weights).encode()).hexdigest() 1417 1418 params = { 1419 "uids": uids, 1420 "encrypted_weights": encrypted_weights, 1421 "netuid": netuid, 1422 "decrypted_weights_hash": weights_hash, 1423 } 1424 1425 return self.compose_call( 1426 "set_weights_encrypted", 1427 params=params, 1428 key=key, 1429 module="SubnetEmissionModule", 1430 ) 1431 1432 def update_subnet( 1433 self, 1434 key: Keypair, 1435 params: SubnetParams, 1436 netuid: int = 0, 1437 ) -> ExtrinsicReceipt: 1438 """ 1439 Update a subnet's configuration. 1440 1441 It requires the founder key for authorization. 1442 1443 Args: 1444 key: The founder keypair of the subnet. 1445 params: The new parameters for the subnet. 1446 netuid: The network identifier. 1447 1448 Returns: 1449 A receipt of the subnet update transaction. 1450 1451 Raises: 1452 AuthorizationError: If the key is not authorized. 1453 ChainTransactionError: If the transaction fails. 1454 """ 1455 1456 general_params = dict(params) 1457 general_params["netuid"] = netuid 1458 if general_params.get("subnet_metadata") is None: 1459 general_params["metadata"] = None 1460 else: 1461 general_params["metadata"] = general_params["subnet_metadata"] 1462 1463 response = self.compose_call( 1464 fn="update_subnet", 1465 params=general_params, 1466 key=key, 1467 ) 1468 1469 return response 1470 1471 def transfer_stake( 1472 self, 1473 key: Keypair, 1474 amount: int, 1475 from_module_key: Ss58Address, 1476 dest_module_address: Ss58Address, 1477 ) -> ExtrinsicReceipt: 1478 """ 1479 Realocate staked tokens from one staked module to another module. 1480 1481 Args: 1482 key: The keypair associated with the account that is delegating the tokens. 1483 amount: The amount of staked tokens to transfer, in nanotokens. 1484 from_module_key: The SS58 address of the module you want to transfer from (currently delegated by the key). 1485 dest_module_address: The SS58 address of the destination (newly delegated key). 1486 netuid: The network identifier. 1487 1488 Returns: 1489 A receipt of the stake transfer transaction. 1490 1491 Raises: 1492 InsufficientStakeError: If the source module key does not have 1493 enough staked tokens. ChainTransactionError: If the transaction 1494 fails. 1495 """ 1496 1497 amount = amount - self.get_existential_deposit() 1498 1499 params = { 1500 "amount": amount, 1501 "module_key": from_module_key, 1502 "new_module_key": dest_module_address, 1503 } 1504 1505 response = self.compose_call("transfer_stake", key=key, params=params) 1506 1507 return response 1508 1509 def bridge( 1510 self, 1511 key: Keypair, 1512 amount: int, 1513 ): 1514 """ 1515 Bridge tokens from the Subspace network to the Torus network. 1516 1517 Args: 1518 key: The keypair associated with the account that is bridging the tokens. 1519 amount: The amount of tokens to bridge, in nanotokens. 1520 1521 Returns: 1522 A receipt of the bridging transaction. 1523 1524 Raises: 1525 InsufficientBalanceError: If the account does not have enough balance. 1526 ChainTransactionError: If the transaction fails. 1527 """ 1528 1529 params = {"amount": amount} 1530 1531 response = self.compose_call("bridge", key=key, params=params) 1532 1533 return response 1534 1535 def bridge_withdraw( 1536 self, 1537 key: Keypair, 1538 amount: int, 1539 ): 1540 """ 1541 Withdraw bridged tokens from the Torus network to the Subspace network. 1542 1543 Args: 1544 key: The keypair associated with the account that is withdrawing the tokens. 1545 amount: The amount of tokens to withdraw, in nanotokens. 1546 1547 Returns: 1548 A receipt of the withdrawal transaction. 1549 1550 Raises: 1551 InsufficientBalanceError: If the account does not have enough balance. 1552 ChainTransactionError: If the transaction fails. 1553 """ 1554 1555 params = {"amount": amount} 1556 1557 response = self.compose_call("bridge_withdraw", key=key, params=params) 1558 1559 return response 1560 1561 def multiunstake( 1562 self, 1563 key: Keypair, 1564 keys: list[Ss58Address], 1565 amounts: list[int], 1566 ) -> ExtrinsicReceipt: 1567 """ 1568 Unstakes tokens from multiple module keys. 1569 1570 And the lists `keys` and `amounts` must be of the same length. Each 1571 amount corresponds to the module key at the same index. 1572 1573 Args: 1574 key: The keypair associated with the unstaker's account. 1575 keys: A list of SS58 addresses of the module keys to unstake from. 1576 amounts: A list of amounts to unstake from each module key, 1577 in nanotokens. 1578 netuid: The network identifier. 1579 1580 Returns: 1581 A receipt of the multi-unstaking transaction. 1582 1583 Raises: 1584 MismatchedLengthError: If the lengths of keys and amounts lists do 1585 not match. InsufficientStakeError: If any of the module keys do not 1586 have enough staked tokens. ChainTransactionError: If the transaction 1587 fails. 1588 """ 1589 1590 assert len(keys) == len(amounts) 1591 1592 params = {"module_keys": keys, "amounts": amounts} 1593 1594 response = self.compose_call( 1595 "remove_stake_multiple", params=params, key=key 1596 ) 1597 1598 return response 1599 1600 def multistake( 1601 self, 1602 key: Keypair, 1603 keys: list[Ss58Address], 1604 amounts: list[int], 1605 ) -> ExtrinsicReceipt: 1606 """ 1607 Stakes tokens to multiple module keys. 1608 1609 The lengths of the `keys` and `amounts` lists must be the same. Each 1610 amount corresponds to the module key at the same index. 1611 1612 Args: 1613 key: The keypair associated with the staker's account. 1614 keys: A list of SS58 addresses of the module keys to stake to. 1615 amounts: A list of amounts to stake to each module key, 1616 in nanotokens. 1617 netuid: The network identifier. 1618 1619 Returns: 1620 A receipt of the multi-staking transaction. 1621 1622 Raises: 1623 MismatchedLengthError: If the lengths of keys and amounts lists 1624 do not match. 1625 ChainTransactionError: If the transaction fails. 1626 """ 1627 1628 assert len(keys) == len(amounts) 1629 1630 params = { 1631 "module_keys": keys, 1632 "amounts": amounts, 1633 } 1634 1635 response = self.compose_call( 1636 "add_stake_multiple", params=params, key=key 1637 ) 1638 1639 return response 1640 1641 def add_profit_shares( 1642 self, 1643 key: Keypair, 1644 keys: list[Ss58Address], 1645 shares: list[int], 1646 ) -> ExtrinsicReceipt: 1647 """ 1648 Allocates profit shares to multiple keys. 1649 1650 The lists `keys` and `shares` must be of the same length, 1651 with each share amount corresponding to the key at the same index. 1652 1653 Args: 1654 key: The keypair associated with the account 1655 distributing the shares. 1656 keys: A list of SS58 addresses to allocate shares to. 1657 shares: A list of share amounts to allocate to each key, 1658 in nanotokens. 1659 1660 Returns: 1661 A receipt of the profit sharing transaction. 1662 1663 Raises: 1664 MismatchedLengthError: If the lengths of keys and shares 1665 lists do not match. 1666 ChainTransactionError: If the transaction fails. 1667 """ 1668 1669 assert len(keys) == len(shares) 1670 1671 params = {"keys": keys, "shares": shares} 1672 1673 response = self.compose_call( 1674 "add_profit_shares", params=params, key=key 1675 ) 1676 1677 return response 1678 1679 def add_subnet_proposal( 1680 self, key: Keypair, params: dict[str, Any], ipfs: str, netuid: int = 0 1681 ) -> ExtrinsicReceipt: 1682 """ 1683 Submits a proposal for creating or modifying a subnet within the 1684 network. 1685 1686 The proposal includes various parameters like the name, founder, share 1687 allocations, and other subnet-specific settings. 1688 1689 Args: 1690 key: The keypair used for signing the proposal transaction. 1691 params: The parameters for the subnet proposal. 1692 netuid: The network identifier. 1693 1694 Returns: 1695 A receipt of the subnet proposal transaction. 1696 1697 Raises: 1698 InvalidParameterError: If the provided subnet 1699 parameters are invalid. 1700 ChainTransactionError: If the transaction fails. 1701 """ 1702 1703 general_params = dict(params) 1704 general_params["netuid"] = netuid 1705 general_params["data"] = ipfs 1706 if "metadata" not in general_params: 1707 general_params["metadata"] = None 1708 1709 # general_params["burn_config"] = json.dumps(general_params["burn_config"]) 1710 response = self.compose_call( 1711 fn="add_subnet_params_proposal", 1712 params=general_params, 1713 key=key, 1714 module="GovernanceModule", 1715 ) 1716 1717 return response 1718 1719 def add_custom_proposal( 1720 self, 1721 key: Keypair, 1722 cid: str, 1723 ) -> ExtrinsicReceipt: 1724 params = {"data": cid} 1725 1726 response = self.compose_call( 1727 fn="add_global_custom_proposal", 1728 params=params, 1729 key=key, 1730 module="GovernanceModule", 1731 ) 1732 return response 1733 1734 def add_custom_subnet_proposal( 1735 self, 1736 key: Keypair, 1737 cid: str, 1738 netuid: int = 0, 1739 ) -> ExtrinsicReceipt: 1740 """ 1741 Submits a proposal for creating or modifying a custom subnet within the 1742 network. 1743 1744 The proposal includes various parameters like the name, founder, share 1745 allocations, and other subnet-specific settings. 1746 1747 Args: 1748 key: The keypair used for signing the proposal transaction. 1749 params: The parameters for the subnet proposal. 1750 netuid: The network identifier. 1751 1752 Returns: 1753 A receipt of the subnet proposal transaction. 1754 """ 1755 1756 params = { 1757 "data": cid, 1758 "netuid": netuid, 1759 } 1760 1761 response = self.compose_call( 1762 fn="add_subnet_custom_proposal", 1763 params=params, 1764 key=key, 1765 module="GovernanceModule", 1766 ) 1767 1768 return response 1769 1770 def add_global_proposal( 1771 self, 1772 key: Keypair, 1773 params: NetworkParams, 1774 cid: str | None, 1775 ) -> ExtrinsicReceipt: 1776 """ 1777 Submits a proposal for altering the global network parameters. 1778 1779 Allows for the submission of a proposal to 1780 change various global parameters 1781 of the network, such as emission rates, rate limits, and voting 1782 thresholds. It is used to 1783 suggest changes that affect the entire network's operation. 1784 1785 Args: 1786 key: The keypair used for signing the proposal transaction. 1787 params: A dictionary containing global network parameters 1788 like maximum allowed subnets, modules, 1789 transaction rate limits, and others. 1790 1791 Returns: 1792 A receipt of the global proposal transaction. 1793 1794 Raises: 1795 InvalidParameterError: If the provided network 1796 parameters are invalid. 1797 ChainTransactionError: If the transaction fails. 1798 """ 1799 general_params = cast(dict[str, Any], params) 1800 cid = cid or "" 1801 general_params["data"] = cid 1802 1803 response = self.compose_call( 1804 fn="add_global_params_proposal", 1805 params=general_params, 1806 key=key, 1807 module="GovernanceModule", 1808 ) 1809 1810 return response 1811 1812 def vote_on_proposal( 1813 self, 1814 key: Keypair, 1815 proposal_id: int, 1816 agree: bool, 1817 ) -> ExtrinsicReceipt: 1818 """ 1819 Casts a vote on a specified proposal within the network. 1820 1821 Args: 1822 key: The keypair used for signing the vote transaction. 1823 proposal_id: The unique identifier of the proposal to vote on. 1824 1825 Returns: 1826 A receipt of the voting transaction in nanotokens. 1827 1828 Raises: 1829 InvalidProposalIDError: If the provided proposal ID does not 1830 exist or is invalid. 1831 ChainTransactionError: If the transaction fails. 1832 """ 1833 1834 params = {"proposal_id": proposal_id, "agree": agree} 1835 1836 response = self.compose_call( 1837 "vote_proposal", 1838 key=key, 1839 params=params, 1840 module="GovernanceModule", 1841 ) 1842 1843 return response 1844 1845 def unvote_on_proposal( 1846 self, 1847 key: Keypair, 1848 proposal_id: int, 1849 ) -> ExtrinsicReceipt: 1850 """ 1851 Retracts a previously cast vote on a specified proposal. 1852 1853 Args: 1854 key: The keypair used for signing the unvote transaction. 1855 proposal_id: The unique identifier of the proposal to withdraw the 1856 vote from. 1857 1858 Returns: 1859 A receipt of the unvoting transaction in nanotokens. 1860 1861 Raises: 1862 InvalidProposalIDError: If the provided proposal ID does not 1863 exist or is invalid. 1864 ChainTransactionError: If the transaction fails to be processed, or 1865 if there was no prior vote to retract. 1866 """ 1867 1868 params = {"proposal_id": proposal_id} 1869 1870 response = self.compose_call( 1871 "remove_vote_proposal", 1872 key=key, 1873 params=params, 1874 module="GovernanceModule", 1875 ) 1876 1877 return response 1878 1879 def enable_vote_power_delegation(self, key: Keypair) -> ExtrinsicReceipt: 1880 """ 1881 Enables vote power delegation for the signer's account. 1882 1883 Args: 1884 key: The keypair used for signing the delegation transaction. 1885 1886 Returns: 1887 A receipt of the vote power delegation transaction. 1888 1889 Raises: 1890 ChainTransactionError: If the transaction fails. 1891 """ 1892 1893 response = self.compose_call( 1894 "enable_vote_power_delegation", 1895 params={}, 1896 key=key, 1897 module="GovernanceModule", 1898 ) 1899 1900 return response 1901 1902 def disable_vote_power_delegation(self, key: Keypair) -> ExtrinsicReceipt: 1903 """ 1904 Disables vote power delegation for the signer's account. 1905 1906 Args: 1907 key: The keypair used for signing the delegation transaction. 1908 1909 Returns: 1910 A receipt of the vote power delegation transaction. 1911 1912 Raises: 1913 ChainTransactionError: If the transaction fails. 1914 """ 1915 1916 response = self.compose_call( 1917 "disable_vote_power_delegation", 1918 params={}, 1919 key=key, 1920 module="GovernanceModule", 1921 ) 1922 1923 return response 1924 1925 def add_dao_application( 1926 self, key: Keypair, application_key: Ss58Address, data: str 1927 ) -> ExtrinsicReceipt: 1928 """ 1929 Submits a new application to the general subnet DAO. 1930 1931 Args: 1932 key: The keypair used for signing the application transaction. 1933 application_key: The SS58 address of the application key. 1934 data: The data associated with the application. 1935 1936 Returns: 1937 A receipt of the application transaction. 1938 1939 Raises: 1940 ChainTransactionError: If the transaction fails. 1941 """ 1942 1943 params = {"application_key": application_key, "data": data} 1944 1945 response = self.compose_call( 1946 "add_dao_application", 1947 module="GovernanceModule", 1948 key=key, 1949 params=params, 1950 ) 1951 1952 return response 1953 1954 def query_map_curator_applications(self) -> dict[str, dict[str, str]]: 1955 query_result = self.query_map( 1956 "CuratorApplications", 1957 module="GovernanceModule", 1958 params=[], 1959 extract_value=False, 1960 ) 1961 applications = query_result.get("CuratorApplications", {}) 1962 return applications 1963 1964 def query_map_proposals( 1965 self, extract_value: bool = False 1966 ) -> dict[int, dict[str, Any]]: 1967 """ 1968 Retrieves a mappping of proposals from the network. 1969 1970 Queries the network and returns a mapping of proposal IDs to 1971 their respective parameters. 1972 1973 Returns: 1974 A dictionary mapping proposal IDs 1975 to dictionaries of their parameters. 1976 1977 Raises: 1978 QueryError: If the query to the network fails or is invalid. 1979 """ 1980 1981 return self.query_map( 1982 "Proposals", extract_value=extract_value, module="GovernanceModule" 1983 )["Proposals"] 1984 1985 def query_map_weights( 1986 self, netuid: int = 0, extract_value: bool = False 1987 ) -> dict[int, list[tuple[int, int]]] | None: 1988 """ 1989 Retrieves a mapping of weights for keys on the network. 1990 1991 Queries the network and returns a mapping of key UIDs to 1992 their respective weights. 1993 1994 Args: 1995 netuid: The network UID from which to get the weights. 1996 1997 Returns: 1998 A dictionary mapping key UIDs to lists of their weights. 1999 2000 Raises: 2001 QueryError: If the query to the network fails or is invalid. 2002 """ 2003 2004 weights_dict = self.query_map( 2005 "Weights", 2006 [netuid], 2007 extract_value=extract_value, 2008 module="SubnetEmissionModule", 2009 ).get("Weights") 2010 return weights_dict 2011 2012 def query_map_key( 2013 self, 2014 netuid: int = 0, 2015 extract_value: bool = False, 2016 ) -> dict[int, Ss58Address]: 2017 """ 2018 Retrieves a map of keys from the network. 2019 2020 Fetches a mapping of key UIDs to their associated 2021 addresses on the network. 2022 The query can be targeted at a specific network UID if required. 2023 2024 Args: 2025 netuid: The network UID from which to get the keys. 2026 2027 Returns: 2028 A dictionary mapping key UIDs to their addresses. 2029 2030 Raises: 2031 QueryError: If the query to the network fails or is invalid. 2032 """ 2033 return self.query_map("Keys", [netuid], extract_value=extract_value)[ 2034 "Keys" 2035 ] 2036 2037 def query_map_address( 2038 self, netuid: int = 0, extract_value: bool = False 2039 ) -> dict[int, str]: 2040 """ 2041 Retrieves a map of key addresses from the network. 2042 2043 Queries the network for a mapping of key UIDs to their addresses. 2044 2045 Args: 2046 netuid: The network UID from which to get the addresses. 2047 2048 Returns: 2049 A dictionary mapping key UIDs to their addresses. 2050 2051 Raises: 2052 QueryError: If the query to the network fails or is invalid. 2053 """ 2054 2055 return self.query_map("Address", [netuid], extract_value=extract_value)[ 2056 "Address" 2057 ] 2058 2059 def query_map_emission( 2060 self, extract_value: bool = False 2061 ) -> dict[int, list[int]]: 2062 """ 2063 Retrieves a map of emissions for keys on the network. 2064 2065 Queries the network to get a mapping of 2066 key UIDs to their emission values. 2067 2068 Returns: 2069 A dictionary mapping key UIDs to lists of their emission values. 2070 2071 Raises: 2072 QueryError: If the query to the network fails or is invalid. 2073 """ 2074 2075 return self.query_map("Emission", extract_value=extract_value)[ 2076 "Emission" 2077 ] 2078 2079 def query_map_pending_emission(self, extract_value: bool = False) -> int: 2080 """ 2081 Retrieves a map of pending emissions for the subnets. 2082 2083 Queries the network for a mapping of subnet UIDs to their pending emission values. 2084 2085 Returns: 2086 A dictionary mapping subnet UIDs to their pending emission values. 2087 2088 Raises: 2089 QueryError: If the query to the network fails or is invalid. 2090 """ 2091 return self.query_map( 2092 "PendingEmission", 2093 extract_value=extract_value, 2094 module="SubnetEmissionModule", 2095 )["PendingEmission"] 2096 2097 def query_map_subnet_emission( 2098 self, extract_value: bool = False 2099 ) -> dict[int, int]: 2100 """ 2101 Retrieves a map of subnet emissions for the network. 2102 2103 Queries the network for a mapping of subnet UIDs to their emission values. 2104 2105 Returns: 2106 A dictionary mapping subnet UIDs to their emission values. 2107 2108 Raises: 2109 QueryError: If the query to the network fails or is invalid. 2110 """ 2111 2112 return self.query_map( 2113 "SubnetEmission", 2114 extract_value=extract_value, 2115 module="SubnetEmissionModule", 2116 )["SubnetEmission"] 2117 2118 def query_map_subnet_consensus( 2119 self, extract_value: bool = False 2120 ) -> dict[int, str]: 2121 """ 2122 Retrieves a map of subnet consensus types for the network. 2123 2124 Queries the network for a mapping of subnet UIDs to their consensus types. 2125 2126 Returns: 2127 A dictionary mapping subnet UIDs to their consensus types. 2128 2129 Raises: 2130 QueryError: If the query to the network fails or is invalid. 2131 """ 2132 2133 return self.query_map( 2134 "SubnetConsensusType", 2135 extract_value=extract_value, 2136 module="SubnetEmissionModule", 2137 )["SubnetConsensusType"] 2138 2139 def query_map_incentive( 2140 self, extract_value: bool = False 2141 ) -> dict[int, list[int]]: 2142 """ 2143 Retrieves a mapping of incentives for keys on the network. 2144 2145 Queries the network and returns a mapping of key UIDs to 2146 their respective incentive values. 2147 2148 Returns: 2149 A dictionary mapping key UIDs to lists of their incentive values. 2150 2151 Raises: 2152 QueryError: If the query to the network fails or is invalid. 2153 """ 2154 2155 return self.query_map("Incentive", extract_value=extract_value)[ 2156 "Incentive" 2157 ] 2158 2159 def query_map_dividend( 2160 self, extract_value: bool = False 2161 ) -> dict[int, list[int]]: 2162 """ 2163 Retrieves a mapping of dividends for keys on the network. 2164 2165 Queries the network for a mapping of key UIDs to 2166 their dividend values. 2167 2168 Returns: 2169 A dictionary mapping key UIDs to lists of their dividend values. 2170 2171 Raises: 2172 QueryError: If the query to the network fails or is invalid. 2173 """ 2174 2175 return self.query_map("Dividends", extract_value=extract_value)[ 2176 "Dividends" 2177 ] 2178 2179 def query_map_regblock( 2180 self, netuid: int = 0, extract_value: bool = False 2181 ) -> dict[int, int]: 2182 """ 2183 Retrieves a mapping of registration blocks for keys on the network. 2184 2185 Queries the network for a mapping of key UIDs to 2186 the blocks where they were registered. 2187 2188 Args: 2189 netuid: The network UID from which to get the registration blocks. 2190 2191 Returns: 2192 A dictionary mapping key UIDs to their registration blocks. 2193 2194 Raises: 2195 QueryError: If the query to the network fails or is invalid. 2196 """ 2197 2198 return self.query_map( 2199 "RegistrationBlock", [netuid], extract_value=extract_value 2200 )["RegistrationBlock"] 2201 2202 def query_map_lastupdate( 2203 self, extract_value: bool = False 2204 ) -> dict[int, list[int]]: 2205 """ 2206 Retrieves a mapping of the last update times for keys on the network. 2207 2208 Queries the network for a mapping of key UIDs to their last update times. 2209 2210 Returns: 2211 A dictionary mapping key UIDs to lists of their last update times. 2212 2213 Raises: 2214 QueryError: If the query to the network fails or is invalid. 2215 """ 2216 2217 return self.query_map("LastUpdate", extract_value=extract_value)[ 2218 "LastUpdate" 2219 ] 2220 2221 def query_map_stakefrom( 2222 self, extract_value: bool = False 2223 ) -> dict[Ss58Address, list[tuple[Ss58Address, int]]]: 2224 """ 2225 Retrieves a mapping of stakes from various sources for keys on the network. 2226 2227 Queries the network to obtain a mapping of key addresses to the sources 2228 and amounts of stakes they have received. 2229 2230 Args: 2231 netuid: The network UID from which to get the stakes. 2232 2233 Returns: 2234 A dictionary mapping key addresses to lists of tuples 2235 (module_key_address, amount). 2236 2237 Raises: 2238 QueryError: If the query to the network fails or is invalid. 2239 """ 2240 2241 result = self.query_map("StakeFrom", [], extract_value=extract_value)[ 2242 "StakeFrom" 2243 ] 2244 2245 return transform_stake_dmap(result) 2246 2247 def query_map_staketo( 2248 self, extract_value: bool = False 2249 ) -> dict[Ss58Address, list[tuple[Ss58Address, int]]]: 2250 """ 2251 Retrieves a mapping of stakes to destinations for keys on the network. 2252 2253 Queries the network for a mapping of key addresses to the destinations 2254 and amounts of stakes they have made. 2255 2256 Args: 2257 netuid: The network UID from which to get the stakes. 2258 2259 Returns: 2260 A dictionary mapping key addresses to lists of tuples 2261 (module_key_address, amount). 2262 2263 Raises: 2264 QueryError: If the query to the network fails or is invalid. 2265 """ 2266 2267 result = self.query_map("StakeTo", [], extract_value=extract_value)[ 2268 "StakeTo" 2269 ] 2270 return transform_stake_dmap(result) 2271 2272 def query_map_delegationfee( 2273 self, netuid: int = 0, extract_value: bool = False 2274 ) -> dict[str, int]: 2275 """ 2276 Retrieves a mapping of delegation fees for keys on the network. 2277 2278 Queries the network to obtain a mapping of key addresses to their 2279 respective delegation fees. 2280 2281 Args: 2282 netuid: The network UID to filter the delegation fees. 2283 2284 Returns: 2285 A dictionary mapping key addresses to their delegation fees. 2286 2287 Raises: 2288 QueryError: If the query to the network fails or is invalid. 2289 """ 2290 2291 return self.query_map( 2292 "DelegationFee", [netuid], extract_value=extract_value 2293 )["DelegationFee"] 2294 2295 def query_map_tempo(self, extract_value: bool = False) -> dict[int, int]: 2296 """ 2297 Retrieves a mapping of tempo settings for the network. 2298 2299 Queries the network to obtain the tempo (rate of reward distributions) 2300 settings for various network subnets. 2301 2302 Returns: 2303 A dictionary mapping network UIDs to their tempo settings. 2304 2305 Raises: 2306 QueryError: If the query to the network fails or is invalid. 2307 """ 2308 2309 return self.query_map("Tempo", extract_value=extract_value)["Tempo"] 2310 2311 def query_map_immunity_period(self, extract_value: bool) -> dict[int, int]: 2312 """ 2313 Retrieves a mapping of immunity periods for the network. 2314 2315 Queries the network for the immunity period settings, 2316 which represent the time duration during which modules 2317 can not get deregistered. 2318 2319 Returns: 2320 A dictionary mapping network UIDs to their immunity period settings. 2321 2322 Raises: 2323 QueryError: If the query to the network fails or is invalid. 2324 """ 2325 2326 return self.query_map("ImmunityPeriod", extract_value=extract_value)[ 2327 "ImmunityPeriod" 2328 ] 2329 2330 def query_map_min_allowed_weights( 2331 self, extract_value: bool = False 2332 ) -> dict[int, int]: 2333 """ 2334 Retrieves a mapping of minimum allowed weights for the network. 2335 2336 Queries the network to obtain the minimum allowed weights, 2337 which are the lowest permissible weight values that can be set by 2338 validators. 2339 2340 Returns: 2341 A dictionary mapping network UIDs to 2342 their minimum allowed weight values. 2343 2344 Raises: 2345 QueryError: If the query to the network fails or is invalid. 2346 """ 2347 2348 return self.query_map("MinAllowedWeights", extract_value=extract_value)[ 2349 "MinAllowedWeights" 2350 ] 2351 2352 def query_map_max_allowed_weights( 2353 self, extract_value: bool = False 2354 ) -> dict[int, int]: 2355 """ 2356 Retrieves a mapping of maximum allowed weights for the network. 2357 2358 Queries the network for the maximum allowed weights, 2359 which are the highest permissible 2360 weight values that can be set by validators. 2361 2362 Returns: 2363 A dictionary mapping network UIDs to 2364 their maximum allowed weight values. 2365 2366 Raises: 2367 QueryError: If the query to the network fails or is invalid. 2368 """ 2369 2370 return self.query_map("MaxAllowedWeights", extract_value=extract_value)[ 2371 "MaxAllowedWeights" 2372 ] 2373 2374 def query_map_max_allowed_uids( 2375 self, extract_value: bool = False 2376 ) -> dict[int, int]: 2377 """ 2378 Queries the network for the maximum number of allowed user IDs (UIDs) 2379 for each network subnet. 2380 2381 Fetches a mapping of network subnets to their respective 2382 limits on the number of user IDs that can be created or used. 2383 2384 Returns: 2385 A dictionary mapping network UIDs (unique identifiers) to their 2386 maximum allowed number of UIDs. 2387 Each entry represents a network subnet 2388 with its corresponding UID limit. 2389 2390 Raises: 2391 QueryError: If the query to the network fails or is invalid. 2392 """ 2393 2394 return self.query_map("MaxAllowedUids", extract_value=extract_value)[ 2395 "MaxAllowedUids" 2396 ] 2397 2398 def query_map_min_stake( 2399 self, extract_value: bool = False 2400 ) -> dict[int, int]: 2401 """ 2402 Retrieves a mapping of minimum allowed stake on the network. 2403 2404 Queries the network to obtain the minimum number of stake, 2405 which is represented in nanotokens. 2406 2407 Returns: 2408 A dictionary mapping network UIDs to 2409 their minimum allowed stake values. 2410 2411 Raises: 2412 QueryError: If the query to the network fails or is invalid. 2413 """ 2414 2415 return self.query_map("MinStake", extract_value=extract_value)[ 2416 "MinStake" 2417 ] 2418 2419 def query_map_max_stake( 2420 self, extract_value: bool = False 2421 ) -> dict[int, int]: 2422 """ 2423 Retrieves a mapping of the maximum stake values for the network. 2424 2425 Queries the network for the maximum stake values across various s 2426 ubnets of the network. 2427 2428 Returns: 2429 A dictionary mapping network UIDs to their maximum stake values. 2430 2431 Raises: 2432 QueryError: If the query to the network fails or is invalid. 2433 """ 2434 2435 return self.query_map("MaxStake", extract_value=extract_value)[ 2436 "MaxStake" 2437 ] 2438 2439 def query_map_founder(self, extract_value: bool = False) -> dict[int, str]: 2440 """ 2441 Retrieves a mapping of founders for the network. 2442 2443 Queries the network to obtain the founders associated with 2444 various subnets. 2445 2446 Returns: 2447 A dictionary mapping network UIDs to their respective founders. 2448 2449 Raises: 2450 QueryError: If the query to the network fails or is invalid. 2451 """ 2452 2453 return self.query_map("Founder", extract_value=extract_value)["Founder"] 2454 2455 def query_map_founder_share( 2456 self, extract_value: bool = False 2457 ) -> dict[int, int]: 2458 """ 2459 Retrieves a mapping of founder shares for the network. 2460 2461 Queries the network for the share percentages 2462 allocated to founders across different subnets. 2463 2464 Returns: 2465 A dictionary mapping network UIDs to their founder share percentages. 2466 2467 Raises: 2468 QueryError: If the query to the network fails or is invalid. 2469 """ 2470 2471 return self.query_map("FounderShare", extract_value=extract_value)[ 2472 "FounderShare" 2473 ] 2474 2475 def query_map_incentive_ratio( 2476 self, extract_value: bool = False 2477 ) -> dict[int, int]: 2478 """ 2479 Retrieves a mapping of incentive ratios for the network. 2480 2481 Queries the network for the incentive ratios, 2482 which are the proportions of rewards or incentives 2483 allocated in different subnets of the network. 2484 2485 Returns: 2486 A dictionary mapping network UIDs to their incentive ratios. 2487 2488 Raises: 2489 QueryError: If the query to the network fails or is invalid. 2490 """ 2491 2492 return self.query_map("IncentiveRatio", extract_value=extract_value)[ 2493 "IncentiveRatio" 2494 ] 2495 2496 def query_map_trust_ratio( 2497 self, extract_value: bool = False 2498 ) -> dict[int, int]: 2499 """ 2500 Retrieves a mapping of trust ratios for the network. 2501 2502 Queries the network for trust ratios, 2503 indicative of the level of trust or credibility assigned 2504 to different subnets of the network. 2505 2506 Returns: 2507 A dictionary mapping network UIDs to their trust ratios. 2508 2509 Raises: 2510 QueryError: If the query to the network fails or is invalid. 2511 """ 2512 2513 return self.query_map("TrustRatio", extract_value=extract_value)[ 2514 "TrustRatio" 2515 ] 2516 2517 def query_map_vote_mode_subnet( 2518 self, extract_value: bool = False 2519 ) -> dict[int, str]: 2520 """ 2521 Retrieves a mapping of vote modes for subnets within the network. 2522 2523 Queries the network for the voting modes used in different 2524 subnets, which define the methodology or approach of voting within those 2525 subnets. 2526 2527 Returns: 2528 A dictionary mapping network UIDs to their vote 2529 modes for subnets. 2530 2531 Raises: 2532 QueryError: If the query to the network fails or is invalid. 2533 """ 2534 2535 return self.query_map("VoteModeSubnet", extract_value=extract_value)[ 2536 "VoteModeSubnet" 2537 ] 2538 2539 def query_map_legit_whitelist( 2540 self, extract_value: bool = False 2541 ) -> dict[Ss58Address, int]: 2542 """ 2543 Retrieves a mapping of whitelisted addresses for the network. 2544 2545 Queries the network for a mapping of whitelisted addresses 2546 and their respective legitimacy status. 2547 2548 Returns: 2549 A dictionary mapping addresses to their legitimacy status. 2550 2551 Raises: 2552 QueryError: If the query to the network fails or is invalid. 2553 """ 2554 2555 return self.query_map( 2556 "LegitWhitelist", 2557 module="GovernanceModule", 2558 extract_value=extract_value, 2559 )["LegitWhitelist"] 2560 2561 def query_map_subnet_names( 2562 self, extract_value: bool = False 2563 ) -> dict[int, str]: 2564 """ 2565 Retrieves a mapping of subnet names within the network. 2566 2567 Queries the network for the names of various subnets, 2568 providing an overview of the different 2569 subnets within the network. 2570 2571 Returns: 2572 A dictionary mapping network UIDs to their subnet names. 2573 2574 Raises: 2575 QueryError: If the query to the network fails or is invalid. 2576 """ 2577 2578 return self.query_map("SubnetNames", extract_value=extract_value)[ 2579 "SubnetNames" 2580 ] 2581 2582 def query_map_balances( 2583 self, extract_value: bool = False, block_hash: str | None = None 2584 ) -> dict[str, dict[str, int | dict[str, int | float]]]: 2585 """ 2586 Retrieves a mapping of account balances within the network. 2587 2588 Queries the network for the balances associated with different accounts. 2589 It provides detailed information including various types of 2590 balances for each account. 2591 2592 Returns: 2593 A dictionary mapping account addresses to their balance details. 2594 2595 Raises: 2596 QueryError: If the query to the network fails or is invalid. 2597 """ 2598 2599 return self.query_map( 2600 "Account", 2601 module="System", 2602 extract_value=extract_value, 2603 block_hash=block_hash, 2604 )["Account"] 2605 2606 def query_map_registration_blocks( 2607 self, netuid: int = 0, extract_value: bool = False 2608 ) -> dict[int, int]: 2609 """ 2610 Retrieves a mapping of registration blocks for UIDs on the network. 2611 2612 Queries the network to find the block numbers at which various 2613 UIDs were registered. 2614 2615 Args: 2616 netuid: The network UID from which to get the registrations. 2617 2618 Returns: 2619 A dictionary mapping UIDs to their registration block numbers. 2620 2621 Raises: 2622 QueryError: If the query to the network fails or is invalid. 2623 """ 2624 2625 return self.query_map( 2626 "RegistrationBlock", [netuid], extract_value=extract_value 2627 )["RegistrationBlock"] 2628 2629 def query_map_name( 2630 self, netuid: int = 0, extract_value: bool = False 2631 ) -> dict[int, str]: 2632 """ 2633 Retrieves a mapping of names for keys on the network. 2634 2635 Queries the network for the names associated with different keys. 2636 It provides a mapping of key UIDs to their registered names. 2637 2638 Args: 2639 netuid: The network UID from which to get the names. 2640 2641 Returns: 2642 A dictionary mapping key UIDs to their names. 2643 2644 Raises: 2645 QueryError: If the query to the network fails or is invalid. 2646 """ 2647 2648 return self.query_map("Name", [netuid], extract_value=extract_value)[ 2649 "Name" 2650 ] 2651 2652 # == QUERY FUNCTIONS == # 2653 2654 def get_immunity_period(self, netuid: int = 0) -> int: 2655 """ 2656 Queries the network for the immunity period setting. 2657 2658 The immunity period is a time duration during which a module 2659 can not be deregistered from the network. 2660 Fetches the immunity period for a specified network subnet. 2661 2662 Args: 2663 netuid: The network UID for which to query the immunity period. 2664 2665 Returns: 2666 The immunity period setting for the specified network subnet. 2667 2668 Raises: 2669 QueryError: If the query to the network fails or is invalid. 2670 """ 2671 2672 return self.query( 2673 "ImmunityPeriod", 2674 params=[netuid], 2675 ) 2676 2677 def get_max_set_weights_per_epoch(self): 2678 return self.query("MaximumSetWeightCallsPerEpoch") 2679 2680 def get_min_allowed_weights(self, netuid: int = 0) -> int: 2681 """ 2682 Queries the network for the minimum allowed weights setting. 2683 2684 Retrieves the minimum weight values that are possible to set 2685 by a validator within a specific network subnet. 2686 2687 Args: 2688 netuid: The network UID for which to query the minimum allowed 2689 weights. 2690 2691 Returns: 2692 The minimum allowed weight values for the specified network 2693 subnet. 2694 2695 Raises: 2696 QueryError: If the query to the network fails or is invalid. 2697 """ 2698 2699 return self.query( 2700 "MinAllowedWeights", 2701 params=[netuid], 2702 ) 2703 2704 def get_dao_treasury_address(self) -> Ss58Address: 2705 return self.query("DaoTreasuryAddress", module="GovernanceModule") 2706 2707 def get_max_allowed_weights(self, netuid: int = 0) -> int: 2708 """ 2709 Queries the network for the maximum allowed weights setting. 2710 2711 Retrieves the maximum weight values that are possible to set 2712 by a validator within a specific network subnet. 2713 2714 Args: 2715 netuid: The network UID for which to query the maximum allowed 2716 weights. 2717 2718 Returns: 2719 The maximum allowed weight values for the specified network 2720 subnet. 2721 2722 Raises: 2723 QueryError: If the query to the network fails or is invalid. 2724 """ 2725 2726 return self.query("MaxAllowedWeights", params=[netuid]) 2727 2728 def get_max_allowed_uids(self, netuid: int = 0) -> int: 2729 """ 2730 Queries the network for the maximum allowed UIDs setting. 2731 2732 Fetches the upper limit on the number of user IDs that can 2733 be allocated or used within a specific network subnet. 2734 2735 Args: 2736 netuid: The network UID for which to query the maximum allowed UIDs. 2737 2738 Returns: 2739 The maximum number of allowed UIDs for the specified network subnet. 2740 2741 Raises: 2742 QueryError: If the query to the network fails or is invalid. 2743 """ 2744 2745 return self.query("MaxAllowedUids", params=[netuid]) 2746 2747 def get_name(self, netuid: int = 0) -> str: 2748 """ 2749 Queries the network for the name of a specific subnet. 2750 2751 Args: 2752 netuid: The network UID for which to query the name. 2753 2754 Returns: 2755 The name of the specified network subnet. 2756 2757 Raises: 2758 QueryError: If the query to the network fails or is invalid. 2759 """ 2760 2761 return self.query("Name", params=[netuid]) 2762 2763 def get_subnet_name(self, netuid: int = 0) -> str: 2764 """ 2765 Queries the network for the name of a specific subnet. 2766 2767 Args: 2768 netuid: The network UID for which to query the name. 2769 2770 Returns: 2771 The name of the specified network subnet. 2772 2773 Raises: 2774 QueryError: If the query to the network fails or is invalid. 2775 """ 2776 2777 return self.query("SubnetNames", params=[netuid]) 2778 2779 def get_global_dao_treasury(self): 2780 return self.query("GlobalDaoTreasury", module="GovernanceModule") 2781 2782 def get_n(self, netuid: int = 0) -> int: 2783 """ 2784 Queries the network for the 'N' hyperparameter, which represents how 2785 many modules are on the network. 2786 2787 Args: 2788 netuid: The network UID for which to query the 'N' hyperparameter. 2789 2790 Returns: 2791 The value of the 'N' hyperparameter for the specified network 2792 subnet. 2793 2794 Raises: 2795 QueryError: If the query to the network fails or is invalid. 2796 """ 2797 2798 return self.query("N", params=[netuid]) 2799 2800 def get_tempo(self, netuid: int = 0) -> int: 2801 """ 2802 Queries the network for the tempo setting, measured in blocks, for the 2803 specified subnet. 2804 2805 Args: 2806 netuid: The network UID for which to query the tempo. 2807 2808 Returns: 2809 The tempo setting for the specified subnet. 2810 2811 Raises: 2812 QueryError: If the query to the network fails or is invalid. 2813 """ 2814 2815 return self.query("Tempo", params=[netuid]) 2816 2817 def get_total_free_issuance(self, block_hash: str | None = None) -> int: 2818 """ 2819 Queries the network for the total free issuance. 2820 2821 Fetches the total amount of free issuance tokens available 2822 2823 Returns: 2824 The total free issuance amount. 2825 2826 Raises: 2827 QueryError: If the query to the network fails or is invalid. 2828 """ 2829 2830 return self.query( 2831 "TotalIssuance", module="Balances", block_hash=block_hash 2832 ) 2833 2834 def get_total_stake(self, block_hash: str | None = None) -> int: 2835 """ 2836 Retrieves a mapping of total stakes for keys on the network. 2837 2838 Queries the network for a mapping of key UIDs to their total stake amounts. 2839 2840 Returns: 2841 A dictionary mapping key UIDs to their total stake amounts. 2842 2843 Raises: 2844 QueryError: If the query to the network fails or is invalid. 2845 """ 2846 2847 return self.query("TotalStake", block_hash=block_hash) 2848 2849 def get_registrations_per_block(self): 2850 """ 2851 Queries the network for the number of registrations per block. 2852 2853 Fetches the number of registrations that are processed per 2854 block within the network. 2855 2856 Returns: 2857 The number of registrations processed per block. 2858 2859 Raises: 2860 QueryError: If the query to the network fails or is invalid. 2861 """ 2862 2863 return self.query( 2864 "RegistrationsPerBlock", 2865 ) 2866 2867 def max_registrations_per_block(self, netuid: int = 0): 2868 """ 2869 Queries the network for the maximum number of registrations per block. 2870 2871 Retrieves the upper limit of registrations that can be processed in 2872 each block within a specific network subnet. 2873 2874 Args: 2875 netuid: The network UID for which to query. 2876 2877 Returns: 2878 The maximum number of registrations per block for 2879 the specified network subnet. 2880 2881 Raises: 2882 QueryError: If the query to the network fails or is invalid. 2883 """ 2884 2885 return self.query( 2886 "MaxRegistrationsPerBlock", 2887 params=[netuid], 2888 ) 2889 2890 def get_proposal(self, proposal_id: int = 0): 2891 """ 2892 Queries the network for a specific proposal. 2893 2894 Args: 2895 proposal_id: The ID of the proposal to query. 2896 2897 Returns: 2898 The details of the specified proposal. 2899 2900 Raises: 2901 QueryError: If the query to the network fails, is invalid, 2902 or if the proposal ID does not exist. 2903 """ 2904 2905 return self.query( 2906 "Proposals", 2907 params=[proposal_id], 2908 ) 2909 2910 def get_trust(self, netuid: int = 0): 2911 """ 2912 Queries the network for the trust setting of a specific network subnet. 2913 2914 Retrieves the trust level or score, which may represent the 2915 level of trustworthiness or reliability within a 2916 particular network subnet. 2917 2918 Args: 2919 netuid: The network UID for which to query the trust setting. 2920 2921 Returns: 2922 The trust level or score for the specified network subnet. 2923 2924 Raises: 2925 QueryError: If the query to the network fails or is invalid. 2926 """ 2927 2928 return self.query( 2929 "Trust", 2930 params=[netuid], 2931 ) 2932 2933 def get_uids(self, key: Ss58Address, netuid: int = 0) -> bool | None: 2934 """ 2935 Queries the network for module UIDs associated with a specific key. 2936 2937 Args: 2938 key: The key address for which to query UIDs. 2939 netuid: The network UID within which to search for the key. 2940 2941 Returns: 2942 A list of UIDs associated with the specified key. 2943 2944 Raises: 2945 QueryError: If the query to the network fails or is invalid. 2946 """ 2947 2948 return self.query( 2949 "Uids", 2950 params=[netuid, key], 2951 ) 2952 2953 def get_unit_emission(self) -> int: 2954 """ 2955 Queries the network for the unit emission setting. 2956 2957 Retrieves the unit emission value, which represents the 2958 emission rate or quantity for the $COMM token. 2959 2960 Returns: 2961 The unit emission value in nanos for the network. 2962 2963 Raises: 2964 QueryError: If the query to the network fails or is invalid. 2965 """ 2966 2967 return self.query("UnitEmission", module="SubnetEmissionModule") 2968 2969 def get_tx_rate_limit(self) -> int: 2970 """ 2971 Queries the network for the transaction rate limit. 2972 2973 Retrieves the rate limit for transactions within the network, 2974 which defines the maximum number of transactions that can be 2975 processed within a certain timeframe. 2976 2977 Returns: 2978 The transaction rate limit for the network. 2979 2980 Raises: 2981 QueryError: If the query to the network fails or is invalid. 2982 """ 2983 2984 return self.query( 2985 "TxRateLimit", 2986 ) 2987 2988 def get_subnet_burn(self) -> int: 2989 """Queries the network for the subnet burn value. 2990 2991 Retrieves the subnet burn value from the network, which represents 2992 the amount of tokens that are burned (permanently removed from 2993 circulation) for subnet-related operations. 2994 2995 Returns: 2996 int: The subnet burn value. 2997 2998 Raises: 2999 QueryError: If the query to the network fails or returns invalid data. 3000 """ 3001 3002 return self.query( 3003 "SubnetBurn", 3004 ) 3005 3006 def get_burn_rate(self) -> int: 3007 """ 3008 Queries the network for the burn rate setting. 3009 3010 Retrieves the burn rate, which represents the rate at 3011 which the $COMM token is permanently 3012 removed or 'burned' from circulation. 3013 3014 Returns: 3015 The burn rate for the network. 3016 3017 Raises: 3018 QueryError: If the query to the network fails or is invalid. 3019 """ 3020 3021 return self.query( 3022 "BurnRate", 3023 params=[], 3024 ) 3025 3026 def get_burn(self, netuid: int = 0) -> int: 3027 """ 3028 Queries the network for the burn setting. 3029 3030 Retrieves the burn value, which represents the amount of the 3031 $COMM token that is 'burned' or permanently removed from 3032 circulation. 3033 3034 Args: 3035 netuid: The network UID for which to query the burn value. 3036 3037 Returns: 3038 The burn value for the specified network subnet. 3039 3040 Raises: 3041 QueryError: If the query to the network fails or is invalid. 3042 """ 3043 3044 return self.query("Burn", params=[netuid]) 3045 3046 def get_min_burn(self) -> int: 3047 """ 3048 Queries the network for the minimum burn setting. 3049 3050 Retrieves the minimum burn value, indicating the lowest 3051 amount of the $COMM tokens that can be 'burned' or 3052 permanently removed from circulation. 3053 3054 Returns: 3055 The minimum burn value for the network. 3056 3057 Raises: 3058 QueryError: If the query to the network fails or is invalid. 3059 """ 3060 3061 return self.query( 3062 "BurnConfig", 3063 params=[], 3064 )["min_burn"] 3065 3066 def get_min_weight_stake(self) -> int: 3067 """ 3068 Queries the network for the minimum weight stake setting. 3069 3070 Retrieves the minimum weight stake, which represents the lowest 3071 stake weight that is allowed for certain operations or 3072 transactions within the network. 3073 3074 Returns: 3075 The minimum weight stake for the network. 3076 3077 Raises: 3078 QueryError: If the query to the network fails or is invalid. 3079 """ 3080 3081 return self.query("MinWeightStake", params=[]) 3082 3083 def get_vote_mode_global(self) -> str: 3084 """ 3085 Queries the network for the global vote mode setting. 3086 3087 Retrieves the global vote mode, which defines the overall voting 3088 methodology or approach used across the network in default. 3089 3090 Returns: 3091 The global vote mode setting for the network. 3092 3093 Raises: 3094 QueryError: If the query to the network fails or is invalid. 3095 """ 3096 3097 return self.query( 3098 "VoteModeGlobal", 3099 ) 3100 3101 def get_max_proposals(self) -> int: 3102 """ 3103 Queries the network for the maximum number of proposals allowed. 3104 3105 Retrieves the upper limit on the number of proposals that can be 3106 active or considered at any given time within the network. 3107 3108 Returns: 3109 The maximum number of proposals allowed on the network. 3110 3111 Raises: 3112 QueryError: If the query to the network fails or is invalid. 3113 """ 3114 3115 return self.query( 3116 "MaxProposals", 3117 ) 3118 3119 def get_max_registrations_per_block(self) -> int: 3120 """ 3121 Queries the network for the maximum number of registrations per block. 3122 3123 Retrieves the maximum number of registrations that can 3124 be processed in each block within the network. 3125 3126 Returns: 3127 The maximum number of registrations per block on the network. 3128 3129 Raises: 3130 QueryError: If the query to the network fails or is invalid. 3131 """ 3132 3133 return self.query( 3134 "MaxRegistrationsPerBlock", 3135 params=[], 3136 ) 3137 3138 def get_max_name_length(self) -> int: 3139 """ 3140 Queries the network for the maximum length allowed for names. 3141 3142 Retrieves the maximum character length permitted for names 3143 within the network. Such as the module names 3144 3145 Returns: 3146 The maximum length allowed for names on the network. 3147 3148 Raises: 3149 QueryError: If the query to the network fails or is invalid. 3150 """ 3151 3152 return self.query( 3153 "MaxNameLength", 3154 params=[], 3155 ) 3156 3157 def get_global_vote_threshold(self) -> int: 3158 """ 3159 Queries the network for the global vote threshold. 3160 3161 Retrieves the global vote threshold, which is the critical value or 3162 percentage required for decisions in the network's governance process. 3163 3164 Returns: 3165 The global vote threshold for the network. 3166 3167 Raises: 3168 QueryError: If the query to the network fails or is invalid. 3169 """ 3170 3171 return self.query( 3172 "GlobalVoteThreshold", 3173 ) 3174 3175 def get_max_allowed_subnets(self) -> int: 3176 """ 3177 Queries the network for the maximum number of allowed subnets. 3178 3179 Retrieves the upper limit on the number of subnets that can 3180 be created or operated within the network. 3181 3182 Returns: 3183 The maximum number of allowed subnets on the network. 3184 3185 Raises: 3186 QueryError: If the query to the network fails or is invalid. 3187 """ 3188 3189 return self.query( 3190 "MaxAllowedSubnets", 3191 params=[], 3192 ) 3193 3194 def get_max_allowed_modules(self) -> int: 3195 """ 3196 Queries the network for the maximum number of allowed modules. 3197 3198 Retrieves the upper limit on the number of modules that 3199 can be registered within the network. 3200 3201 Returns: 3202 The maximum number of allowed modules on the network. 3203 3204 Raises: 3205 QueryError: If the query to the network fails or is invalid. 3206 """ 3207 3208 return self.query( 3209 "MaxAllowedModules", 3210 params=[], 3211 ) 3212 3213 def get_min_stake(self, netuid: int = 0) -> int: 3214 """ 3215 Queries the network for the minimum stake required to register a key. 3216 3217 Retrieves the minimum amount of stake necessary for 3218 registering a key within a specific network subnet. 3219 3220 Args: 3221 netuid: The network UID for which to query the minimum stake. 3222 3223 Returns: 3224 The minimum stake required for key registration in nanos. 3225 3226 Raises: 3227 QueryError: If the query to the network fails or is invalid. 3228 """ 3229 3230 return self.query("MinStake", params=[netuid]) 3231 3232 def get_stakefrom( 3233 self, 3234 key: Ss58Address, 3235 ) -> dict[str, int]: 3236 """ 3237 Retrieves the stake amounts from all stakers to a specific staked address. 3238 3239 Queries the network for the stakes received by a particular staked address 3240 from all stakers. 3241 3242 Args: 3243 key: The address of the key receiving the stakes. 3244 3245 Returns: 3246 A dictionary mapping staker addresses to their respective stake amounts. 3247 3248 Raises: 3249 QueryError: If the query to the network fails or is invalid. 3250 """ 3251 3252 # Has to use query map in order to iterate through the storage prefix. 3253 return self.query_map("StakeFrom", [key], extract_value=False).get( 3254 "StakeFrom", {} 3255 ) 3256 3257 def get_staketo( 3258 self, 3259 key: Ss58Address, 3260 ) -> dict[str, int]: 3261 """ 3262 Retrieves the stake amounts provided by a specific staker to all staked addresses. 3263 3264 Queries the network for the stakes provided by a particular staker to 3265 all staked addresses. 3266 3267 Args: 3268 key: The address of the key providing the stakes. 3269 3270 Returns: 3271 A dictionary mapping staked addresses to their respective received stake amounts. 3272 3273 Raises: 3274 QueryError: If the query to the network fails or is invalid. 3275 """ 3276 3277 # Has to use query map in order to iterate through the storage prefix. 3278 return self.query_map("StakeTo", [key], extract_value=False).get( 3279 "StakeTo", {} 3280 ) 3281 3282 def get_balance( 3283 self, 3284 addr: Ss58Address, 3285 ) -> int: 3286 """ 3287 Retrieves the balance of a specific key. 3288 3289 Args: 3290 addr: The address of the key to query the balance for. 3291 3292 Returns: 3293 The balance of the specified key. 3294 3295 Raises: 3296 QueryError: If the query to the network fails or is invalid. 3297 """ 3298 3299 result = self.query("Account", module="System", params=[addr]) 3300 3301 return result["data"]["free"] 3302 3303 def get_block(self, block_hash: str | None = None) -> dict[Any, Any] | None: 3304 """ 3305 Retrieves information about a specific block in the network. 3306 3307 Queries the network for details about a block, such as its number, 3308 hash, and other relevant information. 3309 3310 Returns: 3311 The requested information about the block, 3312 or None if the block does not exist 3313 or the information is not available. 3314 3315 Raises: 3316 QueryError: If the query to the network fails or is invalid. 3317 """ 3318 3319 with self.get_conn() as substrate: 3320 block: dict[Any, Any] | None = substrate.get_block( # type: ignore 3321 block_hash # type: ignore 3322 ) 3323 3324 return block 3325 3326 def get_existential_deposit(self, block_hash: str | None = None) -> int: 3327 """ 3328 Retrieves the existential deposit value for the network. 3329 3330 The existential deposit is the minimum balance that must be maintained 3331 in an account to prevent it from being purged. Denotated in nano units. 3332 3333 Returns: 3334 The existential deposit value in nano units. 3335 Note: 3336 The value returned is a fixed value defined in the 3337 client and may not reflect changes in the network's configuration. 3338 """ 3339 3340 with self.get_conn() as substrate: 3341 result: int = substrate.get_constant( # type: ignore 3342 "Balances", "ExistentialDeposit", block_hash 3343 ).value # type: ignore 3344 3345 return result 3346 3347 def get_voting_power_delegators(self) -> list[Ss58Address]: 3348 result = self.query( 3349 "NotDelegatingVotingPower", [], module="GovernanceModule" 3350 ) 3351 return result 3352 3353 def add_transfer_dao_treasury_proposal( 3354 self, 3355 key: Keypair, 3356 data: str, 3357 amount_nano: int, 3358 dest: Ss58Address, 3359 ): 3360 params = {"dest": dest, "value": amount_nano, "data": data} 3361 3362 return self.compose_call( 3363 module="GovernanceModule", 3364 fn="add_transfer_dao_treasury_proposal", 3365 params=params, 3366 key=key, 3367 ) 3368 3369 3370if __name__ == "__main__": 3371 from time import sleep 3372 3373 from communex._common import get_node_url 3374 from communex.compat.key import try_classic_load_key 3375 3376 kp = try_classic_load_key("testkey") 3377 node = get_node_url(use_testnet=True) 3378 print(f"Using node: {node}") 3379 client = CommuneClient(node, timeout=65, num_connections=1) 3380 while True: 3381 timeout = 8 3382 sleep(timeout) 3383 block = client.get_block() 3384 print(block["header"]["number"]) # type: ignore
28@dataclass 29class ConnectionContainer: 30 substrate: SubstrateInterface 31 stop_event: threading.Event 32 lock: threading.Lock
35@dataclass 36class Chunk: 37 batch_requests: list[tuple[Any, Any]] 38 prefix_list: list[list[str]] 39 fun_params: list[tuple[Any, Any, Any, Any, str]]
46def send_heartbeat( 47 si: SubstrateInterface, 48 stop: threading.Event, 49 lock: threading.Lock, 50): 51 while not stop.is_set(): 52 # uses substrateinterface wrapper because its very stateful 53 # and we could mess with something by directly using the websocket 54 with lock: 55 _ = si.websocket.pong() # type: ignore 56 sleep(11) # Send heartbeat every 30 seconds
78class CommuneClient: 79 """ 80 A client for interacting with Commune network nodes, querying storage, 81 submitting transactions, etc. 82 83 Attributes: 84 wait_for_finalization: Whether to wait for transaction finalization. 85 86 Example: 87 ```py 88 client = CommuneClient() 89 client.query(name='function_name', params=['param1', 'param2']) 90 ``` 91 92 Raises: 93 AssertionError: If the maximum connections value is less than or equal 94 to zero. 95 """ 96 97 wait_for_finalization: bool 98 _num_connections: int 99 _connection_queue: queue.Queue[ConnectionContainer] 100 _ws_options: dict[str, int] 101 url: str 102 103 def __init__( 104 self, 105 url: str, 106 num_connections: int = 1, 107 wait_for_finalization: bool = False, 108 timeout: int | None = None, 109 ): 110 """ 111 Args: 112 url: The URL of the network node to connect to. 113 num_connections: The number of websocket connections to be opened. 114 """ 115 assert num_connections > 0 116 self._num_connections = num_connections 117 self.wait_for_finalization = wait_for_finalization 118 self._connection_queue = queue.Queue(num_connections) 119 self.url = url 120 121 for _ in range(num_connections): 122 ws_options: dict[str, int] = {} 123 if timeout is not None: 124 ws_options["timeout"] = timeout 125 self._ws_options = ws_options 126 self._connection_queue.put( 127 _instantiate_substrateinterface( 128 url, ws_options, threading.Lock() 129 ) 130 ) 131 132 @property 133 def connections(self) -> int: 134 """ 135 Gets the maximum allowed number of simultaneous connections to the 136 network node. 137 """ 138 return self._num_connections 139 140 @contextmanager 141 def get_conn(self, timeout: float | None = None, init: bool = False): 142 """ 143 Context manager to get a connection from the pool. 144 145 Tries to get a connection from the pool queue. If the queue is empty, 146 it blocks for `timeout` seconds until a connection is available. If 147 `timeout` is None, it blocks indefinitely. 148 149 Args: 150 timeout: The maximum time in seconds to wait for a connection. 151 152 Yields: 153 The connection object from the pool. 154 155 Raises: 156 QueueEmptyError: If no connection is available within the timeout 157 period. 158 """ 159 conn = self._connection_queue.get(timeout=timeout) 160 if init: 161 conn.substrate.init_runtime() # type: ignore 162 try: 163 gc.collect() 164 if conn.substrate.websocket and conn.substrate.websocket.connected: # type: ignore 165 with conn.lock: 166 yield conn.substrate 167 else: 168 # reconnects 169 conn.stop_event.set() 170 conn = _instantiate_substrateinterface( 171 self.url, self._ws_options, threading.Lock() 172 ) 173 with conn.lock: 174 yield conn.substrate 175 finally: 176 self._connection_queue.put(conn) 177 178 def _get_storage_keys( 179 self, 180 storage: str, 181 queries: list[tuple[str, list[Any]]], 182 block_hash: str | None, 183 ): 184 send: list[tuple[str, list[Any]]] = [] 185 prefix_list: list[Any] = [] 186 187 key_idx = 0 188 with self.get_conn(init=True) as substrate: 189 for function, params in queries: 190 storage_key = StorageKey.create_from_storage_function( # type: ignore 191 storage, 192 function, 193 params, 194 runtime_config=substrate.runtime_config, # type: ignore 195 metadata=substrate.metadata, # type: ignore 196 ) 197 198 prefix = storage_key.to_hex() 199 prefix_list.append(prefix) 200 send.append(("state_getKeys", [prefix, block_hash])) 201 key_idx += 1 202 return send, prefix_list 203 204 def _get_lists( 205 self, 206 storage_module: str, 207 queries: list[tuple[str, list[Any]]], 208 substrate: SubstrateInterface, 209 ) -> list[tuple[Any, Any, Any, Any, str]]: 210 """ 211 Generates a list of tuples containing parameters for each storage function based on the given functions and substrate interface. 212 213 Args: 214 functions (dict[str, list[query_call]]): A dictionary where keys are storage module names and values are lists of tuples. 215 Each tuple consists of a storage function name and its parameters. 216 substrate: An instance of the SubstrateInterface class used to interact with the substrate. 217 218 Returns: 219 A list of tuples in the format `(value_type, param_types, key_hashers, params, storage_function)` for each storage function in the given functions. 220 221 Example: 222 >>> _get_lists( 223 functions={'storage_module': [('storage_function', ['param1', 'param2'])]}, 224 substrate=substrate_instance 225 ) 226 [('value_type', 'param_types', 'key_hashers', ['param1', 'param2'], 'storage_function'), ...] 227 """ 228 229 function_parameters: list[tuple[Any, Any, Any, Any, str]] = [] 230 231 metadata_pallet = substrate.metadata.get_metadata_pallet( # type: ignore 232 storage_module 233 ) 234 for storage_function, params in queries: 235 storage_item = metadata_pallet.get_storage_function( # type: ignore 236 storage_function 237 ) 238 239 value_type = storage_item.get_value_type_string() # type: ignore 240 param_types = storage_item.get_params_type_string() # type: ignore 241 key_hashers = storage_item.get_param_hashers() # type: ignore 242 function_parameters.append( 243 ( 244 value_type, 245 param_types, 246 key_hashers, 247 params, 248 storage_function, 249 ) # type: ignore 250 ) 251 return function_parameters 252 253 def _send_batch( 254 self, 255 batch_payload: list[Any], 256 request_ids: list[int], 257 extract_result: bool = True, 258 ): 259 """ 260 Sends a batch of requests to the substrate and collects the results. 261 262 Args: 263 substrate: An instance of the substrate interface. 264 batch_payload: The payload of the batch request. 265 request_ids: A list of request IDs for tracking responses. 266 results: A list to store the results of the requests. 267 extract_result: Whether to extract the result from the response. 268 269 Raises: 270 NetworkQueryError: If there is an `error` in the response message. 271 272 Note: 273 No explicit return value as results are appended to the provided 'results' list. 274 """ 275 results: list[str | dict[Any, Any]] = [] 276 with self.get_conn(init=True) as substrate: 277 try: 278 substrate.websocket.send( # type: ignore 279 json.dumps(batch_payload) 280 ) 281 except NetworkQueryError: 282 pass 283 while len(results) < len(request_ids): 284 received_messages = json.loads( 285 substrate.websocket.recv() # type: ignore 286 ) 287 if isinstance(received_messages, dict): 288 received_messages: list[dict[Any, Any]] = [ 289 received_messages 290 ] 291 292 for message in received_messages: 293 if message.get("id") in request_ids: 294 if extract_result: 295 try: 296 results.append(message["result"]) 297 except Exception: 298 raise ( 299 RuntimeError( 300 f"Error extracting result from message: {message}" 301 ) 302 ) 303 else: 304 results.append(message) 305 if "error" in message: 306 raise NetworkQueryError(message["error"]) 307 308 return results 309 310 def _make_request_smaller( 311 self, 312 batch_request: list[tuple[T1, T2]], 313 prefix_list: list[list[str]], 314 fun_params: list[tuple[Any, Any, Any, Any, str]], 315 ) -> tuple[list[list[tuple[T1, T2]]], list[Chunk]]: 316 """ 317 Splits a batch of requests into smaller batches, each not exceeding the specified maximum size. 318 319 Args: 320 batch_request: A list of requests to be sent in a batch. 321 max_size: Maximum size of each batch in bytes. 322 323 Returns: 324 A list of smaller request batches. 325 326 Example: 327 >>> _make_request_smaller(batch_request=[('method1', 'params1'), ('method2', 'params2')], max_size=1000) 328 [[('method1', 'params1')], [('method2', 'params2')]] 329 """ 330 assert len(prefix_list) == len(fun_params) == len(batch_request) 331 332 def estimate_size(request: tuple[T1, T2]): 333 """Convert the batch request to a string and measure its length""" 334 return len(json.dumps(request)) 335 336 # Initialize variables 337 result: list[list[tuple[T1, T2]]] = [] 338 current_batch = [] 339 current_prefix_batch = [] 340 current_params_batch = [] 341 current_size = 0 342 343 chunk_list: list[Chunk] = [] 344 345 # Iterate through each request in the batch 346 for request, prefix, params in zip( 347 batch_request, prefix_list, fun_params 348 ): 349 request_size = estimate_size(request) 350 351 # Check if adding this request exceeds the max size 352 if current_size + request_size > MAX_REQUEST_SIZE: 353 # If so, start a new batch 354 355 # Essentiatly checks that it's not the first iteration 356 if current_batch: 357 chunk = Chunk( 358 current_batch, 359 current_prefix_batch, 360 current_params_batch, 361 ) 362 chunk_list.append(chunk) 363 result.append(current_batch) 364 365 current_batch = [request] 366 current_prefix_batch = [prefix] 367 current_params_batch = [params] 368 current_size = request_size 369 else: 370 # Otherwise, add to the current batch 371 current_batch.append(request) 372 current_size += request_size 373 current_prefix_batch.append(prefix) 374 current_params_batch.append(params) 375 376 # Add the last batch if it's not empty 377 if current_batch: 378 result.append(current_batch) 379 chunk = Chunk( 380 current_batch, current_prefix_batch, current_params_batch 381 ) 382 chunk_list.append(chunk) 383 384 return result, chunk_list 385 386 def _are_changes_equal(self, change_a: Any, change_b: Any): 387 for (a, b), (c, d) in zip(change_a, change_b): 388 if a != c or b != d: 389 return False 390 391 def _rpc_request_batch( 392 self, 393 batch_requests: list[tuple[str, list[Any]]], 394 extract_result: bool = True, 395 ) -> list[str]: 396 """ 397 Sends batch requests to the substrate node using multiple threads and collects the results. 398 399 Args: 400 substrate: An instance of the substrate interface. 401 batch_requests : A list of requests to be sent in batches. 402 max_size: Maximum size of each batch in bytes. 403 extract_result: Whether to extract the result from the response message. 404 405 Returns: 406 A list of results from the batch requests. 407 408 Example: 409 >>> _rpc_request_batch(substrate_instance, [('method1', ['param1']), ('method2', ['param2'])]) 410 ['result1', 'result2', ...] 411 """ 412 413 chunk_results: list[Any] = [] 414 # smaller_requests = self._make_request_smaller(batch_requests) 415 request_id = 0 416 with ThreadPoolExecutor() as executor: 417 futures: list[Future[list[str | dict[Any, Any]]]] = [] 418 for chunk in [batch_requests]: 419 request_ids: list[int] = [] 420 batch_payload: list[Any] = [] 421 for method, params in chunk: 422 request_id += 1 423 request_ids.append(request_id) 424 batch_payload.append( 425 { 426 "jsonrpc": "2.0", 427 "method": method, 428 "params": params, 429 "id": request_id, 430 } 431 ) 432 433 futures.append( 434 executor.submit( 435 self._send_batch, 436 batch_payload=batch_payload, 437 request_ids=request_ids, 438 extract_result=extract_result, 439 ) 440 ) 441 for future in futures: 442 resul = future.result() 443 chunk_results.append(resul) 444 return chunk_results 445 446 def _rpc_request_batch_chunked( 447 self, chunk_requests: list[Chunk], extract_result: bool = True 448 ): 449 """ 450 Sends batch requests to the substrate node using multiple threads and collects the results. 451 452 Args: 453 substrate: An instance of the substrate interface. 454 batch_requests : A list of requests to be sent in batches. 455 max_size: Maximum size of each batch in bytes. 456 extract_result: Whether to extract the result from the response message. 457 458 Returns: 459 A list of results from the batch requests. 460 461 Example: 462 >>> _rpc_request_batch(substrate_instance, [('method1', ['param1']), ('method2', ['param2'])]) 463 ['result1', 'result2', ...] 464 """ 465 466 def split_chunks( 467 chunk: Chunk, chunk_info: list[Chunk], chunk_info_idx: int 468 ): 469 manhattam_chunks: list[tuple[Any, Any]] = [] 470 mutaded_chunk_info = deepcopy(chunk_info) 471 max_n_keys = 35000 472 for query in chunk.batch_requests: 473 result_keys = query[1][0] 474 keys_amount = len(result_keys) 475 if keys_amount > max_n_keys: 476 mutaded_chunk_info.pop(chunk_info_idx) 477 for i in range(0, keys_amount, max_n_keys): 478 new_chunk = deepcopy(chunk) 479 splitted_keys = result_keys[i : i + max_n_keys] 480 splitted_query = deepcopy(query) 481 splitted_query[1][0] = splitted_keys 482 new_chunk.batch_requests = [splitted_query] 483 manhattam_chunks.append(splitted_query) 484 mutaded_chunk_info.insert(chunk_info_idx, new_chunk) 485 else: 486 manhattam_chunks.append(query) 487 return manhattam_chunks, mutaded_chunk_info 488 489 assert len(chunk_requests) > 0 490 mutated_chunk_info: list[Chunk] = [] 491 chunk_results: list[Any] = [] 492 # smaller_requests = self._make_request_smaller(batch_requests) 493 request_id = 0 494 495 with ThreadPoolExecutor() as executor: 496 futures: list[Future[list[str | dict[Any, Any]]]] = [] 497 for idx, macro_chunk in enumerate(chunk_requests): 498 _, mutated_chunk_info = split_chunks( 499 macro_chunk, chunk_requests, idx 500 ) 501 for chunk in mutated_chunk_info: 502 request_ids: list[int] = [] 503 batch_payload: list[Any] = [] 504 for method, params in chunk.batch_requests: 505 # for method, params in micro_chunk: 506 request_id += 1 507 request_ids.append(request_id) 508 batch_payload.append( 509 { 510 "jsonrpc": "2.0", 511 "method": method, 512 "params": params, 513 "id": request_id, 514 } 515 ) 516 futures.append( 517 executor.submit( 518 self._send_batch, 519 batch_payload=batch_payload, 520 request_ids=request_ids, 521 extract_result=extract_result, 522 ) 523 ) 524 for future in futures: 525 resul = future.result() 526 chunk_results.append(resul) 527 return chunk_results, mutated_chunk_info 528 529 def _decode_response( 530 self, 531 response: list[str], 532 function_parameters: list[tuple[Any, Any, Any, Any, str]], 533 prefix_list: list[Any], 534 block_hash: str, 535 ) -> dict[str, dict[Any, Any]]: 536 """ 537 Decodes a response from the substrate interface and organizes the data into a dictionary. 538 539 Args: 540 response: A list of encoded responses from a substrate query. 541 function_parameters: A list of tuples containing the parameters for each storage function. 542 last_keys: A list of the last keys used in the substrate query. 543 prefix_list: A list of prefixes used in the substrate query. 544 substrate: An instance of the SubstrateInterface class. 545 block_hash: The hash of the block to be queried. 546 547 Returns: 548 A dictionary where each key is a storage function name and the value is another dictionary. 549 This inner dictionary's key is the decoded key from the response and the value is the corresponding decoded value. 550 551 Raises: 552 ValueError: If an unsupported hash type is encountered in the `concat_hash_len` function. 553 554 Example: 555 >>> _decode_response( 556 response=[...], 557 function_parameters=[...], 558 last_keys=[...], 559 prefix_list=[...], 560 substrate=substrate_instance, 561 block_hash="0x123..." 562 ) 563 {'storage_function_name': {decoded_key: decoded_value, ...}, ...} 564 """ 565 566 def get_item_key_value( 567 item_key: tuple[Any, ...] | Any, 568 ) -> tuple[Any, ...] | Any: 569 if isinstance(item_key, tuple): 570 return tuple(k.value for k in item_key) # type: ignore 571 return item_key.value 572 573 def concat_hash_len(key_hasher: str) -> int: 574 """ 575 Determines the length of the hash based on the given key hasher type. 576 577 Args: 578 key_hasher: The type of key hasher. 579 580 Returns: 581 The length of the hash corresponding to the given key hasher type. 582 583 Raises: 584 ValueError: If the key hasher type is not supported. 585 586 Example: 587 >>> concat_hash_len("Blake2_128Concat") 588 16 589 """ 590 591 if key_hasher == "Blake2_128Concat": 592 return 16 593 elif key_hasher == "Twox64Concat": 594 return 8 595 elif key_hasher == "Identity": 596 return 0 597 else: 598 raise ValueError("Unsupported hash type") 599 600 assert len(response) == len(function_parameters) == len(prefix_list) 601 result_dict: dict[str, dict[Any, Any]] = {} 602 for res, fun_params_tuple, prefix in zip( 603 response, function_parameters, prefix_list 604 ): 605 if not res: 606 continue 607 res = res[0] 608 changes = res["changes"] # type: ignore 609 value_type, param_types, key_hashers, params, storage_function = ( 610 fun_params_tuple 611 ) 612 with self.get_conn(init=True) as substrate: 613 for item in changes: 614 # Determine type string 615 key_type_string: list[Any] = [] 616 for n in range(len(params), len(param_types)): 617 key_type_string.append( 618 f"[u8; {concat_hash_len(key_hashers[n])}]" 619 ) 620 key_type_string.append(param_types[n]) 621 622 item_key_obj = substrate.decode_scale( # type: ignore 623 type_string=f"({', '.join(key_type_string)})", 624 scale_bytes="0x" + item[0][len(prefix) :], 625 return_scale_obj=True, 626 block_hash=block_hash, 627 ) 628 # strip key_hashers to use as item key 629 if len(param_types) - len(params) == 1: 630 item_key = item_key_obj.value_object[1] # type: ignore 631 else: 632 item_key = tuple( # type: ignore 633 item_key_obj.value_object[key + 1] # type: ignore 634 for key in range( # type: ignore 635 len(params), len(param_types) + 1, 2 636 ) 637 ) 638 639 item_value = substrate.decode_scale( # type: ignore 640 type_string=value_type, 641 scale_bytes=item[1], 642 return_scale_obj=True, 643 block_hash=block_hash, 644 ) 645 result_dict.setdefault(storage_function, {}) 646 key = get_item_key_value(item_key) # type: ignore 647 result_dict[storage_function][key] = item_value.value # type: ignore 648 649 return result_dict 650 651 def query_batch( 652 self, functions: dict[str, list[tuple[str, list[Any]]]] 653 ) -> dict[str, str]: 654 """ 655 Executes batch queries on a substrate and returns results in a dictionary format. 656 657 Args: 658 substrate: An instance of SubstrateInterface to interact with the substrate. 659 functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls (function name and parameters). 660 661 Returns: 662 A dictionary where keys are storage function names and values are the query results. 663 664 Raises: 665 Exception: If no result is found from the batch queries. 666 667 Example: 668 >>> query_batch(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) 669 {'function_name': 'query_result', ...} 670 """ 671 672 result: dict[str, str] = {} 673 if not functions: 674 raise Exception("No result") 675 with self.get_conn(init=True) as substrate: 676 for module, queries in functions.items(): 677 storage_keys: list[Any] = [] 678 for fn, params in queries: 679 storage_function = substrate.create_storage_key( # type: ignore 680 pallet=module, storage_function=fn, params=params 681 ) 682 storage_keys.append(storage_function) 683 684 block_hash = substrate.get_block_hash() 685 responses: list[Any] = substrate.query_multi( # type: ignore 686 storage_keys=storage_keys, block_hash=block_hash 687 ) 688 689 for item in responses: 690 fun = item[0] 691 query = item[1] 692 storage_fun = fun.storage_function 693 result[storage_fun] = query.value 694 695 return result 696 697 def query_batch_map( 698 self, 699 functions: dict[str, list[tuple[str, list[Any]]]], 700 block_hash: str | None = None, 701 ) -> dict[str, dict[Any, Any]]: 702 """ 703 Queries multiple storage functions using a map batch approach and returns the combined result. 704 705 Args: 706 substrate: An instance of SubstrateInterface for substrate interaction. 707 functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls. 708 709 Returns: 710 The combined result of the map batch query. 711 712 Example: 713 >>> query_batch_map(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) 714 # Returns the combined result of the map batch query 715 """ 716 multi_result: dict[str, dict[Any, Any]] = {} 717 718 def recursive_update( 719 d: dict[str, dict[T1, T2] | dict[str, Any]], 720 u: Mapping[str, dict[Any, Any] | str], 721 ) -> dict[str, dict[T1, T2]]: 722 for k, v in u.items(): 723 if isinstance(v, dict): 724 d[k] = recursive_update(d.get(k, {}), v) # type: ignore 725 else: 726 d[k] = v # type: ignore 727 return d # type: ignore 728 729 def get_page(): 730 send, prefix_list = self._get_storage_keys( 731 storage, queries, block_hash 732 ) 733 with self.get_conn(init=True) as substrate: 734 function_parameters = self._get_lists( 735 storage, queries, substrate 736 ) 737 responses = self._rpc_request_batch(send) 738 # assumption because send is just the storage_function keys 739 # so it should always be really small regardless of the amount of queries 740 assert len(responses) == 1 741 res = responses[0] 742 built_payload: list[tuple[str, list[Any]]] = [] 743 for result_keys in res: 744 built_payload.append( 745 ("state_queryStorageAt", [result_keys, block_hash]) 746 ) 747 _, chunks_info = self._make_request_smaller( 748 built_payload, prefix_list, function_parameters 749 ) 750 chunks_response, chunks_info = self._rpc_request_batch_chunked( 751 chunks_info 752 ) 753 return chunks_response, chunks_info 754 755 if not block_hash: 756 with self.get_conn(init=True) as substrate: 757 block_hash = substrate.get_block_hash() 758 for storage, queries in functions.items(): 759 chunks, chunks_info = get_page() 760 # if this doesn't happen something is wrong on the code 761 # and we won't be able to decode the data properly 762 assert len(chunks) == len(chunks_info) 763 for chunk_info, response in zip(chunks_info, chunks): 764 storage_result = self._decode_response( 765 response, 766 chunk_info.fun_params, 767 chunk_info.prefix_list, 768 block_hash, 769 ) 770 multi_result = recursive_update(multi_result, storage_result) 771 772 return multi_result 773 774 def query( 775 self, 776 name: str, 777 params: list[Any] = [], 778 module: str = "SubspaceModule", 779 block_hash: str | None = None, 780 ) -> Any: 781 """ 782 Queries a storage function on the network. 783 784 Sends a query to the network and retrieves data from a 785 specified storage function. 786 787 Args: 788 name: The name of the storage function to query. 789 params: The parameters to pass to the storage function. 790 module: The module where the storage function is located. 791 792 Returns: 793 The result of the query from the network. 794 795 Raises: 796 NetworkQueryError: If the query fails or is invalid. 797 """ 798 799 result = self.query_batch({module: [(name, params)]}) 800 801 return result[name] 802 803 def query_map( 804 self, 805 name: str, 806 params: list[Any] = [], 807 module: str = "SubspaceModule", 808 extract_value: bool = True, 809 block_hash: str | None = None, 810 ) -> dict[Any, Any]: 811 """ 812 Queries a storage map from a network node. 813 814 Args: 815 name: The name of the storage map to query. 816 params: A list of parameters for the query. 817 module: The module in which the storage map is located. 818 819 Returns: 820 A dictionary representing the key-value pairs 821 retrieved from the storage map. 822 823 Raises: 824 QueryError: If the query to the network fails or is invalid. 825 """ 826 827 result = self.query_batch_map({module: [(name, params)]}, block_hash) 828 829 if extract_value: 830 return {k.value: v.value for k, v in result} # type: ignore 831 832 return result 833 834 def compose_call( 835 self, 836 fn: str, 837 params: dict[str, Any], 838 key: Keypair | None, 839 module: str = "SubspaceModule", 840 wait_for_inclusion: bool = True, 841 wait_for_finalization: bool | None = None, 842 sudo: bool = False, 843 unsigned: bool = False, 844 ) -> ExtrinsicReceipt: 845 """ 846 Composes and submits a call to the network node. 847 848 Composes and signs a call with the provided keypair, and submits it to 849 the network. The call can be a standard extrinsic or a sudo extrinsic if 850 elevated permissions are required. The method can optionally wait for 851 the call's inclusion in a block and/or its finalization. 852 853 Args: 854 fn: The function name to call on the network. 855 params: A dictionary of parameters for the call. 856 key: The keypair for signing the extrinsic. 857 module: The module containing the function. 858 wait_for_inclusion: Wait for the call's inclusion in a block. 859 wait_for_finalization: Wait for the transaction's finalization. 860 sudo: Execute the call as a sudo (superuser) operation. 861 862 Returns: 863 The receipt of the submitted extrinsic, if 864 `wait_for_inclusion` is True. Otherwise, returns a string 865 identifier of the extrinsic. 866 867 Raises: 868 ChainTransactionError: If the transaction fails. 869 """ 870 871 if key is None and not unsigned: 872 raise ValueError("Key must be provided for signed extrinsics.") 873 874 with self.get_conn() as substrate: 875 if wait_for_finalization is None: 876 wait_for_finalization = self.wait_for_finalization 877 878 call = substrate.compose_call( # type: ignore 879 call_module=module, call_function=fn, call_params=params 880 ) 881 if sudo: 882 call = substrate.compose_call( # type: ignore 883 call_module="Sudo", 884 call_function="sudo", 885 call_params={ 886 "call": call.value, # type: ignore 887 }, 888 ) 889 890 if not unsigned: 891 assert key is not None 892 extrinsic = substrate.create_signed_extrinsic( # type: ignore 893 call=call, 894 keypair=key, 895 ) 896 else: 897 extrinsic = substrate.create_unsigned_extrinsic(call=call) # type: ignore 898 899 response = substrate.submit_extrinsic( 900 extrinsic=extrinsic, 901 wait_for_inclusion=wait_for_inclusion, 902 wait_for_finalization=wait_for_finalization, 903 ) 904 if wait_for_inclusion: 905 if not response.is_success: 906 raise ChainTransactionError( 907 response.error_message, # type: ignore 908 response, # type: ignore 909 ) 910 911 return response 912 913 def compose_call_multisig( 914 self, 915 fn: str, 916 params: dict[str, Any], 917 key: Keypair, 918 signatories: list[Ss58Address], 919 threshold: int, 920 module: str = "SubspaceModule", 921 wait_for_inclusion: bool = True, 922 wait_for_finalization: bool | None = None, 923 sudo: bool = False, 924 era: dict[str, int] | None = None, 925 ) -> ExtrinsicReceipt: 926 """ 927 Composes and submits a multisignature call to the network node. 928 929 This method allows the composition and submission of a call that 930 requires multiple signatures for execution, known as a multisignature 931 call. It supports specifying signatories, a threshold of signatures for 932 the call's execution, and an optional era for the call's mortality. The 933 call can be a standard extrinsic, a sudo extrinsic for elevated 934 permissions, or a multisig extrinsic if multiple signatures are 935 required. Optionally, the method can wait for the call's inclusion in a 936 block and/or its finalization. Make sure to pass all keys, 937 that are part of the multisignature. 938 939 Args: 940 fn: The function name to call on the network. params: A dictionary 941 of parameters for the call. key: The keypair for signing the 942 extrinsic. signatories: List of SS58 addresses of the signatories. 943 Include ALL KEYS that are part of the multisig. threshold: The 944 minimum number of signatories required to execute the extrinsic. 945 module: The module containing the function to call. 946 wait_for_inclusion: Whether to wait for the call's inclusion in a 947 block. wait_for_finalization: Whether to wait for the transaction's 948 finalization. sudo: Execute the call as a sudo (superuser) 949 operation. era: Specifies the call's mortality in terms of blocks in 950 the format 951 {'period': amount_blocks}. If omitted, the extrinsic is 952 immortal. 953 954 Returns: 955 The receipt of the submitted extrinsic if `wait_for_inclusion` is 956 True. Otherwise, returns a string identifier of the extrinsic. 957 958 Raises: 959 ChainTransactionError: If the transaction fails. 960 """ 961 962 # getting the call ready 963 with self.get_conn() as substrate: 964 if wait_for_finalization is None: 965 wait_for_finalization = self.wait_for_finalization 966 967 # prepares the `GenericCall` object 968 call = substrate.compose_call( # type: ignore 969 call_module=module, call_function=fn, call_params=params 970 ) 971 if sudo: 972 call = substrate.compose_call( # type: ignore 973 call_module="Sudo", 974 call_function="sudo", 975 call_params={ 976 "call": call.value, # type: ignore 977 }, 978 ) 979 980 # modify the rpc methods at runtime, to allow for correct payment 981 # fee calculation parity has a bug in this version, 982 # where the method has to be removed 983 rpc_methods = substrate.config.get("rpc_methods") # type: ignore 984 985 if "state_call" in rpc_methods: # type: ignore 986 rpc_methods.remove("state_call") # type: ignore 987 988 # create the multisig account 989 multisig_acc = substrate.generate_multisig_account( # type: ignore 990 signatories, threshold 991 ) 992 993 # send the multisig extrinsic 994 extrinsic = substrate.create_multisig_extrinsic( # type: ignore 995 call=call, # type: ignore 996 keypair=key, 997 multisig_account=multisig_acc, # type: ignore 998 era=era, # type: ignore 999 ) # type: ignore 1000 1001 response = substrate.submit_extrinsic( 1002 extrinsic=extrinsic, 1003 wait_for_inclusion=wait_for_inclusion, 1004 wait_for_finalization=wait_for_finalization, 1005 ) 1006 1007 if wait_for_inclusion: 1008 if not response.is_success: 1009 raise ChainTransactionError( 1010 response.error_message, # type: ignore 1011 response, # type: ignore 1012 ) 1013 1014 return response 1015 1016 def transfer( 1017 self, 1018 key: Keypair, 1019 amount: int, 1020 dest: Ss58Address, 1021 ) -> ExtrinsicReceipt: 1022 """ 1023 Transfers a specified amount of tokens from the signer's account to the 1024 specified account. 1025 1026 Args: 1027 key: The keypair associated with the sender's account. 1028 amount: The amount to transfer, in nanotokens. 1029 dest: The SS58 address of the recipient. 1030 1031 Returns: 1032 A receipt of the transaction. 1033 1034 Raises: 1035 InsufficientBalanceError: If the sender's account does not have 1036 enough balance. 1037 ChainTransactionError: If the transaction fails. 1038 """ 1039 1040 params = {"dest": dest, "value": amount} 1041 1042 return self.compose_call( 1043 module="Balances", fn="transfer_keep_alive", params=params, key=key 1044 ) 1045 1046 def transfer_multiple( 1047 self, 1048 key: Keypair, 1049 destinations: list[Ss58Address], 1050 amounts: list[int], 1051 netuid: str | int = 0, 1052 ) -> ExtrinsicReceipt: 1053 """ 1054 Transfers specified amounts of tokens from the signer's account to 1055 multiple target accounts. 1056 1057 The `destinations` and `amounts` lists must be of the same length. 1058 1059 Args: 1060 key: The keypair associated with the sender's account. 1061 destinations: A list of SS58 addresses of the recipients. 1062 amounts: Amount to transfer to each recipient, in nanotokens. 1063 netuid: The network identifier. 1064 1065 Returns: 1066 A receipt of the transaction. 1067 1068 Raises: 1069 InsufficientBalanceError: If the sender's account does not have 1070 enough balance for all transfers. 1071 ChainTransactionError: If the transaction fails. 1072 """ 1073 1074 assert len(destinations) == len(amounts) 1075 1076 # extract existential deposit from amounts 1077 existential_deposit = self.get_existential_deposit() 1078 amounts = [a - existential_deposit for a in amounts] 1079 1080 params = { 1081 "netuid": netuid, 1082 "destinations": destinations, 1083 "amounts": amounts, 1084 } 1085 1086 return self.compose_call( 1087 module="SubspaceModule", 1088 fn="transfer_multiple", 1089 params=params, 1090 key=key, 1091 ) 1092 1093 def stake( 1094 self, 1095 key: Keypair, 1096 amount: int, 1097 dest: Ss58Address, 1098 ) -> ExtrinsicReceipt: 1099 """ 1100 Stakes the specified amount of tokens to a module key address. 1101 1102 Args: 1103 key: The keypair associated with the staker's account. 1104 amount: The amount of tokens to stake, in nanotokens. 1105 dest: The SS58 address of the module key to stake to. 1106 netuid: The network identifier. 1107 1108 Returns: 1109 A receipt of the staking transaction. 1110 1111 Raises: 1112 InsufficientBalanceError: If the staker's account does not have 1113 enough balance. 1114 ChainTransactionError: If the transaction fails. 1115 """ 1116 1117 params = {"amount": amount, "module_key": dest} 1118 1119 return self.compose_call(fn="add_stake", params=params, key=key) 1120 1121 def unstake( 1122 self, 1123 key: Keypair, 1124 amount: int, 1125 dest: Ss58Address, 1126 ) -> ExtrinsicReceipt: 1127 """ 1128 Unstakes the specified amount of tokens from a module key address. 1129 1130 Args: 1131 key: The keypair associated with the unstaker's account. 1132 amount: The amount of tokens to unstake, in nanotokens. 1133 dest: The SS58 address of the module key to unstake from. 1134 netuid: The network identifier. 1135 1136 Returns: 1137 A receipt of the unstaking transaction. 1138 1139 Raises: 1140 InsufficientStakeError: If the staked key does not have enough 1141 staked tokens by the signer key. 1142 ChainTransactionError: If the transaction fails. 1143 """ 1144 1145 params = {"amount": amount, "module_key": dest} 1146 return self.compose_call(fn="remove_stake", params=params, key=key) 1147 1148 def update_module( 1149 self, 1150 key: Keypair, 1151 name: str, 1152 address: str, 1153 metadata: str | None = None, 1154 delegation_fee: int = 20, 1155 weight_setting_delegation_fee: int | None = None, 1156 netuid: int = 0, 1157 ) -> ExtrinsicReceipt: 1158 """ 1159 Updates the parameters of a registered module. 1160 1161 The delegation fee must be an integer between 0 and 100. 1162 1163 Args: 1164 key: The keypair associated with the module's account. 1165 name: The new name for the module. If None, the name is not updated. 1166 address: The new address for the module. 1167 If None, the address is not updated. 1168 delegation_fee: The new delegation fee for the module, 1169 between 0 and 100. 1170 netuid: The network identifier. 1171 1172 Returns: 1173 A receipt of the module update transaction. 1174 1175 Raises: 1176 InvalidParameterError: If the provided parameters are invalid. 1177 ChainTransactionError: If the transaction fails. 1178 """ 1179 1180 assert isinstance(delegation_fee, int) 1181 params = { 1182 "netuid": netuid, 1183 "name": name, 1184 "address": address, 1185 "stake_delegation_fee": delegation_fee, 1186 "validator_weight_fee": weight_setting_delegation_fee, 1187 "metadata": metadata, 1188 } 1189 1190 response = self.compose_call("update_module", params=params, key=key) 1191 1192 return response 1193 1194 def register_module( 1195 self, 1196 key: Keypair, 1197 name: str, 1198 address: str | None = None, 1199 subnet: str = "Rootnet", 1200 metadata: str | None = None, 1201 ) -> ExtrinsicReceipt: 1202 """ 1203 Registers a new module in the network. 1204 1205 Args: 1206 key: The keypair used for registering the module. 1207 name: The name of the module. If None, a default or previously 1208 set name is used. # How does this work? 1209 address: The address of the module. If None, a default or 1210 previously set address is used. # How does this work? 1211 subnet: The network subnet to register the module in. 1212 min_stake: The minimum stake required for the module, in nanotokens. 1213 If None, a default value is used. 1214 1215 Returns: 1216 A receipt of the registration transaction. 1217 1218 Raises: 1219 InvalidParameterError: If the provided parameters are invalid. 1220 ChainTransactionError: If the transaction fails. 1221 """ 1222 1223 key_addr = key.ss58_address 1224 1225 params = { 1226 "network_name": subnet, 1227 "address": address, 1228 "name": name, 1229 "module_key": key_addr, 1230 "metadata": metadata, 1231 } 1232 1233 response = self.compose_call("register", params=params, key=key) 1234 return response 1235 1236 def deregister_module(self, key: Keypair, netuid: int) -> ExtrinsicReceipt: 1237 """ 1238 Deregisters a module from the network. 1239 1240 Args: 1241 key: The keypair associated with the module's account. 1242 netuid: The network identifier. 1243 1244 Returns: 1245 A receipt of the module deregistration transaction. 1246 1247 Raises: 1248 ChainTransactionError: If the transaction fails. 1249 """ 1250 1251 params = {"netuid": netuid} 1252 1253 response = self.compose_call("deregister", params=params, key=key) 1254 1255 return response 1256 1257 def register_subnet( 1258 self, key: Keypair, name: str, metadata: str | None = None 1259 ) -> ExtrinsicReceipt: 1260 """ 1261 Registers a new subnet in the network. 1262 1263 Args: 1264 key (Keypair): The keypair used for registering the subnet. 1265 name (str): The name of the subnet to be registered. 1266 metadata (str | None, optional): Additional metadata for the subnet. Defaults to None. 1267 1268 Returns: 1269 ExtrinsicReceipt: A receipt of the subnet registration transaction. 1270 1271 Raises: 1272 ChainTransactionError: If the transaction fails. 1273 """ 1274 1275 params = { 1276 "name": name, 1277 "metadata": metadata, 1278 } 1279 1280 response = self.compose_call("register_subnet", params=params, key=key) 1281 1282 return response 1283 1284 def vote( 1285 self, 1286 key: Keypair, 1287 uids: list[int], 1288 weights: list[int], 1289 netuid: int = 0, 1290 ) -> ExtrinsicReceipt: 1291 """ 1292 Casts votes on a list of module UIDs with corresponding weights. 1293 1294 The length of the UIDs list and the weights list should be the same. 1295 Each weight corresponds to the UID at the same index. 1296 1297 Args: 1298 key: The keypair used for signing the vote transaction. 1299 uids: A list of module UIDs to vote on. 1300 weights: A list of weights corresponding to each UID. 1301 netuid: The network identifier. 1302 1303 Returns: 1304 A receipt of the voting transaction. 1305 1306 Raises: 1307 InvalidParameterError: If the lengths of UIDs and weights lists 1308 do not match. 1309 ChainTransactionError: If the transaction fails. 1310 """ 1311 1312 assert len(uids) == len(weights) 1313 1314 params = { 1315 "uids": uids, 1316 "weights": weights, 1317 "netuid": netuid, 1318 } 1319 1320 response = self.compose_call( 1321 "set_weights", 1322 params=params, 1323 key=key, 1324 module="SubnetEmissionModule", 1325 ) 1326 1327 return response 1328 1329 def delegate_weight_control( 1330 self, key: Keypair, target: Ss58Address, netuid: int 1331 ): 1332 """ 1333 delegates weight setting control from the current account to the target account. 1334 Both accounts have to be registered and have a valid validator `spec` 1335 """ 1336 1337 params = { 1338 "netuid": netuid, 1339 "target": target, 1340 } 1341 1342 response = self.compose_call( 1343 "delegate_weight_control", 1344 params=params, 1345 key=key, 1346 module="SubnetEmissionModule", 1347 ) 1348 return response 1349 1350 def add_authorities( 1351 self, 1352 key: Keypair, 1353 new_authorities: list[tuple[Ss58Address, tuple[str, str]]], 1354 ): 1355 """ 1356 only for the sudo key 1357 give the authorities as hexadecimal 1358 """ 1359 params = { 1360 "new_authorities": new_authorities, 1361 } 1362 response = self.compose_call( 1363 "add_authorities", 1364 params=params, 1365 key=key, 1366 module="Offworker", 1367 sudo=True, 1368 ) 1369 return response 1370 1371 def vote_encrypted( 1372 self, 1373 key: Keypair, 1374 uids: list[int], 1375 weights: list[int], 1376 netuid: int = 0, 1377 ) -> ExtrinsicReceipt: 1378 """ 1379 Casts encrypted votes for module UIDs with corresponding weights. 1380 1381 Args: 1382 key (Keypair): The keypair used for signing the transaction. 1383 uids (list[int]): List of UIDs to vote for. 1384 weights (list[int]): List of weights corresponding to each UID. 1385 netuid (int, optional): Network UID. Defaults to 0. 1386 1387 Returns: 1388 ExtrinsicReceipt: Receipt of the submitted extrinsic. 1389 1390 Raises: 1391 ValueError: If there's a length mismatch between UIDs and weights, 1392 if subnet data is not found, or if subnet key format is invalid. 1393 """ 1394 if len(uids) != len(weights): 1395 raise ValueError("Length mismatch between UIDs and weights") 1396 1397 subnet_data = self.query( 1398 "SubnetDecryptionData", 1399 module="SubnetEmissionModule", 1400 params=[netuid], 1401 ) 1402 if not subnet_data: 1403 raise ValueError("Subnet data not found") 1404 1405 subnet_key = subnet_data.get("node_public_key") 1406 if not subnet_key or len(subnet_key) < 2: 1407 raise ValueError("Invalid subnet key format") 1408 1409 vote_data = list(zip(uids, weights)) 1410 decryptor = ( 1411 bytes_from_hex(subnet_key[0]), 1412 bytes_from_hex(subnet_key[1]), 1413 ) 1414 validator_key = [int(x) for x in key.public_key] 1415 1416 encrypted_weights = encrypt_weights(decryptor, vote_data, validator_key) 1417 weights_hash = hashlib.sha256(str(weights).encode()).hexdigest() 1418 1419 params = { 1420 "uids": uids, 1421 "encrypted_weights": encrypted_weights, 1422 "netuid": netuid, 1423 "decrypted_weights_hash": weights_hash, 1424 } 1425 1426 return self.compose_call( 1427 "set_weights_encrypted", 1428 params=params, 1429 key=key, 1430 module="SubnetEmissionModule", 1431 ) 1432 1433 def update_subnet( 1434 self, 1435 key: Keypair, 1436 params: SubnetParams, 1437 netuid: int = 0, 1438 ) -> ExtrinsicReceipt: 1439 """ 1440 Update a subnet's configuration. 1441 1442 It requires the founder key for authorization. 1443 1444 Args: 1445 key: The founder keypair of the subnet. 1446 params: The new parameters for the subnet. 1447 netuid: The network identifier. 1448 1449 Returns: 1450 A receipt of the subnet update transaction. 1451 1452 Raises: 1453 AuthorizationError: If the key is not authorized. 1454 ChainTransactionError: If the transaction fails. 1455 """ 1456 1457 general_params = dict(params) 1458 general_params["netuid"] = netuid 1459 if general_params.get("subnet_metadata") is None: 1460 general_params["metadata"] = None 1461 else: 1462 general_params["metadata"] = general_params["subnet_metadata"] 1463 1464 response = self.compose_call( 1465 fn="update_subnet", 1466 params=general_params, 1467 key=key, 1468 ) 1469 1470 return response 1471 1472 def transfer_stake( 1473 self, 1474 key: Keypair, 1475 amount: int, 1476 from_module_key: Ss58Address, 1477 dest_module_address: Ss58Address, 1478 ) -> ExtrinsicReceipt: 1479 """ 1480 Realocate staked tokens from one staked module to another module. 1481 1482 Args: 1483 key: The keypair associated with the account that is delegating the tokens. 1484 amount: The amount of staked tokens to transfer, in nanotokens. 1485 from_module_key: The SS58 address of the module you want to transfer from (currently delegated by the key). 1486 dest_module_address: The SS58 address of the destination (newly delegated key). 1487 netuid: The network identifier. 1488 1489 Returns: 1490 A receipt of the stake transfer transaction. 1491 1492 Raises: 1493 InsufficientStakeError: If the source module key does not have 1494 enough staked tokens. ChainTransactionError: If the transaction 1495 fails. 1496 """ 1497 1498 amount = amount - self.get_existential_deposit() 1499 1500 params = { 1501 "amount": amount, 1502 "module_key": from_module_key, 1503 "new_module_key": dest_module_address, 1504 } 1505 1506 response = self.compose_call("transfer_stake", key=key, params=params) 1507 1508 return response 1509 1510 def bridge( 1511 self, 1512 key: Keypair, 1513 amount: int, 1514 ): 1515 """ 1516 Bridge tokens from the Subspace network to the Torus network. 1517 1518 Args: 1519 key: The keypair associated with the account that is bridging the tokens. 1520 amount: The amount of tokens to bridge, in nanotokens. 1521 1522 Returns: 1523 A receipt of the bridging transaction. 1524 1525 Raises: 1526 InsufficientBalanceError: If the account does not have enough balance. 1527 ChainTransactionError: If the transaction fails. 1528 """ 1529 1530 params = {"amount": amount} 1531 1532 response = self.compose_call("bridge", key=key, params=params) 1533 1534 return response 1535 1536 def bridge_withdraw( 1537 self, 1538 key: Keypair, 1539 amount: int, 1540 ): 1541 """ 1542 Withdraw bridged tokens from the Torus network to the Subspace network. 1543 1544 Args: 1545 key: The keypair associated with the account that is withdrawing the tokens. 1546 amount: The amount of tokens to withdraw, in nanotokens. 1547 1548 Returns: 1549 A receipt of the withdrawal transaction. 1550 1551 Raises: 1552 InsufficientBalanceError: If the account does not have enough balance. 1553 ChainTransactionError: If the transaction fails. 1554 """ 1555 1556 params = {"amount": amount} 1557 1558 response = self.compose_call("bridge_withdraw", key=key, params=params) 1559 1560 return response 1561 1562 def multiunstake( 1563 self, 1564 key: Keypair, 1565 keys: list[Ss58Address], 1566 amounts: list[int], 1567 ) -> ExtrinsicReceipt: 1568 """ 1569 Unstakes tokens from multiple module keys. 1570 1571 And the lists `keys` and `amounts` must be of the same length. Each 1572 amount corresponds to the module key at the same index. 1573 1574 Args: 1575 key: The keypair associated with the unstaker's account. 1576 keys: A list of SS58 addresses of the module keys to unstake from. 1577 amounts: A list of amounts to unstake from each module key, 1578 in nanotokens. 1579 netuid: The network identifier. 1580 1581 Returns: 1582 A receipt of the multi-unstaking transaction. 1583 1584 Raises: 1585 MismatchedLengthError: If the lengths of keys and amounts lists do 1586 not match. InsufficientStakeError: If any of the module keys do not 1587 have enough staked tokens. ChainTransactionError: If the transaction 1588 fails. 1589 """ 1590 1591 assert len(keys) == len(amounts) 1592 1593 params = {"module_keys": keys, "amounts": amounts} 1594 1595 response = self.compose_call( 1596 "remove_stake_multiple", params=params, key=key 1597 ) 1598 1599 return response 1600 1601 def multistake( 1602 self, 1603 key: Keypair, 1604 keys: list[Ss58Address], 1605 amounts: list[int], 1606 ) -> ExtrinsicReceipt: 1607 """ 1608 Stakes tokens to multiple module keys. 1609 1610 The lengths of the `keys` and `amounts` lists must be the same. Each 1611 amount corresponds to the module key at the same index. 1612 1613 Args: 1614 key: The keypair associated with the staker's account. 1615 keys: A list of SS58 addresses of the module keys to stake to. 1616 amounts: A list of amounts to stake to each module key, 1617 in nanotokens. 1618 netuid: The network identifier. 1619 1620 Returns: 1621 A receipt of the multi-staking transaction. 1622 1623 Raises: 1624 MismatchedLengthError: If the lengths of keys and amounts lists 1625 do not match. 1626 ChainTransactionError: If the transaction fails. 1627 """ 1628 1629 assert len(keys) == len(amounts) 1630 1631 params = { 1632 "module_keys": keys, 1633 "amounts": amounts, 1634 } 1635 1636 response = self.compose_call( 1637 "add_stake_multiple", params=params, key=key 1638 ) 1639 1640 return response 1641 1642 def add_profit_shares( 1643 self, 1644 key: Keypair, 1645 keys: list[Ss58Address], 1646 shares: list[int], 1647 ) -> ExtrinsicReceipt: 1648 """ 1649 Allocates profit shares to multiple keys. 1650 1651 The lists `keys` and `shares` must be of the same length, 1652 with each share amount corresponding to the key at the same index. 1653 1654 Args: 1655 key: The keypair associated with the account 1656 distributing the shares. 1657 keys: A list of SS58 addresses to allocate shares to. 1658 shares: A list of share amounts to allocate to each key, 1659 in nanotokens. 1660 1661 Returns: 1662 A receipt of the profit sharing transaction. 1663 1664 Raises: 1665 MismatchedLengthError: If the lengths of keys and shares 1666 lists do not match. 1667 ChainTransactionError: If the transaction fails. 1668 """ 1669 1670 assert len(keys) == len(shares) 1671 1672 params = {"keys": keys, "shares": shares} 1673 1674 response = self.compose_call( 1675 "add_profit_shares", params=params, key=key 1676 ) 1677 1678 return response 1679 1680 def add_subnet_proposal( 1681 self, key: Keypair, params: dict[str, Any], ipfs: str, netuid: int = 0 1682 ) -> ExtrinsicReceipt: 1683 """ 1684 Submits a proposal for creating or modifying a subnet within the 1685 network. 1686 1687 The proposal includes various parameters like the name, founder, share 1688 allocations, and other subnet-specific settings. 1689 1690 Args: 1691 key: The keypair used for signing the proposal transaction. 1692 params: The parameters for the subnet proposal. 1693 netuid: The network identifier. 1694 1695 Returns: 1696 A receipt of the subnet proposal transaction. 1697 1698 Raises: 1699 InvalidParameterError: If the provided subnet 1700 parameters are invalid. 1701 ChainTransactionError: If the transaction fails. 1702 """ 1703 1704 general_params = dict(params) 1705 general_params["netuid"] = netuid 1706 general_params["data"] = ipfs 1707 if "metadata" not in general_params: 1708 general_params["metadata"] = None 1709 1710 # general_params["burn_config"] = json.dumps(general_params["burn_config"]) 1711 response = self.compose_call( 1712 fn="add_subnet_params_proposal", 1713 params=general_params, 1714 key=key, 1715 module="GovernanceModule", 1716 ) 1717 1718 return response 1719 1720 def add_custom_proposal( 1721 self, 1722 key: Keypair, 1723 cid: str, 1724 ) -> ExtrinsicReceipt: 1725 params = {"data": cid} 1726 1727 response = self.compose_call( 1728 fn="add_global_custom_proposal", 1729 params=params, 1730 key=key, 1731 module="GovernanceModule", 1732 ) 1733 return response 1734 1735 def add_custom_subnet_proposal( 1736 self, 1737 key: Keypair, 1738 cid: str, 1739 netuid: int = 0, 1740 ) -> ExtrinsicReceipt: 1741 """ 1742 Submits a proposal for creating or modifying a custom subnet within the 1743 network. 1744 1745 The proposal includes various parameters like the name, founder, share 1746 allocations, and other subnet-specific settings. 1747 1748 Args: 1749 key: The keypair used for signing the proposal transaction. 1750 params: The parameters for the subnet proposal. 1751 netuid: The network identifier. 1752 1753 Returns: 1754 A receipt of the subnet proposal transaction. 1755 """ 1756 1757 params = { 1758 "data": cid, 1759 "netuid": netuid, 1760 } 1761 1762 response = self.compose_call( 1763 fn="add_subnet_custom_proposal", 1764 params=params, 1765 key=key, 1766 module="GovernanceModule", 1767 ) 1768 1769 return response 1770 1771 def add_global_proposal( 1772 self, 1773 key: Keypair, 1774 params: NetworkParams, 1775 cid: str | None, 1776 ) -> ExtrinsicReceipt: 1777 """ 1778 Submits a proposal for altering the global network parameters. 1779 1780 Allows for the submission of a proposal to 1781 change various global parameters 1782 of the network, such as emission rates, rate limits, and voting 1783 thresholds. It is used to 1784 suggest changes that affect the entire network's operation. 1785 1786 Args: 1787 key: The keypair used for signing the proposal transaction. 1788 params: A dictionary containing global network parameters 1789 like maximum allowed subnets, modules, 1790 transaction rate limits, and others. 1791 1792 Returns: 1793 A receipt of the global proposal transaction. 1794 1795 Raises: 1796 InvalidParameterError: If the provided network 1797 parameters are invalid. 1798 ChainTransactionError: If the transaction fails. 1799 """ 1800 general_params = cast(dict[str, Any], params) 1801 cid = cid or "" 1802 general_params["data"] = cid 1803 1804 response = self.compose_call( 1805 fn="add_global_params_proposal", 1806 params=general_params, 1807 key=key, 1808 module="GovernanceModule", 1809 ) 1810 1811 return response 1812 1813 def vote_on_proposal( 1814 self, 1815 key: Keypair, 1816 proposal_id: int, 1817 agree: bool, 1818 ) -> ExtrinsicReceipt: 1819 """ 1820 Casts a vote on a specified proposal within the network. 1821 1822 Args: 1823 key: The keypair used for signing the vote transaction. 1824 proposal_id: The unique identifier of the proposal to vote on. 1825 1826 Returns: 1827 A receipt of the voting transaction in nanotokens. 1828 1829 Raises: 1830 InvalidProposalIDError: If the provided proposal ID does not 1831 exist or is invalid. 1832 ChainTransactionError: If the transaction fails. 1833 """ 1834 1835 params = {"proposal_id": proposal_id, "agree": agree} 1836 1837 response = self.compose_call( 1838 "vote_proposal", 1839 key=key, 1840 params=params, 1841 module="GovernanceModule", 1842 ) 1843 1844 return response 1845 1846 def unvote_on_proposal( 1847 self, 1848 key: Keypair, 1849 proposal_id: int, 1850 ) -> ExtrinsicReceipt: 1851 """ 1852 Retracts a previously cast vote on a specified proposal. 1853 1854 Args: 1855 key: The keypair used for signing the unvote transaction. 1856 proposal_id: The unique identifier of the proposal to withdraw the 1857 vote from. 1858 1859 Returns: 1860 A receipt of the unvoting transaction in nanotokens. 1861 1862 Raises: 1863 InvalidProposalIDError: If the provided proposal ID does not 1864 exist or is invalid. 1865 ChainTransactionError: If the transaction fails to be processed, or 1866 if there was no prior vote to retract. 1867 """ 1868 1869 params = {"proposal_id": proposal_id} 1870 1871 response = self.compose_call( 1872 "remove_vote_proposal", 1873 key=key, 1874 params=params, 1875 module="GovernanceModule", 1876 ) 1877 1878 return response 1879 1880 def enable_vote_power_delegation(self, key: Keypair) -> ExtrinsicReceipt: 1881 """ 1882 Enables vote power delegation for the signer's account. 1883 1884 Args: 1885 key: The keypair used for signing the delegation transaction. 1886 1887 Returns: 1888 A receipt of the vote power delegation transaction. 1889 1890 Raises: 1891 ChainTransactionError: If the transaction fails. 1892 """ 1893 1894 response = self.compose_call( 1895 "enable_vote_power_delegation", 1896 params={}, 1897 key=key, 1898 module="GovernanceModule", 1899 ) 1900 1901 return response 1902 1903 def disable_vote_power_delegation(self, key: Keypair) -> ExtrinsicReceipt: 1904 """ 1905 Disables vote power delegation for the signer's account. 1906 1907 Args: 1908 key: The keypair used for signing the delegation transaction. 1909 1910 Returns: 1911 A receipt of the vote power delegation transaction. 1912 1913 Raises: 1914 ChainTransactionError: If the transaction fails. 1915 """ 1916 1917 response = self.compose_call( 1918 "disable_vote_power_delegation", 1919 params={}, 1920 key=key, 1921 module="GovernanceModule", 1922 ) 1923 1924 return response 1925 1926 def add_dao_application( 1927 self, key: Keypair, application_key: Ss58Address, data: str 1928 ) -> ExtrinsicReceipt: 1929 """ 1930 Submits a new application to the general subnet DAO. 1931 1932 Args: 1933 key: The keypair used for signing the application transaction. 1934 application_key: The SS58 address of the application key. 1935 data: The data associated with the application. 1936 1937 Returns: 1938 A receipt of the application transaction. 1939 1940 Raises: 1941 ChainTransactionError: If the transaction fails. 1942 """ 1943 1944 params = {"application_key": application_key, "data": data} 1945 1946 response = self.compose_call( 1947 "add_dao_application", 1948 module="GovernanceModule", 1949 key=key, 1950 params=params, 1951 ) 1952 1953 return response 1954 1955 def query_map_curator_applications(self) -> dict[str, dict[str, str]]: 1956 query_result = self.query_map( 1957 "CuratorApplications", 1958 module="GovernanceModule", 1959 params=[], 1960 extract_value=False, 1961 ) 1962 applications = query_result.get("CuratorApplications", {}) 1963 return applications 1964 1965 def query_map_proposals( 1966 self, extract_value: bool = False 1967 ) -> dict[int, dict[str, Any]]: 1968 """ 1969 Retrieves a mappping of proposals from the network. 1970 1971 Queries the network and returns a mapping of proposal IDs to 1972 their respective parameters. 1973 1974 Returns: 1975 A dictionary mapping proposal IDs 1976 to dictionaries of their parameters. 1977 1978 Raises: 1979 QueryError: If the query to the network fails or is invalid. 1980 """ 1981 1982 return self.query_map( 1983 "Proposals", extract_value=extract_value, module="GovernanceModule" 1984 )["Proposals"] 1985 1986 def query_map_weights( 1987 self, netuid: int = 0, extract_value: bool = False 1988 ) -> dict[int, list[tuple[int, int]]] | None: 1989 """ 1990 Retrieves a mapping of weights for keys on the network. 1991 1992 Queries the network and returns a mapping of key UIDs to 1993 their respective weights. 1994 1995 Args: 1996 netuid: The network UID from which to get the weights. 1997 1998 Returns: 1999 A dictionary mapping key UIDs to lists of their weights. 2000 2001 Raises: 2002 QueryError: If the query to the network fails or is invalid. 2003 """ 2004 2005 weights_dict = self.query_map( 2006 "Weights", 2007 [netuid], 2008 extract_value=extract_value, 2009 module="SubnetEmissionModule", 2010 ).get("Weights") 2011 return weights_dict 2012 2013 def query_map_key( 2014 self, 2015 netuid: int = 0, 2016 extract_value: bool = False, 2017 ) -> dict[int, Ss58Address]: 2018 """ 2019 Retrieves a map of keys from the network. 2020 2021 Fetches a mapping of key UIDs to their associated 2022 addresses on the network. 2023 The query can be targeted at a specific network UID if required. 2024 2025 Args: 2026 netuid: The network UID from which to get the keys. 2027 2028 Returns: 2029 A dictionary mapping key UIDs to their addresses. 2030 2031 Raises: 2032 QueryError: If the query to the network fails or is invalid. 2033 """ 2034 return self.query_map("Keys", [netuid], extract_value=extract_value)[ 2035 "Keys" 2036 ] 2037 2038 def query_map_address( 2039 self, netuid: int = 0, extract_value: bool = False 2040 ) -> dict[int, str]: 2041 """ 2042 Retrieves a map of key addresses from the network. 2043 2044 Queries the network for a mapping of key UIDs to their addresses. 2045 2046 Args: 2047 netuid: The network UID from which to get the addresses. 2048 2049 Returns: 2050 A dictionary mapping key UIDs to their addresses. 2051 2052 Raises: 2053 QueryError: If the query to the network fails or is invalid. 2054 """ 2055 2056 return self.query_map("Address", [netuid], extract_value=extract_value)[ 2057 "Address" 2058 ] 2059 2060 def query_map_emission( 2061 self, extract_value: bool = False 2062 ) -> dict[int, list[int]]: 2063 """ 2064 Retrieves a map of emissions for keys on the network. 2065 2066 Queries the network to get a mapping of 2067 key UIDs to their emission values. 2068 2069 Returns: 2070 A dictionary mapping key UIDs to lists of their emission values. 2071 2072 Raises: 2073 QueryError: If the query to the network fails or is invalid. 2074 """ 2075 2076 return self.query_map("Emission", extract_value=extract_value)[ 2077 "Emission" 2078 ] 2079 2080 def query_map_pending_emission(self, extract_value: bool = False) -> int: 2081 """ 2082 Retrieves a map of pending emissions for the subnets. 2083 2084 Queries the network for a mapping of subnet UIDs to their pending emission values. 2085 2086 Returns: 2087 A dictionary mapping subnet UIDs to their pending emission values. 2088 2089 Raises: 2090 QueryError: If the query to the network fails or is invalid. 2091 """ 2092 return self.query_map( 2093 "PendingEmission", 2094 extract_value=extract_value, 2095 module="SubnetEmissionModule", 2096 )["PendingEmission"] 2097 2098 def query_map_subnet_emission( 2099 self, extract_value: bool = False 2100 ) -> dict[int, int]: 2101 """ 2102 Retrieves a map of subnet emissions for the network. 2103 2104 Queries the network for a mapping of subnet UIDs to their emission values. 2105 2106 Returns: 2107 A dictionary mapping subnet UIDs to their emission values. 2108 2109 Raises: 2110 QueryError: If the query to the network fails or is invalid. 2111 """ 2112 2113 return self.query_map( 2114 "SubnetEmission", 2115 extract_value=extract_value, 2116 module="SubnetEmissionModule", 2117 )["SubnetEmission"] 2118 2119 def query_map_subnet_consensus( 2120 self, extract_value: bool = False 2121 ) -> dict[int, str]: 2122 """ 2123 Retrieves a map of subnet consensus types for the network. 2124 2125 Queries the network for a mapping of subnet UIDs to their consensus types. 2126 2127 Returns: 2128 A dictionary mapping subnet UIDs to their consensus types. 2129 2130 Raises: 2131 QueryError: If the query to the network fails or is invalid. 2132 """ 2133 2134 return self.query_map( 2135 "SubnetConsensusType", 2136 extract_value=extract_value, 2137 module="SubnetEmissionModule", 2138 )["SubnetConsensusType"] 2139 2140 def query_map_incentive( 2141 self, extract_value: bool = False 2142 ) -> dict[int, list[int]]: 2143 """ 2144 Retrieves a mapping of incentives for keys on the network. 2145 2146 Queries the network and returns a mapping of key UIDs to 2147 their respective incentive values. 2148 2149 Returns: 2150 A dictionary mapping key UIDs to lists of their incentive values. 2151 2152 Raises: 2153 QueryError: If the query to the network fails or is invalid. 2154 """ 2155 2156 return self.query_map("Incentive", extract_value=extract_value)[ 2157 "Incentive" 2158 ] 2159 2160 def query_map_dividend( 2161 self, extract_value: bool = False 2162 ) -> dict[int, list[int]]: 2163 """ 2164 Retrieves a mapping of dividends for keys on the network. 2165 2166 Queries the network for a mapping of key UIDs to 2167 their dividend values. 2168 2169 Returns: 2170 A dictionary mapping key UIDs to lists of their dividend values. 2171 2172 Raises: 2173 QueryError: If the query to the network fails or is invalid. 2174 """ 2175 2176 return self.query_map("Dividends", extract_value=extract_value)[ 2177 "Dividends" 2178 ] 2179 2180 def query_map_regblock( 2181 self, netuid: int = 0, extract_value: bool = False 2182 ) -> dict[int, int]: 2183 """ 2184 Retrieves a mapping of registration blocks for keys on the network. 2185 2186 Queries the network for a mapping of key UIDs to 2187 the blocks where they were registered. 2188 2189 Args: 2190 netuid: The network UID from which to get the registration blocks. 2191 2192 Returns: 2193 A dictionary mapping key UIDs to their registration blocks. 2194 2195 Raises: 2196 QueryError: If the query to the network fails or is invalid. 2197 """ 2198 2199 return self.query_map( 2200 "RegistrationBlock", [netuid], extract_value=extract_value 2201 )["RegistrationBlock"] 2202 2203 def query_map_lastupdate( 2204 self, extract_value: bool = False 2205 ) -> dict[int, list[int]]: 2206 """ 2207 Retrieves a mapping of the last update times for keys on the network. 2208 2209 Queries the network for a mapping of key UIDs to their last update times. 2210 2211 Returns: 2212 A dictionary mapping key UIDs to lists of their last update times. 2213 2214 Raises: 2215 QueryError: If the query to the network fails or is invalid. 2216 """ 2217 2218 return self.query_map("LastUpdate", extract_value=extract_value)[ 2219 "LastUpdate" 2220 ] 2221 2222 def query_map_stakefrom( 2223 self, extract_value: bool = False 2224 ) -> dict[Ss58Address, list[tuple[Ss58Address, int]]]: 2225 """ 2226 Retrieves a mapping of stakes from various sources for keys on the network. 2227 2228 Queries the network to obtain a mapping of key addresses to the sources 2229 and amounts of stakes they have received. 2230 2231 Args: 2232 netuid: The network UID from which to get the stakes. 2233 2234 Returns: 2235 A dictionary mapping key addresses to lists of tuples 2236 (module_key_address, amount). 2237 2238 Raises: 2239 QueryError: If the query to the network fails or is invalid. 2240 """ 2241 2242 result = self.query_map("StakeFrom", [], extract_value=extract_value)[ 2243 "StakeFrom" 2244 ] 2245 2246 return transform_stake_dmap(result) 2247 2248 def query_map_staketo( 2249 self, extract_value: bool = False 2250 ) -> dict[Ss58Address, list[tuple[Ss58Address, int]]]: 2251 """ 2252 Retrieves a mapping of stakes to destinations for keys on the network. 2253 2254 Queries the network for a mapping of key addresses to the destinations 2255 and amounts of stakes they have made. 2256 2257 Args: 2258 netuid: The network UID from which to get the stakes. 2259 2260 Returns: 2261 A dictionary mapping key addresses to lists of tuples 2262 (module_key_address, amount). 2263 2264 Raises: 2265 QueryError: If the query to the network fails or is invalid. 2266 """ 2267 2268 result = self.query_map("StakeTo", [], extract_value=extract_value)[ 2269 "StakeTo" 2270 ] 2271 return transform_stake_dmap(result) 2272 2273 def query_map_delegationfee( 2274 self, netuid: int = 0, extract_value: bool = False 2275 ) -> dict[str, int]: 2276 """ 2277 Retrieves a mapping of delegation fees for keys on the network. 2278 2279 Queries the network to obtain a mapping of key addresses to their 2280 respective delegation fees. 2281 2282 Args: 2283 netuid: The network UID to filter the delegation fees. 2284 2285 Returns: 2286 A dictionary mapping key addresses to their delegation fees. 2287 2288 Raises: 2289 QueryError: If the query to the network fails or is invalid. 2290 """ 2291 2292 return self.query_map( 2293 "DelegationFee", [netuid], extract_value=extract_value 2294 )["DelegationFee"] 2295 2296 def query_map_tempo(self, extract_value: bool = False) -> dict[int, int]: 2297 """ 2298 Retrieves a mapping of tempo settings for the network. 2299 2300 Queries the network to obtain the tempo (rate of reward distributions) 2301 settings for various network subnets. 2302 2303 Returns: 2304 A dictionary mapping network UIDs to their tempo settings. 2305 2306 Raises: 2307 QueryError: If the query to the network fails or is invalid. 2308 """ 2309 2310 return self.query_map("Tempo", extract_value=extract_value)["Tempo"] 2311 2312 def query_map_immunity_period(self, extract_value: bool) -> dict[int, int]: 2313 """ 2314 Retrieves a mapping of immunity periods for the network. 2315 2316 Queries the network for the immunity period settings, 2317 which represent the time duration during which modules 2318 can not get deregistered. 2319 2320 Returns: 2321 A dictionary mapping network UIDs to their immunity period settings. 2322 2323 Raises: 2324 QueryError: If the query to the network fails or is invalid. 2325 """ 2326 2327 return self.query_map("ImmunityPeriod", extract_value=extract_value)[ 2328 "ImmunityPeriod" 2329 ] 2330 2331 def query_map_min_allowed_weights( 2332 self, extract_value: bool = False 2333 ) -> dict[int, int]: 2334 """ 2335 Retrieves a mapping of minimum allowed weights for the network. 2336 2337 Queries the network to obtain the minimum allowed weights, 2338 which are the lowest permissible weight values that can be set by 2339 validators. 2340 2341 Returns: 2342 A dictionary mapping network UIDs to 2343 their minimum allowed weight values. 2344 2345 Raises: 2346 QueryError: If the query to the network fails or is invalid. 2347 """ 2348 2349 return self.query_map("MinAllowedWeights", extract_value=extract_value)[ 2350 "MinAllowedWeights" 2351 ] 2352 2353 def query_map_max_allowed_weights( 2354 self, extract_value: bool = False 2355 ) -> dict[int, int]: 2356 """ 2357 Retrieves a mapping of maximum allowed weights for the network. 2358 2359 Queries the network for the maximum allowed weights, 2360 which are the highest permissible 2361 weight values that can be set by validators. 2362 2363 Returns: 2364 A dictionary mapping network UIDs to 2365 their maximum allowed weight values. 2366 2367 Raises: 2368 QueryError: If the query to the network fails or is invalid. 2369 """ 2370 2371 return self.query_map("MaxAllowedWeights", extract_value=extract_value)[ 2372 "MaxAllowedWeights" 2373 ] 2374 2375 def query_map_max_allowed_uids( 2376 self, extract_value: bool = False 2377 ) -> dict[int, int]: 2378 """ 2379 Queries the network for the maximum number of allowed user IDs (UIDs) 2380 for each network subnet. 2381 2382 Fetches a mapping of network subnets to their respective 2383 limits on the number of user IDs that can be created or used. 2384 2385 Returns: 2386 A dictionary mapping network UIDs (unique identifiers) to their 2387 maximum allowed number of UIDs. 2388 Each entry represents a network subnet 2389 with its corresponding UID limit. 2390 2391 Raises: 2392 QueryError: If the query to the network fails or is invalid. 2393 """ 2394 2395 return self.query_map("MaxAllowedUids", extract_value=extract_value)[ 2396 "MaxAllowedUids" 2397 ] 2398 2399 def query_map_min_stake( 2400 self, extract_value: bool = False 2401 ) -> dict[int, int]: 2402 """ 2403 Retrieves a mapping of minimum allowed stake on the network. 2404 2405 Queries the network to obtain the minimum number of stake, 2406 which is represented in nanotokens. 2407 2408 Returns: 2409 A dictionary mapping network UIDs to 2410 their minimum allowed stake values. 2411 2412 Raises: 2413 QueryError: If the query to the network fails or is invalid. 2414 """ 2415 2416 return self.query_map("MinStake", extract_value=extract_value)[ 2417 "MinStake" 2418 ] 2419 2420 def query_map_max_stake( 2421 self, extract_value: bool = False 2422 ) -> dict[int, int]: 2423 """ 2424 Retrieves a mapping of the maximum stake values for the network. 2425 2426 Queries the network for the maximum stake values across various s 2427 ubnets of the network. 2428 2429 Returns: 2430 A dictionary mapping network UIDs to their maximum stake values. 2431 2432 Raises: 2433 QueryError: If the query to the network fails or is invalid. 2434 """ 2435 2436 return self.query_map("MaxStake", extract_value=extract_value)[ 2437 "MaxStake" 2438 ] 2439 2440 def query_map_founder(self, extract_value: bool = False) -> dict[int, str]: 2441 """ 2442 Retrieves a mapping of founders for the network. 2443 2444 Queries the network to obtain the founders associated with 2445 various subnets. 2446 2447 Returns: 2448 A dictionary mapping network UIDs to their respective founders. 2449 2450 Raises: 2451 QueryError: If the query to the network fails or is invalid. 2452 """ 2453 2454 return self.query_map("Founder", extract_value=extract_value)["Founder"] 2455 2456 def query_map_founder_share( 2457 self, extract_value: bool = False 2458 ) -> dict[int, int]: 2459 """ 2460 Retrieves a mapping of founder shares for the network. 2461 2462 Queries the network for the share percentages 2463 allocated to founders across different subnets. 2464 2465 Returns: 2466 A dictionary mapping network UIDs to their founder share percentages. 2467 2468 Raises: 2469 QueryError: If the query to the network fails or is invalid. 2470 """ 2471 2472 return self.query_map("FounderShare", extract_value=extract_value)[ 2473 "FounderShare" 2474 ] 2475 2476 def query_map_incentive_ratio( 2477 self, extract_value: bool = False 2478 ) -> dict[int, int]: 2479 """ 2480 Retrieves a mapping of incentive ratios for the network. 2481 2482 Queries the network for the incentive ratios, 2483 which are the proportions of rewards or incentives 2484 allocated in different subnets of the network. 2485 2486 Returns: 2487 A dictionary mapping network UIDs to their incentive ratios. 2488 2489 Raises: 2490 QueryError: If the query to the network fails or is invalid. 2491 """ 2492 2493 return self.query_map("IncentiveRatio", extract_value=extract_value)[ 2494 "IncentiveRatio" 2495 ] 2496 2497 def query_map_trust_ratio( 2498 self, extract_value: bool = False 2499 ) -> dict[int, int]: 2500 """ 2501 Retrieves a mapping of trust ratios for the network. 2502 2503 Queries the network for trust ratios, 2504 indicative of the level of trust or credibility assigned 2505 to different subnets of the network. 2506 2507 Returns: 2508 A dictionary mapping network UIDs to their trust ratios. 2509 2510 Raises: 2511 QueryError: If the query to the network fails or is invalid. 2512 """ 2513 2514 return self.query_map("TrustRatio", extract_value=extract_value)[ 2515 "TrustRatio" 2516 ] 2517 2518 def query_map_vote_mode_subnet( 2519 self, extract_value: bool = False 2520 ) -> dict[int, str]: 2521 """ 2522 Retrieves a mapping of vote modes for subnets within the network. 2523 2524 Queries the network for the voting modes used in different 2525 subnets, which define the methodology or approach of voting within those 2526 subnets. 2527 2528 Returns: 2529 A dictionary mapping network UIDs to their vote 2530 modes for subnets. 2531 2532 Raises: 2533 QueryError: If the query to the network fails or is invalid. 2534 """ 2535 2536 return self.query_map("VoteModeSubnet", extract_value=extract_value)[ 2537 "VoteModeSubnet" 2538 ] 2539 2540 def query_map_legit_whitelist( 2541 self, extract_value: bool = False 2542 ) -> dict[Ss58Address, int]: 2543 """ 2544 Retrieves a mapping of whitelisted addresses for the network. 2545 2546 Queries the network for a mapping of whitelisted addresses 2547 and their respective legitimacy status. 2548 2549 Returns: 2550 A dictionary mapping addresses to their legitimacy status. 2551 2552 Raises: 2553 QueryError: If the query to the network fails or is invalid. 2554 """ 2555 2556 return self.query_map( 2557 "LegitWhitelist", 2558 module="GovernanceModule", 2559 extract_value=extract_value, 2560 )["LegitWhitelist"] 2561 2562 def query_map_subnet_names( 2563 self, extract_value: bool = False 2564 ) -> dict[int, str]: 2565 """ 2566 Retrieves a mapping of subnet names within the network. 2567 2568 Queries the network for the names of various subnets, 2569 providing an overview of the different 2570 subnets within the network. 2571 2572 Returns: 2573 A dictionary mapping network UIDs to their subnet names. 2574 2575 Raises: 2576 QueryError: If the query to the network fails or is invalid. 2577 """ 2578 2579 return self.query_map("SubnetNames", extract_value=extract_value)[ 2580 "SubnetNames" 2581 ] 2582 2583 def query_map_balances( 2584 self, extract_value: bool = False, block_hash: str | None = None 2585 ) -> dict[str, dict[str, int | dict[str, int | float]]]: 2586 """ 2587 Retrieves a mapping of account balances within the network. 2588 2589 Queries the network for the balances associated with different accounts. 2590 It provides detailed information including various types of 2591 balances for each account. 2592 2593 Returns: 2594 A dictionary mapping account addresses to their balance details. 2595 2596 Raises: 2597 QueryError: If the query to the network fails or is invalid. 2598 """ 2599 2600 return self.query_map( 2601 "Account", 2602 module="System", 2603 extract_value=extract_value, 2604 block_hash=block_hash, 2605 )["Account"] 2606 2607 def query_map_registration_blocks( 2608 self, netuid: int = 0, extract_value: bool = False 2609 ) -> dict[int, int]: 2610 """ 2611 Retrieves a mapping of registration blocks for UIDs on the network. 2612 2613 Queries the network to find the block numbers at which various 2614 UIDs were registered. 2615 2616 Args: 2617 netuid: The network UID from which to get the registrations. 2618 2619 Returns: 2620 A dictionary mapping UIDs to their registration block numbers. 2621 2622 Raises: 2623 QueryError: If the query to the network fails or is invalid. 2624 """ 2625 2626 return self.query_map( 2627 "RegistrationBlock", [netuid], extract_value=extract_value 2628 )["RegistrationBlock"] 2629 2630 def query_map_name( 2631 self, netuid: int = 0, extract_value: bool = False 2632 ) -> dict[int, str]: 2633 """ 2634 Retrieves a mapping of names for keys on the network. 2635 2636 Queries the network for the names associated with different keys. 2637 It provides a mapping of key UIDs to their registered names. 2638 2639 Args: 2640 netuid: The network UID from which to get the names. 2641 2642 Returns: 2643 A dictionary mapping key UIDs to their names. 2644 2645 Raises: 2646 QueryError: If the query to the network fails or is invalid. 2647 """ 2648 2649 return self.query_map("Name", [netuid], extract_value=extract_value)[ 2650 "Name" 2651 ] 2652 2653 # == QUERY FUNCTIONS == # 2654 2655 def get_immunity_period(self, netuid: int = 0) -> int: 2656 """ 2657 Queries the network for the immunity period setting. 2658 2659 The immunity period is a time duration during which a module 2660 can not be deregistered from the network. 2661 Fetches the immunity period for a specified network subnet. 2662 2663 Args: 2664 netuid: The network UID for which to query the immunity period. 2665 2666 Returns: 2667 The immunity period setting for the specified network subnet. 2668 2669 Raises: 2670 QueryError: If the query to the network fails or is invalid. 2671 """ 2672 2673 return self.query( 2674 "ImmunityPeriod", 2675 params=[netuid], 2676 ) 2677 2678 def get_max_set_weights_per_epoch(self): 2679 return self.query("MaximumSetWeightCallsPerEpoch") 2680 2681 def get_min_allowed_weights(self, netuid: int = 0) -> int: 2682 """ 2683 Queries the network for the minimum allowed weights setting. 2684 2685 Retrieves the minimum weight values that are possible to set 2686 by a validator within a specific network subnet. 2687 2688 Args: 2689 netuid: The network UID for which to query the minimum allowed 2690 weights. 2691 2692 Returns: 2693 The minimum allowed weight values for the specified network 2694 subnet. 2695 2696 Raises: 2697 QueryError: If the query to the network fails or is invalid. 2698 """ 2699 2700 return self.query( 2701 "MinAllowedWeights", 2702 params=[netuid], 2703 ) 2704 2705 def get_dao_treasury_address(self) -> Ss58Address: 2706 return self.query("DaoTreasuryAddress", module="GovernanceModule") 2707 2708 def get_max_allowed_weights(self, netuid: int = 0) -> int: 2709 """ 2710 Queries the network for the maximum allowed weights setting. 2711 2712 Retrieves the maximum weight values that are possible to set 2713 by a validator within a specific network subnet. 2714 2715 Args: 2716 netuid: The network UID for which to query the maximum allowed 2717 weights. 2718 2719 Returns: 2720 The maximum allowed weight values for the specified network 2721 subnet. 2722 2723 Raises: 2724 QueryError: If the query to the network fails or is invalid. 2725 """ 2726 2727 return self.query("MaxAllowedWeights", params=[netuid]) 2728 2729 def get_max_allowed_uids(self, netuid: int = 0) -> int: 2730 """ 2731 Queries the network for the maximum allowed UIDs setting. 2732 2733 Fetches the upper limit on the number of user IDs that can 2734 be allocated or used within a specific network subnet. 2735 2736 Args: 2737 netuid: The network UID for which to query the maximum allowed UIDs. 2738 2739 Returns: 2740 The maximum number of allowed UIDs for the specified network subnet. 2741 2742 Raises: 2743 QueryError: If the query to the network fails or is invalid. 2744 """ 2745 2746 return self.query("MaxAllowedUids", params=[netuid]) 2747 2748 def get_name(self, netuid: int = 0) -> str: 2749 """ 2750 Queries the network for the name of a specific subnet. 2751 2752 Args: 2753 netuid: The network UID for which to query the name. 2754 2755 Returns: 2756 The name of the specified network subnet. 2757 2758 Raises: 2759 QueryError: If the query to the network fails or is invalid. 2760 """ 2761 2762 return self.query("Name", params=[netuid]) 2763 2764 def get_subnet_name(self, netuid: int = 0) -> str: 2765 """ 2766 Queries the network for the name of a specific subnet. 2767 2768 Args: 2769 netuid: The network UID for which to query the name. 2770 2771 Returns: 2772 The name of the specified network subnet. 2773 2774 Raises: 2775 QueryError: If the query to the network fails or is invalid. 2776 """ 2777 2778 return self.query("SubnetNames", params=[netuid]) 2779 2780 def get_global_dao_treasury(self): 2781 return self.query("GlobalDaoTreasury", module="GovernanceModule") 2782 2783 def get_n(self, netuid: int = 0) -> int: 2784 """ 2785 Queries the network for the 'N' hyperparameter, which represents how 2786 many modules are on the network. 2787 2788 Args: 2789 netuid: The network UID for which to query the 'N' hyperparameter. 2790 2791 Returns: 2792 The value of the 'N' hyperparameter for the specified network 2793 subnet. 2794 2795 Raises: 2796 QueryError: If the query to the network fails or is invalid. 2797 """ 2798 2799 return self.query("N", params=[netuid]) 2800 2801 def get_tempo(self, netuid: int = 0) -> int: 2802 """ 2803 Queries the network for the tempo setting, measured in blocks, for the 2804 specified subnet. 2805 2806 Args: 2807 netuid: The network UID for which to query the tempo. 2808 2809 Returns: 2810 The tempo setting for the specified subnet. 2811 2812 Raises: 2813 QueryError: If the query to the network fails or is invalid. 2814 """ 2815 2816 return self.query("Tempo", params=[netuid]) 2817 2818 def get_total_free_issuance(self, block_hash: str | None = None) -> int: 2819 """ 2820 Queries the network for the total free issuance. 2821 2822 Fetches the total amount of free issuance tokens available 2823 2824 Returns: 2825 The total free issuance amount. 2826 2827 Raises: 2828 QueryError: If the query to the network fails or is invalid. 2829 """ 2830 2831 return self.query( 2832 "TotalIssuance", module="Balances", block_hash=block_hash 2833 ) 2834 2835 def get_total_stake(self, block_hash: str | None = None) -> int: 2836 """ 2837 Retrieves a mapping of total stakes for keys on the network. 2838 2839 Queries the network for a mapping of key UIDs to their total stake amounts. 2840 2841 Returns: 2842 A dictionary mapping key UIDs to their total stake amounts. 2843 2844 Raises: 2845 QueryError: If the query to the network fails or is invalid. 2846 """ 2847 2848 return self.query("TotalStake", block_hash=block_hash) 2849 2850 def get_registrations_per_block(self): 2851 """ 2852 Queries the network for the number of registrations per block. 2853 2854 Fetches the number of registrations that are processed per 2855 block within the network. 2856 2857 Returns: 2858 The number of registrations processed per block. 2859 2860 Raises: 2861 QueryError: If the query to the network fails or is invalid. 2862 """ 2863 2864 return self.query( 2865 "RegistrationsPerBlock", 2866 ) 2867 2868 def max_registrations_per_block(self, netuid: int = 0): 2869 """ 2870 Queries the network for the maximum number of registrations per block. 2871 2872 Retrieves the upper limit of registrations that can be processed in 2873 each block within a specific network subnet. 2874 2875 Args: 2876 netuid: The network UID for which to query. 2877 2878 Returns: 2879 The maximum number of registrations per block for 2880 the specified network subnet. 2881 2882 Raises: 2883 QueryError: If the query to the network fails or is invalid. 2884 """ 2885 2886 return self.query( 2887 "MaxRegistrationsPerBlock", 2888 params=[netuid], 2889 ) 2890 2891 def get_proposal(self, proposal_id: int = 0): 2892 """ 2893 Queries the network for a specific proposal. 2894 2895 Args: 2896 proposal_id: The ID of the proposal to query. 2897 2898 Returns: 2899 The details of the specified proposal. 2900 2901 Raises: 2902 QueryError: If the query to the network fails, is invalid, 2903 or if the proposal ID does not exist. 2904 """ 2905 2906 return self.query( 2907 "Proposals", 2908 params=[proposal_id], 2909 ) 2910 2911 def get_trust(self, netuid: int = 0): 2912 """ 2913 Queries the network for the trust setting of a specific network subnet. 2914 2915 Retrieves the trust level or score, which may represent the 2916 level of trustworthiness or reliability within a 2917 particular network subnet. 2918 2919 Args: 2920 netuid: The network UID for which to query the trust setting. 2921 2922 Returns: 2923 The trust level or score for the specified network subnet. 2924 2925 Raises: 2926 QueryError: If the query to the network fails or is invalid. 2927 """ 2928 2929 return self.query( 2930 "Trust", 2931 params=[netuid], 2932 ) 2933 2934 def get_uids(self, key: Ss58Address, netuid: int = 0) -> bool | None: 2935 """ 2936 Queries the network for module UIDs associated with a specific key. 2937 2938 Args: 2939 key: The key address for which to query UIDs. 2940 netuid: The network UID within which to search for the key. 2941 2942 Returns: 2943 A list of UIDs associated with the specified key. 2944 2945 Raises: 2946 QueryError: If the query to the network fails or is invalid. 2947 """ 2948 2949 return self.query( 2950 "Uids", 2951 params=[netuid, key], 2952 ) 2953 2954 def get_unit_emission(self) -> int: 2955 """ 2956 Queries the network for the unit emission setting. 2957 2958 Retrieves the unit emission value, which represents the 2959 emission rate or quantity for the $COMM token. 2960 2961 Returns: 2962 The unit emission value in nanos for the network. 2963 2964 Raises: 2965 QueryError: If the query to the network fails or is invalid. 2966 """ 2967 2968 return self.query("UnitEmission", module="SubnetEmissionModule") 2969 2970 def get_tx_rate_limit(self) -> int: 2971 """ 2972 Queries the network for the transaction rate limit. 2973 2974 Retrieves the rate limit for transactions within the network, 2975 which defines the maximum number of transactions that can be 2976 processed within a certain timeframe. 2977 2978 Returns: 2979 The transaction rate limit for the network. 2980 2981 Raises: 2982 QueryError: If the query to the network fails or is invalid. 2983 """ 2984 2985 return self.query( 2986 "TxRateLimit", 2987 ) 2988 2989 def get_subnet_burn(self) -> int: 2990 """Queries the network for the subnet burn value. 2991 2992 Retrieves the subnet burn value from the network, which represents 2993 the amount of tokens that are burned (permanently removed from 2994 circulation) for subnet-related operations. 2995 2996 Returns: 2997 int: The subnet burn value. 2998 2999 Raises: 3000 QueryError: If the query to the network fails or returns invalid data. 3001 """ 3002 3003 return self.query( 3004 "SubnetBurn", 3005 ) 3006 3007 def get_burn_rate(self) -> int: 3008 """ 3009 Queries the network for the burn rate setting. 3010 3011 Retrieves the burn rate, which represents the rate at 3012 which the $COMM token is permanently 3013 removed or 'burned' from circulation. 3014 3015 Returns: 3016 The burn rate for the network. 3017 3018 Raises: 3019 QueryError: If the query to the network fails or is invalid. 3020 """ 3021 3022 return self.query( 3023 "BurnRate", 3024 params=[], 3025 ) 3026 3027 def get_burn(self, netuid: int = 0) -> int: 3028 """ 3029 Queries the network for the burn setting. 3030 3031 Retrieves the burn value, which represents the amount of the 3032 $COMM token that is 'burned' or permanently removed from 3033 circulation. 3034 3035 Args: 3036 netuid: The network UID for which to query the burn value. 3037 3038 Returns: 3039 The burn value for the specified network subnet. 3040 3041 Raises: 3042 QueryError: If the query to the network fails or is invalid. 3043 """ 3044 3045 return self.query("Burn", params=[netuid]) 3046 3047 def get_min_burn(self) -> int: 3048 """ 3049 Queries the network for the minimum burn setting. 3050 3051 Retrieves the minimum burn value, indicating the lowest 3052 amount of the $COMM tokens that can be 'burned' or 3053 permanently removed from circulation. 3054 3055 Returns: 3056 The minimum burn value for the network. 3057 3058 Raises: 3059 QueryError: If the query to the network fails or is invalid. 3060 """ 3061 3062 return self.query( 3063 "BurnConfig", 3064 params=[], 3065 )["min_burn"] 3066 3067 def get_min_weight_stake(self) -> int: 3068 """ 3069 Queries the network for the minimum weight stake setting. 3070 3071 Retrieves the minimum weight stake, which represents the lowest 3072 stake weight that is allowed for certain operations or 3073 transactions within the network. 3074 3075 Returns: 3076 The minimum weight stake for the network. 3077 3078 Raises: 3079 QueryError: If the query to the network fails or is invalid. 3080 """ 3081 3082 return self.query("MinWeightStake", params=[]) 3083 3084 def get_vote_mode_global(self) -> str: 3085 """ 3086 Queries the network for the global vote mode setting. 3087 3088 Retrieves the global vote mode, which defines the overall voting 3089 methodology or approach used across the network in default. 3090 3091 Returns: 3092 The global vote mode setting for the network. 3093 3094 Raises: 3095 QueryError: If the query to the network fails or is invalid. 3096 """ 3097 3098 return self.query( 3099 "VoteModeGlobal", 3100 ) 3101 3102 def get_max_proposals(self) -> int: 3103 """ 3104 Queries the network for the maximum number of proposals allowed. 3105 3106 Retrieves the upper limit on the number of proposals that can be 3107 active or considered at any given time within the network. 3108 3109 Returns: 3110 The maximum number of proposals allowed on the network. 3111 3112 Raises: 3113 QueryError: If the query to the network fails or is invalid. 3114 """ 3115 3116 return self.query( 3117 "MaxProposals", 3118 ) 3119 3120 def get_max_registrations_per_block(self) -> int: 3121 """ 3122 Queries the network for the maximum number of registrations per block. 3123 3124 Retrieves the maximum number of registrations that can 3125 be processed in each block within the network. 3126 3127 Returns: 3128 The maximum number of registrations per block on the network. 3129 3130 Raises: 3131 QueryError: If the query to the network fails or is invalid. 3132 """ 3133 3134 return self.query( 3135 "MaxRegistrationsPerBlock", 3136 params=[], 3137 ) 3138 3139 def get_max_name_length(self) -> int: 3140 """ 3141 Queries the network for the maximum length allowed for names. 3142 3143 Retrieves the maximum character length permitted for names 3144 within the network. Such as the module names 3145 3146 Returns: 3147 The maximum length allowed for names on the network. 3148 3149 Raises: 3150 QueryError: If the query to the network fails or is invalid. 3151 """ 3152 3153 return self.query( 3154 "MaxNameLength", 3155 params=[], 3156 ) 3157 3158 def get_global_vote_threshold(self) -> int: 3159 """ 3160 Queries the network for the global vote threshold. 3161 3162 Retrieves the global vote threshold, which is the critical value or 3163 percentage required for decisions in the network's governance process. 3164 3165 Returns: 3166 The global vote threshold for the network. 3167 3168 Raises: 3169 QueryError: If the query to the network fails or is invalid. 3170 """ 3171 3172 return self.query( 3173 "GlobalVoteThreshold", 3174 ) 3175 3176 def get_max_allowed_subnets(self) -> int: 3177 """ 3178 Queries the network for the maximum number of allowed subnets. 3179 3180 Retrieves the upper limit on the number of subnets that can 3181 be created or operated within the network. 3182 3183 Returns: 3184 The maximum number of allowed subnets on the network. 3185 3186 Raises: 3187 QueryError: If the query to the network fails or is invalid. 3188 """ 3189 3190 return self.query( 3191 "MaxAllowedSubnets", 3192 params=[], 3193 ) 3194 3195 def get_max_allowed_modules(self) -> int: 3196 """ 3197 Queries the network for the maximum number of allowed modules. 3198 3199 Retrieves the upper limit on the number of modules that 3200 can be registered within the network. 3201 3202 Returns: 3203 The maximum number of allowed modules on the network. 3204 3205 Raises: 3206 QueryError: If the query to the network fails or is invalid. 3207 """ 3208 3209 return self.query( 3210 "MaxAllowedModules", 3211 params=[], 3212 ) 3213 3214 def get_min_stake(self, netuid: int = 0) -> int: 3215 """ 3216 Queries the network for the minimum stake required to register a key. 3217 3218 Retrieves the minimum amount of stake necessary for 3219 registering a key within a specific network subnet. 3220 3221 Args: 3222 netuid: The network UID for which to query the minimum stake. 3223 3224 Returns: 3225 The minimum stake required for key registration in nanos. 3226 3227 Raises: 3228 QueryError: If the query to the network fails or is invalid. 3229 """ 3230 3231 return self.query("MinStake", params=[netuid]) 3232 3233 def get_stakefrom( 3234 self, 3235 key: Ss58Address, 3236 ) -> dict[str, int]: 3237 """ 3238 Retrieves the stake amounts from all stakers to a specific staked address. 3239 3240 Queries the network for the stakes received by a particular staked address 3241 from all stakers. 3242 3243 Args: 3244 key: The address of the key receiving the stakes. 3245 3246 Returns: 3247 A dictionary mapping staker addresses to their respective stake amounts. 3248 3249 Raises: 3250 QueryError: If the query to the network fails or is invalid. 3251 """ 3252 3253 # Has to use query map in order to iterate through the storage prefix. 3254 return self.query_map("StakeFrom", [key], extract_value=False).get( 3255 "StakeFrom", {} 3256 ) 3257 3258 def get_staketo( 3259 self, 3260 key: Ss58Address, 3261 ) -> dict[str, int]: 3262 """ 3263 Retrieves the stake amounts provided by a specific staker to all staked addresses. 3264 3265 Queries the network for the stakes provided by a particular staker to 3266 all staked addresses. 3267 3268 Args: 3269 key: The address of the key providing the stakes. 3270 3271 Returns: 3272 A dictionary mapping staked addresses to their respective received stake amounts. 3273 3274 Raises: 3275 QueryError: If the query to the network fails or is invalid. 3276 """ 3277 3278 # Has to use query map in order to iterate through the storage prefix. 3279 return self.query_map("StakeTo", [key], extract_value=False).get( 3280 "StakeTo", {} 3281 ) 3282 3283 def get_balance( 3284 self, 3285 addr: Ss58Address, 3286 ) -> int: 3287 """ 3288 Retrieves the balance of a specific key. 3289 3290 Args: 3291 addr: The address of the key to query the balance for. 3292 3293 Returns: 3294 The balance of the specified key. 3295 3296 Raises: 3297 QueryError: If the query to the network fails or is invalid. 3298 """ 3299 3300 result = self.query("Account", module="System", params=[addr]) 3301 3302 return result["data"]["free"] 3303 3304 def get_block(self, block_hash: str | None = None) -> dict[Any, Any] | None: 3305 """ 3306 Retrieves information about a specific block in the network. 3307 3308 Queries the network for details about a block, such as its number, 3309 hash, and other relevant information. 3310 3311 Returns: 3312 The requested information about the block, 3313 or None if the block does not exist 3314 or the information is not available. 3315 3316 Raises: 3317 QueryError: If the query to the network fails or is invalid. 3318 """ 3319 3320 with self.get_conn() as substrate: 3321 block: dict[Any, Any] | None = substrate.get_block( # type: ignore 3322 block_hash # type: ignore 3323 ) 3324 3325 return block 3326 3327 def get_existential_deposit(self, block_hash: str | None = None) -> int: 3328 """ 3329 Retrieves the existential deposit value for the network. 3330 3331 The existential deposit is the minimum balance that must be maintained 3332 in an account to prevent it from being purged. Denotated in nano units. 3333 3334 Returns: 3335 The existential deposit value in nano units. 3336 Note: 3337 The value returned is a fixed value defined in the 3338 client and may not reflect changes in the network's configuration. 3339 """ 3340 3341 with self.get_conn() as substrate: 3342 result: int = substrate.get_constant( # type: ignore 3343 "Balances", "ExistentialDeposit", block_hash 3344 ).value # type: ignore 3345 3346 return result 3347 3348 def get_voting_power_delegators(self) -> list[Ss58Address]: 3349 result = self.query( 3350 "NotDelegatingVotingPower", [], module="GovernanceModule" 3351 ) 3352 return result 3353 3354 def add_transfer_dao_treasury_proposal( 3355 self, 3356 key: Keypair, 3357 data: str, 3358 amount_nano: int, 3359 dest: Ss58Address, 3360 ): 3361 params = {"dest": dest, "value": amount_nano, "data": data} 3362 3363 return self.compose_call( 3364 module="GovernanceModule", 3365 fn="add_transfer_dao_treasury_proposal", 3366 params=params, 3367 key=key, 3368 )
A client for interacting with Commune network nodes, querying storage, submitting transactions, etc.
Attributes:
- wait_for_finalization: Whether to wait for transaction finalization.
Example:
client = CommuneClient()
client.query(name='function_name', params=['param1', 'param2'])
Raises:
- AssertionError: If the maximum connections value is less than or equal to zero.
103 def __init__( 104 self, 105 url: str, 106 num_connections: int = 1, 107 wait_for_finalization: bool = False, 108 timeout: int | None = None, 109 ): 110 """ 111 Args: 112 url: The URL of the network node to connect to. 113 num_connections: The number of websocket connections to be opened. 114 """ 115 assert num_connections > 0 116 self._num_connections = num_connections 117 self.wait_for_finalization = wait_for_finalization 118 self._connection_queue = queue.Queue(num_connections) 119 self.url = url 120 121 for _ in range(num_connections): 122 ws_options: dict[str, int] = {} 123 if timeout is not None: 124 ws_options["timeout"] = timeout 125 self._ws_options = ws_options 126 self._connection_queue.put( 127 _instantiate_substrateinterface( 128 url, ws_options, threading.Lock() 129 ) 130 )
Arguments:
- url: The URL of the network node to connect to.
- num_connections: The number of websocket connections to be opened.
132 @property 133 def connections(self) -> int: 134 """ 135 Gets the maximum allowed number of simultaneous connections to the 136 network node. 137 """ 138 return self._num_connections
Gets the maximum allowed number of simultaneous connections to the network node.
140 @contextmanager 141 def get_conn(self, timeout: float | None = None, init: bool = False): 142 """ 143 Context manager to get a connection from the pool. 144 145 Tries to get a connection from the pool queue. If the queue is empty, 146 it blocks for `timeout` seconds until a connection is available. If 147 `timeout` is None, it blocks indefinitely. 148 149 Args: 150 timeout: The maximum time in seconds to wait for a connection. 151 152 Yields: 153 The connection object from the pool. 154 155 Raises: 156 QueueEmptyError: If no connection is available within the timeout 157 period. 158 """ 159 conn = self._connection_queue.get(timeout=timeout) 160 if init: 161 conn.substrate.init_runtime() # type: ignore 162 try: 163 gc.collect() 164 if conn.substrate.websocket and conn.substrate.websocket.connected: # type: ignore 165 with conn.lock: 166 yield conn.substrate 167 else: 168 # reconnects 169 conn.stop_event.set() 170 conn = _instantiate_substrateinterface( 171 self.url, self._ws_options, threading.Lock() 172 ) 173 with conn.lock: 174 yield conn.substrate 175 finally: 176 self._connection_queue.put(conn)
Context manager to get a connection from the pool.
Tries to get a connection from the pool queue. If the queue is empty,
it blocks for timeout
seconds until a connection is available. If
timeout
is None, it blocks indefinitely.
Arguments:
- timeout: The maximum time in seconds to wait for a connection.
Yields:
The connection object from the pool.
Raises:
- QueueEmptyError: If no connection is available within the timeout period.
651 def query_batch( 652 self, functions: dict[str, list[tuple[str, list[Any]]]] 653 ) -> dict[str, str]: 654 """ 655 Executes batch queries on a substrate and returns results in a dictionary format. 656 657 Args: 658 substrate: An instance of SubstrateInterface to interact with the substrate. 659 functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls (function name and parameters). 660 661 Returns: 662 A dictionary where keys are storage function names and values are the query results. 663 664 Raises: 665 Exception: If no result is found from the batch queries. 666 667 Example: 668 >>> query_batch(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) 669 {'function_name': 'query_result', ...} 670 """ 671 672 result: dict[str, str] = {} 673 if not functions: 674 raise Exception("No result") 675 with self.get_conn(init=True) as substrate: 676 for module, queries in functions.items(): 677 storage_keys: list[Any] = [] 678 for fn, params in queries: 679 storage_function = substrate.create_storage_key( # type: ignore 680 pallet=module, storage_function=fn, params=params 681 ) 682 storage_keys.append(storage_function) 683 684 block_hash = substrate.get_block_hash() 685 responses: list[Any] = substrate.query_multi( # type: ignore 686 storage_keys=storage_keys, block_hash=block_hash 687 ) 688 689 for item in responses: 690 fun = item[0] 691 query = item[1] 692 storage_fun = fun.storage_function 693 result[storage_fun] = query.value 694 695 return result
Executes batch queries on a substrate and returns results in a dictionary format.
Arguments:
- substrate: An instance of SubstrateInterface to interact with the substrate.
- functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls (function name and parameters).
Returns:
A dictionary where keys are storage function names and values are the query results.
Raises:
- Exception: If no result is found from the batch queries.
Example:
>>> query_batch(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) {'function_name': 'query_result', ...}
697 def query_batch_map( 698 self, 699 functions: dict[str, list[tuple[str, list[Any]]]], 700 block_hash: str | None = None, 701 ) -> dict[str, dict[Any, Any]]: 702 """ 703 Queries multiple storage functions using a map batch approach and returns the combined result. 704 705 Args: 706 substrate: An instance of SubstrateInterface for substrate interaction. 707 functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls. 708 709 Returns: 710 The combined result of the map batch query. 711 712 Example: 713 >>> query_batch_map(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) 714 # Returns the combined result of the map batch query 715 """ 716 multi_result: dict[str, dict[Any, Any]] = {} 717 718 def recursive_update( 719 d: dict[str, dict[T1, T2] | dict[str, Any]], 720 u: Mapping[str, dict[Any, Any] | str], 721 ) -> dict[str, dict[T1, T2]]: 722 for k, v in u.items(): 723 if isinstance(v, dict): 724 d[k] = recursive_update(d.get(k, {}), v) # type: ignore 725 else: 726 d[k] = v # type: ignore 727 return d # type: ignore 728 729 def get_page(): 730 send, prefix_list = self._get_storage_keys( 731 storage, queries, block_hash 732 ) 733 with self.get_conn(init=True) as substrate: 734 function_parameters = self._get_lists( 735 storage, queries, substrate 736 ) 737 responses = self._rpc_request_batch(send) 738 # assumption because send is just the storage_function keys 739 # so it should always be really small regardless of the amount of queries 740 assert len(responses) == 1 741 res = responses[0] 742 built_payload: list[tuple[str, list[Any]]] = [] 743 for result_keys in res: 744 built_payload.append( 745 ("state_queryStorageAt", [result_keys, block_hash]) 746 ) 747 _, chunks_info = self._make_request_smaller( 748 built_payload, prefix_list, function_parameters 749 ) 750 chunks_response, chunks_info = self._rpc_request_batch_chunked( 751 chunks_info 752 ) 753 return chunks_response, chunks_info 754 755 if not block_hash: 756 with self.get_conn(init=True) as substrate: 757 block_hash = substrate.get_block_hash() 758 for storage, queries in functions.items(): 759 chunks, chunks_info = get_page() 760 # if this doesn't happen something is wrong on the code 761 # and we won't be able to decode the data properly 762 assert len(chunks) == len(chunks_info) 763 for chunk_info, response in zip(chunks_info, chunks): 764 storage_result = self._decode_response( 765 response, 766 chunk_info.fun_params, 767 chunk_info.prefix_list, 768 block_hash, 769 ) 770 multi_result = recursive_update(multi_result, storage_result) 771 772 return multi_result
Queries multiple storage functions using a map batch approach and returns the combined result.
Arguments:
- substrate: An instance of SubstrateInterface for substrate interaction.
- functions (dict[str, list[query_call]]): A dictionary mapping module names to lists of query calls.
Returns:
The combined result of the map batch query.
Example:
>>> query_batch_map(substrate_instance, {'module_name': [('function_name', ['param1', 'param2'])]}) <h1 id="returns-the-combined-result-of-the-map-batch-query">Returns the combined result of the map batch query</h1>
774 def query( 775 self, 776 name: str, 777 params: list[Any] = [], 778 module: str = "SubspaceModule", 779 block_hash: str | None = None, 780 ) -> Any: 781 """ 782 Queries a storage function on the network. 783 784 Sends a query to the network and retrieves data from a 785 specified storage function. 786 787 Args: 788 name: The name of the storage function to query. 789 params: The parameters to pass to the storage function. 790 module: The module where the storage function is located. 791 792 Returns: 793 The result of the query from the network. 794 795 Raises: 796 NetworkQueryError: If the query fails or is invalid. 797 """ 798 799 result = self.query_batch({module: [(name, params)]}) 800 801 return result[name]
Queries a storage function on the network.
Sends a query to the network and retrieves data from a specified storage function.
Arguments:
- name: The name of the storage function to query.
- params: The parameters to pass to the storage function.
- module: The module where the storage function is located.
Returns:
The result of the query from the network.
Raises:
- NetworkQueryError: If the query fails or is invalid.
803 def query_map( 804 self, 805 name: str, 806 params: list[Any] = [], 807 module: str = "SubspaceModule", 808 extract_value: bool = True, 809 block_hash: str | None = None, 810 ) -> dict[Any, Any]: 811 """ 812 Queries a storage map from a network node. 813 814 Args: 815 name: The name of the storage map to query. 816 params: A list of parameters for the query. 817 module: The module in which the storage map is located. 818 819 Returns: 820 A dictionary representing the key-value pairs 821 retrieved from the storage map. 822 823 Raises: 824 QueryError: If the query to the network fails or is invalid. 825 """ 826 827 result = self.query_batch_map({module: [(name, params)]}, block_hash) 828 829 if extract_value: 830 return {k.value: v.value for k, v in result} # type: ignore 831 832 return result
Queries a storage map from a network node.
Arguments:
- name: The name of the storage map to query.
- params: A list of parameters for the query.
- module: The module in which the storage map is located.
Returns:
A dictionary representing the key-value pairs retrieved from the storage map.
Raises:
- QueryError: If the query to the network fails or is invalid.
834 def compose_call( 835 self, 836 fn: str, 837 params: dict[str, Any], 838 key: Keypair | None, 839 module: str = "SubspaceModule", 840 wait_for_inclusion: bool = True, 841 wait_for_finalization: bool | None = None, 842 sudo: bool = False, 843 unsigned: bool = False, 844 ) -> ExtrinsicReceipt: 845 """ 846 Composes and submits a call to the network node. 847 848 Composes and signs a call with the provided keypair, and submits it to 849 the network. The call can be a standard extrinsic or a sudo extrinsic if 850 elevated permissions are required. The method can optionally wait for 851 the call's inclusion in a block and/or its finalization. 852 853 Args: 854 fn: The function name to call on the network. 855 params: A dictionary of parameters for the call. 856 key: The keypair for signing the extrinsic. 857 module: The module containing the function. 858 wait_for_inclusion: Wait for the call's inclusion in a block. 859 wait_for_finalization: Wait for the transaction's finalization. 860 sudo: Execute the call as a sudo (superuser) operation. 861 862 Returns: 863 The receipt of the submitted extrinsic, if 864 `wait_for_inclusion` is True. Otherwise, returns a string 865 identifier of the extrinsic. 866 867 Raises: 868 ChainTransactionError: If the transaction fails. 869 """ 870 871 if key is None and not unsigned: 872 raise ValueError("Key must be provided for signed extrinsics.") 873 874 with self.get_conn() as substrate: 875 if wait_for_finalization is None: 876 wait_for_finalization = self.wait_for_finalization 877 878 call = substrate.compose_call( # type: ignore 879 call_module=module, call_function=fn, call_params=params 880 ) 881 if sudo: 882 call = substrate.compose_call( # type: ignore 883 call_module="Sudo", 884 call_function="sudo", 885 call_params={ 886 "call": call.value, # type: ignore 887 }, 888 ) 889 890 if not unsigned: 891 assert key is not None 892 extrinsic = substrate.create_signed_extrinsic( # type: ignore 893 call=call, 894 keypair=key, 895 ) 896 else: 897 extrinsic = substrate.create_unsigned_extrinsic(call=call) # type: ignore 898 899 response = substrate.submit_extrinsic( 900 extrinsic=extrinsic, 901 wait_for_inclusion=wait_for_inclusion, 902 wait_for_finalization=wait_for_finalization, 903 ) 904 if wait_for_inclusion: 905 if not response.is_success: 906 raise ChainTransactionError( 907 response.error_message, # type: ignore 908 response, # type: ignore 909 ) 910 911 return response
Composes and submits a call to the network node.
Composes and signs a call with the provided keypair, and submits it to the network. The call can be a standard extrinsic or a sudo extrinsic if elevated permissions are required. The method can optionally wait for the call's inclusion in a block and/or its finalization.
Arguments:
- fn: The function name to call on the network.
- params: A dictionary of parameters for the call.
- key: The keypair for signing the extrinsic.
- module: The module containing the function.
- wait_for_inclusion: Wait for the call's inclusion in a block.
- wait_for_finalization: Wait for the transaction's finalization.
- sudo: Execute the call as a sudo (superuser) operation.
Returns:
The receipt of the submitted extrinsic, if
wait_for_inclusion
is True. Otherwise, returns a string identifier of the extrinsic.
Raises:
- ChainTransactionError: If the transaction fails.
913 def compose_call_multisig( 914 self, 915 fn: str, 916 params: dict[str, Any], 917 key: Keypair, 918 signatories: list[Ss58Address], 919 threshold: int, 920 module: str = "SubspaceModule", 921 wait_for_inclusion: bool = True, 922 wait_for_finalization: bool | None = None, 923 sudo: bool = False, 924 era: dict[str, int] | None = None, 925 ) -> ExtrinsicReceipt: 926 """ 927 Composes and submits a multisignature call to the network node. 928 929 This method allows the composition and submission of a call that 930 requires multiple signatures for execution, known as a multisignature 931 call. It supports specifying signatories, a threshold of signatures for 932 the call's execution, and an optional era for the call's mortality. The 933 call can be a standard extrinsic, a sudo extrinsic for elevated 934 permissions, or a multisig extrinsic if multiple signatures are 935 required. Optionally, the method can wait for the call's inclusion in a 936 block and/or its finalization. Make sure to pass all keys, 937 that are part of the multisignature. 938 939 Args: 940 fn: The function name to call on the network. params: A dictionary 941 of parameters for the call. key: The keypair for signing the 942 extrinsic. signatories: List of SS58 addresses of the signatories. 943 Include ALL KEYS that are part of the multisig. threshold: The 944 minimum number of signatories required to execute the extrinsic. 945 module: The module containing the function to call. 946 wait_for_inclusion: Whether to wait for the call's inclusion in a 947 block. wait_for_finalization: Whether to wait for the transaction's 948 finalization. sudo: Execute the call as a sudo (superuser) 949 operation. era: Specifies the call's mortality in terms of blocks in 950 the format 951 {'period': amount_blocks}. If omitted, the extrinsic is 952 immortal. 953 954 Returns: 955 The receipt of the submitted extrinsic if `wait_for_inclusion` is 956 True. Otherwise, returns a string identifier of the extrinsic. 957 958 Raises: 959 ChainTransactionError: If the transaction fails. 960 """ 961 962 # getting the call ready 963 with self.get_conn() as substrate: 964 if wait_for_finalization is None: 965 wait_for_finalization = self.wait_for_finalization 966 967 # prepares the `GenericCall` object 968 call = substrate.compose_call( # type: ignore 969 call_module=module, call_function=fn, call_params=params 970 ) 971 if sudo: 972 call = substrate.compose_call( # type: ignore 973 call_module="Sudo", 974 call_function="sudo", 975 call_params={ 976 "call": call.value, # type: ignore 977 }, 978 ) 979 980 # modify the rpc methods at runtime, to allow for correct payment 981 # fee calculation parity has a bug in this version, 982 # where the method has to be removed 983 rpc_methods = substrate.config.get("rpc_methods") # type: ignore 984 985 if "state_call" in rpc_methods: # type: ignore 986 rpc_methods.remove("state_call") # type: ignore 987 988 # create the multisig account 989 multisig_acc = substrate.generate_multisig_account( # type: ignore 990 signatories, threshold 991 ) 992 993 # send the multisig extrinsic 994 extrinsic = substrate.create_multisig_extrinsic( # type: ignore 995 call=call, # type: ignore 996 keypair=key, 997 multisig_account=multisig_acc, # type: ignore 998 era=era, # type: ignore 999 ) # type: ignore 1000 1001 response = substrate.submit_extrinsic( 1002 extrinsic=extrinsic, 1003 wait_for_inclusion=wait_for_inclusion, 1004 wait_for_finalization=wait_for_finalization, 1005 ) 1006 1007 if wait_for_inclusion: 1008 if not response.is_success: 1009 raise ChainTransactionError( 1010 response.error_message, # type: ignore 1011 response, # type: ignore 1012 ) 1013 1014 return response
Composes and submits a multisignature call to the network node.
This method allows the composition and submission of a call that requires multiple signatures for execution, known as a multisignature call. It supports specifying signatories, a threshold of signatures for the call's execution, and an optional era for the call's mortality. The call can be a standard extrinsic, a sudo extrinsic for elevated permissions, or a multisig extrinsic if multiple signatures are required. Optionally, the method can wait for the call's inclusion in a block and/or its finalization. Make sure to pass all keys, that are part of the multisignature.
Arguments:
- fn: The function name to call on the network. params: A dictionary
- of parameters for the call. key: The keypair for signing the
- extrinsic. signatories: List of SS58 addresses of the signatories.
- Include ALL KEYS that are part of the multisig. threshold: The
- minimum number of signatories required to execute the extrinsic.
- module: The module containing the function to call.
- wait_for_inclusion: Whether to wait for the call's inclusion in a
- block. wait_for_finalization: Whether to wait for the transaction's
- finalization. sudo: Execute the call as a sudo (superuser)
- operation. era: Specifies the call's mortality in terms of blocks in
- the format {'period': amount_blocks}. If omitted, the extrinsic is immortal.
Returns:
The receipt of the submitted extrinsic if
wait_for_inclusion
is True. Otherwise, returns a string identifier of the extrinsic.
Raises:
- ChainTransactionError: If the transaction fails.
1016 def transfer( 1017 self, 1018 key: Keypair, 1019 amount: int, 1020 dest: Ss58Address, 1021 ) -> ExtrinsicReceipt: 1022 """ 1023 Transfers a specified amount of tokens from the signer's account to the 1024 specified account. 1025 1026 Args: 1027 key: The keypair associated with the sender's account. 1028 amount: The amount to transfer, in nanotokens. 1029 dest: The SS58 address of the recipient. 1030 1031 Returns: 1032 A receipt of the transaction. 1033 1034 Raises: 1035 InsufficientBalanceError: If the sender's account does not have 1036 enough balance. 1037 ChainTransactionError: If the transaction fails. 1038 """ 1039 1040 params = {"dest": dest, "value": amount} 1041 1042 return self.compose_call( 1043 module="Balances", fn="transfer_keep_alive", params=params, key=key 1044 )
Transfers a specified amount of tokens from the signer's account to the specified account.
Arguments:
- key: The keypair associated with the sender's account.
- amount: The amount to transfer, in nanotokens.
- dest: The SS58 address of the recipient.
Returns:
A receipt of the transaction.
Raises:
- InsufficientBalanceError: If the sender's account does not have enough balance.
- ChainTransactionError: If the transaction fails.
1046 def transfer_multiple( 1047 self, 1048 key: Keypair, 1049 destinations: list[Ss58Address], 1050 amounts: list[int], 1051 netuid: str | int = 0, 1052 ) -> ExtrinsicReceipt: 1053 """ 1054 Transfers specified amounts of tokens from the signer's account to 1055 multiple target accounts. 1056 1057 The `destinations` and `amounts` lists must be of the same length. 1058 1059 Args: 1060 key: The keypair associated with the sender's account. 1061 destinations: A list of SS58 addresses of the recipients. 1062 amounts: Amount to transfer to each recipient, in nanotokens. 1063 netuid: The network identifier. 1064 1065 Returns: 1066 A receipt of the transaction. 1067 1068 Raises: 1069 InsufficientBalanceError: If the sender's account does not have 1070 enough balance for all transfers. 1071 ChainTransactionError: If the transaction fails. 1072 """ 1073 1074 assert len(destinations) == len(amounts) 1075 1076 # extract existential deposit from amounts 1077 existential_deposit = self.get_existential_deposit() 1078 amounts = [a - existential_deposit for a in amounts] 1079 1080 params = { 1081 "netuid": netuid, 1082 "destinations": destinations, 1083 "amounts": amounts, 1084 } 1085 1086 return self.compose_call( 1087 module="SubspaceModule", 1088 fn="transfer_multiple", 1089 params=params, 1090 key=key, 1091 )
Transfers specified amounts of tokens from the signer's account to multiple target accounts.
The destinations
and amounts
lists must be of the same length.
Arguments:
- key: The keypair associated with the sender's account.
- destinations: A list of SS58 addresses of the recipients.
- amounts: Amount to transfer to each recipient, in nanotokens.
- netuid: The network identifier.
Returns:
A receipt of the transaction.
Raises:
- InsufficientBalanceError: If the sender's account does not have enough balance for all transfers.
- ChainTransactionError: If the transaction fails.
1093 def stake( 1094 self, 1095 key: Keypair, 1096 amount: int, 1097 dest: Ss58Address, 1098 ) -> ExtrinsicReceipt: 1099 """ 1100 Stakes the specified amount of tokens to a module key address. 1101 1102 Args: 1103 key: The keypair associated with the staker's account. 1104 amount: The amount of tokens to stake, in nanotokens. 1105 dest: The SS58 address of the module key to stake to. 1106 netuid: The network identifier. 1107 1108 Returns: 1109 A receipt of the staking transaction. 1110 1111 Raises: 1112 InsufficientBalanceError: If the staker's account does not have 1113 enough balance. 1114 ChainTransactionError: If the transaction fails. 1115 """ 1116 1117 params = {"amount": amount, "module_key": dest} 1118 1119 return self.compose_call(fn="add_stake", params=params, key=key)
Stakes the specified amount of tokens to a module key address.
Arguments:
- key: The keypair associated with the staker's account.
- amount: The amount of tokens to stake, in nanotokens.
- dest: The SS58 address of the module key to stake to.
- netuid: The network identifier.
Returns:
A receipt of the staking transaction.
Raises:
- InsufficientBalanceError: If the staker's account does not have enough balance.
- ChainTransactionError: If the transaction fails.
1121 def unstake( 1122 self, 1123 key: Keypair, 1124 amount: int, 1125 dest: Ss58Address, 1126 ) -> ExtrinsicReceipt: 1127 """ 1128 Unstakes the specified amount of tokens from a module key address. 1129 1130 Args: 1131 key: The keypair associated with the unstaker's account. 1132 amount: The amount of tokens to unstake, in nanotokens. 1133 dest: The SS58 address of the module key to unstake from. 1134 netuid: The network identifier. 1135 1136 Returns: 1137 A receipt of the unstaking transaction. 1138 1139 Raises: 1140 InsufficientStakeError: If the staked key does not have enough 1141 staked tokens by the signer key. 1142 ChainTransactionError: If the transaction fails. 1143 """ 1144 1145 params = {"amount": amount, "module_key": dest} 1146 return self.compose_call(fn="remove_stake", params=params, key=key)
Unstakes the specified amount of tokens from a module key address.
Arguments:
- key: The keypair associated with the unstaker's account.
- amount: The amount of tokens to unstake, in nanotokens.
- dest: The SS58 address of the module key to unstake from.
- netuid: The network identifier.
Returns:
A receipt of the unstaking transaction.
Raises:
- InsufficientStakeError: If the staked key does not have enough staked tokens by the signer key.
- ChainTransactionError: If the transaction fails.
1148 def update_module( 1149 self, 1150 key: Keypair, 1151 name: str, 1152 address: str, 1153 metadata: str | None = None, 1154 delegation_fee: int = 20, 1155 weight_setting_delegation_fee: int | None = None, 1156 netuid: int = 0, 1157 ) -> ExtrinsicReceipt: 1158 """ 1159 Updates the parameters of a registered module. 1160 1161 The delegation fee must be an integer between 0 and 100. 1162 1163 Args: 1164 key: The keypair associated with the module's account. 1165 name: The new name for the module. If None, the name is not updated. 1166 address: The new address for the module. 1167 If None, the address is not updated. 1168 delegation_fee: The new delegation fee for the module, 1169 between 0 and 100. 1170 netuid: The network identifier. 1171 1172 Returns: 1173 A receipt of the module update transaction. 1174 1175 Raises: 1176 InvalidParameterError: If the provided parameters are invalid. 1177 ChainTransactionError: If the transaction fails. 1178 """ 1179 1180 assert isinstance(delegation_fee, int) 1181 params = { 1182 "netuid": netuid, 1183 "name": name, 1184 "address": address, 1185 "stake_delegation_fee": delegation_fee, 1186 "validator_weight_fee": weight_setting_delegation_fee, 1187 "metadata": metadata, 1188 } 1189 1190 response = self.compose_call("update_module", params=params, key=key) 1191 1192 return response
Updates the parameters of a registered module.
The delegation fee must be an integer between 0 and 100.
Arguments:
- key: The keypair associated with the module's account.
- name: The new name for the module. If None, the name is not updated.
- address: The new address for the module. If None, the address is not updated.
- delegation_fee: The new delegation fee for the module, between 0 and 100.
- netuid: The network identifier.
Returns:
A receipt of the module update transaction.
Raises:
- InvalidParameterError: If the provided parameters are invalid.
- ChainTransactionError: If the transaction fails.
1194 def register_module( 1195 self, 1196 key: Keypair, 1197 name: str, 1198 address: str | None = None, 1199 subnet: str = "Rootnet", 1200 metadata: str | None = None, 1201 ) -> ExtrinsicReceipt: 1202 """ 1203 Registers a new module in the network. 1204 1205 Args: 1206 key: The keypair used for registering the module. 1207 name: The name of the module. If None, a default or previously 1208 set name is used. # How does this work? 1209 address: The address of the module. If None, a default or 1210 previously set address is used. # How does this work? 1211 subnet: The network subnet to register the module in. 1212 min_stake: The minimum stake required for the module, in nanotokens. 1213 If None, a default value is used. 1214 1215 Returns: 1216 A receipt of the registration transaction. 1217 1218 Raises: 1219 InvalidParameterError: If the provided parameters are invalid. 1220 ChainTransactionError: If the transaction fails. 1221 """ 1222 1223 key_addr = key.ss58_address 1224 1225 params = { 1226 "network_name": subnet, 1227 "address": address, 1228 "name": name, 1229 "module_key": key_addr, 1230 "metadata": metadata, 1231 } 1232 1233 response = self.compose_call("register", params=params, key=key) 1234 return response
Registers a new module in the network.
Arguments:
- key: The keypair used for registering the module.
- name: The name of the module. If None, a default or previously set name is used. # How does this work?
- address: The address of the module. If None, a default or previously set address is used. # How does this work?
- subnet: The network subnet to register the module in.
- min_stake: The minimum stake required for the module, in nanotokens. If None, a default value is used.
Returns:
A receipt of the registration transaction.
Raises:
- InvalidParameterError: If the provided parameters are invalid.
- ChainTransactionError: If the transaction fails.
1236 def deregister_module(self, key: Keypair, netuid: int) -> ExtrinsicReceipt: 1237 """ 1238 Deregisters a module from the network. 1239 1240 Args: 1241 key: The keypair associated with the module's account. 1242 netuid: The network identifier. 1243 1244 Returns: 1245 A receipt of the module deregistration transaction. 1246 1247 Raises: 1248 ChainTransactionError: If the transaction fails. 1249 """ 1250 1251 params = {"netuid": netuid} 1252 1253 response = self.compose_call("deregister", params=params, key=key) 1254 1255 return response
Deregisters a module from the network.
Arguments:
- key: The keypair associated with the module's account.
- netuid: The network identifier.
Returns:
A receipt of the module deregistration transaction.
Raises:
- ChainTransactionError: If the transaction fails.
1257 def register_subnet( 1258 self, key: Keypair, name: str, metadata: str | None = None 1259 ) -> ExtrinsicReceipt: 1260 """ 1261 Registers a new subnet in the network. 1262 1263 Args: 1264 key (Keypair): The keypair used for registering the subnet. 1265 name (str): The name of the subnet to be registered. 1266 metadata (str | None, optional): Additional metadata for the subnet. Defaults to None. 1267 1268 Returns: 1269 ExtrinsicReceipt: A receipt of the subnet registration transaction. 1270 1271 Raises: 1272 ChainTransactionError: If the transaction fails. 1273 """ 1274 1275 params = { 1276 "name": name, 1277 "metadata": metadata, 1278 } 1279 1280 response = self.compose_call("register_subnet", params=params, key=key) 1281 1282 return response
Registers a new subnet in the network.
Arguments:
- key (Keypair): The keypair used for registering the subnet.
- name (str): The name of the subnet to be registered.
- metadata (str | None, optional): Additional metadata for the subnet. Defaults to None.
Returns:
ExtrinsicReceipt: A receipt of the subnet registration transaction.
Raises:
- ChainTransactionError: If the transaction fails.
1284 def vote( 1285 self, 1286 key: Keypair, 1287 uids: list[int], 1288 weights: list[int], 1289 netuid: int = 0, 1290 ) -> ExtrinsicReceipt: 1291 """ 1292 Casts votes on a list of module UIDs with corresponding weights. 1293 1294 The length of the UIDs list and the weights list should be the same. 1295 Each weight corresponds to the UID at the same index. 1296 1297 Args: 1298 key: The keypair used for signing the vote transaction. 1299 uids: A list of module UIDs to vote on. 1300 weights: A list of weights corresponding to each UID. 1301 netuid: The network identifier. 1302 1303 Returns: 1304 A receipt of the voting transaction. 1305 1306 Raises: 1307 InvalidParameterError: If the lengths of UIDs and weights lists 1308 do not match. 1309 ChainTransactionError: If the transaction fails. 1310 """ 1311 1312 assert len(uids) == len(weights) 1313 1314 params = { 1315 "uids": uids, 1316 "weights": weights, 1317 "netuid": netuid, 1318 } 1319 1320 response = self.compose_call( 1321 "set_weights", 1322 params=params, 1323 key=key, 1324 module="SubnetEmissionModule", 1325 ) 1326 1327 return response
Casts votes on a list of module UIDs with corresponding weights.
The length of the UIDs list and the weights list should be the same. Each weight corresponds to the UID at the same index.
Arguments:
- key: The keypair used for signing the vote transaction.
- uids: A list of module UIDs to vote on.
- weights: A list of weights corresponding to each UID.
- netuid: The network identifier.
Returns:
A receipt of the voting transaction.
Raises:
- InvalidParameterError: If the lengths of UIDs and weights lists do not match.
- ChainTransactionError: If the transaction fails.
1329 def delegate_weight_control( 1330 self, key: Keypair, target: Ss58Address, netuid: int 1331 ): 1332 """ 1333 delegates weight setting control from the current account to the target account. 1334 Both accounts have to be registered and have a valid validator `spec` 1335 """ 1336 1337 params = { 1338 "netuid": netuid, 1339 "target": target, 1340 } 1341 1342 response = self.compose_call( 1343 "delegate_weight_control", 1344 params=params, 1345 key=key, 1346 module="SubnetEmissionModule", 1347 ) 1348 return response
delegates weight setting control from the current account to the target account.
Both accounts have to be registered and have a valid validator spec
1371 def vote_encrypted( 1372 self, 1373 key: Keypair, 1374 uids: list[int], 1375 weights: list[int], 1376 netuid: int = 0, 1377 ) -> ExtrinsicReceipt: 1378 """ 1379 Casts encrypted votes for module UIDs with corresponding weights. 1380 1381 Args: 1382 key (Keypair): The keypair used for signing the transaction. 1383 uids (list[int]): List of UIDs to vote for. 1384 weights (list[int]): List of weights corresponding to each UID. 1385 netuid (int, optional): Network UID. Defaults to 0. 1386 1387 Returns: 1388 ExtrinsicReceipt: Receipt of the submitted extrinsic. 1389 1390 Raises: 1391 ValueError: If there's a length mismatch between UIDs and weights, 1392 if subnet data is not found, or if subnet key format is invalid. 1393 """ 1394 if len(uids) != len(weights): 1395 raise ValueError("Length mismatch between UIDs and weights") 1396 1397 subnet_data = self.query( 1398 "SubnetDecryptionData", 1399 module="SubnetEmissionModule", 1400 params=[netuid], 1401 ) 1402 if not subnet_data: 1403 raise ValueError("Subnet data not found") 1404 1405 subnet_key = subnet_data.get("node_public_key") 1406 if not subnet_key or len(subnet_key) < 2: 1407 raise ValueError("Invalid subnet key format") 1408 1409 vote_data = list(zip(uids, weights)) 1410 decryptor = ( 1411 bytes_from_hex(subnet_key[0]), 1412 bytes_from_hex(subnet_key[1]), 1413 ) 1414 validator_key = [int(x) for x in key.public_key] 1415 1416 encrypted_weights = encrypt_weights(decryptor, vote_data, validator_key) 1417 weights_hash = hashlib.sha256(str(weights).encode()).hexdigest() 1418 1419 params = { 1420 "uids": uids, 1421 "encrypted_weights": encrypted_weights, 1422 "netuid": netuid, 1423 "decrypted_weights_hash": weights_hash, 1424 } 1425 1426 return self.compose_call( 1427 "set_weights_encrypted", 1428 params=params, 1429 key=key, 1430 module="SubnetEmissionModule", 1431 )
Casts encrypted votes for module UIDs with corresponding weights.
Arguments:
- key (Keypair): The keypair used for signing the transaction.
- uids (list[int]): List of UIDs to vote for.
- weights (list[int]): List of weights corresponding to each UID.
- netuid (int, optional): Network UID. Defaults to 0.
Returns:
ExtrinsicReceipt: Receipt of the submitted extrinsic.
Raises:
- ValueError: If there's a length mismatch between UIDs and weights, if subnet data is not found, or if subnet key format is invalid.
1433 def update_subnet( 1434 self, 1435 key: Keypair, 1436 params: SubnetParams, 1437 netuid: int = 0, 1438 ) -> ExtrinsicReceipt: 1439 """ 1440 Update a subnet's configuration. 1441 1442 It requires the founder key for authorization. 1443 1444 Args: 1445 key: The founder keypair of the subnet. 1446 params: The new parameters for the subnet. 1447 netuid: The network identifier. 1448 1449 Returns: 1450 A receipt of the subnet update transaction. 1451 1452 Raises: 1453 AuthorizationError: If the key is not authorized. 1454 ChainTransactionError: If the transaction fails. 1455 """ 1456 1457 general_params = dict(params) 1458 general_params["netuid"] = netuid 1459 if general_params.get("subnet_metadata") is None: 1460 general_params["metadata"] = None 1461 else: 1462 general_params["metadata"] = general_params["subnet_metadata"] 1463 1464 response = self.compose_call( 1465 fn="update_subnet", 1466 params=general_params, 1467 key=key, 1468 ) 1469 1470 return response
Update a subnet's configuration.
It requires the founder key for authorization.
Arguments:
- key: The founder keypair of the subnet.
- params: The new parameters for the subnet.
- netuid: The network identifier.
Returns:
A receipt of the subnet update transaction.
Raises:
- AuthorizationError: If the key is not authorized.
- ChainTransactionError: If the transaction fails.
1472 def transfer_stake( 1473 self, 1474 key: Keypair, 1475 amount: int, 1476 from_module_key: Ss58Address, 1477 dest_module_address: Ss58Address, 1478 ) -> ExtrinsicReceipt: 1479 """ 1480 Realocate staked tokens from one staked module to another module. 1481 1482 Args: 1483 key: The keypair associated with the account that is delegating the tokens. 1484 amount: The amount of staked tokens to transfer, in nanotokens. 1485 from_module_key: The SS58 address of the module you want to transfer from (currently delegated by the key). 1486 dest_module_address: The SS58 address of the destination (newly delegated key). 1487 netuid: The network identifier. 1488 1489 Returns: 1490 A receipt of the stake transfer transaction. 1491 1492 Raises: 1493 InsufficientStakeError: If the source module key does not have 1494 enough staked tokens. ChainTransactionError: If the transaction 1495 fails. 1496 """ 1497 1498 amount = amount - self.get_existential_deposit() 1499 1500 params = { 1501 "amount": amount, 1502 "module_key": from_module_key, 1503 "new_module_key": dest_module_address, 1504 } 1505 1506 response = self.compose_call("transfer_stake", key=key, params=params) 1507 1508 return response
Realocate staked tokens from one staked module to another module.
Arguments:
- key: The keypair associated with the account that is delegating the tokens.
- amount: The amount of staked tokens to transfer, in nanotokens.
- from_module_key: The SS58 address of the module you want to transfer from (currently delegated by the key).
- dest_module_address: The SS58 address of the destination (newly delegated key).
- netuid: The network identifier.
Returns:
A receipt of the stake transfer transaction.
Raises:
- InsufficientStakeError: If the source module key does not have
- enough staked tokens. ChainTransactionError: If the transaction
- fails.
1510 def bridge( 1511 self, 1512 key: Keypair, 1513 amount: int, 1514 ): 1515 """ 1516 Bridge tokens from the Subspace network to the Torus network. 1517 1518 Args: 1519 key: The keypair associated with the account that is bridging the tokens. 1520 amount: The amount of tokens to bridge, in nanotokens. 1521 1522 Returns: 1523 A receipt of the bridging transaction. 1524 1525 Raises: 1526 InsufficientBalanceError: If the account does not have enough balance. 1527 ChainTransactionError: If the transaction fails. 1528 """ 1529 1530 params = {"amount": amount} 1531 1532 response = self.compose_call("bridge", key=key, params=params) 1533 1534 return response
Bridge tokens from the Subspace network to the Torus network.
Arguments:
- key: The keypair associated with the account that is bridging the tokens.
- amount: The amount of tokens to bridge, in nanotokens.
Returns:
A receipt of the bridging transaction.
Raises:
- InsufficientBalanceError: If the account does not have enough balance.
- ChainTransactionError: If the transaction fails.
1536 def bridge_withdraw( 1537 self, 1538 key: Keypair, 1539 amount: int, 1540 ): 1541 """ 1542 Withdraw bridged tokens from the Torus network to the Subspace network. 1543 1544 Args: 1545 key: The keypair associated with the account that is withdrawing the tokens. 1546 amount: The amount of tokens to withdraw, in nanotokens. 1547 1548 Returns: 1549 A receipt of the withdrawal transaction. 1550 1551 Raises: 1552 InsufficientBalanceError: If the account does not have enough balance. 1553 ChainTransactionError: If the transaction fails. 1554 """ 1555 1556 params = {"amount": amount} 1557 1558 response = self.compose_call("bridge_withdraw", key=key, params=params) 1559 1560 return response
Withdraw bridged tokens from the Torus network to the Subspace network.
Arguments:
- key: The keypair associated with the account that is withdrawing the tokens.
- amount: The amount of tokens to withdraw, in nanotokens.
Returns:
A receipt of the withdrawal transaction.
Raises:
- InsufficientBalanceError: If the account does not have enough balance.
- ChainTransactionError: If the transaction fails.
1562 def multiunstake( 1563 self, 1564 key: Keypair, 1565 keys: list[Ss58Address], 1566 amounts: list[int], 1567 ) -> ExtrinsicReceipt: 1568 """ 1569 Unstakes tokens from multiple module keys. 1570 1571 And the lists `keys` and `amounts` must be of the same length. Each 1572 amount corresponds to the module key at the same index. 1573 1574 Args: 1575 key: The keypair associated with the unstaker's account. 1576 keys: A list of SS58 addresses of the module keys to unstake from. 1577 amounts: A list of amounts to unstake from each module key, 1578 in nanotokens. 1579 netuid: The network identifier. 1580 1581 Returns: 1582 A receipt of the multi-unstaking transaction. 1583 1584 Raises: 1585 MismatchedLengthError: If the lengths of keys and amounts lists do 1586 not match. InsufficientStakeError: If any of the module keys do not 1587 have enough staked tokens. ChainTransactionError: If the transaction 1588 fails. 1589 """ 1590 1591 assert len(keys) == len(amounts) 1592 1593 params = {"module_keys": keys, "amounts": amounts} 1594 1595 response = self.compose_call( 1596 "remove_stake_multiple", params=params, key=key 1597 ) 1598 1599 return response
Unstakes tokens from multiple module keys.
And the lists keys
and amounts
must be of the same length. Each
amount corresponds to the module key at the same index.
Arguments:
- key: The keypair associated with the unstaker's account.
- keys: A list of SS58 addresses of the module keys to unstake from.
- amounts: A list of amounts to unstake from each module key, in nanotokens.
- netuid: The network identifier.
Returns:
A receipt of the multi-unstaking transaction.
Raises:
- MismatchedLengthError: If the lengths of keys and amounts lists do
- not match. InsufficientStakeError: If any of the module keys do not
- have enough staked tokens. ChainTransactionError: If the transaction
- fails.
1601 def multistake( 1602 self, 1603 key: Keypair, 1604 keys: list[Ss58Address], 1605 amounts: list[int], 1606 ) -> ExtrinsicReceipt: 1607 """ 1608 Stakes tokens to multiple module keys. 1609 1610 The lengths of the `keys` and `amounts` lists must be the same. Each 1611 amount corresponds to the module key at the same index. 1612 1613 Args: 1614 key: The keypair associated with the staker's account. 1615 keys: A list of SS58 addresses of the module keys to stake to. 1616 amounts: A list of amounts to stake to each module key, 1617 in nanotokens. 1618 netuid: The network identifier. 1619 1620 Returns: 1621 A receipt of the multi-staking transaction. 1622 1623 Raises: 1624 MismatchedLengthError: If the lengths of keys and amounts lists 1625 do not match. 1626 ChainTransactionError: If the transaction fails. 1627 """ 1628 1629 assert len(keys) == len(amounts) 1630 1631 params = { 1632 "module_keys": keys, 1633 "amounts": amounts, 1634 } 1635 1636 response = self.compose_call( 1637 "add_stake_multiple", params=params, key=key 1638 ) 1639 1640 return response
Stakes tokens to multiple module keys.
The lengths of the keys
and amounts
lists must be the same. Each
amount corresponds to the module key at the same index.
Arguments:
- key: The keypair associated with the staker's account.
- keys: A list of SS58 addresses of the module keys to stake to.
- amounts: A list of amounts to stake to each module key, in nanotokens.
- netuid: The network identifier.
Returns:
A receipt of the multi-staking transaction.
Raises:
- MismatchedLengthError: If the lengths of keys and amounts lists do not match.
- ChainTransactionError: If the transaction fails.
1680 def add_subnet_proposal( 1681 self, key: Keypair, params: dict[str, Any], ipfs: str, netuid: int = 0 1682 ) -> ExtrinsicReceipt: 1683 """ 1684 Submits a proposal for creating or modifying a subnet within the 1685 network. 1686 1687 The proposal includes various parameters like the name, founder, share 1688 allocations, and other subnet-specific settings. 1689 1690 Args: 1691 key: The keypair used for signing the proposal transaction. 1692 params: The parameters for the subnet proposal. 1693 netuid: The network identifier. 1694 1695 Returns: 1696 A receipt of the subnet proposal transaction. 1697 1698 Raises: 1699 InvalidParameterError: If the provided subnet 1700 parameters are invalid. 1701 ChainTransactionError: If the transaction fails. 1702 """ 1703 1704 general_params = dict(params) 1705 general_params["netuid"] = netuid 1706 general_params["data"] = ipfs 1707 if "metadata" not in general_params: 1708 general_params["metadata"] = None 1709 1710 # general_params["burn_config"] = json.dumps(general_params["burn_config"]) 1711 response = self.compose_call( 1712 fn="add_subnet_params_proposal", 1713 params=general_params, 1714 key=key, 1715 module="GovernanceModule", 1716 ) 1717 1718 return response
Submits a proposal for creating or modifying a subnet within the network.
The proposal includes various parameters like the name, founder, share allocations, and other subnet-specific settings.
Arguments:
- key: The keypair used for signing the proposal transaction.
- params: The parameters for the subnet proposal.
- netuid: The network identifier.
Returns:
A receipt of the subnet proposal transaction.
Raises:
- InvalidParameterError: If the provided subnet parameters are invalid.
- ChainTransactionError: If the transaction fails.
1720 def add_custom_proposal( 1721 self, 1722 key: Keypair, 1723 cid: str, 1724 ) -> ExtrinsicReceipt: 1725 params = {"data": cid} 1726 1727 response = self.compose_call( 1728 fn="add_global_custom_proposal", 1729 params=params, 1730 key=key, 1731 module="GovernanceModule", 1732 ) 1733 return response
1735 def add_custom_subnet_proposal( 1736 self, 1737 key: Keypair, 1738 cid: str, 1739 netuid: int = 0, 1740 ) -> ExtrinsicReceipt: 1741 """ 1742 Submits a proposal for creating or modifying a custom subnet within the 1743 network. 1744 1745 The proposal includes various parameters like the name, founder, share 1746 allocations, and other subnet-specific settings. 1747 1748 Args: 1749 key: The keypair used for signing the proposal transaction. 1750 params: The parameters for the subnet proposal. 1751 netuid: The network identifier. 1752 1753 Returns: 1754 A receipt of the subnet proposal transaction. 1755 """ 1756 1757 params = { 1758 "data": cid, 1759 "netuid": netuid, 1760 } 1761 1762 response = self.compose_call( 1763 fn="add_subnet_custom_proposal", 1764 params=params, 1765 key=key, 1766 module="GovernanceModule", 1767 ) 1768 1769 return response
Submits a proposal for creating or modifying a custom subnet within the network.
The proposal includes various parameters like the name, founder, share allocations, and other subnet-specific settings.
Arguments:
- key: The keypair used for signing the proposal transaction.
- params: The parameters for the subnet proposal.
- netuid: The network identifier.
Returns:
A receipt of the subnet proposal transaction.
1771 def add_global_proposal( 1772 self, 1773 key: Keypair, 1774 params: NetworkParams, 1775 cid: str | None, 1776 ) -> ExtrinsicReceipt: 1777 """ 1778 Submits a proposal for altering the global network parameters. 1779 1780 Allows for the submission of a proposal to 1781 change various global parameters 1782 of the network, such as emission rates, rate limits, and voting 1783 thresholds. It is used to 1784 suggest changes that affect the entire network's operation. 1785 1786 Args: 1787 key: The keypair used for signing the proposal transaction. 1788 params: A dictionary containing global network parameters 1789 like maximum allowed subnets, modules, 1790 transaction rate limits, and others. 1791 1792 Returns: 1793 A receipt of the global proposal transaction. 1794 1795 Raises: 1796 InvalidParameterError: If the provided network 1797 parameters are invalid. 1798 ChainTransactionError: If the transaction fails. 1799 """ 1800 general_params = cast(dict[str, Any], params) 1801 cid = cid or "" 1802 general_params["data"] = cid 1803 1804 response = self.compose_call( 1805 fn="add_global_params_proposal", 1806 params=general_params, 1807 key=key, 1808 module="GovernanceModule", 1809 ) 1810 1811 return response
Submits a proposal for altering the global network parameters.
Allows for the submission of a proposal to change various global parameters of the network, such as emission rates, rate limits, and voting thresholds. It is used to suggest changes that affect the entire network's operation.
Arguments:
- key: The keypair used for signing the proposal transaction.
- params: A dictionary containing global network parameters like maximum allowed subnets, modules, transaction rate limits, and others.
Returns:
A receipt of the global proposal transaction.
Raises:
- InvalidParameterError: If the provided network parameters are invalid.
- ChainTransactionError: If the transaction fails.
1813 def vote_on_proposal( 1814 self, 1815 key: Keypair, 1816 proposal_id: int, 1817 agree: bool, 1818 ) -> ExtrinsicReceipt: 1819 """ 1820 Casts a vote on a specified proposal within the network. 1821 1822 Args: 1823 key: The keypair used for signing the vote transaction. 1824 proposal_id: The unique identifier of the proposal to vote on. 1825 1826 Returns: 1827 A receipt of the voting transaction in nanotokens. 1828 1829 Raises: 1830 InvalidProposalIDError: If the provided proposal ID does not 1831 exist or is invalid. 1832 ChainTransactionError: If the transaction fails. 1833 """ 1834 1835 params = {"proposal_id": proposal_id, "agree": agree} 1836 1837 response = self.compose_call( 1838 "vote_proposal", 1839 key=key, 1840 params=params, 1841 module="GovernanceModule", 1842 ) 1843 1844 return response
Casts a vote on a specified proposal within the network.
Arguments:
- key: The keypair used for signing the vote transaction.
- proposal_id: The unique identifier of the proposal to vote on.
Returns:
A receipt of the voting transaction in nanotokens.
Raises:
- InvalidProposalIDError: If the provided proposal ID does not exist or is invalid.
- ChainTransactionError: If the transaction fails.
1846 def unvote_on_proposal( 1847 self, 1848 key: Keypair, 1849 proposal_id: int, 1850 ) -> ExtrinsicReceipt: 1851 """ 1852 Retracts a previously cast vote on a specified proposal. 1853 1854 Args: 1855 key: The keypair used for signing the unvote transaction. 1856 proposal_id: The unique identifier of the proposal to withdraw the 1857 vote from. 1858 1859 Returns: 1860 A receipt of the unvoting transaction in nanotokens. 1861 1862 Raises: 1863 InvalidProposalIDError: If the provided proposal ID does not 1864 exist or is invalid. 1865 ChainTransactionError: If the transaction fails to be processed, or 1866 if there was no prior vote to retract. 1867 """ 1868 1869 params = {"proposal_id": proposal_id} 1870 1871 response = self.compose_call( 1872 "remove_vote_proposal", 1873 key=key, 1874 params=params, 1875 module="GovernanceModule", 1876 ) 1877 1878 return response
Retracts a previously cast vote on a specified proposal.
Arguments:
- key: The keypair used for signing the unvote transaction.
- proposal_id: The unique identifier of the proposal to withdraw the vote from.
Returns:
A receipt of the unvoting transaction in nanotokens.
Raises:
- InvalidProposalIDError: If the provided proposal ID does not exist or is invalid.
- ChainTransactionError: If the transaction fails to be processed, or if there was no prior vote to retract.
1880 def enable_vote_power_delegation(self, key: Keypair) -> ExtrinsicReceipt: 1881 """ 1882 Enables vote power delegation for the signer's account. 1883 1884 Args: 1885 key: The keypair used for signing the delegation transaction. 1886 1887 Returns: 1888 A receipt of the vote power delegation transaction. 1889 1890 Raises: 1891 ChainTransactionError: If the transaction fails. 1892 """ 1893 1894 response = self.compose_call( 1895 "enable_vote_power_delegation", 1896 params={}, 1897 key=key, 1898 module="GovernanceModule", 1899 ) 1900 1901 return response
Enables vote power delegation for the signer's account.
Arguments:
- key: The keypair used for signing the delegation transaction.
Returns:
A receipt of the vote power delegation transaction.
Raises:
- ChainTransactionError: If the transaction fails.
1903 def disable_vote_power_delegation(self, key: Keypair) -> ExtrinsicReceipt: 1904 """ 1905 Disables vote power delegation for the signer's account. 1906 1907 Args: 1908 key: The keypair used for signing the delegation transaction. 1909 1910 Returns: 1911 A receipt of the vote power delegation transaction. 1912 1913 Raises: 1914 ChainTransactionError: If the transaction fails. 1915 """ 1916 1917 response = self.compose_call( 1918 "disable_vote_power_delegation", 1919 params={}, 1920 key=key, 1921 module="GovernanceModule", 1922 ) 1923 1924 return response
Disables vote power delegation for the signer's account.
Arguments:
- key: The keypair used for signing the delegation transaction.
Returns:
A receipt of the vote power delegation transaction.
Raises:
- ChainTransactionError: If the transaction fails.
1926 def add_dao_application( 1927 self, key: Keypair, application_key: Ss58Address, data: str 1928 ) -> ExtrinsicReceipt: 1929 """ 1930 Submits a new application to the general subnet DAO. 1931 1932 Args: 1933 key: The keypair used for signing the application transaction. 1934 application_key: The SS58 address of the application key. 1935 data: The data associated with the application. 1936 1937 Returns: 1938 A receipt of the application transaction. 1939 1940 Raises: 1941 ChainTransactionError: If the transaction fails. 1942 """ 1943 1944 params = {"application_key": application_key, "data": data} 1945 1946 response = self.compose_call( 1947 "add_dao_application", 1948 module="GovernanceModule", 1949 key=key, 1950 params=params, 1951 ) 1952 1953 return response
Submits a new application to the general subnet DAO.
Arguments:
- key: The keypair used for signing the application transaction.
- application_key: The SS58 address of the application key.
- data: The data associated with the application.
Returns:
A receipt of the application transaction.
Raises:
- ChainTransactionError: If the transaction fails.
1955 def query_map_curator_applications(self) -> dict[str, dict[str, str]]: 1956 query_result = self.query_map( 1957 "CuratorApplications", 1958 module="GovernanceModule", 1959 params=[], 1960 extract_value=False, 1961 ) 1962 applications = query_result.get("CuratorApplications", {}) 1963 return applications
1965 def query_map_proposals( 1966 self, extract_value: bool = False 1967 ) -> dict[int, dict[str, Any]]: 1968 """ 1969 Retrieves a mappping of proposals from the network. 1970 1971 Queries the network and returns a mapping of proposal IDs to 1972 their respective parameters. 1973 1974 Returns: 1975 A dictionary mapping proposal IDs 1976 to dictionaries of their parameters. 1977 1978 Raises: 1979 QueryError: If the query to the network fails or is invalid. 1980 """ 1981 1982 return self.query_map( 1983 "Proposals", extract_value=extract_value, module="GovernanceModule" 1984 )["Proposals"]
Retrieves a mappping of proposals from the network.
Queries the network and returns a mapping of proposal IDs to their respective parameters.
Returns:
A dictionary mapping proposal IDs to dictionaries of their parameters.
Raises:
- QueryError: If the query to the network fails or is invalid.
1986 def query_map_weights( 1987 self, netuid: int = 0, extract_value: bool = False 1988 ) -> dict[int, list[tuple[int, int]]] | None: 1989 """ 1990 Retrieves a mapping of weights for keys on the network. 1991 1992 Queries the network and returns a mapping of key UIDs to 1993 their respective weights. 1994 1995 Args: 1996 netuid: The network UID from which to get the weights. 1997 1998 Returns: 1999 A dictionary mapping key UIDs to lists of their weights. 2000 2001 Raises: 2002 QueryError: If the query to the network fails or is invalid. 2003 """ 2004 2005 weights_dict = self.query_map( 2006 "Weights", 2007 [netuid], 2008 extract_value=extract_value, 2009 module="SubnetEmissionModule", 2010 ).get("Weights") 2011 return weights_dict
Retrieves a mapping of weights for keys on the network.
Queries the network and returns a mapping of key UIDs to their respective weights.
Arguments:
- netuid: The network UID from which to get the weights.
Returns:
A dictionary mapping key UIDs to lists of their weights.
Raises:
- QueryError: If the query to the network fails or is invalid.
2013 def query_map_key( 2014 self, 2015 netuid: int = 0, 2016 extract_value: bool = False, 2017 ) -> dict[int, Ss58Address]: 2018 """ 2019 Retrieves a map of keys from the network. 2020 2021 Fetches a mapping of key UIDs to their associated 2022 addresses on the network. 2023 The query can be targeted at a specific network UID if required. 2024 2025 Args: 2026 netuid: The network UID from which to get the keys. 2027 2028 Returns: 2029 A dictionary mapping key UIDs to their addresses. 2030 2031 Raises: 2032 QueryError: If the query to the network fails or is invalid. 2033 """ 2034 return self.query_map("Keys", [netuid], extract_value=extract_value)[ 2035 "Keys" 2036 ]
Retrieves a map of keys from the network.
Fetches a mapping of key UIDs to their associated addresses on the network. The query can be targeted at a specific network UID if required.
Arguments:
- netuid: The network UID from which to get the keys.
Returns:
A dictionary mapping key UIDs to their addresses.
Raises:
- QueryError: If the query to the network fails or is invalid.
2038 def query_map_address( 2039 self, netuid: int = 0, extract_value: bool = False 2040 ) -> dict[int, str]: 2041 """ 2042 Retrieves a map of key addresses from the network. 2043 2044 Queries the network for a mapping of key UIDs to their addresses. 2045 2046 Args: 2047 netuid: The network UID from which to get the addresses. 2048 2049 Returns: 2050 A dictionary mapping key UIDs to their addresses. 2051 2052 Raises: 2053 QueryError: If the query to the network fails or is invalid. 2054 """ 2055 2056 return self.query_map("Address", [netuid], extract_value=extract_value)[ 2057 "Address" 2058 ]
Retrieves a map of key addresses from the network.
Queries the network for a mapping of key UIDs to their addresses.
Arguments:
- netuid: The network UID from which to get the addresses.
Returns:
A dictionary mapping key UIDs to their addresses.
Raises:
- QueryError: If the query to the network fails or is invalid.
2060 def query_map_emission( 2061 self, extract_value: bool = False 2062 ) -> dict[int, list[int]]: 2063 """ 2064 Retrieves a map of emissions for keys on the network. 2065 2066 Queries the network to get a mapping of 2067 key UIDs to their emission values. 2068 2069 Returns: 2070 A dictionary mapping key UIDs to lists of their emission values. 2071 2072 Raises: 2073 QueryError: If the query to the network fails or is invalid. 2074 """ 2075 2076 return self.query_map("Emission", extract_value=extract_value)[ 2077 "Emission" 2078 ]
Retrieves a map of emissions for keys on the network.
Queries the network to get a mapping of key UIDs to their emission values.
Returns:
A dictionary mapping key UIDs to lists of their emission values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2080 def query_map_pending_emission(self, extract_value: bool = False) -> int: 2081 """ 2082 Retrieves a map of pending emissions for the subnets. 2083 2084 Queries the network for a mapping of subnet UIDs to their pending emission values. 2085 2086 Returns: 2087 A dictionary mapping subnet UIDs to their pending emission values. 2088 2089 Raises: 2090 QueryError: If the query to the network fails or is invalid. 2091 """ 2092 return self.query_map( 2093 "PendingEmission", 2094 extract_value=extract_value, 2095 module="SubnetEmissionModule", 2096 )["PendingEmission"]
Retrieves a map of pending emissions for the subnets.
Queries the network for a mapping of subnet UIDs to their pending emission values.
Returns:
A dictionary mapping subnet UIDs to their pending emission values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2098 def query_map_subnet_emission( 2099 self, extract_value: bool = False 2100 ) -> dict[int, int]: 2101 """ 2102 Retrieves a map of subnet emissions for the network. 2103 2104 Queries the network for a mapping of subnet UIDs to their emission values. 2105 2106 Returns: 2107 A dictionary mapping subnet UIDs to their emission values. 2108 2109 Raises: 2110 QueryError: If the query to the network fails or is invalid. 2111 """ 2112 2113 return self.query_map( 2114 "SubnetEmission", 2115 extract_value=extract_value, 2116 module="SubnetEmissionModule", 2117 )["SubnetEmission"]
Retrieves a map of subnet emissions for the network.
Queries the network for a mapping of subnet UIDs to their emission values.
Returns:
A dictionary mapping subnet UIDs to their emission values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2119 def query_map_subnet_consensus( 2120 self, extract_value: bool = False 2121 ) -> dict[int, str]: 2122 """ 2123 Retrieves a map of subnet consensus types for the network. 2124 2125 Queries the network for a mapping of subnet UIDs to their consensus types. 2126 2127 Returns: 2128 A dictionary mapping subnet UIDs to their consensus types. 2129 2130 Raises: 2131 QueryError: If the query to the network fails or is invalid. 2132 """ 2133 2134 return self.query_map( 2135 "SubnetConsensusType", 2136 extract_value=extract_value, 2137 module="SubnetEmissionModule", 2138 )["SubnetConsensusType"]
Retrieves a map of subnet consensus types for the network.
Queries the network for a mapping of subnet UIDs to their consensus types.
Returns:
A dictionary mapping subnet UIDs to their consensus types.
Raises:
- QueryError: If the query to the network fails or is invalid.
2140 def query_map_incentive( 2141 self, extract_value: bool = False 2142 ) -> dict[int, list[int]]: 2143 """ 2144 Retrieves a mapping of incentives for keys on the network. 2145 2146 Queries the network and returns a mapping of key UIDs to 2147 their respective incentive values. 2148 2149 Returns: 2150 A dictionary mapping key UIDs to lists of their incentive values. 2151 2152 Raises: 2153 QueryError: If the query to the network fails or is invalid. 2154 """ 2155 2156 return self.query_map("Incentive", extract_value=extract_value)[ 2157 "Incentive" 2158 ]
Retrieves a mapping of incentives for keys on the network.
Queries the network and returns a mapping of key UIDs to their respective incentive values.
Returns:
A dictionary mapping key UIDs to lists of their incentive values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2160 def query_map_dividend( 2161 self, extract_value: bool = False 2162 ) -> dict[int, list[int]]: 2163 """ 2164 Retrieves a mapping of dividends for keys on the network. 2165 2166 Queries the network for a mapping of key UIDs to 2167 their dividend values. 2168 2169 Returns: 2170 A dictionary mapping key UIDs to lists of their dividend values. 2171 2172 Raises: 2173 QueryError: If the query to the network fails or is invalid. 2174 """ 2175 2176 return self.query_map("Dividends", extract_value=extract_value)[ 2177 "Dividends" 2178 ]
Retrieves a mapping of dividends for keys on the network.
Queries the network for a mapping of key UIDs to their dividend values.
Returns:
A dictionary mapping key UIDs to lists of their dividend values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2180 def query_map_regblock( 2181 self, netuid: int = 0, extract_value: bool = False 2182 ) -> dict[int, int]: 2183 """ 2184 Retrieves a mapping of registration blocks for keys on the network. 2185 2186 Queries the network for a mapping of key UIDs to 2187 the blocks where they were registered. 2188 2189 Args: 2190 netuid: The network UID from which to get the registration blocks. 2191 2192 Returns: 2193 A dictionary mapping key UIDs to their registration blocks. 2194 2195 Raises: 2196 QueryError: If the query to the network fails or is invalid. 2197 """ 2198 2199 return self.query_map( 2200 "RegistrationBlock", [netuid], extract_value=extract_value 2201 )["RegistrationBlock"]
Retrieves a mapping of registration blocks for keys on the network.
Queries the network for a mapping of key UIDs to the blocks where they were registered.
Arguments:
- netuid: The network UID from which to get the registration blocks.
Returns:
A dictionary mapping key UIDs to their registration blocks.
Raises:
- QueryError: If the query to the network fails or is invalid.
2203 def query_map_lastupdate( 2204 self, extract_value: bool = False 2205 ) -> dict[int, list[int]]: 2206 """ 2207 Retrieves a mapping of the last update times for keys on the network. 2208 2209 Queries the network for a mapping of key UIDs to their last update times. 2210 2211 Returns: 2212 A dictionary mapping key UIDs to lists of their last update times. 2213 2214 Raises: 2215 QueryError: If the query to the network fails or is invalid. 2216 """ 2217 2218 return self.query_map("LastUpdate", extract_value=extract_value)[ 2219 "LastUpdate" 2220 ]
Retrieves a mapping of the last update times for keys on the network.
Queries the network for a mapping of key UIDs to their last update times.
Returns:
A dictionary mapping key UIDs to lists of their last update times.
Raises:
- QueryError: If the query to the network fails or is invalid.
2222 def query_map_stakefrom( 2223 self, extract_value: bool = False 2224 ) -> dict[Ss58Address, list[tuple[Ss58Address, int]]]: 2225 """ 2226 Retrieves a mapping of stakes from various sources for keys on the network. 2227 2228 Queries the network to obtain a mapping of key addresses to the sources 2229 and amounts of stakes they have received. 2230 2231 Args: 2232 netuid: The network UID from which to get the stakes. 2233 2234 Returns: 2235 A dictionary mapping key addresses to lists of tuples 2236 (module_key_address, amount). 2237 2238 Raises: 2239 QueryError: If the query to the network fails or is invalid. 2240 """ 2241 2242 result = self.query_map("StakeFrom", [], extract_value=extract_value)[ 2243 "StakeFrom" 2244 ] 2245 2246 return transform_stake_dmap(result)
Retrieves a mapping of stakes from various sources for keys on the network.
Queries the network to obtain a mapping of key addresses to the sources and amounts of stakes they have received.
Arguments:
- netuid: The network UID from which to get the stakes.
Returns:
A dictionary mapping key addresses to lists of tuples (module_key_address, amount).
Raises:
- QueryError: If the query to the network fails or is invalid.
2248 def query_map_staketo( 2249 self, extract_value: bool = False 2250 ) -> dict[Ss58Address, list[tuple[Ss58Address, int]]]: 2251 """ 2252 Retrieves a mapping of stakes to destinations for keys on the network. 2253 2254 Queries the network for a mapping of key addresses to the destinations 2255 and amounts of stakes they have made. 2256 2257 Args: 2258 netuid: The network UID from which to get the stakes. 2259 2260 Returns: 2261 A dictionary mapping key addresses to lists of tuples 2262 (module_key_address, amount). 2263 2264 Raises: 2265 QueryError: If the query to the network fails or is invalid. 2266 """ 2267 2268 result = self.query_map("StakeTo", [], extract_value=extract_value)[ 2269 "StakeTo" 2270 ] 2271 return transform_stake_dmap(result)
Retrieves a mapping of stakes to destinations for keys on the network.
Queries the network for a mapping of key addresses to the destinations and amounts of stakes they have made.
Arguments:
- netuid: The network UID from which to get the stakes.
Returns:
A dictionary mapping key addresses to lists of tuples (module_key_address, amount).
Raises:
- QueryError: If the query to the network fails or is invalid.
2273 def query_map_delegationfee( 2274 self, netuid: int = 0, extract_value: bool = False 2275 ) -> dict[str, int]: 2276 """ 2277 Retrieves a mapping of delegation fees for keys on the network. 2278 2279 Queries the network to obtain a mapping of key addresses to their 2280 respective delegation fees. 2281 2282 Args: 2283 netuid: The network UID to filter the delegation fees. 2284 2285 Returns: 2286 A dictionary mapping key addresses to their delegation fees. 2287 2288 Raises: 2289 QueryError: If the query to the network fails or is invalid. 2290 """ 2291 2292 return self.query_map( 2293 "DelegationFee", [netuid], extract_value=extract_value 2294 )["DelegationFee"]
Retrieves a mapping of delegation fees for keys on the network.
Queries the network to obtain a mapping of key addresses to their respective delegation fees.
Arguments:
- netuid: The network UID to filter the delegation fees.
Returns:
A dictionary mapping key addresses to their delegation fees.
Raises:
- QueryError: If the query to the network fails or is invalid.
2296 def query_map_tempo(self, extract_value: bool = False) -> dict[int, int]: 2297 """ 2298 Retrieves a mapping of tempo settings for the network. 2299 2300 Queries the network to obtain the tempo (rate of reward distributions) 2301 settings for various network subnets. 2302 2303 Returns: 2304 A dictionary mapping network UIDs to their tempo settings. 2305 2306 Raises: 2307 QueryError: If the query to the network fails or is invalid. 2308 """ 2309 2310 return self.query_map("Tempo", extract_value=extract_value)["Tempo"]
Retrieves a mapping of tempo settings for the network.
Queries the network to obtain the tempo (rate of reward distributions) settings for various network subnets.
Returns:
A dictionary mapping network UIDs to their tempo settings.
Raises:
- QueryError: If the query to the network fails or is invalid.
2312 def query_map_immunity_period(self, extract_value: bool) -> dict[int, int]: 2313 """ 2314 Retrieves a mapping of immunity periods for the network. 2315 2316 Queries the network for the immunity period settings, 2317 which represent the time duration during which modules 2318 can not get deregistered. 2319 2320 Returns: 2321 A dictionary mapping network UIDs to their immunity period settings. 2322 2323 Raises: 2324 QueryError: If the query to the network fails or is invalid. 2325 """ 2326 2327 return self.query_map("ImmunityPeriod", extract_value=extract_value)[ 2328 "ImmunityPeriod" 2329 ]
Retrieves a mapping of immunity periods for the network.
Queries the network for the immunity period settings, which represent the time duration during which modules can not get deregistered.
Returns:
A dictionary mapping network UIDs to their immunity period settings.
Raises:
- QueryError: If the query to the network fails or is invalid.
2331 def query_map_min_allowed_weights( 2332 self, extract_value: bool = False 2333 ) -> dict[int, int]: 2334 """ 2335 Retrieves a mapping of minimum allowed weights for the network. 2336 2337 Queries the network to obtain the minimum allowed weights, 2338 which are the lowest permissible weight values that can be set by 2339 validators. 2340 2341 Returns: 2342 A dictionary mapping network UIDs to 2343 their minimum allowed weight values. 2344 2345 Raises: 2346 QueryError: If the query to the network fails or is invalid. 2347 """ 2348 2349 return self.query_map("MinAllowedWeights", extract_value=extract_value)[ 2350 "MinAllowedWeights" 2351 ]
Retrieves a mapping of minimum allowed weights for the network.
Queries the network to obtain the minimum allowed weights, which are the lowest permissible weight values that can be set by validators.
Returns:
A dictionary mapping network UIDs to their minimum allowed weight values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2353 def query_map_max_allowed_weights( 2354 self, extract_value: bool = False 2355 ) -> dict[int, int]: 2356 """ 2357 Retrieves a mapping of maximum allowed weights for the network. 2358 2359 Queries the network for the maximum allowed weights, 2360 which are the highest permissible 2361 weight values that can be set by validators. 2362 2363 Returns: 2364 A dictionary mapping network UIDs to 2365 their maximum allowed weight values. 2366 2367 Raises: 2368 QueryError: If the query to the network fails or is invalid. 2369 """ 2370 2371 return self.query_map("MaxAllowedWeights", extract_value=extract_value)[ 2372 "MaxAllowedWeights" 2373 ]
Retrieves a mapping of maximum allowed weights for the network.
Queries the network for the maximum allowed weights, which are the highest permissible weight values that can be set by validators.
Returns:
A dictionary mapping network UIDs to their maximum allowed weight values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2375 def query_map_max_allowed_uids( 2376 self, extract_value: bool = False 2377 ) -> dict[int, int]: 2378 """ 2379 Queries the network for the maximum number of allowed user IDs (UIDs) 2380 for each network subnet. 2381 2382 Fetches a mapping of network subnets to their respective 2383 limits on the number of user IDs that can be created or used. 2384 2385 Returns: 2386 A dictionary mapping network UIDs (unique identifiers) to their 2387 maximum allowed number of UIDs. 2388 Each entry represents a network subnet 2389 with its corresponding UID limit. 2390 2391 Raises: 2392 QueryError: If the query to the network fails or is invalid. 2393 """ 2394 2395 return self.query_map("MaxAllowedUids", extract_value=extract_value)[ 2396 "MaxAllowedUids" 2397 ]
Queries the network for the maximum number of allowed user IDs (UIDs) for each network subnet.
Fetches a mapping of network subnets to their respective limits on the number of user IDs that can be created or used.
Returns:
A dictionary mapping network UIDs (unique identifiers) to their maximum allowed number of UIDs. Each entry represents a network subnet with its corresponding UID limit.
Raises:
- QueryError: If the query to the network fails or is invalid.
2399 def query_map_min_stake( 2400 self, extract_value: bool = False 2401 ) -> dict[int, int]: 2402 """ 2403 Retrieves a mapping of minimum allowed stake on the network. 2404 2405 Queries the network to obtain the minimum number of stake, 2406 which is represented in nanotokens. 2407 2408 Returns: 2409 A dictionary mapping network UIDs to 2410 their minimum allowed stake values. 2411 2412 Raises: 2413 QueryError: If the query to the network fails or is invalid. 2414 """ 2415 2416 return self.query_map("MinStake", extract_value=extract_value)[ 2417 "MinStake" 2418 ]
Retrieves a mapping of minimum allowed stake on the network.
Queries the network to obtain the minimum number of stake, which is represented in nanotokens.
Returns:
A dictionary mapping network UIDs to their minimum allowed stake values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2420 def query_map_max_stake( 2421 self, extract_value: bool = False 2422 ) -> dict[int, int]: 2423 """ 2424 Retrieves a mapping of the maximum stake values for the network. 2425 2426 Queries the network for the maximum stake values across various s 2427 ubnets of the network. 2428 2429 Returns: 2430 A dictionary mapping network UIDs to their maximum stake values. 2431 2432 Raises: 2433 QueryError: If the query to the network fails or is invalid. 2434 """ 2435 2436 return self.query_map("MaxStake", extract_value=extract_value)[ 2437 "MaxStake" 2438 ]
Retrieves a mapping of the maximum stake values for the network.
Queries the network for the maximum stake values across various s ubnets of the network.
Returns:
A dictionary mapping network UIDs to their maximum stake values.
Raises:
- QueryError: If the query to the network fails or is invalid.
2440 def query_map_founder(self, extract_value: bool = False) -> dict[int, str]: 2441 """ 2442 Retrieves a mapping of founders for the network. 2443 2444 Queries the network to obtain the founders associated with 2445 various subnets. 2446 2447 Returns: 2448 A dictionary mapping network UIDs to their respective founders. 2449 2450 Raises: 2451 QueryError: If the query to the network fails or is invalid. 2452 """ 2453 2454 return self.query_map("Founder", extract_value=extract_value)["Founder"]
Retrieves a mapping of founders for the network.
Queries the network to obtain the founders associated with various subnets.
Returns:
A dictionary mapping network UIDs to their respective founders.
Raises:
- QueryError: If the query to the network fails or is invalid.
2476 def query_map_incentive_ratio( 2477 self, extract_value: bool = False 2478 ) -> dict[int, int]: 2479 """ 2480 Retrieves a mapping of incentive ratios for the network. 2481 2482 Queries the network for the incentive ratios, 2483 which are the proportions of rewards or incentives 2484 allocated in different subnets of the network. 2485 2486 Returns: 2487 A dictionary mapping network UIDs to their incentive ratios. 2488 2489 Raises: 2490 QueryError: If the query to the network fails or is invalid. 2491 """ 2492 2493 return self.query_map("IncentiveRatio", extract_value=extract_value)[ 2494 "IncentiveRatio" 2495 ]
Retrieves a mapping of incentive ratios for the network.
Queries the network for the incentive ratios, which are the proportions of rewards or incentives allocated in different subnets of the network.
Returns:
A dictionary mapping network UIDs to their incentive ratios.
Raises:
- QueryError: If the query to the network fails or is invalid.
2497 def query_map_trust_ratio( 2498 self, extract_value: bool = False 2499 ) -> dict[int, int]: 2500 """ 2501 Retrieves a mapping of trust ratios for the network. 2502 2503 Queries the network for trust ratios, 2504 indicative of the level of trust or credibility assigned 2505 to different subnets of the network. 2506 2507 Returns: 2508 A dictionary mapping network UIDs to their trust ratios. 2509 2510 Raises: 2511 QueryError: If the query to the network fails or is invalid. 2512 """ 2513 2514 return self.query_map("TrustRatio", extract_value=extract_value)[ 2515 "TrustRatio" 2516 ]
Retrieves a mapping of trust ratios for the network.
Queries the network for trust ratios, indicative of the level of trust or credibility assigned to different subnets of the network.
Returns:
A dictionary mapping network UIDs to their trust ratios.
Raises:
- QueryError: If the query to the network fails or is invalid.
2518 def query_map_vote_mode_subnet( 2519 self, extract_value: bool = False 2520 ) -> dict[int, str]: 2521 """ 2522 Retrieves a mapping of vote modes for subnets within the network. 2523 2524 Queries the network for the voting modes used in different 2525 subnets, which define the methodology or approach of voting within those 2526 subnets. 2527 2528 Returns: 2529 A dictionary mapping network UIDs to their vote 2530 modes for subnets. 2531 2532 Raises: 2533 QueryError: If the query to the network fails or is invalid. 2534 """ 2535 2536 return self.query_map("VoteModeSubnet", extract_value=extract_value)[ 2537 "VoteModeSubnet" 2538 ]
Retrieves a mapping of vote modes for subnets within the network.
Queries the network for the voting modes used in different subnets, which define the methodology or approach of voting within those subnets.
Returns:
A dictionary mapping network UIDs to their vote modes for subnets.
Raises:
- QueryError: If the query to the network fails or is invalid.
2540 def query_map_legit_whitelist( 2541 self, extract_value: bool = False 2542 ) -> dict[Ss58Address, int]: 2543 """ 2544 Retrieves a mapping of whitelisted addresses for the network. 2545 2546 Queries the network for a mapping of whitelisted addresses 2547 and their respective legitimacy status. 2548 2549 Returns: 2550 A dictionary mapping addresses to their legitimacy status. 2551 2552 Raises: 2553 QueryError: If the query to the network fails or is invalid. 2554 """ 2555 2556 return self.query_map( 2557 "LegitWhitelist", 2558 module="GovernanceModule", 2559 extract_value=extract_value, 2560 )["LegitWhitelist"]
Retrieves a mapping of whitelisted addresses for the network.
Queries the network for a mapping of whitelisted addresses and their respective legitimacy status.
Returns:
A dictionary mapping addresses to their legitimacy status.
Raises:
- QueryError: If the query to the network fails or is invalid.
2562 def query_map_subnet_names( 2563 self, extract_value: bool = False 2564 ) -> dict[int, str]: 2565 """ 2566 Retrieves a mapping of subnet names within the network. 2567 2568 Queries the network for the names of various subnets, 2569 providing an overview of the different 2570 subnets within the network. 2571 2572 Returns: 2573 A dictionary mapping network UIDs to their subnet names. 2574 2575 Raises: 2576 QueryError: If the query to the network fails or is invalid. 2577 """ 2578 2579 return self.query_map("SubnetNames", extract_value=extract_value)[ 2580 "SubnetNames" 2581 ]
Retrieves a mapping of subnet names within the network.
Queries the network for the names of various subnets, providing an overview of the different subnets within the network.
Returns:
A dictionary mapping network UIDs to their subnet names.
Raises:
- QueryError: If the query to the network fails or is invalid.
2583 def query_map_balances( 2584 self, extract_value: bool = False, block_hash: str | None = None 2585 ) -> dict[str, dict[str, int | dict[str, int | float]]]: 2586 """ 2587 Retrieves a mapping of account balances within the network. 2588 2589 Queries the network for the balances associated with different accounts. 2590 It provides detailed information including various types of 2591 balances for each account. 2592 2593 Returns: 2594 A dictionary mapping account addresses to their balance details. 2595 2596 Raises: 2597 QueryError: If the query to the network fails or is invalid. 2598 """ 2599 2600 return self.query_map( 2601 "Account", 2602 module="System", 2603 extract_value=extract_value, 2604 block_hash=block_hash, 2605 )["Account"]
Retrieves a mapping of account balances within the network.
Queries the network for the balances associated with different accounts. It provides detailed information including various types of balances for each account.
Returns:
A dictionary mapping account addresses to their balance details.
Raises:
- QueryError: If the query to the network fails or is invalid.
2607 def query_map_registration_blocks( 2608 self, netuid: int = 0, extract_value: bool = False 2609 ) -> dict[int, int]: 2610 """ 2611 Retrieves a mapping of registration blocks for UIDs on the network. 2612 2613 Queries the network to find the block numbers at which various 2614 UIDs were registered. 2615 2616 Args: 2617 netuid: The network UID from which to get the registrations. 2618 2619 Returns: 2620 A dictionary mapping UIDs to their registration block numbers. 2621 2622 Raises: 2623 QueryError: If the query to the network fails or is invalid. 2624 """ 2625 2626 return self.query_map( 2627 "RegistrationBlock", [netuid], extract_value=extract_value 2628 )["RegistrationBlock"]
Retrieves a mapping of registration blocks for UIDs on the network.
Queries the network to find the block numbers at which various UIDs were registered.
Arguments:
- netuid: The network UID from which to get the registrations.
Returns:
A dictionary mapping UIDs to their registration block numbers.
Raises:
- QueryError: If the query to the network fails or is invalid.
2630 def query_map_name( 2631 self, netuid: int = 0, extract_value: bool = False 2632 ) -> dict[int, str]: 2633 """ 2634 Retrieves a mapping of names for keys on the network. 2635 2636 Queries the network for the names associated with different keys. 2637 It provides a mapping of key UIDs to their registered names. 2638 2639 Args: 2640 netuid: The network UID from which to get the names. 2641 2642 Returns: 2643 A dictionary mapping key UIDs to their names. 2644 2645 Raises: 2646 QueryError: If the query to the network fails or is invalid. 2647 """ 2648 2649 return self.query_map("Name", [netuid], extract_value=extract_value)[ 2650 "Name" 2651 ]
Retrieves a mapping of names for keys on the network.
Queries the network for the names associated with different keys. It provides a mapping of key UIDs to their registered names.
Arguments:
- netuid: The network UID from which to get the names.
Returns:
A dictionary mapping key UIDs to their names.
Raises:
- QueryError: If the query to the network fails or is invalid.
2655 def get_immunity_period(self, netuid: int = 0) -> int: 2656 """ 2657 Queries the network for the immunity period setting. 2658 2659 The immunity period is a time duration during which a module 2660 can not be deregistered from the network. 2661 Fetches the immunity period for a specified network subnet. 2662 2663 Args: 2664 netuid: The network UID for which to query the immunity period. 2665 2666 Returns: 2667 The immunity period setting for the specified network subnet. 2668 2669 Raises: 2670 QueryError: If the query to the network fails or is invalid. 2671 """ 2672 2673 return self.query( 2674 "ImmunityPeriod", 2675 params=[netuid], 2676 )
Queries the network for the immunity period setting.
The immunity period is a time duration during which a module can not be deregistered from the network. Fetches the immunity period for a specified network subnet.
Arguments:
- netuid: The network UID for which to query the immunity period.
Returns:
The immunity period setting for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2681 def get_min_allowed_weights(self, netuid: int = 0) -> int: 2682 """ 2683 Queries the network for the minimum allowed weights setting. 2684 2685 Retrieves the minimum weight values that are possible to set 2686 by a validator within a specific network subnet. 2687 2688 Args: 2689 netuid: The network UID for which to query the minimum allowed 2690 weights. 2691 2692 Returns: 2693 The minimum allowed weight values for the specified network 2694 subnet. 2695 2696 Raises: 2697 QueryError: If the query to the network fails or is invalid. 2698 """ 2699 2700 return self.query( 2701 "MinAllowedWeights", 2702 params=[netuid], 2703 )
Queries the network for the minimum allowed weights setting.
Retrieves the minimum weight values that are possible to set by a validator within a specific network subnet.
Arguments:
- netuid: The network UID for which to query the minimum allowed weights.
Returns:
The minimum allowed weight values for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2708 def get_max_allowed_weights(self, netuid: int = 0) -> int: 2709 """ 2710 Queries the network for the maximum allowed weights setting. 2711 2712 Retrieves the maximum weight values that are possible to set 2713 by a validator within a specific network subnet. 2714 2715 Args: 2716 netuid: The network UID for which to query the maximum allowed 2717 weights. 2718 2719 Returns: 2720 The maximum allowed weight values for the specified network 2721 subnet. 2722 2723 Raises: 2724 QueryError: If the query to the network fails or is invalid. 2725 """ 2726 2727 return self.query("MaxAllowedWeights", params=[netuid])
Queries the network for the maximum allowed weights setting.
Retrieves the maximum weight values that are possible to set by a validator within a specific network subnet.
Arguments:
- netuid: The network UID for which to query the maximum allowed weights.
Returns:
The maximum allowed weight values for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2729 def get_max_allowed_uids(self, netuid: int = 0) -> int: 2730 """ 2731 Queries the network for the maximum allowed UIDs setting. 2732 2733 Fetches the upper limit on the number of user IDs that can 2734 be allocated or used within a specific network subnet. 2735 2736 Args: 2737 netuid: The network UID for which to query the maximum allowed UIDs. 2738 2739 Returns: 2740 The maximum number of allowed UIDs for the specified network subnet. 2741 2742 Raises: 2743 QueryError: If the query to the network fails or is invalid. 2744 """ 2745 2746 return self.query("MaxAllowedUids", params=[netuid])
Queries the network for the maximum allowed UIDs setting.
Fetches the upper limit on the number of user IDs that can be allocated or used within a specific network subnet.
Arguments:
- netuid: The network UID for which to query the maximum allowed UIDs.
Returns:
The maximum number of allowed UIDs for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2748 def get_name(self, netuid: int = 0) -> str: 2749 """ 2750 Queries the network for the name of a specific subnet. 2751 2752 Args: 2753 netuid: The network UID for which to query the name. 2754 2755 Returns: 2756 The name of the specified network subnet. 2757 2758 Raises: 2759 QueryError: If the query to the network fails or is invalid. 2760 """ 2761 2762 return self.query("Name", params=[netuid])
Queries the network for the name of a specific subnet.
Arguments:
- netuid: The network UID for which to query the name.
Returns:
The name of the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2764 def get_subnet_name(self, netuid: int = 0) -> str: 2765 """ 2766 Queries the network for the name of a specific subnet. 2767 2768 Args: 2769 netuid: The network UID for which to query the name. 2770 2771 Returns: 2772 The name of the specified network subnet. 2773 2774 Raises: 2775 QueryError: If the query to the network fails or is invalid. 2776 """ 2777 2778 return self.query("SubnetNames", params=[netuid])
Queries the network for the name of a specific subnet.
Arguments:
- netuid: The network UID for which to query the name.
Returns:
The name of the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2783 def get_n(self, netuid: int = 0) -> int: 2784 """ 2785 Queries the network for the 'N' hyperparameter, which represents how 2786 many modules are on the network. 2787 2788 Args: 2789 netuid: The network UID for which to query the 'N' hyperparameter. 2790 2791 Returns: 2792 The value of the 'N' hyperparameter for the specified network 2793 subnet. 2794 2795 Raises: 2796 QueryError: If the query to the network fails or is invalid. 2797 """ 2798 2799 return self.query("N", params=[netuid])
Queries the network for the 'N' hyperparameter, which represents how many modules are on the network.
Arguments:
- netuid: The network UID for which to query the 'N' hyperparameter.
Returns:
The value of the 'N' hyperparameter for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2801 def get_tempo(self, netuid: int = 0) -> int: 2802 """ 2803 Queries the network for the tempo setting, measured in blocks, for the 2804 specified subnet. 2805 2806 Args: 2807 netuid: The network UID for which to query the tempo. 2808 2809 Returns: 2810 The tempo setting for the specified subnet. 2811 2812 Raises: 2813 QueryError: If the query to the network fails or is invalid. 2814 """ 2815 2816 return self.query("Tempo", params=[netuid])
Queries the network for the tempo setting, measured in blocks, for the specified subnet.
Arguments:
- netuid: The network UID for which to query the tempo.
Returns:
The tempo setting for the specified subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2818 def get_total_free_issuance(self, block_hash: str | None = None) -> int: 2819 """ 2820 Queries the network for the total free issuance. 2821 2822 Fetches the total amount of free issuance tokens available 2823 2824 Returns: 2825 The total free issuance amount. 2826 2827 Raises: 2828 QueryError: If the query to the network fails or is invalid. 2829 """ 2830 2831 return self.query( 2832 "TotalIssuance", module="Balances", block_hash=block_hash 2833 )
Queries the network for the total free issuance.
Fetches the total amount of free issuance tokens available
Returns:
The total free issuance amount.
Raises:
- QueryError: If the query to the network fails or is invalid.
2835 def get_total_stake(self, block_hash: str | None = None) -> int: 2836 """ 2837 Retrieves a mapping of total stakes for keys on the network. 2838 2839 Queries the network for a mapping of key UIDs to their total stake amounts. 2840 2841 Returns: 2842 A dictionary mapping key UIDs to their total stake amounts. 2843 2844 Raises: 2845 QueryError: If the query to the network fails or is invalid. 2846 """ 2847 2848 return self.query("TotalStake", block_hash=block_hash)
Retrieves a mapping of total stakes for keys on the network.
Queries the network for a mapping of key UIDs to their total stake amounts.
Returns:
A dictionary mapping key UIDs to their total stake amounts.
Raises:
- QueryError: If the query to the network fails or is invalid.
2850 def get_registrations_per_block(self): 2851 """ 2852 Queries the network for the number of registrations per block. 2853 2854 Fetches the number of registrations that are processed per 2855 block within the network. 2856 2857 Returns: 2858 The number of registrations processed per block. 2859 2860 Raises: 2861 QueryError: If the query to the network fails or is invalid. 2862 """ 2863 2864 return self.query( 2865 "RegistrationsPerBlock", 2866 )
Queries the network for the number of registrations per block.
Fetches the number of registrations that are processed per block within the network.
Returns:
The number of registrations processed per block.
Raises:
- QueryError: If the query to the network fails or is invalid.
2868 def max_registrations_per_block(self, netuid: int = 0): 2869 """ 2870 Queries the network for the maximum number of registrations per block. 2871 2872 Retrieves the upper limit of registrations that can be processed in 2873 each block within a specific network subnet. 2874 2875 Args: 2876 netuid: The network UID for which to query. 2877 2878 Returns: 2879 The maximum number of registrations per block for 2880 the specified network subnet. 2881 2882 Raises: 2883 QueryError: If the query to the network fails or is invalid. 2884 """ 2885 2886 return self.query( 2887 "MaxRegistrationsPerBlock", 2888 params=[netuid], 2889 )
Queries the network for the maximum number of registrations per block.
Retrieves the upper limit of registrations that can be processed in each block within a specific network subnet.
Arguments:
- netuid: The network UID for which to query.
Returns:
The maximum number of registrations per block for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2891 def get_proposal(self, proposal_id: int = 0): 2892 """ 2893 Queries the network for a specific proposal. 2894 2895 Args: 2896 proposal_id: The ID of the proposal to query. 2897 2898 Returns: 2899 The details of the specified proposal. 2900 2901 Raises: 2902 QueryError: If the query to the network fails, is invalid, 2903 or if the proposal ID does not exist. 2904 """ 2905 2906 return self.query( 2907 "Proposals", 2908 params=[proposal_id], 2909 )
Queries the network for a specific proposal.
Arguments:
- proposal_id: The ID of the proposal to query.
Returns:
The details of the specified proposal.
Raises:
- QueryError: If the query to the network fails, is invalid, or if the proposal ID does not exist.
2911 def get_trust(self, netuid: int = 0): 2912 """ 2913 Queries the network for the trust setting of a specific network subnet. 2914 2915 Retrieves the trust level or score, which may represent the 2916 level of trustworthiness or reliability within a 2917 particular network subnet. 2918 2919 Args: 2920 netuid: The network UID for which to query the trust setting. 2921 2922 Returns: 2923 The trust level or score for the specified network subnet. 2924 2925 Raises: 2926 QueryError: If the query to the network fails or is invalid. 2927 """ 2928 2929 return self.query( 2930 "Trust", 2931 params=[netuid], 2932 )
Queries the network for the trust setting of a specific network subnet.
Retrieves the trust level or score, which may represent the level of trustworthiness or reliability within a particular network subnet.
Arguments:
- netuid: The network UID for which to query the trust setting.
Returns:
The trust level or score for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
2934 def get_uids(self, key: Ss58Address, netuid: int = 0) -> bool | None: 2935 """ 2936 Queries the network for module UIDs associated with a specific key. 2937 2938 Args: 2939 key: The key address for which to query UIDs. 2940 netuid: The network UID within which to search for the key. 2941 2942 Returns: 2943 A list of UIDs associated with the specified key. 2944 2945 Raises: 2946 QueryError: If the query to the network fails or is invalid. 2947 """ 2948 2949 return self.query( 2950 "Uids", 2951 params=[netuid, key], 2952 )
Queries the network for module UIDs associated with a specific key.
Arguments:
- key: The key address for which to query UIDs.
- netuid: The network UID within which to search for the key.
Returns:
A list of UIDs associated with the specified key.
Raises:
- QueryError: If the query to the network fails or is invalid.
2954 def get_unit_emission(self) -> int: 2955 """ 2956 Queries the network for the unit emission setting. 2957 2958 Retrieves the unit emission value, which represents the 2959 emission rate or quantity for the $COMM token. 2960 2961 Returns: 2962 The unit emission value in nanos for the network. 2963 2964 Raises: 2965 QueryError: If the query to the network fails or is invalid. 2966 """ 2967 2968 return self.query("UnitEmission", module="SubnetEmissionModule")
Queries the network for the unit emission setting.
Retrieves the unit emission value, which represents the emission rate or quantity for the $COMM token.
Returns:
The unit emission value in nanos for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
2970 def get_tx_rate_limit(self) -> int: 2971 """ 2972 Queries the network for the transaction rate limit. 2973 2974 Retrieves the rate limit for transactions within the network, 2975 which defines the maximum number of transactions that can be 2976 processed within a certain timeframe. 2977 2978 Returns: 2979 The transaction rate limit for the network. 2980 2981 Raises: 2982 QueryError: If the query to the network fails or is invalid. 2983 """ 2984 2985 return self.query( 2986 "TxRateLimit", 2987 )
Queries the network for the transaction rate limit.
Retrieves the rate limit for transactions within the network, which defines the maximum number of transactions that can be processed within a certain timeframe.
Returns:
The transaction rate limit for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
2989 def get_subnet_burn(self) -> int: 2990 """Queries the network for the subnet burn value. 2991 2992 Retrieves the subnet burn value from the network, which represents 2993 the amount of tokens that are burned (permanently removed from 2994 circulation) for subnet-related operations. 2995 2996 Returns: 2997 int: The subnet burn value. 2998 2999 Raises: 3000 QueryError: If the query to the network fails or returns invalid data. 3001 """ 3002 3003 return self.query( 3004 "SubnetBurn", 3005 )
Queries the network for the subnet burn value.
Retrieves the subnet burn value from the network, which represents the amount of tokens that are burned (permanently removed from circulation) for subnet-related operations.
Returns:
int: The subnet burn value.
Raises:
- QueryError: If the query to the network fails or returns invalid data.
3007 def get_burn_rate(self) -> int: 3008 """ 3009 Queries the network for the burn rate setting. 3010 3011 Retrieves the burn rate, which represents the rate at 3012 which the $COMM token is permanently 3013 removed or 'burned' from circulation. 3014 3015 Returns: 3016 The burn rate for the network. 3017 3018 Raises: 3019 QueryError: If the query to the network fails or is invalid. 3020 """ 3021 3022 return self.query( 3023 "BurnRate", 3024 params=[], 3025 )
Queries the network for the burn rate setting.
Retrieves the burn rate, which represents the rate at which the $COMM token is permanently removed or 'burned' from circulation.
Returns:
The burn rate for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3027 def get_burn(self, netuid: int = 0) -> int: 3028 """ 3029 Queries the network for the burn setting. 3030 3031 Retrieves the burn value, which represents the amount of the 3032 $COMM token that is 'burned' or permanently removed from 3033 circulation. 3034 3035 Args: 3036 netuid: The network UID for which to query the burn value. 3037 3038 Returns: 3039 The burn value for the specified network subnet. 3040 3041 Raises: 3042 QueryError: If the query to the network fails or is invalid. 3043 """ 3044 3045 return self.query("Burn", params=[netuid])
Queries the network for the burn setting.
Retrieves the burn value, which represents the amount of the $COMM token that is 'burned' or permanently removed from circulation.
Arguments:
- netuid: The network UID for which to query the burn value.
Returns:
The burn value for the specified network subnet.
Raises:
- QueryError: If the query to the network fails or is invalid.
3047 def get_min_burn(self) -> int: 3048 """ 3049 Queries the network for the minimum burn setting. 3050 3051 Retrieves the minimum burn value, indicating the lowest 3052 amount of the $COMM tokens that can be 'burned' or 3053 permanently removed from circulation. 3054 3055 Returns: 3056 The minimum burn value for the network. 3057 3058 Raises: 3059 QueryError: If the query to the network fails or is invalid. 3060 """ 3061 3062 return self.query( 3063 "BurnConfig", 3064 params=[], 3065 )["min_burn"]
Queries the network for the minimum burn setting.
Retrieves the minimum burn value, indicating the lowest amount of the $COMM tokens that can be 'burned' or permanently removed from circulation.
Returns:
The minimum burn value for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3067 def get_min_weight_stake(self) -> int: 3068 """ 3069 Queries the network for the minimum weight stake setting. 3070 3071 Retrieves the minimum weight stake, which represents the lowest 3072 stake weight that is allowed for certain operations or 3073 transactions within the network. 3074 3075 Returns: 3076 The minimum weight stake for the network. 3077 3078 Raises: 3079 QueryError: If the query to the network fails or is invalid. 3080 """ 3081 3082 return self.query("MinWeightStake", params=[])
Queries the network for the minimum weight stake setting.
Retrieves the minimum weight stake, which represents the lowest stake weight that is allowed for certain operations or transactions within the network.
Returns:
The minimum weight stake for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3084 def get_vote_mode_global(self) -> str: 3085 """ 3086 Queries the network for the global vote mode setting. 3087 3088 Retrieves the global vote mode, which defines the overall voting 3089 methodology or approach used across the network in default. 3090 3091 Returns: 3092 The global vote mode setting for the network. 3093 3094 Raises: 3095 QueryError: If the query to the network fails or is invalid. 3096 """ 3097 3098 return self.query( 3099 "VoteModeGlobal", 3100 )
Queries the network for the global vote mode setting.
Retrieves the global vote mode, which defines the overall voting methodology or approach used across the network in default.
Returns:
The global vote mode setting for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3102 def get_max_proposals(self) -> int: 3103 """ 3104 Queries the network for the maximum number of proposals allowed. 3105 3106 Retrieves the upper limit on the number of proposals that can be 3107 active or considered at any given time within the network. 3108 3109 Returns: 3110 The maximum number of proposals allowed on the network. 3111 3112 Raises: 3113 QueryError: If the query to the network fails or is invalid. 3114 """ 3115 3116 return self.query( 3117 "MaxProposals", 3118 )
Queries the network for the maximum number of proposals allowed.
Retrieves the upper limit on the number of proposals that can be active or considered at any given time within the network.
Returns:
The maximum number of proposals allowed on the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3120 def get_max_registrations_per_block(self) -> int: 3121 """ 3122 Queries the network for the maximum number of registrations per block. 3123 3124 Retrieves the maximum number of registrations that can 3125 be processed in each block within the network. 3126 3127 Returns: 3128 The maximum number of registrations per block on the network. 3129 3130 Raises: 3131 QueryError: If the query to the network fails or is invalid. 3132 """ 3133 3134 return self.query( 3135 "MaxRegistrationsPerBlock", 3136 params=[], 3137 )
Queries the network for the maximum number of registrations per block.
Retrieves the maximum number of registrations that can be processed in each block within the network.
Returns:
The maximum number of registrations per block on the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3139 def get_max_name_length(self) -> int: 3140 """ 3141 Queries the network for the maximum length allowed for names. 3142 3143 Retrieves the maximum character length permitted for names 3144 within the network. Such as the module names 3145 3146 Returns: 3147 The maximum length allowed for names on the network. 3148 3149 Raises: 3150 QueryError: If the query to the network fails or is invalid. 3151 """ 3152 3153 return self.query( 3154 "MaxNameLength", 3155 params=[], 3156 )
Queries the network for the maximum length allowed for names.
Retrieves the maximum character length permitted for names within the network. Such as the module names
Returns:
The maximum length allowed for names on the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3158 def get_global_vote_threshold(self) -> int: 3159 """ 3160 Queries the network for the global vote threshold. 3161 3162 Retrieves the global vote threshold, which is the critical value or 3163 percentage required for decisions in the network's governance process. 3164 3165 Returns: 3166 The global vote threshold for the network. 3167 3168 Raises: 3169 QueryError: If the query to the network fails or is invalid. 3170 """ 3171 3172 return self.query( 3173 "GlobalVoteThreshold", 3174 )
Queries the network for the global vote threshold.
Retrieves the global vote threshold, which is the critical value or percentage required for decisions in the network's governance process.
Returns:
The global vote threshold for the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3176 def get_max_allowed_subnets(self) -> int: 3177 """ 3178 Queries the network for the maximum number of allowed subnets. 3179 3180 Retrieves the upper limit on the number of subnets that can 3181 be created or operated within the network. 3182 3183 Returns: 3184 The maximum number of allowed subnets on the network. 3185 3186 Raises: 3187 QueryError: If the query to the network fails or is invalid. 3188 """ 3189 3190 return self.query( 3191 "MaxAllowedSubnets", 3192 params=[], 3193 )
Queries the network for the maximum number of allowed subnets.
Retrieves the upper limit on the number of subnets that can be created or operated within the network.
Returns:
The maximum number of allowed subnets on the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3195 def get_max_allowed_modules(self) -> int: 3196 """ 3197 Queries the network for the maximum number of allowed modules. 3198 3199 Retrieves the upper limit on the number of modules that 3200 can be registered within the network. 3201 3202 Returns: 3203 The maximum number of allowed modules on the network. 3204 3205 Raises: 3206 QueryError: If the query to the network fails or is invalid. 3207 """ 3208 3209 return self.query( 3210 "MaxAllowedModules", 3211 params=[], 3212 )
Queries the network for the maximum number of allowed modules.
Retrieves the upper limit on the number of modules that can be registered within the network.
Returns:
The maximum number of allowed modules on the network.
Raises:
- QueryError: If the query to the network fails or is invalid.
3214 def get_min_stake(self, netuid: int = 0) -> int: 3215 """ 3216 Queries the network for the minimum stake required to register a key. 3217 3218 Retrieves the minimum amount of stake necessary for 3219 registering a key within a specific network subnet. 3220 3221 Args: 3222 netuid: The network UID for which to query the minimum stake. 3223 3224 Returns: 3225 The minimum stake required for key registration in nanos. 3226 3227 Raises: 3228 QueryError: If the query to the network fails or is invalid. 3229 """ 3230 3231 return self.query("MinStake", params=[netuid])
Queries the network for the minimum stake required to register a key.
Retrieves the minimum amount of stake necessary for registering a key within a specific network subnet.
Arguments:
- netuid: The network UID for which to query the minimum stake.
Returns:
The minimum stake required for key registration in nanos.
Raises:
- QueryError: If the query to the network fails or is invalid.
3233 def get_stakefrom( 3234 self, 3235 key: Ss58Address, 3236 ) -> dict[str, int]: 3237 """ 3238 Retrieves the stake amounts from all stakers to a specific staked address. 3239 3240 Queries the network for the stakes received by a particular staked address 3241 from all stakers. 3242 3243 Args: 3244 key: The address of the key receiving the stakes. 3245 3246 Returns: 3247 A dictionary mapping staker addresses to their respective stake amounts. 3248 3249 Raises: 3250 QueryError: If the query to the network fails or is invalid. 3251 """ 3252 3253 # Has to use query map in order to iterate through the storage prefix. 3254 return self.query_map("StakeFrom", [key], extract_value=False).get( 3255 "StakeFrom", {} 3256 )
Retrieves the stake amounts from all stakers to a specific staked address.
Queries the network for the stakes received by a particular staked address from all stakers.
Arguments:
- key: The address of the key receiving the stakes.
Returns:
A dictionary mapping staker addresses to their respective stake amounts.
Raises:
- QueryError: If the query to the network fails or is invalid.
3258 def get_staketo( 3259 self, 3260 key: Ss58Address, 3261 ) -> dict[str, int]: 3262 """ 3263 Retrieves the stake amounts provided by a specific staker to all staked addresses. 3264 3265 Queries the network for the stakes provided by a particular staker to 3266 all staked addresses. 3267 3268 Args: 3269 key: The address of the key providing the stakes. 3270 3271 Returns: 3272 A dictionary mapping staked addresses to their respective received stake amounts. 3273 3274 Raises: 3275 QueryError: If the query to the network fails or is invalid. 3276 """ 3277 3278 # Has to use query map in order to iterate through the storage prefix. 3279 return self.query_map("StakeTo", [key], extract_value=False).get( 3280 "StakeTo", {} 3281 )
Retrieves the stake amounts provided by a specific staker to all staked addresses.
Queries the network for the stakes provided by a particular staker to all staked addresses.
Arguments:
- key: The address of the key providing the stakes.
Returns:
A dictionary mapping staked addresses to their respective received stake amounts.
Raises:
- QueryError: If the query to the network fails or is invalid.
3283 def get_balance( 3284 self, 3285 addr: Ss58Address, 3286 ) -> int: 3287 """ 3288 Retrieves the balance of a specific key. 3289 3290 Args: 3291 addr: The address of the key to query the balance for. 3292 3293 Returns: 3294 The balance of the specified key. 3295 3296 Raises: 3297 QueryError: If the query to the network fails or is invalid. 3298 """ 3299 3300 result = self.query("Account", module="System", params=[addr]) 3301 3302 return result["data"]["free"]
Retrieves the balance of a specific key.
Arguments:
- addr: The address of the key to query the balance for.
Returns:
The balance of the specified key.
Raises:
- QueryError: If the query to the network fails or is invalid.
3304 def get_block(self, block_hash: str | None = None) -> dict[Any, Any] | None: 3305 """ 3306 Retrieves information about a specific block in the network. 3307 3308 Queries the network for details about a block, such as its number, 3309 hash, and other relevant information. 3310 3311 Returns: 3312 The requested information about the block, 3313 or None if the block does not exist 3314 or the information is not available. 3315 3316 Raises: 3317 QueryError: If the query to the network fails or is invalid. 3318 """ 3319 3320 with self.get_conn() as substrate: 3321 block: dict[Any, Any] | None = substrate.get_block( # type: ignore 3322 block_hash # type: ignore 3323 ) 3324 3325 return block
Retrieves information about a specific block in the network.
Queries the network for details about a block, such as its number, hash, and other relevant information.
Returns:
The requested information about the block, or None if the block does not exist or the information is not available.
Raises:
- QueryError: If the query to the network fails or is invalid.
3327 def get_existential_deposit(self, block_hash: str | None = None) -> int: 3328 """ 3329 Retrieves the existential deposit value for the network. 3330 3331 The existential deposit is the minimum balance that must be maintained 3332 in an account to prevent it from being purged. Denotated in nano units. 3333 3334 Returns: 3335 The existential deposit value in nano units. 3336 Note: 3337 The value returned is a fixed value defined in the 3338 client and may not reflect changes in the network's configuration. 3339 """ 3340 3341 with self.get_conn() as substrate: 3342 result: int = substrate.get_constant( # type: ignore 3343 "Balances", "ExistentialDeposit", block_hash 3344 ).value # type: ignore 3345 3346 return result
Retrieves the existential deposit value for the network.
The existential deposit is the minimum balance that must be maintained in an account to prevent it from being purged. Denotated in nano units.
Returns:
The existential deposit value in nano units.
Note:
The value returned is a fixed value defined in the client and may not reflect changes in the network's configuration.
3354 def add_transfer_dao_treasury_proposal( 3355 self, 3356 key: Keypair, 3357 data: str, 3358 amount_nano: int, 3359 dest: Ss58Address, 3360 ): 3361 params = {"dest": dest, "value": amount_nano, "data": data} 3362 3363 return self.compose_call( 3364 module="GovernanceModule", 3365 fn="add_transfer_dao_treasury_proposal", 3366 params=params, 3367 key=key, 3368 )