diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fc0af80d..3e219beb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. ## [Unreleased] ### Added +- chore: add `scripts/src_vs_proto` and contents to pull fields from the proto and compare them to the setters and attributes we provide functionality in our token transactions, thus enabling more automatic issue management" ### Changed diff --git a/scripts/src_vs_proto/src_vs_proto/steps_4_token_classes_proto_attributes.py b/scripts/src_vs_proto/src_vs_proto/steps_4_token_classes_proto_attributes.py new file mode 100644 index 000000000..e7536f5ce --- /dev/null +++ b/scripts/src_vs_proto/src_vs_proto/steps_4_token_classes_proto_attributes.py @@ -0,0 +1,2 @@ +# Auto-generated token classes with proto attributes and setters + diff --git a/scripts/src_vs_proto/src_vs_proto/steps_4_token_classes_proto_errors.log b/scripts/src_vs_proto/src_vs_proto/steps_4_token_classes_proto_errors.log new file mode 100644 index 000000000..416d406e6 --- /dev/null +++ b/scripts/src_vs_proto/src_vs_proto/steps_4_token_classes_proto_errors.log @@ -0,0 +1 @@ +# No errors encountered diff --git a/scripts/src_vs_proto/step_1_transactions_proto_mapping.py b/scripts/src_vs_proto/step_1_transactions_proto_mapping.py new file mode 100644 index 000000000..9ee2a1258 --- /dev/null +++ b/scripts/src_vs_proto/step_1_transactions_proto_mapping.py @@ -0,0 +1,101 @@ +# scripts/generate_transactions_mapping.py +import inspect +from pathlib import Path +import importlib +import ast + +PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent # go up to hedera_sdk_python +TOKENS_DIR = PROJECT_ROOT / "src" / "hiero_sdk_python" / "tokens" +OUTPUT_DIR = PROJECT_ROOT / "scripts" / "src_vs_proto" +OUTPUT_FILE = OUTPUT_DIR / "step_2_transactions_mapping.py" + +def find_proto_import(file_path): + """Parse transaction file to find the protobuf import.""" + with open(file_path, "r") as f: + tree = ast.parse(f.read(), filename=str(file_path)) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom): + if node.module and node.module.startswith("hiero_sdk_python.hapi.services"): + for alias in node.names: + if alias.name.endswith("TransactionBody"): + return node.module, alias.name + return None, None + +transactions_mapping = {} +unmatched_transactions = [] + +# Keep track of modules to import +token_modules_set = set() +proto_modules_set = set() + +token_files = list(TOKENS_DIR.glob("token_*_transaction.py")) + +for token_file in token_files: + module_name = f"hiero_sdk_python.tokens.{token_file.stem}" + token_modules_set.add(token_file.stem) + try: + module = importlib.import_module(module_name) + except Exception as e: + print(f"Failed to import {module_name}: {e}") + continue + + # Find the Transaction class + transaction_class = None + for name, obj in inspect.getmembers(module, inspect.isclass): + if "Transaction" in [base.__name__ for base in obj.__bases__]: + transaction_class = obj + transaction_class_name = obj.__name__ + break + + if not transaction_class: + continue + + # Find proto import + proto_module_name, proto_class_name = find_proto_import(token_file) + proto_cls_str = proto_class_name if proto_class_name else "None" + if proto_module_name: + proto_modules_set.add(proto_module_name) + else: + unmatched_transactions.append(transaction_class_name) + proto_module_name = None + + transactions_mapping[transaction_class_name] = { + "cls": f"{token_file.stem}.{transaction_class_name}", # will become proper import + "proto_cls": proto_cls_str, + "proto_module": proto_module_name + } + +# Write to file +with open(OUTPUT_FILE, "w") as f: + f.write("# Auto-generated transactions mapping\n\n") + + # Write token imports + f.write("from hiero_sdk_python.tokens import (\n") + for module in sorted(token_modules_set): + f.write(f" {module},\n") + f.write(")\n\n") + + # Write proto imports + f.write("from hiero_sdk_python.hapi.services import (\n") + for module in sorted(proto_modules_set): + # Only write the last part of the module for correct import + short_module = module.split('.')[-1] + f.write(f" {short_module},\n") + f.write(")\n\n") + + # Write TRANSACTIONS dictionary + f.write("TRANSACTIONS = {\n") + for k, v in transactions_mapping.items(): + cls_module, cls_name = v['cls'].split(".") + cls_str = f"{cls_module}.{cls_name}" + proto_cls_str = f"{v['proto_module'].split('.')[-1]}.{v['proto_cls']}" if v['proto_module'] else "None" + f.write(f" '{k}': {{'cls': {cls_str}, 'proto_cls': {proto_cls_str}}},\n") + f.write("}\n\n") + + # Summary + f.write("# Summary\n") + f.write(f"TOTAL_TOKENS = {len(token_files)}\n") + f.write(f"PROTO_IDENTIFIED = {len(token_files)-len(unmatched_transactions)}\n") + f.write(f"UNMATCHED_TRANSACTIONS = {unmatched_transactions}\n") + +print(f"Mapping written to {OUTPUT_FILE}") diff --git a/scripts/src_vs_proto/step_2.2_transactions_mapping_manual.py b/scripts/src_vs_proto/step_2.2_transactions_mapping_manual.py new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/src_vs_proto/step_2_transactions_mapping.py b/scripts/src_vs_proto/step_2_transactions_mapping.py new file mode 100644 index 000000000..43549dc01 --- /dev/null +++ b/scripts/src_vs_proto/step_2_transactions_mapping.py @@ -0,0 +1,60 @@ +# Auto-generated transactions mapping + +from hiero_sdk_python.tokens import ( + token_airdrop_transaction, + token_associate_transaction, + token_burn_transaction, + token_create_transaction, + token_delete_transaction, + token_dissociate_transaction, + token_fee_schedule_update_transaction, + token_freeze_transaction, + token_grant_kyc_transaction, + token_mint_transaction, + token_pause_transaction, + token_reject_transaction, + token_revoke_kyc_transaction, + token_unfreeze_transaction, + token_unpause_transaction, + token_update_nfts_transaction, + token_update_transaction, + token_wipe_transaction, +) + +from hiero_sdk_python.hapi.services import ( + schedulable_transaction_body_pb2, + token_burn_pb2, + token_grant_kyc_pb2, + token_mint_pb2, + token_pause_pb2, + token_reject_pb2, + token_revoke_kyc_pb2, + token_update_nfts_pb2, + token_wipe_account_pb2, +) + +TRANSACTIONS = { + 'TokenFeeScheduleUpdateTransaction': {'cls': token_fee_schedule_update_transaction.TokenFeeScheduleUpdateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenFreezeTransaction': {'cls': token_freeze_transaction.TokenFreezeTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenRevokeKycTransaction': {'cls': token_revoke_kyc_transaction.TokenRevokeKycTransaction, 'proto_cls': token_revoke_kyc_pb2.TokenRevokeKycTransactionBody}, + 'AbstractTokenTransferTransaction': {'cls': token_airdrop_transaction.AbstractTokenTransferTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenUpdateNftsTransaction': {'cls': token_update_nfts_transaction.TokenUpdateNftsTransaction, 'proto_cls': token_update_nfts_pb2.TokenUpdateNftsTransactionBody}, + 'TokenAssociateTransaction': {'cls': token_associate_transaction.TokenAssociateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenMintTransaction': {'cls': token_mint_transaction.TokenMintTransaction, 'proto_cls': token_mint_pb2.TokenMintTransactionBody}, + 'TokenCreateTransaction': {'cls': token_create_transaction.TokenCreateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenWipeTransaction': {'cls': token_wipe_transaction.TokenWipeTransaction, 'proto_cls': token_wipe_account_pb2.TokenWipeAccountTransactionBody}, + 'TokenPauseTransaction': {'cls': token_pause_transaction.TokenPauseTransaction, 'proto_cls': token_pause_pb2.TokenPauseTransactionBody}, + 'TokenBurnTransaction': {'cls': token_burn_transaction.TokenBurnTransaction, 'proto_cls': token_burn_pb2.TokenBurnTransactionBody}, + 'TokenUnfreezeTransaction': {'cls': token_unfreeze_transaction.TokenUnfreezeTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenRejectTransaction': {'cls': token_reject_transaction.TokenRejectTransaction, 'proto_cls': token_reject_pb2.TokenRejectTransactionBody}, + 'TokenDissociateTransaction': {'cls': token_dissociate_transaction.TokenDissociateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenDeleteTransaction': {'cls': token_delete_transaction.TokenDeleteTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenUnpauseTransaction': {'cls': token_unpause_transaction.TokenUnpauseTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenUpdateTransaction': {'cls': token_update_transaction.TokenUpdateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenGrantKycTransaction': {'cls': token_grant_kyc_transaction.TokenGrantKycTransaction, 'proto_cls': token_grant_kyc_pb2.TokenGrantKycTransactionBody}, +} + +# Summary +TOTAL_TOKENS = 18 +PROTO_IDENTIFIED = 18 +UNMATCHED_TRANSACTIONS = [] diff --git a/scripts/src_vs_proto/step_3_missing_functionality.py b/scripts/src_vs_proto/step_3_missing_functionality.py new file mode 100644 index 000000000..204267e63 --- /dev/null +++ b/scripts/src_vs_proto/step_3_missing_functionality.py @@ -0,0 +1,82 @@ +# scripts/missing_functionality.py +import inspect +from step_2_transactions_mapping import TRANSACTIONS + +# Helper functions for terminal styling +def bold(text): + return f"\033[1m{text}\033[0m" + +def red(text): + return f"\033[91m{text}\033[0m" + +def green(text): + return f"\033[92m{text}\033[0m" + +def get_transaction_methods(cls): + return set(func for func, _ in inspect.getmembers(cls, predicate=inspect.isfunction)) + +def get_transaction_attributes(cls): + init_sig = inspect.signature(cls.__init__) + return set(init_sig.parameters.keys()) - {'self'} + +def get_proto_fields(proto_cls, transaction_cls_name=None): + """ + Return only the protobuf fields relevant to this transaction class. + + If transaction_cls_name is given, filter to the one field that matches + this transaction type (e.g., TokenUnpauseTransaction -> token_unpause). + """ + all_fields = set(proto_cls.DESCRIPTOR.fields_by_name.keys()) + + if transaction_cls_name: + # Convert class name like TokenUnpauseTransaction -> token_unpause + relevant_field = transaction_cls_name.replace("Transaction", "") + relevant_field = relevant_field[0].lower() + relevant_field[1:] # lowercase first char + relevant_field = relevant_field.replace("Token", "token_") if "Token" in transaction_cls_name else relevant_field + # Keep only the relevant proto field if it exists + return {f for f in all_fields if f.endswith(relevant_field)} + + return all_fields + +def check_transaction(transaction_cls, proto_cls): + proto_fields = get_proto_fields(proto_cls, transaction_cls.__name__) + methods = get_transaction_methods(transaction_cls) + attributes = get_transaction_attributes(transaction_cls) + + actual_setters = {m for m in methods if m.startswith("set_")} + missing_setters = {f"set_{field}" for field in proto_fields} - actual_setters + + actual_attrs = attributes + missing_attrs = proto_fields - actual_attrs + + return { + "transaction": transaction_cls.__name__, + "proto_fields": proto_fields, + "attributes": attributes, + "actual_attrs": actual_attrs, + "methods": methods, + "actual_setters": actual_setters, + "missing_setters": missing_setters, + "missing_attrs": missing_attrs + } + +def main(): + for name, mapping in TRANSACTIONS.items(): + cls = mapping["cls"] + proto_cls = mapping["proto_cls"] + result = check_transaction(cls, proto_cls) + + print(f"\n{bold(f'=== {name} ===')}") + print(f"{bold('Proto fields:')} {sorted(result['proto_fields'])}") + print(f"{bold('Attributes in __init__:')} {sorted(result['attributes'])}") + + print(f"\n{bold('Actual found')}") + print(f" {bold('Attributes:')} {green(sorted(result['actual_attrs']))}") + print(f" {bold('Setter methods:')} {green(sorted(result['actual_setters']))}") + + print(f"\n{bold('Missing')}") + print(f" {bold('Setter methods:')} {red(sorted(result['missing_setters']))}") + print(f" {bold('Attributes:')} {red(sorted(result['missing_attrs']))}") + +if __name__ == "__main__": + main() diff --git a/scripts/src_vs_proto/steps_1_extracted_token_classes_with_paths.py b/scripts/src_vs_proto/steps_1_extracted_token_classes_with_paths.py new file mode 100644 index 000000000..dca6b82c7 --- /dev/null +++ b/scripts/src_vs_proto/steps_1_extracted_token_classes_with_paths.py @@ -0,0 +1,53 @@ +# Auto-generated imports for token classes + +from hiero_sdk_python.tokens.abstract_token_transfer_transaction import AbstractTokenTransferTransaction +from hiero_sdk_python.tokens.custom_fee import CustomFee +from hiero_sdk_python.tokens.custom_fixed_fee import CustomFixedFee +from hiero_sdk_python.tokens.custom_fractional_fee import CustomFractionalFee +from hiero_sdk_python.tokens.custom_royalty_fee import CustomRoyaltyFee +from hiero_sdk_python.tokens.fee_assessment_method import FeeAssessmentMethod +from hiero_sdk_python.tokens.hbar_allowance import HbarAllowance +from hiero_sdk_python.tokens.hbar_transfer import HbarTransfer +from hiero_sdk_python.tokens.nft_id import NftId +from hiero_sdk_python.tokens.supply_type import SupplyType +from hiero_sdk_python.tokens.token_airdrop_claim import TokenClaimAirdropTransaction +from hiero_sdk_python.tokens.token_airdrop_pending_id import PendingAirdropId +from hiero_sdk_python.tokens.token_airdrop_pending_record import PendingAirdropRecord +from hiero_sdk_python.tokens.token_airdrop_transaction import TokenAirdropTransaction +from hiero_sdk_python.tokens.token_airdrop_transaction_cancel import TokenCancelAirdropTransaction +from hiero_sdk_python.tokens.token_allowance import TokenAllowance +from hiero_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction +from hiero_sdk_python.tokens.token_burn_transaction import TokenBurnTransaction +from hiero_sdk_python.tokens.token_create_transaction import TokenCreateTransaction +from hiero_sdk_python.tokens.token_create_transaction import TokenCreateValidator +from hiero_sdk_python.tokens.token_create_transaction import TokenKeys +from hiero_sdk_python.tokens.token_create_transaction import TokenParams +from hiero_sdk_python.tokens.token_delete_transaction import TokenDeleteTransaction +from hiero_sdk_python.tokens.token_dissociate_transaction import TokenDissociateTransaction +from hiero_sdk_python.tokens.token_fee_schedule_update_transaction import TokenFeeScheduleUpdateTransaction +from hiero_sdk_python.tokens.token_freeze_status import TokenFreezeStatus +from hiero_sdk_python.tokens.token_freeze_transaction import TokenFreezeTransaction +from hiero_sdk_python.tokens.token_grant_kyc_transaction import TokenGrantKycTransaction +from hiero_sdk_python.tokens.token_id import TokenId +from hiero_sdk_python.tokens.token_info import TokenInfo +from hiero_sdk_python.tokens.token_key_validation import TokenKeyValidation +from hiero_sdk_python.tokens.token_kyc_status import TokenKycStatus +from hiero_sdk_python.tokens.token_mint_transaction import TokenMintTransaction +from hiero_sdk_python.tokens.token_nft_allowance import TokenNftAllowance +from hiero_sdk_python.tokens.token_nft_info import TokenNftInfo +from hiero_sdk_python.tokens.token_nft_transfer import TokenNftTransfer +from hiero_sdk_python.tokens.token_pause_status import TokenPauseStatus +from hiero_sdk_python.tokens.token_pause_transaction import TokenPauseTransaction +from hiero_sdk_python.tokens.token_reject_transaction import TokenRejectTransaction +from hiero_sdk_python.tokens.token_relationship import TokenRelationship +from hiero_sdk_python.tokens.token_revoke_kyc_transaction import TokenRevokeKycTransaction +from hiero_sdk_python.tokens.token_transfer import TokenTransfer +from hiero_sdk_python.tokens.token_transfer_list import TokenTransferList +from hiero_sdk_python.tokens.token_type import TokenType +from hiero_sdk_python.tokens.token_unfreeze_transaction import TokenUnfreezeTransaction +from hiero_sdk_python.tokens.token_unpause_transaction import TokenUnpauseTransaction +from hiero_sdk_python.tokens.token_update_nfts_transaction import TokenUpdateNftsTransaction +from hiero_sdk_python.tokens.token_update_transaction import TokenUpdateKeys +from hiero_sdk_python.tokens.token_update_transaction import TokenUpdateParams +from hiero_sdk_python.tokens.token_update_transaction import TokenUpdateTransaction +from hiero_sdk_python.tokens.token_wipe_transaction import TokenWipeTransaction diff --git a/scripts/src_vs_proto/steps_1_find_all_file_imports.py b/scripts/src_vs_proto/steps_1_find_all_file_imports.py new file mode 100644 index 000000000..376033625 --- /dev/null +++ b/scripts/src_vs_proto/steps_1_find_all_file_imports.py @@ -0,0 +1,53 @@ +# scripts/extract_token_classes_with_paths.py +""" +Scans the hiero_sdk_python tokens source directory and extracts +all top-level classes in each Python file. Generates a Python file +with explicit imports for each class from its file. + +Example output: + +from hiero_sdk_python.tokens.token_freeze_transaction import TokenFreezeTransaction +from hiero_sdk_python.tokens.custom_fee import CustomFee +... +""" + +import ast +from pathlib import Path + +# Paths (adjust if needed) +PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent +TOKENS_DIR = PROJECT_ROOT / "src" / "hiero_sdk_python" / "tokens" +OUTPUT_DIR = PROJECT_ROOT / "scripts" / "src_vs_proto" +OUTPUT_FILE = OUTPUT_DIR / "steps_1_extracted_token_classes_with_paths.py" + +def extract_classes_from_file(file_path: Path): + """Return a list of top-level class names defined in a Python file.""" + with open(file_path, "r", encoding="utf-8") as f: + tree = ast.parse(f.read(), filename=str(file_path)) + return [node.name for node in tree.body if isinstance(node, ast.ClassDef)] + +def main(): + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + + imports = [] + + for py_file in TOKENS_DIR.glob("*.py"): + classes = extract_classes_from_file(py_file) + if not classes: + continue + module_name = py_file.stem # file name without .py + for cls in classes: + import_line = f"from hiero_sdk_python.tokens.{module_name} import {cls}" + imports.append(import_line) + print(f"Found class {cls} in {module_name}.py") + + # Write the output file + with open(OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("# Auto-generated imports for token classes\n\n") + for line in sorted(imports): + f.write(f"{line}\n") + + print(f"\nAll token classes with proper paths written to {OUTPUT_FILE}") + +if __name__ == "__main__": + main() diff --git a/scripts/src_vs_proto/steps_2_extracted_token_proto_imports.py b/scripts/src_vs_proto/steps_2_extracted_token_proto_imports.py new file mode 100644 index 000000000..e95f244bf --- /dev/null +++ b/scripts/src_vs_proto/steps_2_extracted_token_proto_imports.py @@ -0,0 +1,194 @@ +# Auto-generated proto imports per token module + +token_proto_map = { + 'abstract_token_transfer_transaction': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'custom_fee': [ + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'AccountID'), + ('hiero_sdk_python.hapi.services.custom_fees_pb2', 'CustomFee'), + ], + 'custom_fixed_fee': [ + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ], + 'custom_fractional_fee': [ + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'Fraction'), + ], + 'custom_royalty_fee': [ + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services', 'custom_fees_pb2'), + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'Fraction'), + ], + 'hbar_allowance': [ + ('hiero_sdk_python.hapi.services.crypto_approve_allowance_pb2', 'CryptoAllowance'), + ], + 'hbar_transfer': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'nft_id': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_airdrop_claim': [ + ('hiero_sdk_python.hapi.services.token_claim_airdrop_pb2', 'TokenClaimAirdropTransactionBody'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ], + 'token_airdrop_pending_id': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_airdrop_pending_record': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_record_pb2'), + ], + 'token_airdrop_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_airdrop_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_airdrop_transaction_cancel': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ('hiero_sdk_python.hapi.services', 'token_cancel_airdrop_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_allowance': [ + ('hiero_sdk_python.hapi.services.crypto_approve_allowance_pb2', 'TokenAllowance'), + ], + 'token_associate_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_associate_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_burn_transaction': [ + ('hiero_sdk_python.hapi.services.token_burn_pb2', 'TokenBurnTransactionBody'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services', 'token_burn_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_create_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_create_pb2'), + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_delete_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_delete_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_dissociate_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_dissociate_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_fee_schedule_update_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_fee_schedule_update_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_freeze_status': [ + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'TokenFreezeStatus'), + ], + 'token_freeze_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_freeze_account_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_grant_kyc_transaction': [ + ('hiero_sdk_python.hapi.services.token_grant_kyc_pb2', 'TokenGrantKycTransactionBody'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ('hiero_sdk_python.hapi.services', 'token_grant_kyc_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ], + 'token_id': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_info': [ + ('hiero_sdk_python.hapi.services', 'token_get_info_pb2'), + ], + 'token_key_validation': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_kyc_status': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_mint_transaction': [ + ('hiero_sdk_python.hapi.services.token_mint_pb2', 'TokenMintTransactionBody'), + ('hiero_sdk_python.hapi.services', 'token_mint_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_nft_allowance': [ + ('hiero_sdk_python.hapi.services.crypto_approve_allowance_pb2', 'NftAllowance'), + ('hiero_sdk_python.hapi.services.crypto_delete_allowance_pb2', 'NftRemoveAllowance'), + ], + 'token_nft_info': [ + ('hiero_sdk_python.hapi.services', 'timestamp_pb2'), + ('hiero_sdk_python.hapi.services', 'token_get_nft_info_pb2'), + ], + 'token_nft_transfer': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_pause_status': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_pause_transaction': [ + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services', 'token_pause_pb2'), + ('hiero_sdk_python.hapi.services.token_pause_pb2', 'TokenPauseTransactionBody'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_reject_transaction': [ + ('hiero_sdk_python.hapi.services.token_reject_pb2', 'TokenReference'), + ('hiero_sdk_python.hapi.services.token_reject_pb2', 'TokenRejectTransactionBody'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_relationship': [ + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'TokenRelationship'), + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'TokenFreezeStatus'), + ('hiero_sdk_python.hapi.services.basic_types_pb2', 'TokenKycStatus'), + ], + 'token_revoke_kyc_transaction': [ + ('hiero_sdk_python.hapi.services.token_revoke_kyc_pb2', 'TokenRevokeKycTransactionBody'), + ('hiero_sdk_python.hapi.services', 'token_revoke_kyc_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_transfer': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_transfer_list': [ + ('hiero_sdk_python.hapi.services', 'basic_types_pb2'), + ], + 'token_unfreeze_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_unfreeze_account_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], + 'token_unpause_transaction': [ + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ('hiero_sdk_python.hapi.services.token_unpause_pb2', 'TokenUnpauseTransactionBody'), + ('hiero_sdk_python.hapi.services.transaction_pb2', 'TransactionBody'), + ], + 'token_update_nfts_transaction': [ + ('hiero_sdk_python.hapi.services.token_update_nfts_pb2', 'TokenUpdateNftsTransactionBody'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ('hiero_sdk_python.hapi.services', 'token_update_nfts_pb2'), + ], + 'token_update_transaction': [ + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ('hiero_sdk_python.hapi.services', 'token_update_pb2'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ], + 'token_wipe_transaction': [ + ('hiero_sdk_python.hapi.services', 'token_wipe_account_pb2'), + ('hiero_sdk_python.hapi.services.token_wipe_account_pb2', 'TokenWipeAccountTransactionBody'), + ('hiero_sdk_python.hapi.services', 'transaction_pb2'), + ('hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2', 'SchedulableTransactionBody'), + ], +} diff --git a/scripts/src_vs_proto/steps_2_find_all_protos.py b/scripts/src_vs_proto/steps_2_find_all_protos.py new file mode 100644 index 000000000..4e23e480d --- /dev/null +++ b/scripts/src_vs_proto/steps_2_find_all_protos.py @@ -0,0 +1,56 @@ +""" +Scan token modules, extract all proto imports and classes. +Generates a mapping: + token_module -> list of (proto_module, proto_class) +""" + +import ast +from pathlib import Path + +PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent +TOKENS_DIR = PROJECT_ROOT / "src/hiero_sdk_python/tokens" +OUTPUT_FILE = Path(__file__).resolve().parent / "steps_2_extracted_token_proto_imports.py" + +def extract_proto_imports(file_path: Path): + """ + Return list of tuples: (module_name, class_name_or_None) + """ + proto_imports = [] + with open(file_path, "r", encoding="utf-8") as f: + tree = ast.parse(f.read(), filename=str(file_path)) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom): + module = node.module or "" + if module.startswith("hiero_sdk_python.hapi.services"): + for alias in node.names: + proto_imports.append((module, alias.name)) + elif isinstance(node, ast.Import): + for alias in node.names: + if alias.name.startswith("hiero_sdk_python.hapi.services"): + proto_imports.append((alias.name, None)) # module only + return proto_imports + +def main(): + all_proto_imports = {} + for py_file in TOKENS_DIR.glob("*.py"): + token_module = py_file.stem + proto_entries = extract_proto_imports(py_file) + if proto_entries: + all_proto_imports[token_module] = proto_entries + + # Write Python file with mapping + with open(OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("# Auto-generated proto imports per token module\n\n") + f.write("token_proto_map = {\n") + for token_module, entries in sorted(all_proto_imports.items()): + f.write(f" '{token_module}': [\n") + for mod, cls in entries: + f.write(f" ('{mod}', '{cls}'" if cls else f" ('{mod}', None)") + f.write("),\n") + f.write(" ],\n") + f.write("}\n") + + print(f"āœ… All proto imports written to {OUTPUT_FILE}") + +if __name__ == "__main__": + main() diff --git a/scripts/src_vs_proto/steps_3_extract_setters_attributes.py b/scripts/src_vs_proto/steps_3_extract_setters_attributes.py new file mode 100644 index 000000000..de1d2e630 --- /dev/null +++ b/scripts/src_vs_proto/steps_3_extract_setters_attributes.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +""" +Step 3 Refactor: Token class parser, exporter, and controller +""" + +import ast +from pathlib import Path +from typing import Dict, List, Any + + +class TokenClassParser: + """Parses .py files to extract token class attributes and setters.""" + + def __init__(self, tokens_dir: Path): + self.tokens_dir = tokens_dir + self.errors: List[str] = [] + + def extract_classes_from_file(self, file_path: Path) -> Dict[str, Dict[str, List[str]]]: + """Extract classes with attributes and setter methods.""" + classes_info = {} + try: + with open(file_path, "r", encoding="utf-8") as f: + tree = ast.parse(f.read(), filename=str(file_path)) + except Exception as e: + self.errors.append(f"{file_path}: Failed to parse ({e})") + return classes_info + + for node in tree.body: + if isinstance(node, ast.ClassDef): + cls_name = node.name + init_attrs = [] + setters = [] + for item in node.body: + if isinstance(item, ast.FunctionDef): + if item.name == "__init__": + init_attrs = [arg.arg for arg in item.args.args if arg.arg != "self"] + if item.name.startswith("set_"): + setters.append(item.name) + classes_info[cls_name] = {"attributes": init_attrs, "setters": setters} + return classes_info + + def parse_all(self) -> Dict[str, Any]: + """Walk tokens directory and parse all classes.""" + all_classes_info = {} + modules_seen = set() + + for py_file in self.tokens_dir.glob("*.py"): + if py_file.name == "__init__.py": + continue + module_name = py_file.stem + modules_seen.add(module_name) + class_info = self.extract_classes_from_file(py_file) + if class_info: + all_classes_info.update({f"{module_name}.{k}": v for k, v in class_info.items()}) + else: + self.errors.append(f"{py_file}: No classes found or all failed parsing.") + + return {"modules": sorted(modules_seen), "classes": all_classes_info, "errors": self.errors} + + +class TokenClassExporter: + """Handles writing the parsed data to files.""" + + def __init__(self, output_dir: Path): + self.output_dir = output_dir + self.output_file = output_dir / "steps_3_token_classes_info_readable.py" + self.error_file = output_dir / "steps_3_token_classes_errors.log" + self.output_dir.mkdir(parents=True, exist_ok=True) + + def write_class_info(self, modules: List[str], classes_info: Dict[str, Any]) -> None: + with open(self.output_file, "w", encoding="utf-8") as f: + f.write("# Auto-generated class info: imports, attributes and setters\n\n") + for mod in modules: + f.write(f"from hiero_sdk_python.tokens import {mod}\n") + f.write("\n") + + for full_cls_name, info in sorted(classes_info.items()): + file_name = full_cls_name.split(".")[0] + ".py" + f.write(f"# File: {file_name}\n") + f.write(f"{full_cls_name} = {{\n") + f.write(" 'attributes': [\n") + for attr in info['attributes']: + f.write(f" '{attr}',\n") + f.write(" ],\n") + f.write(" 'setters': [\n") + for setter in info['setters']: + f.write(f" '{setter}',\n") + f.write(" ]\n") + f.write("}\n\n") + + def write_error_log(self, errors: List[str]) -> None: + with open(self.error_file, "w", encoding="utf-8") as f: + if errors: + f.write("# Errors encountered during parsing\n\n") + for err in errors: + f.write(err + "\n") + else: + f.write("# No errors encountered\n") + + def export(self, modules, classes_info, errors): + self.write_class_info(modules, classes_info) + self.write_error_log(errors) + print(f"āœ… Class info written to: {self.output_file}") + print(f"🪶 Errors (if any) written to: {self.error_file}") + + +class TokenClassExtractor: + """Controller that ties everything together.""" + + def __init__(self, project_root: Path): + self.tokens_dir = project_root / "src" / "hiero_sdk_python" / "tokens" + self.output_dir = project_root / "scripts" / "src_vs_proto" + + def run(self): + parser = TokenClassParser(self.tokens_dir) + exporter = TokenClassExporter(self.output_dir) + + print(f"šŸ” Scanning token modules in {self.tokens_dir}...") + result = parser.parse_all() + + exporter.export(result["modules"], result["classes"], result["errors"]) + print("āœ… Done.") + + +if __name__ == "__main__": + project_root = Path(__file__).resolve().parent.parent.parent + TokenClassExtractor(project_root).run() diff --git a/scripts/src_vs_proto/steps_3_extract_setters_attributes2.py b/scripts/src_vs_proto/steps_3_extract_setters_attributes2.py new file mode 100644 index 000000000..eec2db2d2 --- /dev/null +++ b/scripts/src_vs_proto/steps_3_extract_setters_attributes2.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +""" +Step 3 Refactor: Token class parser, exporter, and controller +Enhanced to capture: +- Attributes from __init__ +- Setters (set_/add_/remove_) +- All other methods, including private SDK helpers (_build_proto_body, _get_method, _from_proto) +- Optional proto conversion helpers (to_proto/from_proto) +""" + +import ast +from pathlib import Path +from typing import Dict, List, Any + + +class TokenClassParser: + """Parses .py files to extract token class attributes and methods.""" + + def __init__(self, tokens_dir: Path): + self.tokens_dir = tokens_dir + self.errors: List[str] = [] + + def extract_classes_from_file(self, file_path: Path) -> Dict[str, Dict[str, List[str]]]: + """Extract classes with attributes and SDK methods from a Python file.""" + classes_info = {} + try: + with open(file_path, "r", encoding="utf-8") as f: + tree = ast.parse(f.read(), filename=str(file_path)) + except Exception as e: + self.errors.append(f"{file_path}: Failed to parse ({e})") + return classes_info + + for node in tree.body: + if isinstance(node, ast.ClassDef): + cls_name = node.name + attributes = [] + setters = [] + others = [] + + for item in node.body: + if isinstance(item, ast.FunctionDef): + # Capture __init__ args as attributes + if item.name == "__init__": + attributes = [arg.arg for arg in item.args.args if arg.arg != "self"] + + # Setters / repeated-field helpers + elif item.name.startswith(("set_", "add_", "remove_")): + setters.append(item.name) + + # All other methods (including private helpers starting with _) + else: + others.append(item.name) + + classes_info[cls_name] = { + "attributes": attributes, + "setters": setters, + "other_methods": others + } + + return classes_info + + def parse_all(self) -> Dict[str, Any]: + """Walk tokens directory and parse all classes.""" + all_classes_info = {} + modules_seen = set() + + for py_file in self.tokens_dir.glob("*.py"): + if py_file.name == "__init__.py": + continue + module_name = py_file.stem + modules_seen.add(module_name) + class_info = self.extract_classes_from_file(py_file) + if class_info: + all_classes_info.update({f"{module_name}.{k}": v for k, v in class_info.items()}) + else: + self.errors.append(f"{py_file}: No classes found or all failed parsing.") + + return {"modules": sorted(modules_seen), "classes": all_classes_info, "errors": self.errors} + + +class TokenClassExporter: + """Handles writing the parsed data to files.""" + + def __init__(self, output_dir: Path): + self.output_dir = output_dir + self.output_file = output_dir / "steps_3_token_classes_info_readable.py" + self.error_file = output_dir / "steps_3_token_classes_errors.log" + self.output_dir.mkdir(parents=True, exist_ok=True) + + def write_class_info(self, modules: List[str], classes_info: Dict[str, Any]) -> None: + with open(self.output_file, "w", encoding="utf-8") as f: + f.write("# Auto-generated class info: attributes, setters, other methods\n\n") + for mod in modules: + f.write(f"from hiero_sdk_python.tokens import {mod}\n") + f.write("\n") + + for full_cls_name, info in sorted(classes_info.items()): + file_name = full_cls_name.split(".")[0] + ".py" + f.write(f"# File: {file_name}\n") + f.write(f"{full_cls_name} = {{\n") + f.write(" 'attributes': [\n") + for attr in info['attributes']: + f.write(f" '{attr}',\n") + f.write(" ],\n") + f.write(" 'setters': [\n") + for setter in info['setters']: + f.write(f" '{setter}',\n") + f.write(" ],\n") + f.write(" 'other_methods': [\n") + for method in info['other_methods']: + f.write(f" '{method}',\n") + f.write(" ]\n") + f.write("}\n\n") + + def write_error_log(self, errors: List[str]) -> None: + with open(self.error_file, "w", encoding="utf-8") as f: + if errors: + f.write("# Errors encountered during parsing\n\n") + for err in errors: + f.write(err + "\n") + else: + f.write("# No errors encountered\n") + + def export(self, modules, classes_info, errors): + self.write_class_info(modules, classes_info) + self.write_error_log(errors) + print(f"āœ… Class info written to: {self.output_file}") + print(f"🪶 Errors (if any) written to: {self.error_file}") + + +class TokenClassExtractor: + """Controller that ties everything together.""" + + def __init__(self, project_root: Path): + self.tokens_dir = project_root / "src" / "hiero_sdk_python" / "tokens" + self.output_dir = project_root / "scripts" / "src_vs_proto" + + def run(self): + parser = TokenClassParser(self.tokens_dir) + exporter = TokenClassExporter(self.output_dir) + + print(f"šŸ” Scanning token modules in {self.tokens_dir}...") + result = parser.parse_all() + + exporter.export(result["modules"], result["classes"], result["errors"]) + print("āœ… Done.") + + +if __name__ == "__main__": + project_root = Path(__file__).resolve().parent.parent.parent + TokenClassExtractor(project_root).run() diff --git a/scripts/src_vs_proto/steps_3_token_classes_errors.log b/scripts/src_vs_proto/steps_3_token_classes_errors.log new file mode 100644 index 000000000..416d406e6 --- /dev/null +++ b/scripts/src_vs_proto/steps_3_token_classes_errors.log @@ -0,0 +1 @@ +# No errors encountered diff --git a/scripts/src_vs_proto/steps_3_token_classes_info_readable.py b/scripts/src_vs_proto/steps_3_token_classes_info_readable.py new file mode 100644 index 000000000..06b37a2d1 --- /dev/null +++ b/scripts/src_vs_proto/steps_3_token_classes_info_readable.py @@ -0,0 +1,969 @@ +# Auto-generated class info: attributes, setters, other methods + +from hiero_sdk_python.tokens import abstract_token_transfer_transaction +from hiero_sdk_python.tokens import custom_fee +from hiero_sdk_python.tokens import custom_fixed_fee +from hiero_sdk_python.tokens import custom_fractional_fee +from hiero_sdk_python.tokens import custom_royalty_fee +from hiero_sdk_python.tokens import fee_assessment_method +from hiero_sdk_python.tokens import hbar_allowance +from hiero_sdk_python.tokens import hbar_transfer +from hiero_sdk_python.tokens import nft_id +from hiero_sdk_python.tokens import supply_type +from hiero_sdk_python.tokens import token_airdrop_claim +from hiero_sdk_python.tokens import token_airdrop_pending_id +from hiero_sdk_python.tokens import token_airdrop_pending_record +from hiero_sdk_python.tokens import token_airdrop_transaction +from hiero_sdk_python.tokens import token_airdrop_transaction_cancel +from hiero_sdk_python.tokens import token_allowance +from hiero_sdk_python.tokens import token_associate_transaction +from hiero_sdk_python.tokens import token_burn_transaction +from hiero_sdk_python.tokens import token_create_transaction +from hiero_sdk_python.tokens import token_delete_transaction +from hiero_sdk_python.tokens import token_dissociate_transaction +from hiero_sdk_python.tokens import token_fee_schedule_update_transaction +from hiero_sdk_python.tokens import token_freeze_status +from hiero_sdk_python.tokens import token_freeze_transaction +from hiero_sdk_python.tokens import token_grant_kyc_transaction +from hiero_sdk_python.tokens import token_id +from hiero_sdk_python.tokens import token_info +from hiero_sdk_python.tokens import token_key_validation +from hiero_sdk_python.tokens import token_kyc_status +from hiero_sdk_python.tokens import token_mint_transaction +from hiero_sdk_python.tokens import token_nft_allowance +from hiero_sdk_python.tokens import token_nft_info +from hiero_sdk_python.tokens import token_nft_transfer +from hiero_sdk_python.tokens import token_pause_status +from hiero_sdk_python.tokens import token_pause_transaction +from hiero_sdk_python.tokens import token_reject_transaction +from hiero_sdk_python.tokens import token_relationship +from hiero_sdk_python.tokens import token_revoke_kyc_transaction +from hiero_sdk_python.tokens import token_transfer +from hiero_sdk_python.tokens import token_transfer_list +from hiero_sdk_python.tokens import token_type +from hiero_sdk_python.tokens import token_unfreeze_transaction +from hiero_sdk_python.tokens import token_unpause_transaction +from hiero_sdk_python.tokens import token_update_nfts_transaction +from hiero_sdk_python.tokens import token_update_transaction +from hiero_sdk_python.tokens import token_wipe_transaction + +# File: abstract_token_transfer_transaction.py +abstract_token_transfer_transaction.AbstractTokenTransferTransaction = { + 'attributes': [ + ], + 'setters': [ + 'add_token_transfer', + 'add_token_transfer_with_decimals', + 'add_approved_token_transfer', + 'add_approved_token_transfer_with_decimals', + 'add_nft_transfer', + 'add_approved_nft_transfer', + ], + 'other_methods': [ + '_init_token_transfers', + '_init_nft_transfers', + '_add_token_transfer', + '_add_nft_transfer', + 'build_token_transfers', + ] +} + +# File: custom_fee.py +custom_fee.CustomFee = { + 'attributes': [ + 'fee_collector_account_id', + 'all_collectors_are_exempt', + ], + 'setters': [ + 'set_fee_collector_account_id', + 'set_all_collectors_are_exempt', + ], + 'other_methods': [ + '_from_proto', + '_get_fee_collector_account_id_protobuf', + '_to_proto', + '_validate_checksums', + '__eq__', + ] +} + +# File: custom_fixed_fee.py +custom_fixed_fee.CustomFixedFee = { + 'attributes': [ + 'amount', + 'denominating_token_id', + 'fee_collector_account_id', + 'all_collectors_are_exempt', + ], + 'setters': [ + 'set_amount_in_tinybars', + 'set_hbar_amount', + 'set_denominating_token_id', + 'set_denominating_token_to_same_token', + ], + 'other_methods': [ + '_from_fixed_fee_proto', + '_to_proto', + '_to_topic_fee_proto', + '_validate_checksums', + '_from_proto', + '__eq__', + ] +} + +# File: custom_fractional_fee.py +custom_fractional_fee.CustomFractionalFee = { + 'attributes': [ + 'numerator', + 'denominator', + 'min_amount', + 'max_amount', + 'assessment_method', + 'fee_collector_account_id', + 'all_collectors_are_exempt', + ], + 'setters': [ + 'set_numerator', + 'set_denominator', + 'set_min_amount', + 'set_max_amount', + 'set_assessment_method', + ], + 'other_methods': [ + '_to_proto', + '_from_proto', + ] +} + +# File: custom_royalty_fee.py +custom_royalty_fee.CustomRoyaltyFee = { + 'attributes': [ + 'numerator', + 'denominator', + 'fallback_fee', + 'fee_collector_account_id', + 'all_collectors_are_exempt', + ], + 'setters': [ + 'set_numerator', + 'set_denominator', + 'set_fallback_fee', + ], + 'other_methods': [ + '_to_proto', + '_from_proto', + ] +} + +# File: fee_assessment_method.py +fee_assessment_method.FeeAssessmentMethod = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: hbar_allowance.py +hbar_allowance.HbarAllowance = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + '__str__', + '__repr__', + '_from_proto_field', + ] +} + +# File: hbar_transfer.py +hbar_transfer.HbarTransfer = { + 'attributes': [ + 'account_id', + 'amount', + 'is_approved', + ], + 'setters': [ + ], + 'other_methods': [ + '_to_proto', + '_from_proto', + '__str__', + '__repr__', + ] +} + +# File: nft_id.py +nft_id.NftId = { + 'attributes': [ + 'token_id', + 'serial_number', + ], + 'setters': [ + ], + 'other_methods': [ + '__post_init__', + '_from_proto', + '_to_proto', + 'from_string', + 'to_string_with_checksum', + '__str__', + ] +} + +# File: supply_type.py +supply_type.SupplyType = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: token_airdrop_claim.py +token_airdrop_claim.TokenClaimAirdropTransaction = { + 'attributes': [ + 'pending_airdrop_ids', + ], + 'setters': [ + 'add_pending_airdrop_id', + 'add_pending_airdrop_ids', + ], + 'other_methods': [ + '_validate_all', + '_validate_final', + '_pending_airdrop_ids_to_proto', + '_from_proto', + 'build_transaction_body', + '_get_method', + 'get_pending_airdrop_ids', + '__repr__', + '__str__', + ] +} + +# File: token_airdrop_pending_id.py +token_airdrop_pending_id.PendingAirdropId = { + 'attributes': [ + 'sender_id', + 'receiver_id', + 'token_id', + 'nft_id', + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + '__str__', + '__repr__', + '__eq__', + '__hash__', + ] +} + +# File: token_airdrop_pending_record.py +token_airdrop_pending_record.PendingAirdropRecord = { + 'attributes': [ + 'pending_airdrop_id', + 'amount', + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + '__str__', + ] +} + +# File: token_airdrop_transaction.py +token_airdrop_transaction.TokenAirdropTransaction = { + 'attributes': [ + 'token_transfers', + 'nft_transfers', + ], + 'setters': [ + ], + 'other_methods': [ + '_build_proto_body', + '_from_proto', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_airdrop_transaction_cancel.py +token_airdrop_transaction_cancel.TokenCancelAirdropTransaction = { + 'attributes': [ + 'pending_airdrops', + ], + 'setters': [ + 'set_pending_airdrops', + 'add_pending_airdrop', + ], + 'other_methods': [ + 'clear_pending_airdrops', + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_allowance.py +token_allowance.TokenAllowance = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + '__str__', + '__repr__', + '_from_proto_field', + ] +} + +# File: token_associate_transaction.py +token_associate_transaction.TokenAssociateTransaction = { + 'attributes': [ + 'account_id', + 'token_ids', + ], + 'setters': [ + 'set_account_id', + 'add_token_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_burn_transaction.py +token_burn_transaction.TokenBurnTransaction = { + 'attributes': [ + 'token_id', + 'amount', + 'serials', + ], + 'setters': [ + 'set_token_id', + 'set_amount', + 'set_serials', + 'add_serial', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + +# File: token_create_transaction.py +token_create_transaction.TokenCreateTransaction = { + 'attributes': [ + 'token_params', + 'keys', + ], + 'setters': [ + 'set_token_params', + 'set_token_keys', + 'set_token_name', + 'set_token_symbol', + 'set_treasury_account_id', + 'set_decimals', + 'set_initial_supply', + 'set_token_type', + 'set_max_supply', + 'set_supply_type', + 'set_freeze_default', + 'set_expiration_time', + 'set_auto_renew_period', + 'set_auto_renew_account_id', + 'set_memo', + 'set_admin_key', + 'set_supply_key', + 'set_freeze_key', + 'set_wipe_key', + 'set_metadata_key', + 'set_pause_key', + 'set_kyc_key', + 'set_custom_fees', + 'set_fee_schedule_key', + ], + 'other_methods': [ + '_to_proto_key', + 'freeze_with', + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_create_transaction.py +token_create_transaction.TokenCreateValidator = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_validate_token_params', + '_validate_token_freeze_status', + '_validate_required_fields', + '_validate_name_and_symbol', + '_validate_initial_supply', + '_validate_decimals_and_token_type', + '_validate_supply_max_and_type', + ] +} + +# File: token_create_transaction.py +token_create_transaction.TokenKeys = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: token_create_transaction.py +token_create_transaction.TokenParams = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: token_delete_transaction.py +token_delete_transaction.TokenDeleteTransaction = { + 'attributes': [ + 'token_id', + ], + 'setters': [ + 'set_token_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_dissociate_transaction.py +token_dissociate_transaction.TokenDissociateTransaction = { + 'attributes': [ + 'account_id', + 'token_ids', + ], + 'setters': [ + 'set_account_id', + 'add_token_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_fee_schedule_update_transaction.py +token_fee_schedule_update_transaction.TokenFeeScheduleUpdateTransaction = { + 'attributes': [ + 'token_id', + 'custom_fees', + ], + 'setters': [ + 'set_token_id', + 'set_custom_fees', + ], + 'other_methods': [ + '_validate_checksums', + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '__repr__', + ] +} + +# File: token_freeze_status.py +token_freeze_status.TokenFreezeStatus = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '__eq__', + ] +} + +# File: token_freeze_transaction.py +token_freeze_transaction.TokenFreezeTransaction = { + 'attributes': [ + 'token_id', + 'account_id', + ], + 'setters': [ + 'set_token_id', + 'set_account_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_grant_kyc_transaction.py +token_grant_kyc_transaction.TokenGrantKycTransaction = { + 'attributes': [ + 'token_id', + 'account_id', + ], + 'setters': [ + 'set_token_id', + 'set_account_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + +# File: token_id.py +token_id.TokenId = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '__post_init__', + '_from_proto', + '_to_proto', + 'from_string', + 'validate_checksum', + 'to_string_with_checksum', + '__str__', + '__hash__', + ] +} + +# File: token_info.py +token_info.TokenInfo = { + 'attributes': [ + ], + 'setters': [ + 'set_admin_key', + 'set_kyc_key', + 'set_freeze_key', + 'set_wipe_key', + 'set_supply_key', + 'set_metadata_key', + 'set_fee_schedule_key', + 'set_default_freeze_status', + 'set_default_kyc_status', + 'set_auto_renew_account', + 'set_auto_renew_period', + 'set_expiry', + 'set_pause_key', + 'set_pause_status', + 'set_supply_type', + 'set_metadata', + 'set_custom_fees', + ], + 'other_methods': [ + '_get', + '_from_proto', + '_copy_key_if_present', + '_parse_custom_fees', + '_copy_msg_to_proto', + '_set_bool', + '_set_enum', + '_append_custom_fees', + '_to_proto', + '__str__', + ] +} + +# File: token_key_validation.py +token_key_validation.TokenKeyValidation = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + '__eq__', + ] +} + +# File: token_kyc_status.py +token_kyc_status.TokenKycStatus = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '__eq__', + ] +} + +# File: token_mint_transaction.py +token_mint_transaction.TokenMintTransaction = { + 'attributes': [ + 'token_id', + 'amount', + 'metadata', + ], + 'setters': [ + 'set_token_id', + 'set_amount', + 'set_metadata', + ], + 'other_methods': [ + '_validate_parameters', + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_nft_allowance.py +token_nft_allowance.TokenNftAllowance = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_from_wipe_proto', + '_to_proto', + '_to_wipe_proto', + '__str__', + '__repr__', + '_from_proto_field', + ] +} + +# File: token_nft_info.py +token_nft_info.TokenNftInfo = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + '__str__', + ] +} + +# File: token_nft_transfer.py +token_nft_transfer.TokenNftTransfer = { + 'attributes': [ + 'token_id', + 'sender_id', + 'receiver_id', + 'serial_number', + 'is_approved', + ], + 'setters': [ + ], + 'other_methods': [ + '_to_proto', + '_from_proto', + '__str__', + ] +} + +# File: token_pause_status.py +token_pause_status.TokenPauseStatus = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '__eq__', + ] +} + +# File: token_pause_transaction.py +token_pause_transaction.TokenPauseTransaction = { + 'attributes': [ + 'token_id', + ], + 'setters': [ + 'set_token_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + +# File: token_reject_transaction.py +token_reject_transaction.TokenRejectTransaction = { + 'attributes': [ + 'owner_id', + 'token_ids', + 'nft_ids', + ], + 'setters': [ + 'set_owner_id', + 'set_token_ids', + 'set_nft_ids', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + +# File: token_relationship.py +token_relationship.TokenRelationship = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + '_from_proto', + '_to_proto', + ] +} + +# File: token_revoke_kyc_transaction.py +token_revoke_kyc_transaction.TokenRevokeKycTransaction = { + 'attributes': [ + 'token_id', + 'account_id', + ], + 'setters': [ + 'set_token_id', + 'set_account_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + +# File: token_transfer.py +token_transfer.TokenTransfer = { + 'attributes': [ + 'token_id', + 'account_id', + 'amount', + 'expected_decimals', + 'is_approved', + ], + 'setters': [ + ], + 'other_methods': [ + '_to_proto', + '_from_proto', + '__str__', + ] +} + +# File: token_transfer_list.py +token_transfer_list.TokenTransferList = { + 'attributes': [ + 'token', + 'transfers', + 'nft_transfers', + 'expected_decimals', + ], + 'setters': [ + 'add_token_transfer', + 'add_nft_transfer', + ], + 'other_methods': [ + '_to_proto', + '__str__', + ] +} + +# File: token_type.py +token_type.TokenType = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: token_unfreeze_transaction.py +token_unfreeze_transaction.TokenUnfreezeTransaction = { + 'attributes': [ + 'account_id', + 'token_id', + ], + 'setters': [ + 'set_token_id', + 'set_account_id', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_unpause_transaction.py +token_unpause_transaction.TokenUnpauseTransaction = { + 'attributes': [ + 'token_id', + ], + 'setters': [ + 'set_token_id', + ], + 'other_methods': [ + '_validate_checksum', + '_from_proto', + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + ] +} + +# File: token_update_nfts_transaction.py +token_update_nfts_transaction.TokenUpdateNftsTransaction = { + 'attributes': [ + 'token_id', + 'serial_numbers', + 'metadata', + ], + 'setters': [ + 'set_token_id', + 'set_serial_numbers', + 'set_metadata', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + +# File: token_update_transaction.py +token_update_transaction.TokenUpdateKeys = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: token_update_transaction.py +token_update_transaction.TokenUpdateParams = { + 'attributes': [ + ], + 'setters': [ + ], + 'other_methods': [ + ] +} + +# File: token_update_transaction.py +token_update_transaction.TokenUpdateTransaction = { + 'attributes': [ + 'token_id', + 'token_params', + 'token_keys', + 'token_key_verification_mode', + ], + 'setters': [ + 'set_token_id', + 'set_treasury_account_id', + 'set_token_name', + 'set_token_symbol', + 'set_token_memo', + 'set_metadata', + 'set_auto_renew_account_id', + 'set_auto_renew_period', + 'set_expiration_time', + 'set_admin_key', + 'set_freeze_key', + 'set_wipe_key', + 'set_supply_key', + 'set_pause_key', + 'set_metadata_key', + 'set_kyc_key', + 'set_fee_schedule_key', + 'set_key_verification_mode', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_set_keys_to_proto', + ] +} + +# File: token_wipe_transaction.py +token_wipe_transaction.TokenWipeTransaction = { + 'attributes': [ + 'token_id', + 'account_id', + 'amount', + 'serial', + ], + 'setters': [ + 'set_token_id', + 'set_account_id', + 'set_amount', + 'set_serial', + ], + 'other_methods': [ + '_build_proto_body', + 'build_transaction_body', + 'build_scheduled_body', + '_get_method', + '_from_proto', + ] +} + diff --git a/scripts/src_vs_proto/steps_4_extract_token_proto_attributes_setters.py b/scripts/src_vs_proto/steps_4_extract_token_proto_attributes_setters.py new file mode 100644 index 000000000..4a6c2b1cf --- /dev/null +++ b/scripts/src_vs_proto/steps_4_extract_token_proto_attributes_setters.py @@ -0,0 +1,126 @@ +""" +Step 4: Extract all protobuf message classes and enums from token proto modules. +Generates proto_mappings[class_name] -> {attributes, setters} for messages +and proto_enums[enum_name] -> {values} for enums. +""" + +import importlib +from pathlib import Path +from steps_2_extracted_token_proto_imports import token_proto_map + +OUTPUT_FILE = Path(__file__).parent / "steps_4_token_classes_proto_attributes.py" + +proto_mappings = {} +proto_enums = {} + +def extract_all_protos(module): + """ + Recursively extract all protobuf messages and enums from a module. + Returns: + messages: dict[class_name] = [field names] + enums: dict[enum_name] = [enum value names] + """ + messages = {} + enums = {} + + def visit(obj): + try: + if hasattr(obj, "DESCRIPTOR"): + # Message class + if hasattr(obj.DESCRIPTOR, "fields"): + messages[obj.DESCRIPTOR.name] = [f.name for f in obj.DESCRIPTOR.fields] + # Enum class + elif hasattr(obj.DESCRIPTOR, "values"): + enums[obj.DESCRIPTOR.name] = [v.name for v in obj.DESCRIPTOR.values] + except Exception: + pass + + # Recurse into nested classes + for subname, subobj in vars(obj).items(): + if isinstance(subobj, type): + visit(subobj) + + for name, obj in vars(module).items(): + if isinstance(obj, type): + visit(obj) + + return messages, enums + +def main(): + global proto_mappings, proto_enums + + for token_module, proto_entries in token_proto_map.items(): + for proto_module, proto_class in proto_entries: + # Clean double prefixes if they exist + if proto_module.startswith("hiero_sdk_python.hapi.services.hiero_sdk_python.hapi.services"): + proto_module = proto_module[len("hiero_sdk_python.hapi.services."):] + + try: + mod = importlib.import_module(proto_module) + except Exception as e: + print(f"āŒ Failed to import {proto_module}: {e}") + continue + + messages = {} + enums = {} + + if proto_class: + cls = getattr(mod, proto_class, None) + if cls is not None: + # Extract messages/enums from specific class + m, e = extract_all_protos(cls) + messages.update(m) + enums.update(e) + else: + print(f"āš ļø Class {proto_class} not found in {proto_module}") + else: + # Extract all messages/enums from module + m, e = extract_all_protos(mod) + messages.update(m) + enums.update(e) + + # Add messages to proto_mappings + for cls_name, fields in messages.items(): + proto_mappings[cls_name] = { + "attributes": fields, + "setters": [f"set_{f}" for f in fields] + } + + # Add enums to proto_enums + for enum_name, values in enums.items(): + proto_enums[enum_name] = {"values": values} + + # Write output to file + with open(OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("# Auto-generated proto attributes and setters\n\n") + f.write("proto_mappings = {\n") + for cls_name, data in sorted(proto_mappings.items()): + f.write(f" '{cls_name}': {{\n") + f.write(" 'attributes': [\n") + for a in data['attributes']: + f.write(f" '{a}',\n") + f.write(" ],\n") + f.write(" 'setters': [\n") + for s in data['setters']: + f.write(f" '{s}',\n") + f.write(" ]\n") + f.write(" },\n") + f.write("}\n\n") + + f.write("# Auto-generated proto enums\n\n") + f.write("proto_enums = {\n") + for enum_name, data in sorted(proto_enums.items()): + f.write(f" '{enum_name}': {{\n") + f.write(" 'values': [\n") + for v in data['values']: + f.write(f" '{v}',\n") + f.write(" ]\n") + f.write(" },\n") + f.write("}\n") + + print(f"āœ… Proto mappings written to {OUTPUT_FILE}") + print(f"āœ… Total message classes extracted: {len(proto_mappings)}") + print(f"āœ… Total enums extracted: {len(proto_enums)}") + +if __name__ == "__main__": + main() diff --git a/scripts/src_vs_proto/steps_4_token_classes_proto_attributes.py b/scripts/src_vs_proto/steps_4_token_classes_proto_attributes.py new file mode 100644 index 000000000..e5ee0c287 --- /dev/null +++ b/scripts/src_vs_proto/steps_4_token_classes_proto_attributes.py @@ -0,0 +1,1299 @@ +# Auto-generated proto attributes and setters + +proto_mappings = { + 'AccountAmount': { + 'attributes': [ + 'accountID', + 'amount', + 'is_approval', + 'pre_tx_allowance_hook', + 'pre_post_tx_allowance_hook', + ], + 'setters': [ + 'set_accountID', + 'set_amount', + 'set_is_approval', + 'set_pre_tx_allowance_hook', + 'set_pre_post_tx_allowance_hook', + ] + }, + 'AccountID': { + 'attributes': [ + 'shardNum', + 'realmNum', + 'accountNum', + 'alias', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + 'set_accountNum', + 'set_alias', + ] + }, + 'AssessedCustomFee': { + 'attributes': [ + 'amount', + 'token_id', + 'fee_collector_account_id', + 'effective_payer_account_id', + ], + 'setters': [ + 'set_amount', + 'set_token_id', + 'set_fee_collector_account_id', + 'set_effective_payer_account_id', + ] + }, + 'AtomicBatchTransactionBody': { + 'attributes': [ + 'transactions', + ], + 'setters': [ + 'set_transactions', + ] + }, + 'ContractID': { + 'attributes': [ + 'shardNum', + 'realmNum', + 'contractNum', + 'evm_address', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + 'set_contractNum', + 'set_evm_address', + ] + }, + 'CurrentAndNextFeeSchedule': { + 'attributes': [ + 'currentFeeSchedule', + 'nextFeeSchedule', + ], + 'setters': [ + 'set_currentFeeSchedule', + 'set_nextFeeSchedule', + ] + }, + 'CustomFee': { + 'attributes': [ + 'fixed_fee', + 'fractional_fee', + 'royalty_fee', + 'fee_collector_account_id', + 'all_collectors_are_exempt', + ], + 'setters': [ + 'set_fixed_fee', + 'set_fractional_fee', + 'set_royalty_fee', + 'set_fee_collector_account_id', + 'set_all_collectors_are_exempt', + ] + }, + 'CustomFeeLimit': { + 'attributes': [ + 'account_id', + 'fees', + ], + 'setters': [ + 'set_account_id', + 'set_fees', + ] + }, + 'EvmHookCall': { + 'attributes': [ + 'data', + 'gas_limit', + ], + 'setters': [ + 'set_data', + 'set_gas_limit', + ] + }, + 'FeeComponents': { + 'attributes': [ + 'min', + 'max', + 'constant', + 'bpt', + 'vpt', + 'rbh', + 'sbh', + 'gas', + 'tv', + 'bpr', + 'sbpr', + ], + 'setters': [ + 'set_min', + 'set_max', + 'set_constant', + 'set_bpt', + 'set_vpt', + 'set_rbh', + 'set_sbh', + 'set_gas', + 'set_tv', + 'set_bpr', + 'set_sbpr', + ] + }, + 'FeeData': { + 'attributes': [ + 'nodedata', + 'networkdata', + 'servicedata', + 'subType', + ], + 'setters': [ + 'set_nodedata', + 'set_networkdata', + 'set_servicedata', + 'set_subType', + ] + }, + 'FeeExemptKeyList': { + 'attributes': [ + 'keys', + ], + 'setters': [ + 'set_keys', + ] + }, + 'FeeSchedule': { + 'attributes': [ + 'transactionFeeSchedule', + 'expiryTime', + ], + 'setters': [ + 'set_transactionFeeSchedule', + 'set_expiryTime', + ] + }, + 'FileID': { + 'attributes': [ + 'shardNum', + 'realmNum', + 'fileNum', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + 'set_fileNum', + ] + }, + 'FixedCustomFee': { + 'attributes': [ + 'fixed_fee', + 'fee_collector_account_id', + ], + 'setters': [ + 'set_fixed_fee', + 'set_fee_collector_account_id', + ] + }, + 'FixedCustomFeeList': { + 'attributes': [ + 'fees', + ], + 'setters': [ + 'set_fees', + ] + }, + 'FixedFee': { + 'attributes': [ + 'amount', + 'denominating_token_id', + ], + 'setters': [ + 'set_amount', + 'set_denominating_token_id', + ] + }, + 'Fraction': { + 'attributes': [ + 'numerator', + 'denominator', + ], + 'setters': [ + 'set_numerator', + 'set_denominator', + ] + }, + 'FractionalFee': { + 'attributes': [ + 'fractional_amount', + 'minimum_amount', + 'maximum_amount', + 'net_of_transfers', + ], + 'setters': [ + 'set_fractional_amount', + 'set_minimum_amount', + 'set_maximum_amount', + 'set_net_of_transfers', + ] + }, + 'HookCall': { + 'attributes': [ + 'full_hook_id', + 'hook_id', + 'evm_hook_call', + ], + 'setters': [ + 'set_full_hook_id', + 'set_hook_id', + 'set_evm_hook_call', + ] + }, + 'HookEntityId': { + 'attributes': [ + 'account_id', + ], + 'setters': [ + 'set_account_id', + ] + }, + 'HookId': { + 'attributes': [ + 'entity_id', + 'hook_id', + ], + 'setters': [ + 'set_entity_id', + 'set_hook_id', + ] + }, + 'Key': { + 'attributes': [ + 'contractID', + 'ed25519', + 'RSA_3072', + 'ECDSA_384', + 'thresholdKey', + 'keyList', + 'ECDSA_secp256k1', + 'delegatable_contract_id', + ], + 'setters': [ + 'set_contractID', + 'set_ed25519', + 'set_RSA_3072', + 'set_ECDSA_384', + 'set_thresholdKey', + 'set_keyList', + 'set_ECDSA_secp256k1', + 'set_delegatable_contract_id', + ] + }, + 'KeyList': { + 'attributes': [ + 'keys', + ], + 'setters': [ + 'set_keys', + ] + }, + 'NftID': { + 'attributes': [ + 'token_ID', + 'serial_number', + ], + 'setters': [ + 'set_token_ID', + 'set_serial_number', + ] + }, + 'NftTransfer': { + 'attributes': [ + 'senderAccountID', + 'receiverAccountID', + 'serialNumber', + 'is_approval', + 'pre_tx_sender_allowance_hook', + 'pre_post_tx_sender_allowance_hook', + 'pre_tx_receiver_allowance_hook', + 'pre_post_tx_receiver_allowance_hook', + ], + 'setters': [ + 'set_senderAccountID', + 'set_receiverAccountID', + 'set_serialNumber', + 'set_is_approval', + 'set_pre_tx_sender_allowance_hook', + 'set_pre_post_tx_sender_allowance_hook', + 'set_pre_tx_receiver_allowance_hook', + 'set_pre_post_tx_receiver_allowance_hook', + ] + }, + 'NodeAddress': { + 'attributes': [ + 'ipAddress', + 'portno', + 'memo', + 'RSA_PubKey', + 'nodeId', + 'nodeAccountId', + 'nodeCertHash', + 'serviceEndpoint', + 'description', + 'stake', + ], + 'setters': [ + 'set_ipAddress', + 'set_portno', + 'set_memo', + 'set_RSA_PubKey', + 'set_nodeId', + 'set_nodeAccountId', + 'set_nodeCertHash', + 'set_serviceEndpoint', + 'set_description', + 'set_stake', + ] + }, + 'NodeAddressBook': { + 'attributes': [ + 'nodeAddress', + ], + 'setters': [ + 'set_nodeAddress', + ] + }, + 'PendingAirdropId': { + 'attributes': [ + 'sender_id', + 'receiver_id', + 'fungible_token_type', + 'non_fungible_token', + ], + 'setters': [ + 'set_sender_id', + 'set_receiver_id', + 'set_fungible_token_type', + 'set_non_fungible_token', + ] + }, + 'PendingAirdropRecord': { + 'attributes': [ + 'pending_airdrop_id', + 'pending_airdrop_value', + ], + 'setters': [ + 'set_pending_airdrop_id', + 'set_pending_airdrop_value', + ] + }, + 'PendingAirdropValue': { + 'attributes': [ + 'amount', + ], + 'setters': [ + 'set_amount', + ] + }, + 'RealmID': { + 'attributes': [ + 'shardNum', + 'realmNum', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + ] + }, + 'RoyaltyFee': { + 'attributes': [ + 'exchange_value_fraction', + 'fallback_fee', + ], + 'setters': [ + 'set_exchange_value_fraction', + 'set_fallback_fee', + ] + }, + 'ScheduleID': { + 'attributes': [ + 'shardNum', + 'realmNum', + 'scheduleNum', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + 'set_scheduleNum', + ] + }, + 'SemanticVersion': { + 'attributes': [ + 'major', + 'minor', + 'patch', + 'pre', + 'build', + ], + 'setters': [ + 'set_major', + 'set_minor', + 'set_patch', + 'set_pre', + 'set_build', + ] + }, + 'ServiceEndpoint': { + 'attributes': [ + 'ipAddressV4', + 'port', + 'domain_name', + ], + 'setters': [ + 'set_ipAddressV4', + 'set_port', + 'set_domain_name', + ] + }, + 'ServicesConfigurationList': { + 'attributes': [ + 'nameValue', + ], + 'setters': [ + 'set_nameValue', + ] + }, + 'Setting': { + 'attributes': [ + 'name', + 'value', + 'data', + ], + 'setters': [ + 'set_name', + 'set_value', + 'set_data', + ] + }, + 'ShardID': { + 'attributes': [ + 'shardNum', + ], + 'setters': [ + 'set_shardNum', + ] + }, + 'Signature': { + 'attributes': [ + 'contract', + 'ed25519', + 'RSA_3072', + 'ECDSA_384', + 'thresholdSignature', + 'signatureList', + ], + 'setters': [ + 'set_contract', + 'set_ed25519', + 'set_RSA_3072', + 'set_ECDSA_384', + 'set_thresholdSignature', + 'set_signatureList', + ] + }, + 'SignatureList': { + 'attributes': [ + 'sigs', + ], + 'setters': [ + 'set_sigs', + ] + }, + 'SignatureMap': { + 'attributes': [ + 'sigPair', + ], + 'setters': [ + 'set_sigPair', + ] + }, + 'SignaturePair': { + 'attributes': [ + 'pubKeyPrefix', + 'contract', + 'ed25519', + 'RSA_3072', + 'ECDSA_384', + 'ECDSA_secp256k1', + ], + 'setters': [ + 'set_pubKeyPrefix', + 'set_contract', + 'set_ed25519', + 'set_RSA_3072', + 'set_ECDSA_384', + 'set_ECDSA_secp256k1', + ] + }, + 'StakingInfo': { + 'attributes': [ + 'decline_reward', + 'stake_period_start', + 'pending_reward', + 'staked_to_me', + 'staked_account_id', + 'staked_node_id', + ], + 'setters': [ + 'set_decline_reward', + 'set_stake_period_start', + 'set_pending_reward', + 'set_staked_to_me', + 'set_staked_account_id', + 'set_staked_node_id', + ] + }, + 'ThresholdKey': { + 'attributes': [ + 'threshold', + 'keys', + ], + 'setters': [ + 'set_threshold', + 'set_keys', + ] + }, + 'ThresholdSignature': { + 'attributes': [ + 'sigs', + ], + 'setters': [ + 'set_sigs', + ] + }, + 'Timestamp': { + 'attributes': [ + 'seconds', + 'nanos', + ], + 'setters': [ + 'set_seconds', + 'set_nanos', + ] + }, + 'TimestampSeconds': { + 'attributes': [ + 'seconds', + ], + 'setters': [ + 'set_seconds', + ] + }, + 'TokenAirdropTransactionBody': { + 'attributes': [ + 'token_transfers', + ], + 'setters': [ + 'set_token_transfers', + ] + }, + 'TokenAssociateTransactionBody': { + 'attributes': [ + 'account', + 'tokens', + ], + 'setters': [ + 'set_account', + 'set_tokens', + ] + }, + 'TokenAssociation': { + 'attributes': [ + 'token_id', + 'account_id', + ], + 'setters': [ + 'set_token_id', + 'set_account_id', + ] + }, + 'TokenBalance': { + 'attributes': [ + 'tokenId', + 'balance', + 'decimals', + ], + 'setters': [ + 'set_tokenId', + 'set_balance', + 'set_decimals', + ] + }, + 'TokenBalances': { + 'attributes': [ + 'tokenBalances', + ], + 'setters': [ + 'set_tokenBalances', + ] + }, + 'TokenBurnTransactionBody': { + 'attributes': [ + 'token', + 'amount', + 'serialNumbers', + ], + 'setters': [ + 'set_token', + 'set_amount', + 'set_serialNumbers', + ] + }, + 'TokenCancelAirdropTransactionBody': { + 'attributes': [ + 'pending_airdrops', + ], + 'setters': [ + 'set_pending_airdrops', + ] + }, + 'TokenCreateTransactionBody': { + 'attributes': [ + 'name', + 'symbol', + 'decimals', + 'initialSupply', + 'treasury', + 'adminKey', + 'kycKey', + 'freezeKey', + 'wipeKey', + 'supplyKey', + 'freezeDefault', + 'expiry', + 'autoRenewAccount', + 'autoRenewPeriod', + 'memo', + 'tokenType', + 'supplyType', + 'maxSupply', + 'fee_schedule_key', + 'custom_fees', + 'pause_key', + 'metadata', + 'metadata_key', + ], + 'setters': [ + 'set_name', + 'set_symbol', + 'set_decimals', + 'set_initialSupply', + 'set_treasury', + 'set_adminKey', + 'set_kycKey', + 'set_freezeKey', + 'set_wipeKey', + 'set_supplyKey', + 'set_freezeDefault', + 'set_expiry', + 'set_autoRenewAccount', + 'set_autoRenewPeriod', + 'set_memo', + 'set_tokenType', + 'set_supplyType', + 'set_maxSupply', + 'set_fee_schedule_key', + 'set_custom_fees', + 'set_pause_key', + 'set_metadata', + 'set_metadata_key', + ] + }, + 'TokenDeleteTransactionBody': { + 'attributes': [ + 'token', + ], + 'setters': [ + 'set_token', + ] + }, + 'TokenDissociateTransactionBody': { + 'attributes': [ + 'account', + 'tokens', + ], + 'setters': [ + 'set_account', + 'set_tokens', + ] + }, + 'TokenFeeScheduleUpdateTransactionBody': { + 'attributes': [ + 'token_id', + 'custom_fees', + ], + 'setters': [ + 'set_token_id', + 'set_custom_fees', + ] + }, + 'TokenFreezeAccountTransactionBody': { + 'attributes': [ + 'token', + 'account', + ], + 'setters': [ + 'set_token', + 'set_account', + ] + }, + 'TokenGetInfoQuery': { + 'attributes': [ + 'header', + 'token', + ], + 'setters': [ + 'set_header', + 'set_token', + ] + }, + 'TokenGetInfoResponse': { + 'attributes': [ + 'header', + 'tokenInfo', + ], + 'setters': [ + 'set_header', + 'set_tokenInfo', + ] + }, + 'TokenGetNftInfoQuery': { + 'attributes': [ + 'header', + 'nftID', + ], + 'setters': [ + 'set_header', + 'set_nftID', + ] + }, + 'TokenGetNftInfoResponse': { + 'attributes': [ + 'header', + 'nft', + ], + 'setters': [ + 'set_header', + 'set_nft', + ] + }, + 'TokenGrantKycTransactionBody': { + 'attributes': [ + 'token', + 'account', + ], + 'setters': [ + 'set_token', + 'set_account', + ] + }, + 'TokenID': { + 'attributes': [ + 'shardNum', + 'realmNum', + 'tokenNum', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + 'set_tokenNum', + ] + }, + 'TokenInfo': { + 'attributes': [ + 'tokenId', + 'name', + 'symbol', + 'decimals', + 'totalSupply', + 'treasury', + 'adminKey', + 'kycKey', + 'freezeKey', + 'wipeKey', + 'supplyKey', + 'defaultFreezeStatus', + 'defaultKycStatus', + 'deleted', + 'autoRenewAccount', + 'autoRenewPeriod', + 'expiry', + 'memo', + 'tokenType', + 'supplyType', + 'maxSupply', + 'fee_schedule_key', + 'custom_fees', + 'pause_key', + 'pause_status', + 'ledger_id', + 'metadata', + 'metadata_key', + ], + 'setters': [ + 'set_tokenId', + 'set_name', + 'set_symbol', + 'set_decimals', + 'set_totalSupply', + 'set_treasury', + 'set_adminKey', + 'set_kycKey', + 'set_freezeKey', + 'set_wipeKey', + 'set_supplyKey', + 'set_defaultFreezeStatus', + 'set_defaultKycStatus', + 'set_deleted', + 'set_autoRenewAccount', + 'set_autoRenewPeriod', + 'set_expiry', + 'set_memo', + 'set_tokenType', + 'set_supplyType', + 'set_maxSupply', + 'set_fee_schedule_key', + 'set_custom_fees', + 'set_pause_key', + 'set_pause_status', + 'set_ledger_id', + 'set_metadata', + 'set_metadata_key', + ] + }, + 'TokenMintTransactionBody': { + 'attributes': [ + 'token', + 'amount', + 'metadata', + ], + 'setters': [ + 'set_token', + 'set_amount', + 'set_metadata', + ] + }, + 'TokenNftInfo': { + 'attributes': [ + 'nftID', + 'accountID', + 'creationTime', + 'metadata', + 'ledger_id', + 'spender_id', + ], + 'setters': [ + 'set_nftID', + 'set_accountID', + 'set_creationTime', + 'set_metadata', + 'set_ledger_id', + 'set_spender_id', + ] + }, + 'TokenPauseTransactionBody': { + 'attributes': [ + 'token', + ], + 'setters': [ + 'set_token', + ] + }, + 'TokenRelationship': { + 'attributes': [ + 'tokenId', + 'symbol', + 'balance', + 'kycStatus', + 'freezeStatus', + 'decimals', + 'automatic_association', + ], + 'setters': [ + 'set_tokenId', + 'set_symbol', + 'set_balance', + 'set_kycStatus', + 'set_freezeStatus', + 'set_decimals', + 'set_automatic_association', + ] + }, + 'TokenRevokeKycTransactionBody': { + 'attributes': [ + 'token', + 'account', + ], + 'setters': [ + 'set_token', + 'set_account', + ] + }, + 'TokenTransferList': { + 'attributes': [ + 'token', + 'transfers', + 'nftTransfers', + 'expected_decimals', + ], + 'setters': [ + 'set_token', + 'set_transfers', + 'set_nftTransfers', + 'set_expected_decimals', + ] + }, + 'TokenUnfreezeAccountTransactionBody': { + 'attributes': [ + 'token', + 'account', + ], + 'setters': [ + 'set_token', + 'set_account', + ] + }, + 'TokenUpdateNftsTransactionBody': { + 'attributes': [ + 'token', + 'serial_numbers', + 'metadata', + ], + 'setters': [ + 'set_token', + 'set_serial_numbers', + 'set_metadata', + ] + }, + 'TokenUpdateTransactionBody': { + 'attributes': [ + 'token', + 'symbol', + 'name', + 'treasury', + 'adminKey', + 'kycKey', + 'freezeKey', + 'wipeKey', + 'supplyKey', + 'autoRenewAccount', + 'autoRenewPeriod', + 'expiry', + 'memo', + 'fee_schedule_key', + 'pause_key', + 'metadata', + 'metadata_key', + 'key_verification_mode', + ], + 'setters': [ + 'set_token', + 'set_symbol', + 'set_name', + 'set_treasury', + 'set_adminKey', + 'set_kycKey', + 'set_freezeKey', + 'set_wipeKey', + 'set_supplyKey', + 'set_autoRenewAccount', + 'set_autoRenewPeriod', + 'set_expiry', + 'set_memo', + 'set_fee_schedule_key', + 'set_pause_key', + 'set_metadata', + 'set_metadata_key', + 'set_key_verification_mode', + ] + }, + 'TokenWipeAccountTransactionBody': { + 'attributes': [ + 'token', + 'account', + 'amount', + 'serialNumbers', + ], + 'setters': [ + 'set_token', + 'set_account', + 'set_amount', + 'set_serialNumbers', + ] + }, + 'TopicID': { + 'attributes': [ + 'shardNum', + 'realmNum', + 'topicNum', + ], + 'setters': [ + 'set_shardNum', + 'set_realmNum', + 'set_topicNum', + ] + }, + 'Transaction': { + 'attributes': [ + 'body', + 'sigs', + 'sigMap', + 'bodyBytes', + 'signedTransactionBytes', + ], + 'setters': [ + 'set_body', + 'set_sigs', + 'set_sigMap', + 'set_bodyBytes', + 'set_signedTransactionBytes', + ] + }, + 'TransactionBody': { + 'attributes': [ + 'transactionID', + 'nodeAccountID', + 'transactionFee', + 'transactionValidDuration', + 'generateRecord', + 'memo', + 'batch_key', + 'contractCall', + 'contractCreateInstance', + 'contractUpdateInstance', + 'cryptoAddLiveHash', + 'cryptoCreateAccount', + 'cryptoDelete', + 'cryptoDeleteLiveHash', + 'cryptoTransfer', + 'cryptoUpdateAccount', + 'fileAppend', + 'fileCreate', + 'fileDelete', + 'fileUpdate', + 'systemDelete', + 'systemUndelete', + 'contractDeleteInstance', + 'freeze', + 'consensusCreateTopic', + 'consensusUpdateTopic', + 'consensusDeleteTopic', + 'consensusSubmitMessage', + 'uncheckedSubmit', + 'tokenCreation', + 'tokenFreeze', + 'tokenUnfreeze', + 'tokenGrantKyc', + 'tokenRevokeKyc', + 'tokenDeletion', + 'tokenUpdate', + 'tokenMint', + 'tokenBurn', + 'tokenWipe', + 'tokenAssociate', + 'tokenDissociate', + 'scheduleCreate', + 'scheduleDelete', + 'scheduleSign', + 'token_fee_schedule_update', + 'token_pause', + 'token_unpause', + 'cryptoApproveAllowance', + 'cryptoDeleteAllowance', + 'ethereumTransaction', + 'node_stake_update', + 'util_prng', + 'token_update_nfts', + 'nodeCreate', + 'nodeUpdate', + 'nodeDelete', + 'tokenReject', + 'tokenAirdrop', + 'tokenCancelAirdrop', + 'tokenClaimAirdrop', + 'state_signature_transaction', + 'hints_preprocessing_vote', + 'hints_key_publication', + 'hints_partial_signature', + 'history_proof_signature', + 'history_proof_key_publication', + 'history_proof_vote', + 'crs_publication', + 'atomic_batch', + 'lambda_sstore', + 'hook_dispatch', + 'max_custom_fees', + ], + 'setters': [ + 'set_transactionID', + 'set_nodeAccountID', + 'set_transactionFee', + 'set_transactionValidDuration', + 'set_generateRecord', + 'set_memo', + 'set_batch_key', + 'set_contractCall', + 'set_contractCreateInstance', + 'set_contractUpdateInstance', + 'set_cryptoAddLiveHash', + 'set_cryptoCreateAccount', + 'set_cryptoDelete', + 'set_cryptoDeleteLiveHash', + 'set_cryptoTransfer', + 'set_cryptoUpdateAccount', + 'set_fileAppend', + 'set_fileCreate', + 'set_fileDelete', + 'set_fileUpdate', + 'set_systemDelete', + 'set_systemUndelete', + 'set_contractDeleteInstance', + 'set_freeze', + 'set_consensusCreateTopic', + 'set_consensusUpdateTopic', + 'set_consensusDeleteTopic', + 'set_consensusSubmitMessage', + 'set_uncheckedSubmit', + 'set_tokenCreation', + 'set_tokenFreeze', + 'set_tokenUnfreeze', + 'set_tokenGrantKyc', + 'set_tokenRevokeKyc', + 'set_tokenDeletion', + 'set_tokenUpdate', + 'set_tokenMint', + 'set_tokenBurn', + 'set_tokenWipe', + 'set_tokenAssociate', + 'set_tokenDissociate', + 'set_scheduleCreate', + 'set_scheduleDelete', + 'set_scheduleSign', + 'set_token_fee_schedule_update', + 'set_token_pause', + 'set_token_unpause', + 'set_cryptoApproveAllowance', + 'set_cryptoDeleteAllowance', + 'set_ethereumTransaction', + 'set_node_stake_update', + 'set_util_prng', + 'set_token_update_nfts', + 'set_nodeCreate', + 'set_nodeUpdate', + 'set_nodeDelete', + 'set_tokenReject', + 'set_tokenAirdrop', + 'set_tokenCancelAirdrop', + 'set_tokenClaimAirdrop', + 'set_state_signature_transaction', + 'set_hints_preprocessing_vote', + 'set_hints_key_publication', + 'set_hints_partial_signature', + 'set_history_proof_signature', + 'set_history_proof_key_publication', + 'set_history_proof_vote', + 'set_crs_publication', + 'set_atomic_batch', + 'set_lambda_sstore', + 'set_hook_dispatch', + 'set_max_custom_fees', + ] + }, + 'TransactionFeeSchedule': { + 'attributes': [ + 'hederaFunctionality', + 'feeData', + 'fees', + ], + 'setters': [ + 'set_hederaFunctionality', + 'set_feeData', + 'set_fees', + ] + }, + 'TransactionID': { + 'attributes': [ + 'transactionValidStart', + 'accountID', + 'scheduled', + 'nonce', + ], + 'setters': [ + 'set_transactionValidStart', + 'set_accountID', + 'set_scheduled', + 'set_nonce', + ] + }, + 'TransactionRecord': { + 'attributes': [ + 'receipt', + 'transactionHash', + 'consensusTimestamp', + 'transactionID', + 'memo', + 'transactionFee', + 'contractCallResult', + 'contractCreateResult', + 'transferList', + 'tokenTransferLists', + 'scheduleRef', + 'assessed_custom_fees', + 'automatic_token_associations', + 'parent_consensus_timestamp', + 'alias', + 'ethereum_hash', + 'paid_staking_rewards', + 'prng_bytes', + 'prng_number', + 'evm_address', + 'new_pending_airdrops', + ], + 'setters': [ + 'set_receipt', + 'set_transactionHash', + 'set_consensusTimestamp', + 'set_transactionID', + 'set_memo', + 'set_transactionFee', + 'set_contractCallResult', + 'set_contractCreateResult', + 'set_transferList', + 'set_tokenTransferLists', + 'set_scheduleRef', + 'set_assessed_custom_fees', + 'set_automatic_token_associations', + 'set_parent_consensus_timestamp', + 'set_alias', + 'set_ethereum_hash', + 'set_paid_staking_rewards', + 'set_prng_bytes', + 'set_prng_number', + 'set_evm_address', + 'set_new_pending_airdrops', + ] + }, + 'TransferList': { + 'attributes': [ + 'accountAmounts', + ], + 'setters': [ + 'set_accountAmounts', + ] + }, +} + +# Auto-generated proto enums + +proto_enums = { +} diff --git a/scripts/src_vs_proto/steps_4_token_classes_proto_errors.log b/scripts/src_vs_proto/steps_4_token_classes_proto_errors.log new file mode 100644 index 000000000..ef5c73dad --- /dev/null +++ b/scripts/src_vs_proto/steps_4_token_classes_proto_errors.log @@ -0,0 +1,5 @@ +# Errors encountered during proto extraction + +hiero_sdk_python.hapi.services.basic_types_pb2.TokenFreezeStatus: 'google._upb._message.EnumDescriptor' object has no attribute 'fields' +hiero_sdk_python.hapi.services.basic_types_pb2.TokenFreezeStatus: 'google._upb._message.EnumDescriptor' object has no attribute 'fields' +hiero_sdk_python.hapi.services.basic_types_pb2.TokenKycStatus: 'google._upb._message.EnumDescriptor' object has no attribute 'fields' diff --git a/scripts/src_vs_proto/steps_5_mapping_src_proto.py b/scripts/src_vs_proto/steps_5_mapping_src_proto.py new file mode 100644 index 000000000..d23916c80 --- /dev/null +++ b/scripts/src_vs_proto/steps_5_mapping_src_proto.py @@ -0,0 +1,135 @@ +""" +Step 5: Build a mapping between token source classes and proto classes. + +āœ… Generates: +- Full imports for Pylance (no missing references) +- Clean TRANSACTIONS dict mapping token classes → proto classes + +Output: steps_5_proto_to_src.py +""" + +import sys +from pathlib import Path +from collections import defaultdict + +# Paths +STEP1_FILE = Path(__file__).parent / "steps_1_extracted_token_classes_with_paths.py" +STEP2_FILE = Path(__file__).parent / "steps_2_extracted_token_proto_imports.py" +OUTPUT_FILE = Path(__file__).parent / "steps_5_proto_to_src.py" + + +# --------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------- +def load_imports(filepath: Path): + """Return {class_name: module_name} from step 1.""" + classes = {} + with open(filepath, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if line.startswith("from hiero_sdk_python.tokens."): + # from hiero_sdk_python.tokens.token_freeze_transaction import TokenFreezeTransaction + parts = line.split() + module = parts[1].replace("hiero_sdk_python.tokens.", "") + cls = parts[-1] + classes[cls] = module + return classes + + +def load_proto_imports(filepath: Path): + """Return {token_module: proto_path} from step 2.""" + protos = {} + current_module = None + with open(filepath, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if line.startswith("#") and line.endswith(".py"): + current_module = line.replace("#", "").replace(".py", "").strip() + elif line.startswith("import ") and current_module: + proto_path = line.replace("import ", "").strip() + protos[current_module] = proto_path + return protos + + +def build_mapping(classes, protos): + """Build the mapping of class → proto reference.""" + mapping = {} + proto_imports = set() + token_imports = set() + matched, unmatched = [], [] + + for cls, module in sorted(classes.items()): + token_imports.add(module) + proto_path = protos.get(module) + if not proto_path: + mapping[cls] = {"cls": f"{module}.{cls}", "proto_cls": None} + unmatched.append(cls) + continue + + parts = proto_path.split(".") + # Handle both cases: *_pb2 or *_pb2.ClassName + if len(parts) > 1 and parts[-1][0].isupper(): + proto_mod = ".".join(parts[:-1]) + proto_cls = parts[-1] + proto_ref = f"{proto_mod.split('.')[-1]}.{proto_cls}" + proto_imports.add(proto_mod) + else: + proto_mod = proto_path + proto_ref = proto_mod.split(".")[-1] + proto_imports.add(proto_mod) + + mapping[cls] = { + "cls": f"{module}.{cls}", + "proto_cls": proto_ref, + } + matched.append(cls) + + return mapping, token_imports, proto_imports, matched, unmatched + + +# --------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------- +def main(): + classes = load_imports(STEP1_FILE) + protos = load_proto_imports(STEP2_FILE) + mapping, token_imports, proto_imports, matched, unmatched = build_mapping(classes, protos) + + OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True) + with open(OUTPUT_FILE, "w", encoding="utf-8") as f: + f.write("# Auto-generated: mapping of src token classes to proto classes\n") + f.write("# This file includes imports for IDE/Pylance support.\n\n") + + # Token module imports + for mod in sorted(token_imports): + f.write(f"from hiero_sdk_python.tokens import {mod}\n") + f.write("\n") + + # Proto imports + for proto in sorted(proto_imports): + short = proto.split(".")[-1] + f.write(f"from hiero_sdk_python.hapi.services import {short}\n") + f.write("\n") + + f.write("TRANSACTIONS = {\n") + for cls, data in sorted(mapping.items()): + proto_str = "None" if not data["proto_cls"] else data["proto_cls"] + f.write( + f" '{cls}': {{'cls': {data['cls']}, 'proto_cls': {proto_str}}},\n" + ) + f.write("}\n") + + print(f"\nāœ… Mapping written to: {OUTPUT_FILE}") + print(f"Total token classes: {len(classes)}") + print(f"Matched: {len(matched)}") + print(f"Unmatched: {len(unmatched)}") + + if unmatched: + print("\nāš ļø Unmatched classes:") + for name in unmatched: + print(f" - {name}") + + +if __name__ == "__main__": + main() + diff --git a/scripts/src_vs_proto/steps_5_proto_to_src.py b/scripts/src_vs_proto/steps_5_proto_to_src.py new file mode 100644 index 000000000..efb5a6f18 --- /dev/null +++ b/scripts/src_vs_proto/steps_5_proto_to_src.py @@ -0,0 +1,114 @@ +# Auto-generated: mapping of src token classes to proto classes +# This file includes imports for IDE/Pylance support. + +from hiero_sdk_python.tokens import abstract_token_transfer_transaction +from hiero_sdk_python.tokens import custom_fee +from hiero_sdk_python.tokens import custom_fixed_fee +from hiero_sdk_python.tokens import custom_fractional_fee +from hiero_sdk_python.tokens import custom_royalty_fee +from hiero_sdk_python.tokens import fee_assessment_method +from hiero_sdk_python.tokens import hbar_allowance +from hiero_sdk_python.tokens import hbar_transfer +from hiero_sdk_python.tokens import nft_id +from hiero_sdk_python.tokens import supply_type +from hiero_sdk_python.tokens import token_airdrop_claim +from hiero_sdk_python.tokens import token_airdrop_pending_id +from hiero_sdk_python.tokens import token_airdrop_pending_record +from hiero_sdk_python.tokens import token_airdrop_transaction +from hiero_sdk_python.tokens import token_airdrop_transaction_cancel +from hiero_sdk_python.tokens import token_allowance +from hiero_sdk_python.tokens import token_associate_transaction +from hiero_sdk_python.tokens import token_burn_transaction +from hiero_sdk_python.tokens import token_create_transaction +from hiero_sdk_python.tokens import token_delete_transaction +from hiero_sdk_python.tokens import token_dissociate_transaction +from hiero_sdk_python.tokens import token_fee_schedule_update_transaction +from hiero_sdk_python.tokens import token_freeze_status +from hiero_sdk_python.tokens import token_freeze_transaction +from hiero_sdk_python.tokens import token_grant_kyc_transaction +from hiero_sdk_python.tokens import token_id +from hiero_sdk_python.tokens import token_info +from hiero_sdk_python.tokens import token_key_validation +from hiero_sdk_python.tokens import token_kyc_status +from hiero_sdk_python.tokens import token_mint_transaction +from hiero_sdk_python.tokens import token_nft_allowance +from hiero_sdk_python.tokens import token_nft_info +from hiero_sdk_python.tokens import token_nft_transfer +from hiero_sdk_python.tokens import token_pause_status +from hiero_sdk_python.tokens import token_pause_transaction +from hiero_sdk_python.tokens import token_reject_transaction +from hiero_sdk_python.tokens import token_relationship +from hiero_sdk_python.tokens import token_revoke_kyc_transaction +from hiero_sdk_python.tokens import token_transfer +from hiero_sdk_python.tokens import token_transfer_list +from hiero_sdk_python.tokens import token_type +from hiero_sdk_python.tokens import token_unfreeze_transaction +from hiero_sdk_python.tokens import token_unpause_transaction +from hiero_sdk_python.tokens import token_update_nfts_transaction +from hiero_sdk_python.tokens import token_update_transaction +from hiero_sdk_python.tokens import token_wipe_transaction + +from hiero_sdk_python.hapi.services import basic_types_pb2 +from hiero_sdk_python.hapi.services import crypto_approve_allowance_pb2 +from hiero_sdk_python.hapi.services import crypto_delete_allowance_pb2 +from hiero_sdk_python.hapi.services import custom_fees_pb2 +from hiero_sdk_python.hapi.services import schedulable_transaction_body_pb2 +from hiero_sdk_python.hapi.services import token_get_info_pb2 +from hiero_sdk_python.hapi.services import token_get_nft_info_pb2 +from hiero_sdk_python.hapi.services import token_update_nfts_pb2 +from hiero_sdk_python.hapi.services import transaction_pb2 +from hiero_sdk_python.hapi.services import transaction_record_pb2 + +TRANSACTIONS = { + 'AbstractTokenTransferTransaction': {'cls': abstract_token_transfer_transaction.AbstractTokenTransferTransaction, 'proto_cls': basic_types_pb2}, + 'CustomFee': {'cls': custom_fee.CustomFee, 'proto_cls': None}, + 'CustomFixedFee': {'cls': custom_fixed_fee.CustomFixedFee, 'proto_cls': custom_fees_pb2}, + 'CustomFractionalFee': {'cls': custom_fractional_fee.CustomFractionalFee, 'proto_cls': None}, + 'CustomRoyaltyFee': {'cls': custom_royalty_fee.CustomRoyaltyFee, 'proto_cls': None}, + 'FeeAssessmentMethod': {'cls': fee_assessment_method.FeeAssessmentMethod, 'proto_cls': None}, + 'HbarAllowance': {'cls': hbar_allowance.HbarAllowance, 'proto_cls': crypto_approve_allowance_pb2.CryptoAllowance}, + 'HbarTransfer': {'cls': hbar_transfer.HbarTransfer, 'proto_cls': basic_types_pb2}, + 'NftId': {'cls': nft_id.NftId, 'proto_cls': basic_types_pb2}, + 'PendingAirdropId': {'cls': token_airdrop_pending_id.PendingAirdropId, 'proto_cls': basic_types_pb2}, + 'PendingAirdropRecord': {'cls': token_airdrop_pending_record.PendingAirdropRecord, 'proto_cls': transaction_record_pb2}, + 'SupplyType': {'cls': supply_type.SupplyType, 'proto_cls': None}, + 'TokenAirdropTransaction': {'cls': token_airdrop_transaction.TokenAirdropTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenAllowance': {'cls': token_allowance.TokenAllowance, 'proto_cls': crypto_approve_allowance_pb2.TokenAllowance}, + 'TokenAssociateTransaction': {'cls': token_associate_transaction.TokenAssociateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenBurnTransaction': {'cls': token_burn_transaction.TokenBurnTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenCancelAirdropTransaction': {'cls': token_airdrop_transaction_cancel.TokenCancelAirdropTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenClaimAirdropTransaction': {'cls': token_airdrop_claim.TokenClaimAirdropTransaction, 'proto_cls': transaction_pb2}, + 'TokenCreateTransaction': {'cls': token_create_transaction.TokenCreateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenCreateValidator': {'cls': token_create_transaction.TokenCreateValidator, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenDeleteTransaction': {'cls': token_delete_transaction.TokenDeleteTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenDissociateTransaction': {'cls': token_dissociate_transaction.TokenDissociateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenFeeScheduleUpdateTransaction': {'cls': token_fee_schedule_update_transaction.TokenFeeScheduleUpdateTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenFreezeStatus': {'cls': token_freeze_status.TokenFreezeStatus, 'proto_cls': basic_types_pb2.TokenFreezeStatus}, + 'TokenFreezeTransaction': {'cls': token_freeze_transaction.TokenFreezeTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenGrantKycTransaction': {'cls': token_grant_kyc_transaction.TokenGrantKycTransaction, 'proto_cls': transaction_pb2}, + 'TokenId': {'cls': token_id.TokenId, 'proto_cls': basic_types_pb2}, + 'TokenInfo': {'cls': token_info.TokenInfo, 'proto_cls': token_get_info_pb2}, + 'TokenKeyValidation': {'cls': token_key_validation.TokenKeyValidation, 'proto_cls': basic_types_pb2}, + 'TokenKeys': {'cls': token_create_transaction.TokenKeys, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenKycStatus': {'cls': token_kyc_status.TokenKycStatus, 'proto_cls': basic_types_pb2}, + 'TokenMintTransaction': {'cls': token_mint_transaction.TokenMintTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenNftAllowance': {'cls': token_nft_allowance.TokenNftAllowance, 'proto_cls': crypto_delete_allowance_pb2.NftRemoveAllowance}, + 'TokenNftInfo': {'cls': token_nft_info.TokenNftInfo, 'proto_cls': token_get_nft_info_pb2}, + 'TokenNftTransfer': {'cls': token_nft_transfer.TokenNftTransfer, 'proto_cls': basic_types_pb2}, + 'TokenParams': {'cls': token_create_transaction.TokenParams, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenPauseStatus': {'cls': token_pause_status.TokenPauseStatus, 'proto_cls': basic_types_pb2}, + 'TokenPauseTransaction': {'cls': token_pause_transaction.TokenPauseTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenRejectTransaction': {'cls': token_reject_transaction.TokenRejectTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenRelationship': {'cls': token_relationship.TokenRelationship, 'proto_cls': basic_types_pb2.TokenKycStatus}, + 'TokenRevokeKycTransaction': {'cls': token_revoke_kyc_transaction.TokenRevokeKycTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenTransfer': {'cls': token_transfer.TokenTransfer, 'proto_cls': basic_types_pb2}, + 'TokenTransferList': {'cls': token_transfer_list.TokenTransferList, 'proto_cls': basic_types_pb2}, + 'TokenType': {'cls': token_type.TokenType, 'proto_cls': None}, + 'TokenUnfreezeTransaction': {'cls': token_unfreeze_transaction.TokenUnfreezeTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, + 'TokenUnpauseTransaction': {'cls': token_unpause_transaction.TokenUnpauseTransaction, 'proto_cls': transaction_pb2.TransactionBody}, + 'TokenUpdateKeys': {'cls': token_update_transaction.TokenUpdateKeys, 'proto_cls': transaction_pb2}, + 'TokenUpdateNftsTransaction': {'cls': token_update_nfts_transaction.TokenUpdateNftsTransaction, 'proto_cls': token_update_nfts_pb2}, + 'TokenUpdateParams': {'cls': token_update_transaction.TokenUpdateParams, 'proto_cls': transaction_pb2}, + 'TokenUpdateTransaction': {'cls': token_update_transaction.TokenUpdateTransaction, 'proto_cls': transaction_pb2}, + 'TokenWipeTransaction': {'cls': token_wipe_transaction.TokenWipeTransaction, 'proto_cls': schedulable_transaction_body_pb2.SchedulableTransactionBody}, +} diff --git a/scripts/src_vs_proto/steps_6_token_burn.py b/scripts/src_vs_proto/steps_6_token_burn.py new file mode 100644 index 000000000..fa0f80deb --- /dev/null +++ b/scripts/src_vs_proto/steps_6_token_burn.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +""" +Step 6 (Fixed Dynamic): Compare *all* token transaction SDK classes with proto attributes. +Now properly finds nested entries like token_burn_transaction.TokenBurnTransaction. +""" + +from pathlib import Path +import importlib.util +import sys +import re + +STEP3_FILE = Path(__file__).resolve().parent / "steps_3_token_classes_info_readable.py" +STEP4_FILE = Path(__file__).resolve().parent / "steps_4_token_classes_proto_attributes.py" + +RED = "\033[91m" +GREEN = "\033[92m" +YELLOW = "\033[93m" +BLUE = "\033[94m" +RESET = "\033[0m" + + +def load_module(file_path: Path, module_name: str): + if not file_path.exists(): + raise FileNotFoundError(f"File not found: {file_path}") + spec = importlib.util.spec_from_file_location(module_name, file_path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module + + +def camel_to_snake(name: str) -> str: + s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1) + return s2.lower() + + +PROTO_TO_SDK_MAP = { + "token": "token_id", + "tokens": "token_ids", + "serialNumbers": "serials", + "account": "account_id", + "set_account": "set_account_id", +} + + +def map_proto_to_sdk(proto_attr: str) -> str: + return PROTO_TO_SDK_MAP.get(proto_attr, camel_to_snake(proto_attr)) + + +def predicted_proto_setters(proto_attrs): + return [f"set_{map_proto_to_sdk(a)}" for a in proto_attrs] + + +def find_proto_class_name(sdk_class_name: str, proto_mappings: dict): + base = sdk_class_name.replace("Transaction", "TransactionBody") + if base in proto_mappings: + return base + for proto_name in proto_mappings.keys(): + if proto_name.lower().startswith(sdk_class_name.lower().replace("transaction", "")): + return proto_name + return None + + +def collect_sdk_classes(step3_module): + """ + Recursively collect dict objects representing SDK classes + from the parsed Step 3 module. + """ + sdk_classes = {} + for name, val in vars(step3_module).items(): + if isinstance(val, dict) and "attributes" in val and "setters" in val: + sdk_classes[name] = val + elif isinstance(val, type(step3_module)): # submodule-like object + for subname, subval in vars(val).items(): + if isinstance(subval, dict) and "attributes" in subval: + sdk_classes[f"{name}.{subname}"] = subval + return sdk_classes + + +if __name__ == "__main__": + step3_module = load_module(STEP3_FILE, "step3_token_classes") + step4_module = load_module(STEP4_FILE, "step4_proto_attributes") + proto_mappings = getattr(step4_module, "proto_mappings", {}) + + print("\nšŸ“¦ Proto mappings available:") + for k in sorted(proto_mappings.keys()): + print(" -", k) + + sdk_classes = collect_sdk_classes(step3_module) + print(f"\nšŸ” Found {len(sdk_classes)} SDK token transaction classes to compare.\n") + + for full_cls_name, sdk_class_info in sorted(sdk_classes.items()): + sdk_class_name = full_cls_name.split(".")[-1] + proto_class_name = find_proto_class_name(sdk_class_name, proto_mappings) + + if not proto_class_name: + print(f"\nāš ļø No proto mapping found for SDK class {sdk_class_name}") + continue + + proto_info = proto_mappings.get(proto_class_name, {"attributes": [], "setters": []}) + actual_proto_attrs = [map_proto_to_sdk(a) for a in proto_info["attributes"]] + predicted_setters = predicted_proto_setters(proto_info["attributes"]) + + sdk_attrs = sdk_class_info.get("attributes", []) + sdk_methods = sdk_class_info.get("setters", []) + sdk_class_info.get("other_methods", []) + + missing_attrs = [a for a in actual_proto_attrs if a not in sdk_attrs] + missing_setters = [s for s in predicted_setters if s not in sdk_methods] + extra_sdk_methods = [m for m in sdk_methods if m not in predicted_setters] + + print(f"\nšŸ’  {sdk_class_name} vs {proto_class_name}") + print(f"{GREEN}SDK Attributes: {sdk_attrs}{RESET}") + print(f"{GREEN}SDK Setters: {sdk_class_info.get('setters', [])}{RESET}") + print("āœ… SDK Other Methods:", sdk_class_info.get("other_methods", [])) + print("šŸ“¦ Actual Proto Attributes:", actual_proto_attrs) + print("šŸ“¦ Predicted Proto Setters:", predicted_setters) + + if missing_attrs or missing_setters: + print(f"{RED}āš ļø Missing in SDK:{RESET}") + if missing_attrs: + print(f"{RED} - Attributes: {missing_attrs}{RESET}") + if missing_setters: + print(f"{RED} - Predicted Setters / Methods: {missing_setters}{RESET}") + else: + print(f"{GREEN}āœ… SDK fully covers proto attributes and predicted setters{RESET}") + + if extra_sdk_methods: + print("✨ Extra SDK methods beyond proto setters:", extra_sdk_methods)