From 459a09ce37f50025de0f9da54c101fa65f70b777 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 5 Feb 2024 14:52:05 +0200 Subject: [PATCH 1/5] implement token management transactions parser --- multiversx_sdk/core/errors.py | 5 + .../relayed_transactions_factory_test.py | 1 + .../transaction_outcome_parsers/resources.py | 49 ++ ..._management_transactions_outcome_parser.py | 255 +++++++++++ ...gement_transactions_outcome_parser_test.py | 430 ++++++++++++++++++ ...ement_transactions_outcome_parser_types.py | 110 +++++ 6 files changed, 850 insertions(+) create mode 100644 multiversx_sdk/core/transaction_outcome_parsers/resources.py create mode 100644 multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py create mode 100644 multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py create mode 100644 multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py diff --git a/multiversx_sdk/core/errors.py b/multiversx_sdk/core/errors.py index 4e768d21..060c4c85 100644 --- a/multiversx_sdk/core/errors.py +++ b/multiversx_sdk/core/errors.py @@ -54,3 +54,8 @@ def __init__(self, message: str) -> None: class InvalidInnerTransactionError(Exception): def __init__(self, message: str) -> None: super().__init__(message) + + +class ParseTransactionOutcomeError(Exception): + def __init__(self, message: str) -> None: + super().__init__(message) diff --git a/multiversx_sdk/core/transaction_factories/relayed_transactions_factory_test.py b/multiversx_sdk/core/transaction_factories/relayed_transactions_factory_test.py index 3878f37a..9e1f629e 100644 --- a/multiversx_sdk/core/transaction_factories/relayed_transactions_factory_test.py +++ b/multiversx_sdk/core/transaction_factories/relayed_transactions_factory_test.py @@ -228,4 +228,5 @@ def test_compute_relayed_v2_transaction(self): assert relayed_transaction.version == 2 assert relayed_transaction.options == 0 + assert relayed_transaction.gas_limit == 60414500 assert relayed_transaction.data.decode() == "relayedTxV2@000000000000000000010000000000000000000000000000000000000002ffff@0f@676574436f6e7472616374436f6e666967@fc3ed87a51ee659f937c1a1ed11c1ae677e99629fae9cc289461f033e6514d1a8cfad1144ae9c1b70f28554d196bd6ba1604240c1c1dc19c959e96c1c3b62d0c" diff --git a/multiversx_sdk/core/transaction_outcome_parsers/resources.py b/multiversx_sdk/core/transaction_outcome_parsers/resources.py new file mode 100644 index 00000000..1d480390 --- /dev/null +++ b/multiversx_sdk/core/transaction_outcome_parsers/resources.py @@ -0,0 +1,49 @@ +from typing import List + + +class TransactionEvent: + def __init__(self, + address: str = "", + identifier: str = "", + topics: List[str] = [], + data: str = "") -> None: + self.address = address + self.identifier = identifier + self.topics = topics + self.data = data + + +class TransactionLogs: + def __init__(self, + address: str = "", + events: List[TransactionEvent] = []) -> None: + self.address = address + self.events = events + + +class SmartContractResult: + def __init__(self, + hash: str = "", + timestamp: int = 0, + sender: str = "", + receiver: str = "", + data: str = "", + original_tx_hash: str = "", + miniblock_hash: str = "", + logs: TransactionLogs = TransactionLogs()) -> None: + self.hash = hash + self.timestamp = timestamp + self.sender = sender + self.receiver = receiver + self.data = data + self.original_tx_hash = original_tx_hash + self.miniblock_hash = miniblock_hash + self.logs = logs + + +class TransactionOutcome: + def __init__(self, + transaction_results: List[SmartContractResult], + transaction_logs: TransactionLogs) -> None: + self.transaction_results = transaction_results + self.transaction_logs = transaction_logs diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py new file mode 100644 index 00000000..e80ff4e1 --- /dev/null +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py @@ -0,0 +1,255 @@ +import base64 +from typing import List + +from multiversx_sdk.core.address import Address +from multiversx_sdk.core.constants import DEFAULT_HRP +from multiversx_sdk.core.errors import ParseTransactionOutcomeError +from multiversx_sdk.core.transaction_outcome_parsers.resources import ( + TransactionEvent, TransactionOutcome) +from multiversx_sdk.core.transaction_outcome_parsers.token_management_transactions_outcome_parser_types import ( + AddQuantityOutcome, BurnOutcome, BurnQuantityOutcome, FreezeOutcome, + IssueFungibleOutcome, IssueNonFungibleOutcome, IssueSemiFungibleOutcome, + MintOutcome, NFTCreateOutcome, PauseOutcome, RegisterAndSetAllRolesOutcome, + RegisterMetaEsdtOutcome, SetSpecialRoleOutcome, UnFreezeOutcome, + UnPauseOutcome, UpdateAttributesOutcome, WipeOutcome) + + +class TokenManagementTransactionsOutcomeParser: + def __init__(self) -> None: + pass + + def parse_issue_fungible(self, transaction_outcome: TransactionOutcome) -> IssueFungibleOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "issue") + identifier = self.extract_token_identifier(event) + + return IssueFungibleOutcome(identifier) + + def parse_issue_non_fungible(self, transaction_outcome: TransactionOutcome) -> IssueNonFungibleOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "issueNonFungible") + identifier = self.extract_token_identifier(event) + + return IssueNonFungibleOutcome(identifier) + + def parse_issue_semi_fungible(self, transaction_outcome: TransactionOutcome) -> IssueSemiFungibleOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "issueSemiFungible") + identifier = self.extract_token_identifier(event) + + return IssueSemiFungibleOutcome(identifier) + + def parse_register_meta_esdt(self, transaction_outcome: TransactionOutcome) -> RegisterMetaEsdtOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "registerMetaESDT") + identifier = self.extract_token_identifier(event) + + return RegisterMetaEsdtOutcome(identifier) + + def parse_register_and_set_all_roles(self, transaction_outcome: TransactionOutcome) -> RegisterAndSetAllRolesOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + register_event = self.find_single_event_by_identifier(transaction_outcome, "registerAndSetAllRoles") + token_identifier = self.extract_token_identifier(register_event) + + set_role_event = self.find_single_event_by_identifier(transaction_outcome, "ESDTSetRole") + encoded_roles = set_role_event.topics[3:] + + roles: List[str] = [] + for role in encoded_roles: + hex_encoded_role = base64.b64decode(role).hex() + roles.append(bytes.fromhex(hex_encoded_role).decode()) + + return RegisterAndSetAllRolesOutcome(token_identifier, roles) + + def parse_set_burn_role_globally(self, transaction_outcome: TransactionOutcome) -> None: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + def parse_unset_burn_role_globally(self, transaction_outcome: TransactionOutcome) -> None: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + def parse_set_special_role(self, transaction_outcome: TransactionOutcome) -> SetSpecialRoleOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTSetRole") + user_address = event.address + token_identifier = self.extract_token_identifier(event) + + encoded_roles = event.topics[3:] + roles: List[str] = [] + + for role in encoded_roles: + hex_encoded_role = base64.b64decode(role).hex() + roles.append(bytes.fromhex(hex_encoded_role).decode()) + + return SetSpecialRoleOutcome(user_address, token_identifier, roles) + + def parse_nft_create(self, transaction_outcome: TransactionOutcome) -> NFTCreateOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTCreate") + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + amount = self.extract_amount(event) + + return NFTCreateOutcome(token_identifier, nonce, amount) + + def parse_local_mint(self, transaction_outcome: TransactionOutcome) -> MintOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTLocalMint") + user_address = event.address + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + minted_supply = self.extract_amount(event) + + return MintOutcome(user_address, token_identifier, nonce, minted_supply) + + def parse_local_burn(self, transaction_outcome: TransactionOutcome) -> BurnOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTLocalBurn") + user_address = event.address + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + burnt_supply = self.extract_amount(event) + + return BurnOutcome(user_address, token_identifier, nonce, burnt_supply) + + def parse_pause(self, transaction_outcome: TransactionOutcome) -> PauseOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTPause") + identifier = self.extract_token_identifier(event) + + return PauseOutcome(identifier) + + def parse_unpause(self, transaction_outcome: TransactionOutcome) -> UnPauseOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTUnPause") + identifier = self.extract_token_identifier(event) + + return UnPauseOutcome(identifier) + + def parse_freeze(self, transaction_outcome: TransactionOutcome) -> FreezeOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTFreeze") + user_address = self.extract_address(event) + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + balance = self.extract_amount(event) + + return FreezeOutcome(user_address, token_identifier, nonce, balance) + + def parse_unfreeze(self, transaction_outcome: TransactionOutcome) -> UnFreezeOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTUnFreeze") + user_address = self.extract_address(event) + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + balance = self.extract_amount(event) + + return UnFreezeOutcome(user_address, token_identifier, nonce, balance) + + def parse_wipe(self, transaction_outcome: TransactionOutcome) -> WipeOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTWipe") + user_address = self.extract_address(event) + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + balance = self.extract_amount(event) + + return WipeOutcome(user_address, token_identifier, nonce, balance) + + def parse_update_attributes(self, transaction_outcome: TransactionOutcome) -> UpdateAttributesOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTUpdateAttributes") + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + attributes = base64.b64decode(event.topics[3]) if event.topics[3] else b"" + + return UpdateAttributesOutcome(token_identifier, nonce, attributes) + + def parse_add_quantity(self, transaction_outcome: TransactionOutcome) -> AddQuantityOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTAddQuantity") + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + added_quantity = self.extract_amount(event) + + return AddQuantityOutcome(token_identifier, nonce, added_quantity) + + def parse_burn_quantity(self, transaction_outcome: TransactionOutcome) -> BurnQuantityOutcome: + self.ensure_no_error(transaction_outcome.transaction_logs.events) + + event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTBurn") + token_identifier = self.extract_token_identifier(event) + nonce = self.extract_nonce(event) + added_quantity = self.extract_amount(event) + + return BurnQuantityOutcome(token_identifier, nonce, added_quantity) + + def ensure_no_error(self, transaction_events: List[TransactionEvent]) -> None: + for event in transaction_events: + if event.identifier == "signalError": + hex_data = base64.b64decode(event.data or "").hex() + data = bytes.fromhex(hex_data).decode() + + hex_message = base64.b64decode(event.topics[1] or "").hex() + message = bytes.fromhex(hex_message).decode() + + raise ParseTransactionOutcomeError(f"encountered signalError: {message} ({bytes.fromhex(data[1:]).decode()})") + + def find_single_event_by_identifier(self, transaction_outcome: TransactionOutcome, identifier: str) -> TransactionEvent: + events = self.gather_all_events(transaction_outcome) + events_with_matching_id = [event for event in events if event.identifier == identifier] + + if len(events_with_matching_id) == 0: + raise ParseTransactionOutcomeError(f"cannot find event of type {identifier}") + + if len(events_with_matching_id) > 1: + raise ParseTransactionOutcomeError(f"found more than one event of type {identifier}") + + return events_with_matching_id[0] + + def gather_all_events(self, transaction_outcome: TransactionOutcome) -> List[TransactionEvent]: + all_events = [*transaction_outcome.transaction_logs.events] + + for result in transaction_outcome.transaction_results: + all_events.extend([*result.logs.events]) + + return all_events + + def extract_token_identifier(self, event: TransactionEvent) -> str: + if event.topics[0]: + hex_ticker = base64.b64decode(event.topics[0]).hex() + return bytes.fromhex(hex_ticker).decode() + return "" + + def extract_nonce(self, event: TransactionEvent) -> str: + if event.topics[1]: + hex_nonce = base64.b64decode(event.topics[1]).hex() + return str(int(hex_nonce, 16)) + return "" + + def extract_amount(self, event: TransactionEvent) -> str: + if event.topics[2]: + hex_amount = base64.b64decode(event.topics[2]).hex() + return str(int(hex_amount, 16)) + return "" + + def extract_address(self, event: TransactionEvent) -> str: + if event.topics[3]: + hex_address = base64.b64decode(event.topics[3]).hex() + return Address.new_from_hex(hex_address, DEFAULT_HRP).to_bech32() + return "" diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py new file mode 100644 index 00000000..c3c9f4e9 --- /dev/null +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py @@ -0,0 +1,430 @@ +import re + +import pytest + +from multiversx_sdk.core.errors import ParseTransactionOutcomeError +from multiversx_sdk.core.transaction_outcome_parsers.resources import ( + SmartContractResult, TransactionEvent, TransactionLogs, TransactionOutcome) +from multiversx_sdk.core.transaction_outcome_parsers.token_management_transactions_outcome_parser import \ + TokenManagementTransactionsOutcomeParser + + +class TestTokenManagementTransactionsOutcomeParser: + parser = TokenManagementTransactionsOutcomeParser() + + def test_ensure_error(self): + event = TransactionEvent( + address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + identifier="signalError", + topics=["Avk0jZ1kR+l9c76wQQoYcu4hvXPz+jxxTdqQeaCrbX8=", "dGlja2VyIG5hbWUgaXMgbm90IHZhbGlk"], + data="QDc1NzM2NTcyMjA2NTcyNzI2Zjcy" + ) + + with pytest.raises(ParseTransactionOutcomeError, match=re.escape("encountered signalError: ticker name is not valid (user error)")): + self.parser.ensure_no_error([event]) + + event = TransactionEvent( + address="erd1qqqqqqqqqqqqqpgq50wpucem6hvn0g8mwa670fznqz4n38h9d8ss564tlz", + identifier="writeLog", + topics=["ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gOTc4MzIwMDAsIGdhcyB1c2VkID0gNTg5MTc1"], + data="QDc1NzM2NTcyMjA2NTcyNzI2Zjcy" + ) + self.parser.ensure_no_error([event]) + + def test_parse_issue_fungible(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="issue", + topics=[ + "WlpaLTllZTg3ZA==", + "U0VDT05E", + "Wlpa", + "RnVuZ2libGVFU0RU", + "Ag==" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_issue_fungible(tx_results_and_logs) + assert outcome.identifier == "ZZZ-9ee87d" + + def test_parse_issue_non_fungible(self): + first_event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="upgradeProperties", + topics=["TkZULWYwMWQxZQ==", + "", + "Y2FuVXBncmFkZQ==", + "dHJ1ZQ==", + "Y2FuQWRkU3BlY2lhbFJvbGVz", + "dHJ1ZQ==" + ] + ) + + second_event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTSetBurnRoleForAll", + topics=["TkZULWYwMWQxZQ==", + "", + "", + "RVNEVFJvbGVCdXJuRm9yQWxs" + ] + ) + + third_event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="issueNonFungible", + topics=["TkZULWYwMWQxZQ==", + "TkZURVNU", + "TkZU", + "Tm9uRnVuZ2libGVFU0RU" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [first_event, second_event, third_event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_issue_non_fungible(tx_results_and_logs) + assert outcome.identifier == "NFT-f01d1e" + + def test_parse_issue_semi_fungible(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="issueSemiFungible", + topics=[ + "U0VNSUZORy0yYzZkOWY=", + "U0VNSQ==", + "U0VNSUZORw==", + "U2VtaUZ1bmdpYmxlRVNEVA==" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_issue_semi_fungible(tx_results_and_logs) + assert outcome.identifier == "SEMIFNG-2c6d9f" + + def test_parse_register_meta_esdt(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="registerMetaESDT", + topics=[ + "TUVUQVRFU1QtZTA1ZDEx", + "TUVURVNU", + "TUVUQVRFU1Q=", + "TWV0YUVTRFQ=" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_register_meta_esdt(tx_results_and_logs) + assert outcome.identifier == "METATEST-e05d11" + + def test_parse_register_and_set_all_roles(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="registerAndSetAllRoles", + topics=[ + "TE1BTy1kOWY4OTI=", + "TE1BTw==", + "TE1BTw==", + "RnVuZ2libGVFU0RU", + "Ag==" + ] + ) + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + + result_event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTSetRole", + topics=[ + "TE1BTy1kOWY4OTI=", + "", + "", + "RVNEVFJvbGVMb2NhbE1pbnQ=", + "RVNEVFJvbGVMb2NhbEJ1cm4=" + ] + ) + result_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [result_event]) + sc_result = SmartContractResult( + hash="777a55e938a76ae57c832e235ee6360c03f4d80e7fee10ed5e71a9ba293d1ea2", + timestamp=1706171168, + sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + receiver="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + data="RVNEVFNldFJvbGVANGM0ZDQxNGYyZDY0Mzk2NjM4MzkzMkA0NTUzNDQ1NDUyNmY2YzY1NGM2ZjYzNjE2YzRkNjk2ZTc0QDQ1NTM0NDU0NTI2ZjZjNjU0YzZmNjM2MTZjNDI3NTcyNmU=", + original_tx_hash="24b8bb9782c07092e8ce75b819690de58839f650a1287e27bbcc652c6d310664", + miniblock_hash="042835c44b06cf0cbf0d26e903873a71f1418598dbbf8dde5f5e1616498ffa03", + logs=result_log + ) + + tx_results_and_logs = TransactionOutcome([sc_result], tx_log) + outcome = self.parser.parse_register_and_set_all_roles(tx_results_and_logs) + + assert outcome.token_identifier == "LMAO-d9f892" + assert outcome.roles == ["ESDTRoleLocalMint", "ESDTRoleLocalBurn"] + + def test_parse_set_special_role(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTSetRole", + topics=[ + "TUVUQVRFU1QtZTA1ZDEx", + "", + "", + "RVNEVFJvbGVORlRDcmVhdGU=", + "RVNEVFJvbGVORlRBZGRRdWFudGl0eQ==", + "RVNEVFJvbGVORlRCdXJu" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_set_special_role(tx_results_and_logs) + assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" + assert outcome.token_identifier == "METATEST-e05d11" + assert outcome.roles == ["ESDTRoleNFTCreate", "ESDTRoleNFTAddQuantity", "ESDTRoleNFTBurn"] + + def test_parse_nft_create(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTNFTCreate", + topics=[ + "TkZULWYwMWQxZQ==", + "AQ==", + "AQ==", + "CAESAgABIuUBCAESCE5GVEZJUlNUGiA8NdfqyxqZpKDMqlN+8MwK4Qn0H2wrQCID5jO/uwcfXCDEEyouUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4RzJDaHR0cHM6Ly9pcGZzLmlvL2lwZnMvUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4Rzo9dGFnczo7bWV0YWRhdGE6UW1SY1A5NGtYcjV6WmpSR3ZpN21KNnVuN0xweFVoWVZSNFI0UnBpY3h6Z1lrdA==" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_nft_create(tx_results_and_logs) + assert outcome.token_identifier == "NFT-f01d1e" + assert outcome.nonce == "1" + assert outcome.initial_quantity == "1" + + def test_parse_local_mint(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTLocalMint", + topics=[ + "QUFBLTI5YzRjOQ==", + "", + "AYag" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_local_mint(tx_results_and_logs) + assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" + assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.nonce == "" + assert outcome.minted_supply == "100000" + + def test_parse_local_burn(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTLocalBurn", + topics=[ + "QUFBLTI5YzRjOQ==", + "", + "AYag" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_local_burn(tx_results_and_logs) + assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" + assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.nonce == "" + assert outcome.burnt_supply == "100000" + + def test_parse_pause(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTPause", + topics=[ + "QUFBLTI5YzRjOQ==" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_pause(tx_results_and_logs) + assert outcome.identifier == "AAA-29c4c9" + + def test_parse_unpause(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTUnPause", + topics=[ + "QUFBLTI5YzRjOQ==" + ] + ) + empty_result = SmartContractResult() + tx_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [event]) + tx_results_and_logs = TransactionOutcome([empty_result], tx_log) + + outcome = self.parser.parse_unpause(tx_results_and_logs) + assert outcome.identifier == "AAA-29c4c9" + + def test_parse_freeze(self): + event = TransactionEvent( + address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + identifier="ESDTFreeze", + topics=[ + "QUFBLTI5YzRjOQ==", + "", + "mJaA", + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" + ] + ) + tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) + sc_result = SmartContractResult( + hash="db39f9a792f56641aff6196d542d6aff437a6cb8b39c78c6b8b48b5a7830d714", + timestamp=1706177672, + sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", + original_tx_hash="1594205eff82126a8c34da4db46fcf6a7838b953317f6c1186b6a514be91895d", + miniblock_hash="a6a783d73d61d93041aa04382107f92a704fcfcf42567bdd7a045c7cd5c97c4a", + logs=tx_log + ) + tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) + + outcome = self.parser.parse_freeze(tx_results_and_logs) + assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.nonce == "" + assert outcome.balance == "10000000" + + def test_parse_unfreeze(self): + event = TransactionEvent( + address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + identifier="ESDTUnFreeze", + topics=[ + "QUFBLTI5YzRjOQ==", + "", + "mJaA", + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" + ] + ) + tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) + sc_result = SmartContractResult( + hash="db39f9a792f56641aff6196d542d6aff437a6cb8b39c78c6b8b48b5a7830d714", + timestamp=1706177672, + sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", + original_tx_hash="1594205eff82126a8c34da4db46fcf6a7838b953317f6c1186b6a514be91895d", + miniblock_hash="a6a783d73d61d93041aa04382107f92a704fcfcf42567bdd7a045c7cd5c97c4a", + logs=tx_log + ) + tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) + + outcome = self.parser.parse_unfreeze(tx_results_and_logs) + assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.nonce == "" + assert outcome.balance == "10000000" + + def test_parse_wipe(self): + event = TransactionEvent( + address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + identifier="ESDTWipe", + topics=[ + "QUFBLTI5YzRjOQ==", + "", + "mJaA", + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" + ] + ) + tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) + sc_result = SmartContractResult( + hash="6e5baf006ee871d856360ae7ac4e4e3b3ad756db532b218601f236461583c511", + timestamp=1706177672, + sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", + original_tx_hash="1594205eff82126a8c34da4db46fcf6a7838b953317f6c1186b6a514be91895d", + miniblock_hash="a6a783d73d61d93041aa04382107f92a704fcfcf42567bdd7a045c7cd5c97c4a", + logs=tx_log + ) + tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) + + outcome = self.parser.parse_wipe(tx_results_and_logs) + assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.nonce == "" + assert outcome.balance == "10000000" + + def test_parse_update_attributes(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTNFTUpdateAttributes", + topics=[ + "TkZULWYwMWQxZQ==", + "AQ==", + "", + "bWV0YWRhdGE6aXBmc0NJRC90ZXN0Lmpzb247dGFnczp0YWcxLHRhZzI=" + ] + ) + tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) + tx_result = SmartContractResult() + tx_results_and_logs = TransactionOutcome([tx_result], tx_log) + + outcome = self.parser.parse_update_attributes(tx_results_and_logs) + assert outcome.token_identifier == "NFT-f01d1e" + assert outcome.nonce == "1" + assert outcome.attributes.decode() == "metadata:ipfsCID/test.json;tags:tag1,tag2" + + def test_parse_add_quantity(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTNFTAddQuantity", + topics=[ + "U0VNSUZORy0yYzZkOWY=", + "AQ==", + "Cg==" + ] + ) + tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) + tx_result = SmartContractResult() + tx_results_and_logs = TransactionOutcome([tx_result], tx_log) + + outcome = self.parser.parse_add_quantity(tx_results_and_logs) + assert outcome.token_identifier == "SEMIFNG-2c6d9f" + assert outcome.nonce == "1" + assert outcome.added_quantity == "10" + + def test_parse_burn_quantity(self): + event = TransactionEvent( + address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", + identifier="ESDTNFTBurn", + topics=[ + "U0VNSUZORy0yYzZkOWY=", + "AQ==", + "EA==" + ] + ) + tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) + tx_result = SmartContractResult() + tx_results_and_logs = TransactionOutcome([tx_result], tx_log) + + outcome = self.parser.parse_burn_quantity(tx_results_and_logs) + assert outcome.token_identifier == "SEMIFNG-2c6d9f" + assert outcome.nonce == "1" + assert outcome.burnt_quantity == "16" diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py new file mode 100644 index 00000000..0b23e754 --- /dev/null +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py @@ -0,0 +1,110 @@ +from dataclasses import dataclass +from typing import List + + +@dataclass +class IssueFungibleOutcome: + identifier: str + + +@dataclass +class IssueNonFungibleOutcome: + identifier: str + + +@dataclass +class IssueSemiFungibleOutcome: + identifier: str + + +@dataclass +class RegisterMetaEsdtOutcome: + identifier: str + + +@dataclass +class RegisterAndSetAllRolesOutcome: + token_identifier: str + roles: List[str] + + +@dataclass +class SetSpecialRoleOutcome: + user_address: str + token_identifier: str + roles: List[str] + + +@dataclass +class NFTCreateOutcome: + token_identifier: str + nonce: str + initial_quantity: str + + +@dataclass +class MintOutcome: + user_address: str + token_identifier: str + nonce: str + minted_supply: str + + +@dataclass +class BurnOutcome: + user_address: str + token_identifier: str + nonce: str + burnt_supply: str + + +@dataclass +class PauseOutcome: + identifier: str + + +@dataclass +class UnPauseOutcome: + identifier: str + + +@dataclass +class FreezeOutcome: + user_address: str + token_identifier: str + nonce: str + balance: str + + +@dataclass +class UnFreezeOutcome(FreezeOutcome): + pass + + +@dataclass +class WipeOutcome: + user_address: str + token_identifier: str + nonce: str + balance: str + + +@dataclass +class UpdateAttributesOutcome: + token_identifier: str + nonce: str + attributes: bytes + + +@dataclass +class AddQuantityOutcome: + token_identifier: str + nonce: str + added_quantity: str + + +@dataclass +class BurnQuantityOutcome: + token_identifier: str + nonce: str + burnt_quantity: str From c7c3bafc126d042298069e441f9a02288db0e54b Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 5 Feb 2024 16:38:18 +0200 Subject: [PATCH 2/5] fixes after review --- ..._management_transactions_outcome_parser.py | 17 +++++---- ...gement_transactions_outcome_parser_test.py | 34 ++++++++--------- ...ement_transactions_outcome_parser_types.py | 37 ++++++++++--------- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py index e80ff4e1..534e2d72 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py @@ -2,6 +2,7 @@ from typing import List from multiversx_sdk.core.address import Address +from multiversx_sdk.core.codec import decode_unsigned_number from multiversx_sdk.core.constants import DEFAULT_HRP from multiversx_sdk.core.errors import ParseTransactionOutcomeError from multiversx_sdk.core.transaction_outcome_parsers.resources import ( @@ -236,17 +237,17 @@ def extract_token_identifier(self, event: TransactionEvent) -> str: return bytes.fromhex(hex_ticker).decode() return "" - def extract_nonce(self, event: TransactionEvent) -> str: + def extract_nonce(self, event: TransactionEvent) -> int: if event.topics[1]: - hex_nonce = base64.b64decode(event.topics[1]).hex() - return str(int(hex_nonce, 16)) - return "" + nonce = base64.b64decode(event.topics[1]) + return decode_unsigned_number(nonce) + return 0 - def extract_amount(self, event: TransactionEvent) -> str: + def extract_amount(self, event: TransactionEvent) -> int: if event.topics[2]: - hex_amount = base64.b64decode(event.topics[2]).hex() - return str(int(hex_amount, 16)) - return "" + amount = base64.b64decode(event.topics[2]) + return decode_unsigned_number(amount) + return 0 def extract_address(self, event: TransactionEvent) -> str: if event.topics[3]: diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py index c3c9f4e9..d39dd396 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py @@ -208,8 +208,8 @@ def test_parse_nft_create(self): outcome = self.parser.parse_nft_create(tx_results_and_logs) assert outcome.token_identifier == "NFT-f01d1e" - assert outcome.nonce == "1" - assert outcome.initial_quantity == "1" + assert outcome.nonce == 1 + assert outcome.initial_quantity == 1 def test_parse_local_mint(self): event = TransactionEvent( @@ -228,8 +228,8 @@ def test_parse_local_mint(self): outcome = self.parser.parse_local_mint(tx_results_and_logs) assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert outcome.token_identifier == "AAA-29c4c9" - assert outcome.nonce == "" - assert outcome.minted_supply == "100000" + assert outcome.nonce == 0 + assert outcome.minted_supply == 100000 def test_parse_local_burn(self): event = TransactionEvent( @@ -248,8 +248,8 @@ def test_parse_local_burn(self): outcome = self.parser.parse_local_burn(tx_results_and_logs) assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert outcome.token_identifier == "AAA-29c4c9" - assert outcome.nonce == "" - assert outcome.burnt_supply == "100000" + assert outcome.nonce == 0 + assert outcome.burnt_supply == 100000 def test_parse_pause(self): event = TransactionEvent( @@ -308,8 +308,8 @@ def test_parse_freeze(self): outcome = self.parser.parse_freeze(tx_results_and_logs) assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert outcome.token_identifier == "AAA-29c4c9" - assert outcome.nonce == "" - assert outcome.balance == "10000000" + assert outcome.nonce == 0 + assert outcome.balance == 10000000 def test_parse_unfreeze(self): event = TransactionEvent( @@ -338,8 +338,8 @@ def test_parse_unfreeze(self): outcome = self.parser.parse_unfreeze(tx_results_and_logs) assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert outcome.token_identifier == "AAA-29c4c9" - assert outcome.nonce == "" - assert outcome.balance == "10000000" + assert outcome.nonce == 0 + assert outcome.balance == 10000000 def test_parse_wipe(self): event = TransactionEvent( @@ -368,8 +368,8 @@ def test_parse_wipe(self): outcome = self.parser.parse_wipe(tx_results_and_logs) assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert outcome.token_identifier == "AAA-29c4c9" - assert outcome.nonce == "" - assert outcome.balance == "10000000" + assert outcome.nonce == 0 + assert outcome.balance == 10000000 def test_parse_update_attributes(self): event = TransactionEvent( @@ -388,7 +388,7 @@ def test_parse_update_attributes(self): outcome = self.parser.parse_update_attributes(tx_results_and_logs) assert outcome.token_identifier == "NFT-f01d1e" - assert outcome.nonce == "1" + assert outcome.nonce == 1 assert outcome.attributes.decode() == "metadata:ipfsCID/test.json;tags:tag1,tag2" def test_parse_add_quantity(self): @@ -407,8 +407,8 @@ def test_parse_add_quantity(self): outcome = self.parser.parse_add_quantity(tx_results_and_logs) assert outcome.token_identifier == "SEMIFNG-2c6d9f" - assert outcome.nonce == "1" - assert outcome.added_quantity == "10" + assert outcome.nonce == 1 + assert outcome.added_quantity == 10 def test_parse_burn_quantity(self): event = TransactionEvent( @@ -426,5 +426,5 @@ def test_parse_burn_quantity(self): outcome = self.parser.parse_burn_quantity(tx_results_and_logs) assert outcome.token_identifier == "SEMIFNG-2c6d9f" - assert outcome.nonce == "1" - assert outcome.burnt_quantity == "16" + assert outcome.nonce == 1 + assert outcome.burnt_quantity == 16 diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py index 0b23e754..f8a74e45 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_types.py @@ -38,24 +38,24 @@ class SetSpecialRoleOutcome: @dataclass class NFTCreateOutcome: token_identifier: str - nonce: str - initial_quantity: str + nonce: int + initial_quantity: int @dataclass class MintOutcome: user_address: str token_identifier: str - nonce: str - minted_supply: str + nonce: int + minted_supply: int @dataclass class BurnOutcome: user_address: str token_identifier: str - nonce: str - burnt_supply: str + nonce: int + burnt_supply: int @dataclass @@ -72,39 +72,42 @@ class UnPauseOutcome: class FreezeOutcome: user_address: str token_identifier: str - nonce: str - balance: str + nonce: int + balance: int @dataclass -class UnFreezeOutcome(FreezeOutcome): - pass +class UnFreezeOutcome: + user_address: str + token_identifier: str + nonce: int + balance: int @dataclass class WipeOutcome: user_address: str token_identifier: str - nonce: str - balance: str + nonce: int + balance: int @dataclass class UpdateAttributesOutcome: token_identifier: str - nonce: str + nonce: int attributes: bytes @dataclass class AddQuantityOutcome: token_identifier: str - nonce: str - added_quantity: str + nonce: int + added_quantity: int @dataclass class BurnQuantityOutcome: token_identifier: str - nonce: str - burnt_quantity: str + nonce: int + burnt_quantity: int From 71f3ca9c80485c70e6c1cd60e98035b9df821a12 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 6 Feb 2024 13:12:02 +0200 Subject: [PATCH 3/5] small refactoring and fixes --- .../transaction_outcome_parsers/resources.py | 4 - ..._management_transactions_outcome_parser.py | 36 ++++---- ...gement_transactions_outcome_parser_test.py | 89 ++++++++++--------- 3 files changed, 65 insertions(+), 64 deletions(-) diff --git a/multiversx_sdk/core/transaction_outcome_parsers/resources.py b/multiversx_sdk/core/transaction_outcome_parsers/resources.py index 1d480390..929eeb31 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/resources.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/resources.py @@ -28,16 +28,12 @@ def __init__(self, sender: str = "", receiver: str = "", data: str = "", - original_tx_hash: str = "", - miniblock_hash: str = "", logs: TransactionLogs = TransactionLogs()) -> None: self.hash = hash self.timestamp = timestamp self.sender = sender self.receiver = receiver self.data = data - self.original_tx_hash = original_tx_hash - self.miniblock_hash = miniblock_hash self.logs = logs diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py index 534e2d72..70f3c95c 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py @@ -232,25 +232,29 @@ def gather_all_events(self, transaction_outcome: TransactionOutcome) -> List[Tra return all_events def extract_token_identifier(self, event: TransactionEvent) -> str: - if event.topics[0]: - hex_ticker = base64.b64decode(event.topics[0]).hex() - return bytes.fromhex(hex_ticker).decode() - return "" + if not event.topics[0]: + return "" + + ticker = base64.b64decode(event.topics[0]) + return ticker.decode() def extract_nonce(self, event: TransactionEvent) -> int: - if event.topics[1]: - nonce = base64.b64decode(event.topics[1]) - return decode_unsigned_number(nonce) - return 0 + if not event.topics[1]: + return 0 + + nonce = base64.b64decode(event.topics[1]) + return decode_unsigned_number(nonce) def extract_amount(self, event: TransactionEvent) -> int: - if event.topics[2]: - amount = base64.b64decode(event.topics[2]) - return decode_unsigned_number(amount) - return 0 + if not event.topics[2]: + return 0 + + amount = base64.b64decode(event.topics[2]) + return decode_unsigned_number(amount) def extract_address(self, event: TransactionEvent) -> str: - if event.topics[3]: - hex_address = base64.b64decode(event.topics[3]).hex() - return Address.new_from_hex(hex_address, DEFAULT_HRP).to_bech32() - return "" + if not event.topics[3]: + return "" + + address = base64.b64decode(event.topics[3]) + return Address(address, DEFAULT_HRP).to_bech32() diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py index d39dd396..bcac7296 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py @@ -1,12 +1,16 @@ +import base64 import re import pytest +from multiversx_sdk.core.address import Address +from multiversx_sdk.core.codec import decode_unsigned_number from multiversx_sdk.core.errors import ParseTransactionOutcomeError from multiversx_sdk.core.transaction_outcome_parsers.resources import ( SmartContractResult, TransactionEvent, TransactionLogs, TransactionOutcome) from multiversx_sdk.core.transaction_outcome_parsers.token_management_transactions_outcome_parser import \ TokenManagementTransactionsOutcomeParser +from multiversx_sdk.network_providers.constants import DEFAULT_ADDRESS_HRP class TestTokenManagementTransactionsOutcomeParser: @@ -49,7 +53,7 @@ def test_parse_issue_fungible(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_issue_fungible(tx_results_and_logs) - assert outcome.identifier == "ZZZ-9ee87d" + assert outcome.identifier == base64.b64decode(event.topics[0]).decode() def test_parse_issue_non_fungible(self): first_event = TransactionEvent( @@ -88,7 +92,7 @@ def test_parse_issue_non_fungible(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_issue_non_fungible(tx_results_and_logs) - assert outcome.identifier == "NFT-f01d1e" + assert outcome.identifier == base64.b64decode(third_event.topics[0]).decode() def test_parse_issue_semi_fungible(self): event = TransactionEvent( @@ -106,7 +110,7 @@ def test_parse_issue_semi_fungible(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_issue_semi_fungible(tx_results_and_logs) - assert outcome.identifier == "SEMIFNG-2c6d9f" + assert outcome.identifier == base64.b64decode(event.topics[0]).decode() def test_parse_register_meta_esdt(self): event = TransactionEvent( @@ -124,7 +128,7 @@ def test_parse_register_meta_esdt(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_register_meta_esdt(tx_results_and_logs) - assert outcome.identifier == "METATEST-e05d11" + assert outcome.identifier == base64.b64decode(event.topics[0]).decode() def test_parse_register_and_set_all_roles(self): event = TransactionEvent( @@ -158,16 +162,14 @@ def test_parse_register_and_set_all_roles(self): sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", data="RVNEVFNldFJvbGVANGM0ZDQxNGYyZDY0Mzk2NjM4MzkzMkA0NTUzNDQ1NDUyNmY2YzY1NGM2ZjYzNjE2YzRkNjk2ZTc0QDQ1NTM0NDU0NTI2ZjZjNjU0YzZmNjM2MTZjNDI3NTcyNmU=", - original_tx_hash="24b8bb9782c07092e8ce75b819690de58839f650a1287e27bbcc652c6d310664", - miniblock_hash="042835c44b06cf0cbf0d26e903873a71f1418598dbbf8dde5f5e1616498ffa03", logs=result_log ) tx_results_and_logs = TransactionOutcome([sc_result], tx_log) outcome = self.parser.parse_register_and_set_all_roles(tx_results_and_logs) - assert outcome.token_identifier == "LMAO-d9f892" - assert outcome.roles == ["ESDTRoleLocalMint", "ESDTRoleLocalBurn"] + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.roles == [base64.b64decode(result_event.topics[3]).decode(), base64.b64decode(result_event.topics[4]).decode()] def test_parse_set_special_role(self): event = TransactionEvent( @@ -188,8 +190,12 @@ def test_parse_set_special_role(self): outcome = self.parser.parse_set_special_role(tx_results_and_logs) assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" - assert outcome.token_identifier == "METATEST-e05d11" - assert outcome.roles == ["ESDTRoleNFTCreate", "ESDTRoleNFTAddQuantity", "ESDTRoleNFTBurn"] + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.roles == [ + base64.b64decode(event.topics[3]).decode(), + base64.b64decode(event.topics[4]).decode(), + base64.b64decode(event.topics[5]).decode() + ] def test_parse_nft_create(self): event = TransactionEvent( @@ -207,9 +213,9 @@ def test_parse_nft_create(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_nft_create(tx_results_and_logs) - assert outcome.token_identifier == "NFT-f01d1e" - assert outcome.nonce == 1 - assert outcome.initial_quantity == 1 + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) + assert outcome.initial_quantity == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_local_mint(self): event = TransactionEvent( @@ -226,10 +232,10 @@ def test_parse_local_mint(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_local_mint(tx_results_and_logs) - assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" - assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.user_address == event.address + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() assert outcome.nonce == 0 - assert outcome.minted_supply == 100000 + assert outcome.minted_supply == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_local_burn(self): event = TransactionEvent( @@ -246,10 +252,10 @@ def test_parse_local_burn(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_local_burn(tx_results_and_logs) - assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" - assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.user_address == event.address + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() assert outcome.nonce == 0 - assert outcome.burnt_supply == 100000 + assert outcome.burnt_supply == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_pause(self): event = TransactionEvent( @@ -264,7 +270,7 @@ def test_parse_pause(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_pause(tx_results_and_logs) - assert outcome.identifier == "AAA-29c4c9" + assert outcome.identifier == base64.b64decode(event.topics[0]).decode() def test_parse_unpause(self): event = TransactionEvent( @@ -279,7 +285,7 @@ def test_parse_unpause(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_unpause(tx_results_and_logs) - assert outcome.identifier == "AAA-29c4c9" + assert outcome.identifier == base64.b64decode(event.topics[0]).decode() def test_parse_freeze(self): event = TransactionEvent( @@ -299,17 +305,15 @@ def test_parse_freeze(self): sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", - original_tx_hash="1594205eff82126a8c34da4db46fcf6a7838b953317f6c1186b6a514be91895d", - miniblock_hash="a6a783d73d61d93041aa04382107f92a704fcfcf42567bdd7a045c7cd5c97c4a", logs=tx_log ) tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) outcome = self.parser.parse_freeze(tx_results_and_logs) - assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.user_address == Address(base64.b64decode(event.topics[3]), DEFAULT_ADDRESS_HRP).to_bech32() + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() assert outcome.nonce == 0 - assert outcome.balance == 10000000 + assert outcome.balance == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_unfreeze(self): event = TransactionEvent( @@ -329,17 +333,15 @@ def test_parse_unfreeze(self): sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", - original_tx_hash="1594205eff82126a8c34da4db46fcf6a7838b953317f6c1186b6a514be91895d", - miniblock_hash="a6a783d73d61d93041aa04382107f92a704fcfcf42567bdd7a045c7cd5c97c4a", logs=tx_log ) tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) outcome = self.parser.parse_unfreeze(tx_results_and_logs) - assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.user_address == Address(base64.b64decode(event.topics[3]), DEFAULT_ADDRESS_HRP).to_bech32() + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() assert outcome.nonce == 0 - assert outcome.balance == 10000000 + assert outcome.balance == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_wipe(self): event = TransactionEvent( @@ -359,17 +361,15 @@ def test_parse_wipe(self): sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", - original_tx_hash="1594205eff82126a8c34da4db46fcf6a7838b953317f6c1186b6a514be91895d", - miniblock_hash="a6a783d73d61d93041aa04382107f92a704fcfcf42567bdd7a045c7cd5c97c4a", logs=tx_log ) tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) outcome = self.parser.parse_wipe(tx_results_and_logs) - assert outcome.user_address == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert outcome.token_identifier == "AAA-29c4c9" + assert outcome.user_address == Address(base64.b64decode(event.topics[3]), DEFAULT_ADDRESS_HRP).to_bech32() + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() assert outcome.nonce == 0 - assert outcome.balance == 10000000 + assert outcome.balance == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_update_attributes(self): event = TransactionEvent( @@ -387,8 +387,9 @@ def test_parse_update_attributes(self): tx_results_and_logs = TransactionOutcome([tx_result], tx_log) outcome = self.parser.parse_update_attributes(tx_results_and_logs) - assert outcome.token_identifier == "NFT-f01d1e" - assert outcome.nonce == 1 + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) + assert outcome.attributes == base64.b64decode(event.topics[3]) assert outcome.attributes.decode() == "metadata:ipfsCID/test.json;tags:tag1,tag2" def test_parse_add_quantity(self): @@ -406,9 +407,9 @@ def test_parse_add_quantity(self): tx_results_and_logs = TransactionOutcome([tx_result], tx_log) outcome = self.parser.parse_add_quantity(tx_results_and_logs) - assert outcome.token_identifier == "SEMIFNG-2c6d9f" - assert outcome.nonce == 1 - assert outcome.added_quantity == 10 + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) + assert outcome.added_quantity == decode_unsigned_number(base64.b64decode(event.topics[2])) def test_parse_burn_quantity(self): event = TransactionEvent( @@ -425,6 +426,6 @@ def test_parse_burn_quantity(self): tx_results_and_logs = TransactionOutcome([tx_result], tx_log) outcome = self.parser.parse_burn_quantity(tx_results_and_logs) - assert outcome.token_identifier == "SEMIFNG-2c6d9f" - assert outcome.nonce == 1 - assert outcome.burnt_quantity == 16 + assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) + assert outcome.burnt_quantity == decode_unsigned_number(base64.b64decode(event.topics[2])) From 4421ebe9a7d942c9ce48f723debe481af483aa4a Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 6 Feb 2024 15:12:36 +0200 Subject: [PATCH 4/5] test fixes --- ...gement_transactions_outcome_parser_test.py | 199 ++++++++++++------ 1 file changed, 133 insertions(+), 66 deletions(-) diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py index bcac7296..63042eab 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py @@ -3,14 +3,11 @@ import pytest -from multiversx_sdk.core.address import Address -from multiversx_sdk.core.codec import decode_unsigned_number from multiversx_sdk.core.errors import ParseTransactionOutcomeError from multiversx_sdk.core.transaction_outcome_parsers.resources import ( SmartContractResult, TransactionEvent, TransactionLogs, TransactionOutcome) from multiversx_sdk.core.transaction_outcome_parsers.token_management_transactions_outcome_parser import \ TokenManagementTransactionsOutcomeParser -from multiversx_sdk.network_providers.constants import DEFAULT_ADDRESS_HRP class TestTokenManagementTransactionsOutcomeParser: @@ -37,11 +34,14 @@ def test_ensure_error(self): self.parser.ensure_no_error([event]) def test_parse_issue_fungible(self): + identifier = "ZZZ-9ee87d" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="issue", topics=[ - "WlpaLTllZTg3ZA==", + identifier_base64, "U0VDT05E", "Wlpa", "RnVuZ2libGVFU0RU", @@ -53,9 +53,12 @@ def test_parse_issue_fungible(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_issue_fungible(tx_results_and_logs) - assert outcome.identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.identifier == identifier def test_parse_issue_non_fungible(self): + identifier = "NFT-f01d1e" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + first_event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="upgradeProperties", @@ -81,7 +84,7 @@ def test_parse_issue_non_fungible(self): third_event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="issueNonFungible", - topics=["TkZULWYwMWQxZQ==", + topics=[identifier_base64, "TkZURVNU", "TkZU", "Tm9uRnVuZ2libGVFU0RU" @@ -92,14 +95,17 @@ def test_parse_issue_non_fungible(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_issue_non_fungible(tx_results_and_logs) - assert outcome.identifier == base64.b64decode(third_event.topics[0]).decode() + assert outcome.identifier == identifier def test_parse_issue_semi_fungible(self): + identifier = "SEMIFNG-2c6d9f" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="issueSemiFungible", topics=[ - "U0VNSUZORy0yYzZkOWY=", + identifier_base64, "U0VNSQ==", "U0VNSUZORw==", "U2VtaUZ1bmdpYmxlRVNEVA==" @@ -110,14 +116,17 @@ def test_parse_issue_semi_fungible(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_issue_semi_fungible(tx_results_and_logs) - assert outcome.identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.identifier == identifier def test_parse_register_meta_esdt(self): + identifier = "METATEST-e05d11" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="registerMetaESDT", topics=[ - "TUVUQVRFU1QtZTA1ZDEx", + identifier_base64, "TUVURVNU", "TUVUQVRFU1Q=", "TWV0YUVTRFQ=" @@ -128,14 +137,18 @@ def test_parse_register_meta_esdt(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_register_meta_esdt(tx_results_and_logs) - assert outcome.identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.identifier == identifier def test_parse_register_and_set_all_roles(self): + identifier = "LMAO-d9f892" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + roles = ["ESDTRoleLocalMint", "ESDTRoleLocalBurn"] + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="registerAndSetAllRoles", topics=[ - "TE1BTy1kOWY4OTI=", + identifier_base64, "TE1BTw==", "TE1BTw==", "RnVuZ2libGVFU0RU", @@ -168,15 +181,19 @@ def test_parse_register_and_set_all_roles(self): tx_results_and_logs = TransactionOutcome([sc_result], tx_log) outcome = self.parser.parse_register_and_set_all_roles(tx_results_and_logs) - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.roles == [base64.b64decode(result_event.topics[3]).decode(), base64.b64decode(result_event.topics[4]).decode()] + assert outcome.token_identifier == identifier + assert outcome.roles == roles def test_parse_set_special_role(self): + identifier = "METATEST-e05d11" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + roles = ["ESDTRoleNFTCreate", "ESDTRoleNFTAddQuantity", "ESDTRoleNFTBurn"] + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTSetRole", topics=[ - "TUVUQVRFU1QtZTA1ZDEx", + identifier_base64, "", "", "RVNEVFJvbGVORlRDcmVhdGU=", @@ -190,19 +207,20 @@ def test_parse_set_special_role(self): outcome = self.parser.parse_set_special_role(tx_results_and_logs) assert outcome.user_address == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.roles == [ - base64.b64decode(event.topics[3]).decode(), - base64.b64decode(event.topics[4]).decode(), - base64.b64decode(event.topics[5]).decode() - ] + assert outcome.token_identifier == identifier + assert outcome.roles == roles def test_parse_nft_create(self): + identifier = "NFT-f01d1e" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 1 + initial_quantity = 1 + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTNFTCreate", topics=[ - "TkZULWYwMWQxZQ==", + identifier_base64, "AQ==", "AQ==", "CAESAgABIuUBCAESCE5GVEZJUlNUGiA8NdfqyxqZpKDMqlN+8MwK4Qn0H2wrQCID5jO/uwcfXCDEEyouUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4RzJDaHR0cHM6Ly9pcGZzLmlvL2lwZnMvUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4Rzo9dGFnczo7bWV0YWRhdGE6UW1SY1A5NGtYcjV6WmpSR3ZpN21KNnVuN0xweFVoWVZSNFI0UnBpY3h6Z1lrdA==" @@ -213,16 +231,21 @@ def test_parse_nft_create(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_nft_create(tx_results_and_logs) - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) - assert outcome.initial_quantity == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.initial_quantity == initial_quantity def test_parse_local_mint(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 0 + minted_supply = 100000 + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTLocalMint", topics=[ - "QUFBLTI5YzRjOQ==", + identifier_base64, "", "AYag" ] @@ -233,16 +256,21 @@ def test_parse_local_mint(self): outcome = self.parser.parse_local_mint(tx_results_and_logs) assert outcome.user_address == event.address - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == 0 - assert outcome.minted_supply == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.minted_supply == minted_supply def test_parse_local_burn(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 0 + burnt_supply = 100000 + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTLocalBurn", topics=[ - "QUFBLTI5YzRjOQ==", + identifier_base64, "", "AYag" ] @@ -253,16 +281,19 @@ def test_parse_local_burn(self): outcome = self.parser.parse_local_burn(tx_results_and_logs) assert outcome.user_address == event.address - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == 0 - assert outcome.burnt_supply == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.burnt_supply == burnt_supply def test_parse_pause(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTPause", topics=[ - "QUFBLTI5YzRjOQ==" + identifier_base64 ] ) empty_result = SmartContractResult() @@ -270,14 +301,17 @@ def test_parse_pause(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_pause(tx_results_and_logs) - assert outcome.identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.identifier == identifier def test_parse_unpause(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTUnPause", topics=[ - "QUFBLTI5YzRjOQ==" + identifier_base64 ] ) empty_result = SmartContractResult() @@ -285,14 +319,20 @@ def test_parse_unpause(self): tx_results_and_logs = TransactionOutcome([empty_result], tx_log) outcome = self.parser.parse_unpause(tx_results_and_logs) - assert outcome.identifier == base64.b64decode(event.topics[0]).decode() + assert outcome.identifier == identifier def test_parse_freeze(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 0 + balance = 10000000 + address = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + event = TransactionEvent( address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", identifier="ESDTFreeze", topics=[ - "QUFBLTI5YzRjOQ==", + identifier_base64, "", "mJaA", "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" @@ -310,17 +350,23 @@ def test_parse_freeze(self): tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) outcome = self.parser.parse_freeze(tx_results_and_logs) - assert outcome.user_address == Address(base64.b64decode(event.topics[3]), DEFAULT_ADDRESS_HRP).to_bech32() - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == 0 - assert outcome.balance == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.user_address == address + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.balance == balance def test_parse_unfreeze(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 0 + balance = 10000000 + address = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + event = TransactionEvent( address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", identifier="ESDTUnFreeze", topics=[ - "QUFBLTI5YzRjOQ==", + identifier_base64, "", "mJaA", "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" @@ -338,17 +384,23 @@ def test_parse_unfreeze(self): tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) outcome = self.parser.parse_unfreeze(tx_results_and_logs) - assert outcome.user_address == Address(base64.b64decode(event.topics[3]), DEFAULT_ADDRESS_HRP).to_bech32() - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == 0 - assert outcome.balance == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.user_address == address + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.balance == balance def test_parse_wipe(self): + identifier = "AAA-29c4c9" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 0 + balance = 10000000 + address = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + event = TransactionEvent( address="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", identifier="ESDTWipe", topics=[ - "QUFBLTI5YzRjOQ==", + identifier_base64, "", "mJaA", "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" @@ -366,20 +418,26 @@ def test_parse_wipe(self): tx_results_and_logs = TransactionOutcome([sc_result], TransactionLogs()) outcome = self.parser.parse_wipe(tx_results_and_logs) - assert outcome.user_address == Address(base64.b64decode(event.topics[3]), DEFAULT_ADDRESS_HRP).to_bech32() - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == 0 - assert outcome.balance == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.user_address == address + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.balance == balance def test_parse_update_attributes(self): + identifier = "NFT-f01d1e" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 1 + attributes = "metadata:ipfsCID/test.json;tags:tag1,tag2" + attributes_base64 = base64.b64encode(attributes.encode()).decode() + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTNFTUpdateAttributes", topics=[ - "TkZULWYwMWQxZQ==", + identifier_base64, "AQ==", "", - "bWV0YWRhdGE6aXBmc0NJRC90ZXN0Lmpzb247dGFnczp0YWcxLHRhZzI=" + attributes_base64 ] ) tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) @@ -387,17 +445,21 @@ def test_parse_update_attributes(self): tx_results_and_logs = TransactionOutcome([tx_result], tx_log) outcome = self.parser.parse_update_attributes(tx_results_and_logs) - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) - assert outcome.attributes == base64.b64decode(event.topics[3]) - assert outcome.attributes.decode() == "metadata:ipfsCID/test.json;tags:tag1,tag2" + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.attributes.decode() == attributes def test_parse_add_quantity(self): + identifier = "NFT-f01d1e" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 1 + added_quantity = 10 + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTNFTAddQuantity", topics=[ - "U0VNSUZORy0yYzZkOWY=", + identifier_base64, "AQ==", "Cg==" ] @@ -407,16 +469,21 @@ def test_parse_add_quantity(self): tx_results_and_logs = TransactionOutcome([tx_result], tx_log) outcome = self.parser.parse_add_quantity(tx_results_and_logs) - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) - assert outcome.added_quantity == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.added_quantity == added_quantity def test_parse_burn_quantity(self): + identifier = "NFT-f01d1e" + identifier_base64 = base64.b64encode(identifier.encode()).decode() + nonce = 1 + burnt_quantity = 16 + event = TransactionEvent( address="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", identifier="ESDTNFTBurn", topics=[ - "U0VNSUZORy0yYzZkOWY=", + identifier_base64, "AQ==", "EA==" ] @@ -426,6 +493,6 @@ def test_parse_burn_quantity(self): tx_results_and_logs = TransactionOutcome([tx_result], tx_log) outcome = self.parser.parse_burn_quantity(tx_results_and_logs) - assert outcome.token_identifier == base64.b64decode(event.topics[0]).decode() - assert outcome.nonce == decode_unsigned_number(base64.b64decode(event.topics[1])) - assert outcome.burnt_quantity == decode_unsigned_number(base64.b64decode(event.topics[2])) + assert outcome.token_identifier == identifier + assert outcome.nonce == nonce + assert outcome.burnt_quantity == burnt_quantity From ac6434601a95715b8a74e69c28b299f0968b792d Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 12 Feb 2024 11:01:33 +0200 Subject: [PATCH 5/5] fixes after review --- .../transaction_outcome_parsers/resources.py | 4 - ..._management_transactions_outcome_parser.py | 166 +++++++++--------- ...gement_transactions_outcome_parser_test.py | 24 +-- 3 files changed, 89 insertions(+), 105 deletions(-) diff --git a/multiversx_sdk/core/transaction_outcome_parsers/resources.py b/multiversx_sdk/core/transaction_outcome_parsers/resources.py index 929eeb31..599444a6 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/resources.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/resources.py @@ -23,14 +23,10 @@ def __init__(self, class SmartContractResult: def __init__(self, - hash: str = "", - timestamp: int = 0, sender: str = "", receiver: str = "", data: str = "", logs: TransactionLogs = TransactionLogs()) -> None: - self.hash = hash - self.timestamp = timestamp self.sender = sender self.receiver = receiver self.data = data diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py index 70f3c95c..78e4ae87 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser.py @@ -20,44 +20,44 @@ def __init__(self) -> None: pass def parse_issue_fungible(self, transaction_outcome: TransactionOutcome) -> IssueFungibleOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "issue") - identifier = self.extract_token_identifier(event) + event = self._find_single_event_by_identifier(transaction_outcome, "issue") + identifier = self._extract_token_identifier(event) return IssueFungibleOutcome(identifier) def parse_issue_non_fungible(self, transaction_outcome: TransactionOutcome) -> IssueNonFungibleOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "issueNonFungible") - identifier = self.extract_token_identifier(event) + event = self._find_single_event_by_identifier(transaction_outcome, "issueNonFungible") + identifier = self._extract_token_identifier(event) return IssueNonFungibleOutcome(identifier) def parse_issue_semi_fungible(self, transaction_outcome: TransactionOutcome) -> IssueSemiFungibleOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "issueSemiFungible") - identifier = self.extract_token_identifier(event) + event = self._find_single_event_by_identifier(transaction_outcome, "issueSemiFungible") + identifier = self._extract_token_identifier(event) return IssueSemiFungibleOutcome(identifier) def parse_register_meta_esdt(self, transaction_outcome: TransactionOutcome) -> RegisterMetaEsdtOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "registerMetaESDT") - identifier = self.extract_token_identifier(event) + event = self._find_single_event_by_identifier(transaction_outcome, "registerMetaESDT") + identifier = self._extract_token_identifier(event) return RegisterMetaEsdtOutcome(identifier) def parse_register_and_set_all_roles(self, transaction_outcome: TransactionOutcome) -> RegisterAndSetAllRolesOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - register_event = self.find_single_event_by_identifier(transaction_outcome, "registerAndSetAllRoles") - token_identifier = self.extract_token_identifier(register_event) + register_event = self._find_single_event_by_identifier(transaction_outcome, "registerAndSetAllRoles") + token_identifier = self._extract_token_identifier(register_event) - set_role_event = self.find_single_event_by_identifier(transaction_outcome, "ESDTSetRole") + set_role_event = self._find_single_event_by_identifier(transaction_outcome, "ESDTSetRole") encoded_roles = set_role_event.topics[3:] roles: List[str] = [] @@ -68,17 +68,17 @@ def parse_register_and_set_all_roles(self, transaction_outcome: TransactionOutco return RegisterAndSetAllRolesOutcome(token_identifier, roles) def parse_set_burn_role_globally(self, transaction_outcome: TransactionOutcome) -> None: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) def parse_unset_burn_role_globally(self, transaction_outcome: TransactionOutcome) -> None: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) def parse_set_special_role(self, transaction_outcome: TransactionOutcome) -> SetSpecialRoleOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTSetRole") + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTSetRole") user_address = event.address - token_identifier = self.extract_token_identifier(event) + token_identifier = self._extract_token_identifier(event) encoded_roles = event.topics[3:] roles: List[str] = [] @@ -90,117 +90,117 @@ def parse_set_special_role(self, transaction_outcome: TransactionOutcome) -> Set return SetSpecialRoleOutcome(user_address, token_identifier, roles) def parse_nft_create(self, transaction_outcome: TransactionOutcome) -> NFTCreateOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTCreate") - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - amount = self.extract_amount(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTNFTCreate") + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + amount = self._extract_amount(event) return NFTCreateOutcome(token_identifier, nonce, amount) def parse_local_mint(self, transaction_outcome: TransactionOutcome) -> MintOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTLocalMint") + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTLocalMint") user_address = event.address - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - minted_supply = self.extract_amount(event) + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + minted_supply = self._extract_amount(event) return MintOutcome(user_address, token_identifier, nonce, minted_supply) def parse_local_burn(self, transaction_outcome: TransactionOutcome) -> BurnOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTLocalBurn") + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTLocalBurn") user_address = event.address - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - burnt_supply = self.extract_amount(event) + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + burnt_supply = self._extract_amount(event) return BurnOutcome(user_address, token_identifier, nonce, burnt_supply) def parse_pause(self, transaction_outcome: TransactionOutcome) -> PauseOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTPause") - identifier = self.extract_token_identifier(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTPause") + identifier = self._extract_token_identifier(event) return PauseOutcome(identifier) def parse_unpause(self, transaction_outcome: TransactionOutcome) -> UnPauseOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTUnPause") - identifier = self.extract_token_identifier(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTUnPause") + identifier = self._extract_token_identifier(event) return UnPauseOutcome(identifier) def parse_freeze(self, transaction_outcome: TransactionOutcome) -> FreezeOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTFreeze") - user_address = self.extract_address(event) - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - balance = self.extract_amount(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTFreeze") + user_address = self._extract_address(event) + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + balance = self._extract_amount(event) return FreezeOutcome(user_address, token_identifier, nonce, balance) def parse_unfreeze(self, transaction_outcome: TransactionOutcome) -> UnFreezeOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTUnFreeze") - user_address = self.extract_address(event) - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - balance = self.extract_amount(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTUnFreeze") + user_address = self._extract_address(event) + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + balance = self._extract_amount(event) return UnFreezeOutcome(user_address, token_identifier, nonce, balance) def parse_wipe(self, transaction_outcome: TransactionOutcome) -> WipeOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTWipe") - user_address = self.extract_address(event) - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - balance = self.extract_amount(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTWipe") + user_address = self._extract_address(event) + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + balance = self._extract_amount(event) return WipeOutcome(user_address, token_identifier, nonce, balance) def parse_update_attributes(self, transaction_outcome: TransactionOutcome) -> UpdateAttributesOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTUpdateAttributes") - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTNFTUpdateAttributes") + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) attributes = base64.b64decode(event.topics[3]) if event.topics[3] else b"" return UpdateAttributesOutcome(token_identifier, nonce, attributes) def parse_add_quantity(self, transaction_outcome: TransactionOutcome) -> AddQuantityOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTAddQuantity") - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - added_quantity = self.extract_amount(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTNFTAddQuantity") + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + added_quantity = self._extract_amount(event) return AddQuantityOutcome(token_identifier, nonce, added_quantity) def parse_burn_quantity(self, transaction_outcome: TransactionOutcome) -> BurnQuantityOutcome: - self.ensure_no_error(transaction_outcome.transaction_logs.events) + self._ensure_no_error(transaction_outcome.transaction_logs.events) - event = self.find_single_event_by_identifier(transaction_outcome, "ESDTNFTBurn") - token_identifier = self.extract_token_identifier(event) - nonce = self.extract_nonce(event) - added_quantity = self.extract_amount(event) + event = self._find_single_event_by_identifier(transaction_outcome, "ESDTNFTBurn") + token_identifier = self._extract_token_identifier(event) + nonce = self._extract_nonce(event) + burnt_quantity = self._extract_amount(event) - return BurnQuantityOutcome(token_identifier, nonce, added_quantity) + return BurnQuantityOutcome(token_identifier, nonce, burnt_quantity) - def ensure_no_error(self, transaction_events: List[TransactionEvent]) -> None: + def _ensure_no_error(self, transaction_events: List[TransactionEvent]) -> None: for event in transaction_events: if event.identifier == "signalError": hex_data = base64.b64decode(event.data or "").hex() @@ -211,8 +211,8 @@ def ensure_no_error(self, transaction_events: List[TransactionEvent]) -> None: raise ParseTransactionOutcomeError(f"encountered signalError: {message} ({bytes.fromhex(data[1:]).decode()})") - def find_single_event_by_identifier(self, transaction_outcome: TransactionOutcome, identifier: str) -> TransactionEvent: - events = self.gather_all_events(transaction_outcome) + def _find_single_event_by_identifier(self, transaction_outcome: TransactionOutcome, identifier: str) -> TransactionEvent: + events = self._gather_all_events(transaction_outcome) events_with_matching_id = [event for event in events if event.identifier == identifier] if len(events_with_matching_id) == 0: @@ -223,7 +223,7 @@ def find_single_event_by_identifier(self, transaction_outcome: TransactionOutcom return events_with_matching_id[0] - def gather_all_events(self, transaction_outcome: TransactionOutcome) -> List[TransactionEvent]: + def _gather_all_events(self, transaction_outcome: TransactionOutcome) -> List[TransactionEvent]: all_events = [*transaction_outcome.transaction_logs.events] for result in transaction_outcome.transaction_results: @@ -231,28 +231,28 @@ def gather_all_events(self, transaction_outcome: TransactionOutcome) -> List[Tra return all_events - def extract_token_identifier(self, event: TransactionEvent) -> str: + def _extract_token_identifier(self, event: TransactionEvent) -> str: if not event.topics[0]: return "" ticker = base64.b64decode(event.topics[0]) return ticker.decode() - def extract_nonce(self, event: TransactionEvent) -> int: + def _extract_nonce(self, event: TransactionEvent) -> int: if not event.topics[1]: return 0 nonce = base64.b64decode(event.topics[1]) return decode_unsigned_number(nonce) - def extract_amount(self, event: TransactionEvent) -> int: + def _extract_amount(self, event: TransactionEvent) -> int: if not event.topics[2]: return 0 amount = base64.b64decode(event.topics[2]) return decode_unsigned_number(amount) - def extract_address(self, event: TransactionEvent) -> str: + def _extract_address(self, event: TransactionEvent) -> str: if not event.topics[3]: return "" diff --git a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py index 63042eab..51117091 100644 --- a/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transaction_outcome_parsers/token_management_transactions_outcome_parser_test.py @@ -21,17 +21,13 @@ def test_ensure_error(self): data="QDc1NzM2NTcyMjA2NTcyNzI2Zjcy" ) - with pytest.raises(ParseTransactionOutcomeError, match=re.escape("encountered signalError: ticker name is not valid (user error)")): - self.parser.ensure_no_error([event]) + sc_result = SmartContractResult() + logs = TransactionLogs("", [event]) - event = TransactionEvent( - address="erd1qqqqqqqqqqqqqpgq50wpucem6hvn0g8mwa670fznqz4n38h9d8ss564tlz", - identifier="writeLog", - topics=["ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gOTc4MzIwMDAsIGdhcyB1c2VkID0gNTg5MTc1"], - data="QDc1NzM2NTcyMjA2NTcyNzI2Zjcy" - ) - self.parser.ensure_no_error([event]) + tx_outcome = TransactionOutcome([sc_result], logs) + + with pytest.raises(ParseTransactionOutcomeError, match=re.escape("encountered signalError: ticker name is not valid (user error)")): + self.parser.parse_issue_fungible(tx_outcome) def test_parse_issue_fungible(self): identifier = "ZZZ-9ee87d" @@ -170,8 +166,6 @@ def test_parse_register_and_set_all_roles(self): ) result_log = TransactionLogs("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", [result_event]) sc_result = SmartContractResult( - hash="777a55e938a76ae57c832e235ee6360c03f4d80e7fee10ed5e71a9ba293d1ea2", - timestamp=1706171168, sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2", data="RVNEVFNldFJvbGVANGM0ZDQxNGYyZDY0Mzk2NjM4MzkzMkA0NTUzNDQ1NDUyNmY2YzY1NGM2ZjYzNjE2YzRkNjk2ZTc0QDQ1NTM0NDU0NTI2ZjZjNjU0YzZmNjM2MTZjNDI3NTcyNmU=", @@ -340,8 +334,6 @@ def test_parse_freeze(self): ) tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) sc_result = SmartContractResult( - hash="db39f9a792f56641aff6196d542d6aff437a6cb8b39c78c6b8b48b5a7830d714", - timestamp=1706177672, sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", @@ -374,8 +366,6 @@ def test_parse_unfreeze(self): ) tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) sc_result = SmartContractResult( - hash="db39f9a792f56641aff6196d542d6aff437a6cb8b39c78c6b8b48b5a7830d714", - timestamp=1706177672, sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==", @@ -408,8 +398,6 @@ def test_parse_wipe(self): ) tx_log = TransactionLogs("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", [event]) sc_result = SmartContractResult( - hash="6e5baf006ee871d856360ae7ac4e4e3b3ad756db532b218601f236461583c511", - timestamp=1706177672, sender="erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", receiver="erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==",