From 3055e8464eccb0f08959e102d7406e4129add381 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 15 Dec 2025 02:03:50 +0100 Subject: [PATCH 1/3] Enabled wallet history using scantensor api --- bittensor_cli/cli.py | 3 - bittensor_cli/src/commands/wallets.py | 114 ++++++++++++++------------ 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 574882709..d6c8ffaba 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -3699,9 +3699,6 @@ def wallet_history( # console.print(no_use_config_str) # For Rao games - print_error("This command is disabled on the 'rao' network.") - raise typer.Exit() - self.verbosity_handler(quiet, verbose, False, False) wallet = self.wallet_ask( wallet_name, diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 8813e6839..2ef2b0ae6 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -726,51 +726,64 @@ async def wallet_balance( async def get_wallet_transfers(wallet_address: str) -> list[dict]: - """Get all transfers associated with the provided wallet address.""" - - api_url = "https://api.subquery.network/sq/TaoStats/bittensor-indexer" - max_txn = 1000 - graphql_query = """ - query ($first: Int!, $after: Cursor, $filter: TransferFilter, $order: [TransfersOrderBy!]!) { - transfers(first: $first, after: $after, filter: $filter, orderBy: $order) { - nodes { - id - from - to - amount - extrinsicId - blockNumber - } - pageInfo { - endCursor - hasNextPage - hasPreviousPage - } - totalCount - } - } """ - variables = { - "first": max_txn, - "filter": { - "or": [ - {"from": {"equalTo": wallet_address}}, - {"to": {"equalTo": wallet_address}}, - ] - }, - "order": "BLOCK_NUMBER_DESC", - } - async with aiohttp.ClientSession() as session: - response = await session.post( - api_url, json={"query": graphql_query, "variables": variables} - ) - data = await response.json() - - # Extract nodes and pageInfo from the response - transfer_data = data.get("data", {}).get("transfers", {}) - transfers = transfer_data.get("nodes", []) - - return transfers + Get all transfers associated with the provided wallet address. + + Args: + wallet_address: The SS58 address of the wallet to fetch transfers for. + + Returns: + A list of transfer dictionaries containing transaction details. + + Raises: + ValueError: If the API response is invalid or the request fails. + """ + api_url = f"https://mainnet.scantensor.opentensor.ai/account/{wallet_address}/transactions" + timeout = aiohttp.ClientTimeout(total=30) + + try: + async with aiohttp.ClientSession(timeout=timeout) as session: + async with session.get(api_url) as response: + # Check if the request was successful + if response.status != 200: + error_msg = ( + f"Failed to fetch wallet transfers. " + f"API returned status {response.status}" + ) + print_error(error_msg) + raise ValueError(error_msg) + + # Parse JSON response + try: + data = await response.json() + except aiohttp.ContentTypeError as e: + error_msg = "Invalid response format from API" + print_error(f"{error_msg}: {str(e)}") + raise ValueError(error_msg) from e + + # Validate that data is a list + if not isinstance(data, list): + error_msg = ( + f"Expected list of transfers, but got {type(data).__name__}. " + f"Returning empty list." + ) + print_error(error_msg) + return [] + + return data + + except aiohttp.ClientError as e: + error_msg = f"Network error while fetching wallet transfers: {str(e)}" + print_error(error_msg) + raise ValueError(error_msg) from e + except asyncio.TimeoutError: + error_msg = "Request timed out while fetching wallet transfers" + print_error(error_msg) + raise ValueError(error_msg) + except Exception as e: + error_msg = f"Unexpected error while fetching wallet transfers: {str(e)}" + print_error(error_msg) + raise ValueError(error_msg) from e def create_transfer_history_table(transfers: list[dict]) -> Table: @@ -826,19 +839,19 @@ def create_transfer_history_table(transfers: list[dict]) -> Table: ratio=2, ) - for item in transfers: + for id, item in enumerate(transfers): try: tao_amount = int(item["amount"]) / RAO_PER_TAO except ValueError: tao_amount = item["amount"] table.add_row( - item["id"], + str(id + 1), item["from"], item["to"], f"{tao_amount:.3f}", - str(item["extrinsicId"]), - item["blockNumber"], - f"{taostats_url_base}/{item['blockNumber']}-{item['extrinsicId']:04}", + str(item.get("event_index", "")), + str(item["block_number"]), + f"{taostats_url_base}/{item['block_number']}-{item.get('event_index', 0):04}", ) table.add_row() return table @@ -846,13 +859,12 @@ def create_transfer_history_table(transfers: list[dict]) -> Table: async def wallet_history(wallet: Wallet): """Check the transfer history of the provided wallet.""" - print_verbose(f"Fetching history for wallet: {wallet.name}") + print_verbose(f"Wallet name: {wallet.name}") wallet_address = wallet.get_coldkeypub().ss58_address transfers = await get_wallet_transfers(wallet_address) table = create_transfer_history_table(transfers) console.print(table) - async def wallet_list( wallet_path: str, json_output: bool, wallet_name: Optional[str] = None ): From ab98b4796a36ceef9f7af14324f818688aa8c5b2 Mon Sep 17 00:00:00 2001 From: 0xsid0703 Date: Mon, 15 Dec 2025 02:07:09 +0100 Subject: [PATCH 2/3] Removed useless log --- bittensor_cli/src/commands/wallets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 2ef2b0ae6..bd5f7dd36 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -859,7 +859,7 @@ def create_transfer_history_table(transfers: list[dict]) -> Table: async def wallet_history(wallet: Wallet): """Check the transfer history of the provided wallet.""" - print_verbose(f"Wallet name: {wallet.name}") + print_verbose(f"Fetching history for wallet: {wallet.name}") wallet_address = wallet.get_coldkeypub().ss58_address transfers = await get_wallet_transfers(wallet_address) table = create_transfer_history_table(transfers) From b5a352acff055b3f88ee116bd068110e0dc01222 Mon Sep 17 00:00:00 2001 From: BD Himes <37844818+thewhaleking@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:02:33 +0200 Subject: [PATCH 3/3] Ruff --- bittensor_cli/src/commands/wallets.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index bd5f7dd36..26ee297b5 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -728,19 +728,19 @@ async def wallet_balance( async def get_wallet_transfers(wallet_address: str) -> list[dict]: """ Get all transfers associated with the provided wallet address. - + Args: wallet_address: The SS58 address of the wallet to fetch transfers for. - + Returns: A list of transfer dictionaries containing transaction details. - + Raises: ValueError: If the API response is invalid or the request fails. """ api_url = f"https://mainnet.scantensor.opentensor.ai/account/{wallet_address}/transactions" timeout = aiohttp.ClientTimeout(total=30) - + try: async with aiohttp.ClientSession(timeout=timeout) as session: async with session.get(api_url) as response: @@ -752,7 +752,7 @@ async def get_wallet_transfers(wallet_address: str) -> list[dict]: ) print_error(error_msg) raise ValueError(error_msg) - + # Parse JSON response try: data = await response.json() @@ -760,7 +760,7 @@ async def get_wallet_transfers(wallet_address: str) -> list[dict]: error_msg = "Invalid response format from API" print_error(f"{error_msg}: {str(e)}") raise ValueError(error_msg) from e - + # Validate that data is a list if not isinstance(data, list): error_msg = ( @@ -769,9 +769,9 @@ async def get_wallet_transfers(wallet_address: str) -> list[dict]: ) print_error(error_msg) return [] - + return data - + except aiohttp.ClientError as e: error_msg = f"Network error while fetching wallet transfers: {str(e)}" print_error(error_msg) @@ -865,6 +865,7 @@ async def wallet_history(wallet: Wallet): table = create_transfer_history_table(transfers) console.print(table) + async def wallet_list( wallet_path: str, json_output: bool, wallet_name: Optional[str] = None ):