From bc06edc6359916f952a52ec8a7457b0afba2544e Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 29 Jul 2023 10:32:09 +0300 Subject: [PATCH 1/7] Return back jobs endpoint. --- moonstreamapi/moonstreamapi/actions.py | 32 +++++++++++ .../moonstreamapi/routes/subscriptions.py | 54 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index a4360e94..086c7b66 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -791,6 +791,38 @@ def query_parameter_hash(params: Dict[str, Any]) -> str: return hash +def parse_abi_to_name_tags(user_abi: List[Dict[str, Any]]): + return [ + f"abi_name:{method['name']}" + for method in user_abi + if method["type"] in ("event", "function") + ] + + +def filter_tasks(entries, tag_filters): + return [entry for entry in entries if any(tag in tag_filters for tag in entry.tags)] + + +def fetch_and_filter_tasks( + journal_id, address, subscription_type_id, token, user_abi, limit=100 +) -> List[BugoutSearchResult]: + """ + Fetch tasks from journal and filter them by user abi + """ + entries = get_all_entries_from_search( + journal_id=journal_id, + search_query=f"tag:address:{address} tag:subscription_type:{subscription_type_id}", + limit=limit, + token=token, + ) + + user_loaded_abi_tags = parse_abi_to_name_tags(json.loads(user_abi)) + + moonworm_tasks = filter_tasks(entries, user_loaded_abi_tags) + + return moonworm_tasks + + def get_list_of_support_interfaces( blockchain_type: AvailableBlockchainType, address: str, diff --git a/moonstreamapi/moonstreamapi/routes/subscriptions.py b/moonstreamapi/moonstreamapi/routes/subscriptions.py index 257c387e..7d513e3d 100644 --- a/moonstreamapi/moonstreamapi/routes/subscriptions.py +++ b/moonstreamapi/moonstreamapi/routes/subscriptions.py @@ -21,6 +21,7 @@ from ..actions import ( EntityCollectionNotFoundException, check_if_smart_contract, get_list_of_support_interfaces, + get_moonworm_tasks, ) from ..admin import subscription_types from .. import data @@ -600,6 +601,59 @@ async def list_subscription_types() -> data.SubscriptionTypesListResponse: return data.SubscriptionTypesListResponse(subscription_types=results) +@router.get( + "/{subscription_id}/jobs", + tags=["subscriptions"], + response_model=List[BugoutSearchResult], +) +async def get_subscription_jobs_handler( + request: Request, + subscription_id: str, +) -> Any: + token = request.state.token + user = request.state.user + + try: + collection_id = get_entity_subscription_collection_id( + resource_type=BUGOUT_RESOURCE_TYPE_ENTITY_SUBSCRIPTION, + token=MOONSTREAM_ADMIN_ACCESS_TOKEN, + user_id=user.id, + ) + + # get subscription entity + subscription_resource = ec.get_entity( + token=token, + collection_id=collection_id, + entity_id=subscription_id, + ) + + except EntityCollectionNotFoundException as e: + raise MoonstreamHTTPException( + status_code=404, + detail="User subscriptions collection not found", + internal_error=e, + ) + except Exception as e: + logger.error( + f"Error get subscriptions for user ({user}) with token ({token}), error: {str(e)}" + ) + raise MoonstreamHTTPException(status_code=500, internal_error=e) + + for field in subscription_resource.required_fields: + if "subscription_type_id" in field: + subscription_type_id = field["subscription_type_id"] + + subscription_address = subscription_resource.address + + get_moonworm_jobs_response = get_moonworm_tasks( + subscription_type_id=subscription_type_id, + address=subscription_address, + user_abi=subscription_resource.secondary_fields.get("abi") or [], + ) + + return get_moonworm_jobs_response + + @router.get( "/is_contract", tags=["subscriptions"], From 9d9fef00595ae1bcafe943d6d0eeef480f808e8b Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 29 Jul 2023 10:40:02 +0300 Subject: [PATCH 2/7] Add changes. --- moonstreamapi/moonstreamapi/actions.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index 086c7b66..536945fb 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -915,14 +915,14 @@ def get_list_of_support_interfaces( if interface["name"] in general_interfaces } - for selector_name in basic_selectors: + for interface_name, selector in basic_selectors.items(): selector_result = contract.get_function_by_name("supportsInterface").call( - bytes.fromhex(selectors[selector_name]) + bytes.fromhex(selector) ) if selector_result: - result[selector_name] = { - "selector": basic_selectors[selector_name], - "abi": selectors[selectors[selector_name]]["abi"], + result[interface_name] = { + "selector": basic_selectors[interface_name], + "abi": selectors[selectors[interface_name]]["abi"], } return result From d9f82b7e28921fa5c6a3abdac02454cc87b72527 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 18 Aug 2023 19:53:42 +0300 Subject: [PATCH 3/7] add changes --- moonstreamapi/moonstreamapi/actions.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index 536945fb..f683eb65 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -823,6 +823,30 @@ def fetch_and_filter_tasks( return moonworm_tasks +def get_moonworm_tasks( + subscription_type_id: str, + address: str, + user_abi: List[Dict[str, Any]], +) -> List[BugoutSearchResult]: + """ + Get moonworm tasks from journal and filter them by user abi + """ + + try: + moonworm_tasks = fetch_and_filter_tasks( + journal_id=MOONSTREAM_MOONWORM_TASKS_JOURNAL, + address=address, + subscription_type_id=subscription_type_id, + token=MOONSTREAM_ADMIN_ACCESS_TOKEN, + user_abi=user_abi, + ) + except Exception as e: + logger.error(f"Error get moonworm tasks: {str(e)}") + MoonstreamHTTPException(status_code=500, internal_error=e) + + return moonworm_tasks + + def get_list_of_support_interfaces( blockchain_type: AvailableBlockchainType, address: str, From 28c660c979b59f04f5c8965927fbde4f3125e5bd Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 19 Aug 2023 02:55:45 +0300 Subject: [PATCH 4/7] Add changes. --- moonstreamapi/moonstreamapi/actions.py | 148 +++++++++++++------------ 1 file changed, 78 insertions(+), 70 deletions(-) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index d0e72d31..5913af4b 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -6,6 +6,7 @@ from collections import OrderedDict from enum import Enum from itertools import chain from typing import Any, Dict, List, Optional, Union +import traceback import boto3 # type: ignore from bugout.data import ( @@ -486,7 +487,7 @@ def get_all_entries_from_search( limit=limit, offset=offset, ) - results.extend(existing_methods.results) # type: ignore + results.extend(existing_methods.results) # type: ignore if len(results) != existing_methods.total_results: for offset in range(limit, existing_methods.total_results, limit): @@ -499,7 +500,7 @@ def get_all_entries_from_search( limit=limit, offset=offset, ) - results.extend(existing_methods.results) # type: ignore + results.extend(existing_methods.results) # type: ignore return results @@ -849,97 +850,104 @@ def get_list_of_support_interfaces( Returns list of interfaces supported by given address """ - _, _, is_contract = check_if_smart_contract( - blockchain_type=blockchain_type, address=address, user_token=user_token - ) + try: + web3_client = connect(blockchain_type, user_token=user_token) - if not is_contract: - raise AddressNotSmartContractException(f"Address not are smart contract") - - web3_client = connect(blockchain_type, user_token=user_token) - - contract = web3_client.eth.contract( - address=Web3.toChecksumAddress(address), - abi=supportsInterface_abi, - ) - - calls = [] - - list_of_interfaces = list(selectors.keys()) - - list_of_interfaces.sort() - - for interaface in list_of_interfaces: - calls.append( - ( - contract.address, - FunctionSignature(contract.get_function_by_name("supportsInterface")) - .encode_data([bytes.fromhex(interaface)]) - .hex(), - ) + contract = web3_client.eth.contract( + address=Web3.toChecksumAddress(address), + abi=supportsInterface_abi, ) - result = {} - - if blockchain_type in multicall_contracts: calls = [] list_of_interfaces = list(selectors.keys()) list_of_interfaces.sort() - for interface in list_of_interfaces: + for interaface in list_of_interfaces: calls.append( ( contract.address, FunctionSignature( contract.get_function_by_name("supportsInterface") ) - .encode_data([bytes.fromhex(interface)]) + .encode_data([bytes.fromhex(interaface)]) .hex(), ) ) - try: - multicall_result = multicall( - web3_client=web3_client, - blockchain_type=blockchain_type, - calls=calls, - method=multicall_method, - ) - except Exception as e: - logger.error(f"Error while getting list of support interfaces: {e}") + result = {} - for i, selector in enumerate(list_of_interfaces): - if multicall_result[i][0]: - supported = FunctionSignature( - contract.get_function_by_name("supportsInterface") - ).decode_data(multicall_result[i][1]) + if blockchain_type in multicall_contracts: + calls = [] - if supported[0]: - result[selectors[selector]["name"]] = { # type: ignore - "selector": selector, - "abi": selectors[selector]["abi"], # type: ignore + list_of_interfaces = list(selectors.keys()) + + list_of_interfaces.sort() + + for interface in list_of_interfaces: + calls.append( + ( + contract.address, + FunctionSignature( + contract.get_function_by_name("supportsInterface") + ) + .encode_data([bytes.fromhex(interface)]) + .hex(), + ) + ) + + try: + multicall_result = multicall( + web3_client=web3_client, + blockchain_type=blockchain_type, + calls=calls, + method=multicall_method, + ) + except Exception as e: + logger.error(f"Error while getting list of support interfaces: {e}") + + for i, selector in enumerate(list_of_interfaces): + if multicall_result[i][0]: + supported = FunctionSignature( + contract.get_function_by_name("supportsInterface") + ).decode_data(multicall_result[i][1]) + + if supported[0]: + result[selectors[selector]["name"]] = { # type: ignore + "selector": selector, + "abi": selectors[selector]["abi"], # type: ignore + } + + else: + general_interfaces = ["IERC165", "IERC721", "IERC1155", "IERC20"] + + basic_selectors = { + interface["name"]: selector + for selector, interface in selectors.items() + if interface["name"] in general_interfaces + } + + for interface_name, selector in basic_selectors.items(): + selector_result = contract.get_function_by_name( + "supportsInterface" + ).call(bytes.fromhex(selector)) + if selector_result: + result[interface_name] = { + "selector": basic_selectors[interface_name], + "abi": selectors[selectors[interface_name]]["abi"], } + except Exception as err: + traceback.print_exc() + logger.error(f"Error while getting list of support interfaces: {err}") + _, _, is_contract = check_if_smart_contract( + blockchain_type=blockchain_type, address=address, user_token=user_token + ) - else: - general_interfaces = ["IERC165", "IERC721", "IERC1155", "IERC20"] - - basic_selectors = { - interface["name"]: selector - for selector, interface in selectors.items() - if interface["name"] in general_interfaces - } - - for interface_name, selector in basic_selectors.items(): - selector_result = contract.get_function_by_name("supportsInterface").call( - bytes.fromhex(selector) - ) - if selector_result: - result[interface_name] = { - "selector": basic_selectors[interface_name], - "abi": selectors[selectors[interface_name]]["abi"], - } + if not is_contract: + raise AddressNotSmartContractException(f"Address not are smart contract") + else: + raise err return result From cc47bc761b63eb337c58bd90feeecfc0a3158f8a Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 22 Aug 2023 01:33:53 +0300 Subject: [PATCH 5/7] Fix single calls logic. --- moonstreamapi/moonstreamapi/actions.py | 44 +++++++++----------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index 5913af4b..8f9b0061 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -853,28 +853,21 @@ def get_list_of_support_interfaces( try: web3_client = connect(blockchain_type, user_token=user_token) + # GET LAST BLOCK + + print("web3_client", web3_client.eth.get_block("latest")) + contract = web3_client.eth.contract( address=Web3.toChecksumAddress(address), abi=supportsInterface_abi, ) - calls = [] + _, _, is_contract = check_if_smart_contract( + blockchain_type=blockchain_type, address=address, user_token=user_token + ) - list_of_interfaces = list(selectors.keys()) - - list_of_interfaces.sort() - - for interaface in list_of_interfaces: - calls.append( - ( - contract.address, - FunctionSignature( - contract.get_function_by_name("supportsInterface") - ) - .encode_data([bytes.fromhex(interaface)]) - .hex(), - ) - ) + if not is_contract: + raise AddressNotSmartContractException(f"Address not are smart contract") result = {} @@ -929,25 +922,18 @@ def get_list_of_support_interfaces( } for interface_name, selector in basic_selectors.items(): - selector_result = contract.get_function_by_name( - "supportsInterface" - ).call(bytes.fromhex(selector)) + selector_result = contract.functions.supportsInterface( + bytes.fromhex(selector) + ).call() # returns bool + if selector_result: result[interface_name] = { "selector": basic_selectors[interface_name], - "abi": selectors[selectors[interface_name]]["abi"], + "abi": selectors[basic_selectors[interface_name]]["abi"], } except Exception as err: - traceback.print_exc() logger.error(f"Error while getting list of support interfaces: {err}") - _, _, is_contract = check_if_smart_contract( - blockchain_type=blockchain_type, address=address, user_token=user_token - ) - - if not is_contract: - raise AddressNotSmartContractException(f"Address not are smart contract") - else: - raise err + MoonstreamHTTPException(status_code=500, internal_error=err) return result From 6b9fd67d6b4640e762f57df2367df28ec4530655 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 22 Aug 2023 03:17:19 +0300 Subject: [PATCH 6/7] remove traceback. --- moonstreamapi/moonstreamapi/actions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index 8f9b0061..31eb4c6c 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -6,7 +6,6 @@ from collections import OrderedDict from enum import Enum from itertools import chain from typing import Any, Dict, List, Optional, Union -import traceback import boto3 # type: ignore from bugout.data import ( From 1ddf96b258618e76863167cf55396b486e0c5a09 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 30 Aug 2023 05:17:30 +0300 Subject: [PATCH 7/7] Add changes. --- moonstreamapi/moonstreamapi/actions.py | 18 +++++++----------- .../moonstreamapi/routes/subscriptions.py | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/moonstreamapi/moonstreamapi/actions.py b/moonstreamapi/moonstreamapi/actions.py index 31eb4c6c..13d4d0e6 100644 --- a/moonstreamapi/moonstreamapi/actions.py +++ b/moonstreamapi/moonstreamapi/actions.py @@ -850,17 +850,6 @@ def get_list_of_support_interfaces( """ try: - web3_client = connect(blockchain_type, user_token=user_token) - - # GET LAST BLOCK - - print("web3_client", web3_client.eth.get_block("latest")) - - contract = web3_client.eth.contract( - address=Web3.toChecksumAddress(address), - abi=supportsInterface_abi, - ) - _, _, is_contract = check_if_smart_contract( blockchain_type=blockchain_type, address=address, user_token=user_token ) @@ -868,6 +857,13 @@ def get_list_of_support_interfaces( if not is_contract: raise AddressNotSmartContractException(f"Address not are smart contract") + web3_client = connect(blockchain_type, user_token=user_token) + + contract = web3_client.eth.contract( + address=Web3.toChecksumAddress(address), + abi=supportsInterface_abi, + ) + result = {} if blockchain_type in multicall_contracts: diff --git a/moonstreamapi/moonstreamapi/routes/subscriptions.py b/moonstreamapi/moonstreamapi/routes/subscriptions.py index a1874b64..af4977af 100644 --- a/moonstreamapi/moonstreamapi/routes/subscriptions.py +++ b/moonstreamapi/moonstreamapi/routes/subscriptions.py @@ -650,7 +650,7 @@ async def list_subscription_types() -> data.SubscriptionTypesListResponse: ) async def get_subscription_jobs_handler( request: Request, - subscription_id: str, + subscription_id: str = Path(...), ) -> Any: token = request.state.token user = request.state.user