From 31900fd609a54ca51afbe4984e035e6d24aed53c Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 12 Nov 2024 17:32:31 +0200 Subject: [PATCH 1/2] update TransactionOnNetwork to specs --- multiversx_sdk/core/address.py | 15 ++ multiversx_sdk/core/address_test.py | 6 +- multiversx_sdk/core/transaction_on_network.py | 160 ++++---------- ...gation_transactions_outcome_parser_test.py | 27 ++- ...rt_contract_transactions_outcome_parser.py | 6 +- ...ntract_transactions_outcome_parser_test.py | 94 +++++--- ...gement_transactions_outcome_parser_test.py | 167 ++++++++++---- .../transaction_events_parser_test.py | 67 ++++-- .../network_providers/api_network_provider.py | 2 +- .../api_network_provider_test.py | 21 +- .../network_providers/http_resources.py | 208 ++++++++++++------ .../proxy_network_provider.py | 2 +- .../proxy_network_provider_test.py | 25 +-- .../network_providers/transaction_awaiter.py | 4 +- .../transaction_awaiter_test.py | 6 +- .../network_providers/transaction_decoder.py | 2 +- .../transaction_decoder_test.py | 31 +-- .../testutils/mock_network_provider.py | 20 +- .../testutils/mock_transaction_on_network.py | 59 +++++ 19 files changed, 577 insertions(+), 345 deletions(-) create mode 100644 multiversx_sdk/testutils/mock_transaction_on_network.py diff --git a/multiversx_sdk/core/address.py b/multiversx_sdk/core/address.py index a735efb5..39069502 100644 --- a/multiversx_sdk/core/address.py +++ b/multiversx_sdk/core/address.py @@ -21,12 +21,27 @@ def __init__(self, pubkey: bytes, hrp: str) -> None: Args: pubkey (bytes): the sequence of bytes\n hrp (str): the human readable part""" + + # used for creating an empty address + if not len(pubkey): + self.pubkey = bytes() + self.hrp = DEFAULT_HRP + return + if len(pubkey) != PUBKEY_LENGTH: raise BadPubkeyLengthError(len(pubkey), PUBKEY_LENGTH) self.pubkey = bytes(pubkey) self.hrp = hrp + @classmethod + def empty(cls,) -> 'Address': + """ + Creates an empty address object. + Generally speaking, this should not be used by client code **(internal use only)**. + """ + return Address(b"", "") + @classmethod def new_from_bech32(cls, value: str) -> 'Address': """Creates an address object from the bech32 representation of an address. diff --git a/multiversx_sdk/core/address_test.py b/multiversx_sdk/core/address_test.py index 31815962..0d7cdc80 100644 --- a/multiversx_sdk/core/address_test.py +++ b/multiversx_sdk/core/address_test.py @@ -19,11 +19,15 @@ def test_address(): assert "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" == address.to_bech32() with pytest.raises(BadPubkeyLengthError): - address = Address(bytes(), "erd") + address = Address(bytes.fromhex("fd691bb5e85d102687d8"), "erd") with pytest.raises(BadAddressError): address = Address.new_from_bech32("bad") + address = Address.empty() + assert address.pubkey == bytes() + assert address.hrp == "erd" + def test_address_with_custom_hrp(): address = Address.new_from_hex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", "test") diff --git a/multiversx_sdk/core/transaction_on_network.py b/multiversx_sdk/core/transaction_on_network.py index 46007509..a8fae619 100644 --- a/multiversx_sdk/core/transaction_on_network.py +++ b/multiversx_sdk/core/transaction_on_network.py @@ -1,128 +1,60 @@ -from typing import Any, Callable, Optional +from dataclasses import dataclass +from typing import Any, Callable from multiversx_sdk.core.address import Address from multiversx_sdk.core.transaction_status import TransactionStatus -class EmptyAddress(Address): - def __init__(self): - ... - - def to_bech32(self) -> str: - return "" - - def to_hex(self) -> str: - return "" - - def hex(self) -> str: - return "" - - def get_public_key(self) -> bytes: - return b"" - - def get_hrp(self) -> str: - return "" - - def is_smart_contract(self) -> bool: - return False - - def __eq__(self, other: object) -> bool: - if not isinstance(other, EmptyAddress): - return False - return True - - -class TransactionOnNetwork: - def __init__(self) -> None: - self.is_completed: Optional[bool] = None - self.hash: str = "" - self.type: str = "" - self.nonce: int = 0 - self.round: int = 0 - self.epoch: int = 0 - self.value: int = 0 - self.receiver: Address = EmptyAddress() - self.sender: Address = EmptyAddress() - self.gas_limit: int = 0 - self.gas_price: int = 0 - self.data: str = "" - self.signature: str = "" - self.status: TransactionStatus = TransactionStatus("") - self.timestamp: int = 0 - self.function: str = "" - - self.block_nonce: int = 0 - self.hyperblock_nonce: int = 0 - self.hyperblock_hash: str = "" - - self.contract_results: list[SmartContractResult] = [] - self.logs: TransactionLogs = TransactionLogs() - self.raw_response: dict[str, Any] = {} - - def get_status(self) -> TransactionStatus: - return self.status - - def to_dictionary(self) -> dict[str, Any]: - return { - "isCompleted": self.is_completed, - "hash": self.hash, - "type": self.type, - "nonce": self.nonce, - "round": self.round, - "epoch": self.epoch, - "value": self.value, - "receiver": self.receiver.to_bech32(), - "sender": self.sender.to_bech32(), - "gasLimit": self.gas_limit, - "gasPrice": self.gas_price, - "data": self.data, - "signature": self.signature, - "status": self.status.status, - "timestamp": self.timestamp, - "blockNonce": self.block_nonce, - "hyperblockNonce": self.hyperblock_nonce, - "hyperblockHash": self.hyperblock_hash, - "smartContractResults": [item.__dict__ for item in self.contract_results], - "logs": self.logs.__dict__, - } - - +@dataclass class TransactionEvent: - def __init__(self, - raw: dict[str, Any] = {}, - address: Address = EmptyAddress(), - identifier: str = "", - topics: list[bytes] = [], - data: bytes = b"", - additional_data: list[bytes] = []) -> None: - self.raw = raw - self.address = address - self.identifier = identifier - self.topics = topics - self.data = data - self.additional_data = additional_data + raw: dict[str, Any] + address: Address + identifier: str + topics: list[bytes] + data: bytes + additional_data: list[bytes] +@dataclass class TransactionLogs: - def __init__(self, - address: Address = EmptyAddress(), - events: list[TransactionEvent] = []) -> None: - self.address = address - self.events = events + address: Address + events: list[TransactionEvent] +@dataclass class SmartContractResult: - def __init__(self, - raw: dict[str, Any] = {}, - sender: Address = EmptyAddress(), - receiver: Address = EmptyAddress(), - data: bytes = b"", - logs: TransactionLogs = TransactionLogs()) -> None: - self.raw = raw - self.sender = sender - self.receiver = receiver - self.data = data - self.logs = logs + raw: dict[str, Any] + sender: Address + receiver: Address + data: bytes + logs: TransactionLogs + + +@dataclass +class TransactionOnNetwork: + raw: dict[str, Any] + sender: Address + receiver: Address + hash: bytes + nonce: int + round: int + epoch: int + timestamp: int + block_hash: bytes + miniblock_hash: bytes + sender_shard: int + receiver_shard: int + value: int + gas_limit: int + gas_price: int + function: str + data: bytes + version: int + options: int + signature: bytes + status: TransactionStatus + smart_contract_results: list[SmartContractResult] + logs: TransactionLogs def find_events_by_identifier(transaction: TransactionOnNetwork, identifier: str) -> list[TransactionEvent]: @@ -154,7 +86,7 @@ def find_events_by_predicate( def gather_all_events(transaction: TransactionOnNetwork) -> list[TransactionEvent]: all_events = [*transaction.logs.events] - for result in transaction.contract_results: + for result in transaction.smart_contract_results: all_events.extend(result.logs.events) return all_events diff --git a/multiversx_sdk/core/transactions_outcome_parsers/delegation_transactions_outcome_parser_test.py b/multiversx_sdk/core/transactions_outcome_parsers/delegation_transactions_outcome_parser_test.py index 60c967dc..c1958458 100644 --- a/multiversx_sdk/core/transactions_outcome_parsers/delegation_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transactions_outcome_parsers/delegation_transactions_outcome_parser_test.py @@ -3,10 +3,11 @@ from multiversx_sdk.core.address import Address from multiversx_sdk.core.transaction_on_network import (SmartContractResult, TransactionEvent, - TransactionLogs, - TransactionOnNetwork) + TransactionLogs) from multiversx_sdk.core.transactions_outcome_parsers.delegation_transactions_outcome_parser import \ DelegationTransactionsOutcomeParser +from multiversx_sdk.testutils.mock_transaction_on_network import \ + get_empty_transaction_on_network from multiversx_sdk.testutils.utils import base64_topics_to_bytes @@ -25,9 +26,12 @@ def test_parse_create_new_delegation_contract(self): ] delegate_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="delegate", - topics=base64_topics_to_bytes(encodedTopics) + topics=base64_topics_to_bytes(encodedTopics), + data=b"", + additional_data=[] ) encodedTopics = [ @@ -36,18 +40,24 @@ def test_parse_create_new_delegation_contract(self): ] sc_deploy_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqy8lllls62y8s5"), identifier="SCDeploy", - topics=base64_topics_to_bytes(encodedTopics) + topics=base64_topics_to_bytes(encodedTopics), + data=b"", + additional_data=[] ) - logs = TransactionLogs(events=[delegate_event, sc_deploy_event]) + logs = TransactionLogs(address=Address.empty(), events=[delegate_event, sc_deploy_event]) encoded_topics = ["b2g6sUl6beG17FCUIkFwCOTGJjoJJi5SjkP2077e6xA="] sc_result_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="completedTxEvent", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) sc_result_log = TransactionLogs( @@ -56,6 +66,7 @@ def test_parse_create_new_delegation_contract(self): ) sc_result = SmartContractResult( + raw={}, sender=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqylllslmq6y6"), receiver=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), data=base64.b64decode( @@ -63,8 +74,8 @@ def test_parse_create_new_delegation_contract(self): logs=sc_result_log ) - tx = TransactionOnNetwork() - tx.contract_results = [sc_result] + tx = get_empty_transaction_on_network() + tx.smart_contract_results = [sc_result] tx.logs = logs outcome = self.parser.parse_create_new_delegation_contract(tx) diff --git a/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser.py b/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser.py index 77c19d97..e06c3fdf 100644 --- a/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser.py +++ b/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser.py @@ -89,7 +89,7 @@ def _find_direct_sc_call_outcome_within_sc_results( SmartContractCallOutcome, None]: eligible_results: list[SmartContractResult] = [] - for result in transaction.contract_results: + for result in transaction.smart_contract_results: matches_criteria_on_data = result.data.decode().startswith(ARGS_SEPARATOR) matches_criteria_on_receiver = result.receiver == transaction.sender matches_criteria_on_previous_hash = result @@ -124,7 +124,7 @@ def _find_direct_sc_call_outcome_if_error(self, transaction: TransactionOnNetwor eligible_events = [event for event in transaction.logs.events if event.identifier == event_identifier] # then, we search in the logs of contract_results - for result in transaction.contract_results: + for result in transaction.smart_contract_results: if result.raw.get("prevTxHash", "") != transaction.hash: continue @@ -168,7 +168,7 @@ def _find_direct_sc_call_outcome_within_write_log_events( eligible_events = [event for event in transaction.logs.events if event.identifier == event_identifier] # then, we search in the logs of contract_results - for restult in transaction.contract_results: + for restult in transaction.smart_contract_results: if restult.raw.get("prevTxHash", "") != transaction.hash: continue diff --git a/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser_test.py b/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser_test.py index 134403db..b658782c 100644 --- a/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transactions_outcome_parsers/smart_contract_transactions_outcome_parser_test.py @@ -7,12 +7,14 @@ from multiversx_sdk.core.address import Address from multiversx_sdk.core.transaction_on_network import (SmartContractResult, TransactionEvent, - TransactionLogs, - TransactionOnNetwork) + TransactionLogs) from multiversx_sdk.core.transactions_outcome_parsers.smart_contract_transactions_outcome_parser import \ SmartContractTransactionsOutcomeParser from multiversx_sdk.network_providers.proxy_network_provider import \ ProxyNetworkProvider +from multiversx_sdk.testutils.mock_transaction_on_network import ( + get_empty_smart_contract_result, get_empty_transaction_logs, + get_empty_transaction_on_network) class TestSmartContractTransactionsOutcomeParser: @@ -24,12 +26,16 @@ def test_parse_minimalistic_deploy_outcome(self): code_hash = b"abba" event = TransactionEvent( + raw={}, + address=Address.empty(), identifier="SCDeploy", - topics=[contract.get_public_key(), deployer.get_public_key(), code_hash] + topics=[contract.get_public_key(), deployer.get_public_key(), code_hash], + data=b"", + additional_data=[] ) - transaction = TransactionOnNetwork() - transaction.logs = TransactionLogs(events=[event]) + transaction = get_empty_transaction_on_network() + transaction.logs = TransactionLogs(address=Address.empty(), events=[event]) parsed = self.parser.parse_deploy(transaction) assert len(parsed.contracts) == 1 @@ -42,21 +48,32 @@ def test_parse_deploy_outcome(self): deployer = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") code_hash = bytes.fromhex("abba") - event = TransactionEvent() - event.identifier = "SCDeploy" - event.topics = [ - contract.get_public_key(), - deployer.get_public_key(), - code_hash - ] + event = TransactionEvent( + raw={}, + address=Address.empty(), + identifier="SCDeploy", + topics=[ + contract.get_public_key(), + deployer.get_public_key(), + code_hash + ], + data=b"", + additional_data=[] + ) - logs = TransactionLogs(events=[event]) - contract_result = SmartContractResult(data="@6f6b".encode()) + logs = TransactionLogs(address=Address.empty(), events=[event]) + contract_result = SmartContractResult( + raw={}, + sender=Address.empty(), + receiver=Address.empty(), + data="@6f6b".encode(), + logs=get_empty_transaction_logs() + ) - tx_on_network = TransactionOnNetwork() + tx_on_network = get_empty_transaction_on_network() tx_on_network.nonce = 7 tx_on_network.logs = logs - tx_on_network.contract_results = [contract_result] + tx_on_network.smart_contract_results = [contract_result] parsed = self.parser.parse_deploy(tx_on_network) @@ -70,17 +87,21 @@ def test_parse_deploy_outcome(self): def test_parse_deploy_outcome_with_error(self): deployer = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") - event = TransactionEvent() - event.identifier = "signalError" - event.topics = [ - deployer.get_public_key(), - b"wrong number of arguments", - ] - event.data = "@75736572206572726f72".encode() + event = TransactionEvent( + raw={}, + address=Address.empty(), + identifier="signalError", + topics=[ + deployer.get_public_key(), + b"wrong number of arguments" + ], + data="@75736572206572726f72".encode(), + additional_data=[] + ) - logs = TransactionLogs(events=[event]) + logs = TransactionLogs(address=Address.empty(), events=[event]) - tx_on_network = TransactionOnNetwork() + tx_on_network = get_empty_transaction_on_network() tx_on_network.nonce = 7 tx_on_network.logs = logs @@ -96,11 +117,12 @@ def test_parse_execute_outcome_with_abi(self): abi = Abi.load(abi_path) parser = SmartContractTransactionsOutcomeParser(abi) - transaction = TransactionOnNetwork() + transaction = get_empty_transaction_on_network() transaction.function = "getUltimateAnswer" - transaction.contract_results = [ - SmartContractResult(data="@6f6b@2a".encode()) - ] + + sc_result = get_empty_smart_contract_result() + sc_result.data = "@6f6b@2a".encode() + transaction.smart_contract_results = [sc_result] parsed_tx = parser.parse_execute(transaction) assert parsed_tx.return_code == "ok" @@ -112,10 +134,10 @@ def test_parse_execute_without_function_name(self): abi = Abi.load(abi_path) parser = SmartContractTransactionsOutcomeParser(abi) - transaction = TransactionOnNetwork() - transaction.contract_results = [ - SmartContractResult(data="@6f6b@2a".encode()) - ] + transaction = get_empty_transaction_on_network() + sc_result = get_empty_smart_contract_result() + sc_result.data = "@6f6b@2a".encode() + transaction.smart_contract_results = [sc_result] with pytest.raises(Exception, match=re.escape('Function name is not available in the transaction, thus endpoint definition (ABI) cannot be picked (for parsing). Please provide the "function" parameter explicitly.')): parser.parse_execute(transaction) @@ -128,8 +150,10 @@ def test_parse_successful_deploy(self): tx_on_network = proxy.get_transaction(successful_tx_hash) parsed = self.parser.parse_deploy(tx_on_network) - assert parsed.contracts[0].address.to_bech32() == "erd1qqqqqqqqqqqqqpgq29deu3uhcvuk7jhxd5cxrvh23xulkcewd8ssyf38ec" - assert parsed.contracts[0].owner_address.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + assert parsed.contracts[0].address.to_bech32( + ) == "erd1qqqqqqqqqqqqqpgq29deu3uhcvuk7jhxd5cxrvh23xulkcewd8ssyf38ec" + assert parsed.contracts[0].owner_address.to_bech32( + ) == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @pytest.mark.networkInteraction def test_parse_failed_deploy(self): diff --git a/multiversx_sdk/core/transactions_outcome_parsers/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/core/transactions_outcome_parsers/token_management_transactions_outcome_parser_test.py index 8ffab7f4..8192a0b8 100644 --- a/multiversx_sdk/core/transactions_outcome_parsers/token_management_transactions_outcome_parser_test.py +++ b/multiversx_sdk/core/transactions_outcome_parsers/token_management_transactions_outcome_parser_test.py @@ -7,10 +7,11 @@ from multiversx_sdk.core.errors import ParseTransactionOnNetworkError from multiversx_sdk.core.transaction_on_network import (SmartContractResult, TransactionEvent, - TransactionLogs, - TransactionOnNetwork) + TransactionLogs) from multiversx_sdk.core.transactions_outcome_parsers.token_management_transactions_outcome_parser import \ TokenManagementTransactionsOutcomeParser +from multiversx_sdk.testutils.mock_transaction_on_network import \ + get_empty_transaction_on_network from multiversx_sdk.testutils.utils import base64_topics_to_bytes @@ -20,14 +21,16 @@ class TestTokenManagementTransactionsOutcomeParser: def test_ensure_error(self): encoded_topics = ["Avk0jZ1kR+l9c76wQQoYcu4hvXPz+jxxTdqQeaCrbX8=", "dGlja2VyIG5hbWUgaXMgbm90IHZhbGlk"] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), identifier="signalError", topics=base64_topics_to_bytes(encoded_topics), + data=b"", additional_data=[base64.b64decode("QDc1NzM2NTcyMjA2NTcyNzI2Zjcy")] ) - tx = TransactionOnNetwork() - tx.logs = TransactionLogs(events=[event]) + tx = get_empty_transaction_on_network() + tx.logs = TransactionLogs(address=Address.empty(), events=[event]) with pytest.raises(ParseTransactionOnNetworkError, match=re.escape("encountered signalError: ticker name is not valid (user error)")): self.parser.parse_issue_fungible(tx) @@ -43,11 +46,14 @@ def test_parse_issue_fungible(self): "Ag==" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="issue", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -67,9 +73,12 @@ def test_parse_issue_non_fungible(self): "dHJ1ZQ==" ] first_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="upgradeProperties", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) encoded_topics = [ "TkZULWYwMWQxZQ==", @@ -78,9 +87,12 @@ def test_parse_issue_non_fungible(self): "RVNEVFJvbGVCdXJuRm9yQWxs" ] second_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTSetBurnRoleForAll", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) encoded_topics = [ identifier_base64, @@ -89,11 +101,14 @@ def test_parse_issue_non_fungible(self): "Tm9uRnVuZ2libGVFU0RU" ] third_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="issueNonFungible", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs( Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [first_event, second_event, third_event] @@ -113,11 +128,14 @@ def test_parse_issue_semi_fungible(self): "U2VtaUZ1bmdpYmxlRVNEVA==" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="issueSemiFungible", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -135,11 +153,14 @@ def test_parse_register_meta_esdt(self): "TWV0YUVTRFQ=" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="registerMetaESDT", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -161,15 +182,21 @@ def test_parse_register_and_set_all_roles(self): "Ag==" ] first_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="registerAndSetAllRoles", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) encoded_topics = [second_identifier_base64, "TE1BTw==", "TE1BTw==", "RnVuZ2libGVFU0RU", "Ag=="] second_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="registerAndSetAllRoles", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) tx_log = TransactionLogs( Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), @@ -183,9 +210,12 @@ def test_parse_register_and_set_all_roles(self): "RVNEVFJvbGVMb2NhbEJ1cm4=" ] first_result_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTSetRole", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) encoded_topics = [ "VFNULTEyMzQ1Ng==", @@ -195,23 +225,27 @@ def test_parse_register_and_set_all_roles(self): "RVNEVFJvbGVMb2NhbEJ1cm4=" ] second_result_event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTSetRole", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) result_logs = TransactionLogs( Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [first_result_event, second_result_event] ) sc_result = SmartContractResult( + raw={}, sender=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), receiver=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), data="RVNEVFNldFJvbGVANGM0ZDQxNGYyZDY0Mzk2NjM4MzkzMkA0NTUzNDQ1NDUyNmY2YzY1NGM2ZjYzNjE2YzRkNjk2ZTc0QDQ1NTM0NDU0NTI2ZjZjNjU0YzZmNjM2MTZjNDI3NTcyNmU=".encode(), logs=result_logs ) - tx = TransactionOnNetwork() - tx.contract_results = [sc_result] + tx = get_empty_transaction_on_network() + tx.smart_contract_results = [sc_result] tx.logs = tx_log outcome = self.parser.parse_register_and_set_all_roles(tx) @@ -234,11 +268,14 @@ def test_parse_set_special_role(self): "RVNEVFJvbGVORlRCdXJu" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTSetRole", - topics=base64_topics_to_bytes(encoded_roles) + topics=base64_topics_to_bytes(encoded_roles), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -260,11 +297,14 @@ def test_parse_nft_create(self): "CAESAgABIuUBCAESCE5GVEZJUlNUGiA8NdfqyxqZpKDMqlN+8MwK4Qn0H2wrQCID5jO/uwcfXCDEEyouUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4RzJDaHR0cHM6Ly9pcGZzLmlvL2lwZnMvUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4Rzo9dGFnczo7bWV0YWRhdGE6UW1SY1A5NGtYcjV6WmpSR3ZpN21KNnVuN0xweFVoWVZSNFI0UnBpY3h6Z1lrdA==" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTCreate", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -285,11 +325,14 @@ def test_parse_local_mint(self): "AYag" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTLocalMint", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -311,11 +354,14 @@ def test_parse_local_burn(self): "AYag" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTLocalBurn", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -330,11 +376,14 @@ def test_parse_pause(self): identifier = "AAA-29c4c9" identifier_base64 = base64.b64encode(identifier.encode()).decode() event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTPause", - topics=base64_topics_to_bytes([identifier_base64]) + topics=base64_topics_to_bytes([identifier_base64]), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -346,11 +395,14 @@ def test_parse_unpause(self): identifier = "AAA-29c4c9" identifier_base64 = base64.b64encode(identifier.encode()).decode() event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTUnPause", - topics=base64_topics_to_bytes([identifier_base64]) + topics=base64_topics_to_bytes([identifier_base64]), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) @@ -371,20 +423,24 @@ def test_parse_freeze(self): "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), identifier="ESDTFreeze", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) tx_log = TransactionLogs(Address.new_from_bech32( "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) sc_result = SmartContractResult( + raw={}, sender=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), receiver=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==".encode(), logs=tx_log ) - tx = TransactionOnNetwork() - tx.contract_results = [sc_result] + tx = get_empty_transaction_on_network() + tx.smart_contract_results = [sc_result] outcome = self.parser.parse_freeze(tx) assert len(outcome) == 1 @@ -406,20 +462,24 @@ def test_parse_unfreeze(self): "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), identifier="ESDTUnFreeze", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) tx_log = TransactionLogs(Address.new_from_bech32( "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) sc_result = SmartContractResult( + raw={}, sender=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), receiver=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==".encode(), logs=tx_log ) - tx = TransactionOnNetwork() - tx.contract_results = [sc_result] + tx = get_empty_transaction_on_network() + tx.smart_contract_results = [sc_result] outcome = self.parser.parse_unfreeze(tx) assert len(outcome) == 1 @@ -441,20 +501,24 @@ def test_parse_wipe(self): "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), identifier="ESDTWipe", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) tx_log = TransactionLogs(Address.new_from_bech32( "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) sc_result = SmartContractResult( + raw={}, sender=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), receiver=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), data="RVNEVEZyZWV6ZUA0MTQxNDEyZDMyMzk2MzM0NjMzOQ==".encode(), logs=tx_log ) - tx = TransactionOnNetwork() - tx.contract_results = [sc_result] + tx = get_empty_transaction_on_network() + tx.smart_contract_results = [sc_result] outcome = self.parser.parse_wipe(tx) assert len(outcome) == 1 @@ -476,11 +540,14 @@ def test_parse_update_attributes(self): attributes_base64 ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTUpdateAttributes", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) @@ -501,11 +568,14 @@ def test_parse_add_quantity(self): "Cg==" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTAddQuantity", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) @@ -526,11 +596,14 @@ def test_parse_burn_quantity(self): "EA==" ] event = TransactionEvent( + raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTBurn", - topics=base64_topics_to_bytes(encoded_topics) + topics=base64_topics_to_bytes(encoded_topics), + data=b"", + additional_data=[] ) - tx = TransactionOnNetwork() + tx = get_empty_transaction_on_network() tx.logs = TransactionLogs(Address.new_from_bech32( "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) diff --git a/multiversx_sdk/core/transactions_outcome_parsers/transaction_events_parser_test.py b/multiversx_sdk/core/transactions_outcome_parsers/transaction_events_parser_test.py index 2aafa161..effcf988 100644 --- a/multiversx_sdk/core/transactions_outcome_parsers/transaction_events_parser_test.py +++ b/multiversx_sdk/core/transactions_outcome_parsers/transaction_events_parser_test.py @@ -9,12 +9,13 @@ from multiversx_sdk.abi.small_int_values import U64Value from multiversx_sdk.core.address import Address from multiversx_sdk.core.transaction_on_network import ( - SmartContractResult, TransactionEvent, TransactionLogs, - TransactionOnNetwork, find_events_by_first_topic, + TransactionEvent, TransactionLogs, find_events_by_first_topic, find_events_by_identifier) from multiversx_sdk.core.transactions_outcome_parsers.transaction_events_parser import \ TransactionEventsParser from multiversx_sdk.network_providers import ApiNetworkProvider +from multiversx_sdk.testutils.mock_transaction_on_network import ( + get_empty_smart_contract_result, get_empty_transaction_on_network) testdata = Path(__file__).parent.parent.parent / "testutils" / "testdata" @@ -25,8 +26,12 @@ def test_parse_events_minimalistic(): values = parser.parse_events( events=[ TransactionEvent( + raw={}, + address=Address.empty(), identifier="transferOverMaxAmount", - topics=["transferOverMaxAmount".encode(), bytes([0x2a]), bytes([0x2b])] + topics=["transferOverMaxAmount".encode(), bytes([0x2a]), bytes([0x2b])], + data=b"", + additional_data=[] ) ] ) @@ -41,31 +46,38 @@ def test_parse_esdt_safe_deposit_event(): abi = Abi.load(testdata / "esdt-safe.abi.json") parser = TransactionEventsParser(abi=abi) - transaction = TransactionOnNetwork() + transaction = get_empty_transaction_on_network() logs = TransactionLogs( + address=Address.empty(), events=[ TransactionEvent( + raw={}, + address=Address.empty(), + identifier="", topics=[ bytes.fromhex("6465706f736974"), bytes.fromhex("726cc2d4b46dd6bd74a4c84d02715bf85cae76318cab81bc09e7c261d4149a67"), bytes.fromhex("0000000c5745474c442d30316534396400000000000000000000000164") ], + data=b"", additional_data=[bytes.fromhex("00000000000003db000000")] ) ] ) - transaction.contract_results = [ - SmartContractResult(data=bytes.fromhex("4036663662"), logs=logs) - ] + sc_result = get_empty_smart_contract_result() + sc_result.data = bytes.fromhex("4036663662") + sc_result.logs = logs + transaction.smart_contract_results = [sc_result] events = find_events_by_first_topic(transaction, "deposit") parsed = parser.parse_events(events) assert len(parsed) == 1 assert parsed[0] == SimpleNamespace( - dest_address=Address.new_from_bech32("erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun").get_public_key(), + dest_address=Address.new_from_bech32( + "erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun").get_public_key(), tokens=[SimpleNamespace( token_identifier="WEGLD-01e49d", token_nonce=0, @@ -84,12 +96,18 @@ def test_parse_multisig_start_perform_action(): abi = Abi.load(testdata / "multisig-full.abi.json") parser = TransactionEventsParser(abi=abi) - transaction = TransactionOnNetwork() - transaction.contract_results = [SmartContractResult(data=bytes.fromhex("4036663662"))] - transaction.logs = TransactionLogs(events=[TransactionEvent( + sc_result = get_empty_smart_contract_result() + sc_result.data = data = bytes.fromhex("4036663662") + transaction = get_empty_transaction_on_network() + transaction.smart_contract_results = [sc_result] + transaction.logs = TransactionLogs(address=Address.empty(), events=[TransactionEvent( + raw={}, + address=Address.empty(), identifier="performAction", topics=[bytes.fromhex("7374617274506572666f726d416374696f6e")], - additional_data=[bytes.fromhex("00000001000000000500000000000000000500d006f73c4221216fa679bc559005584c4f1160e569e1000000000000000003616464000000010000000107000000010139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1")] + data=b"", + additional_data=[bytes.fromhex( + "00000001000000000500000000000000000500d006f73c4221216fa679bc559005584c4f1160e569e1000000000000000003616464000000010000000107000000010139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1")] )]) events = find_events_by_first_topic(transaction, "startPerformAction") @@ -102,7 +120,8 @@ def test_parse_multisig_start_perform_action(): action_data=SimpleNamespace( **{ "0": SimpleNamespace( - to=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgq6qr0w0zzyysklfneh32eqp2cf383zc89d8sstnkl60").get_public_key(), + to=Address.new_from_bech32( + "erd1qqqqqqqqqqqqqpgq6qr0w0zzyysklfneh32eqp2cf383zc89d8sstnkl60").get_public_key(), egld_amount=0, opt_gas_limit=None, endpoint_name=b'add', @@ -111,7 +130,8 @@ def test_parse_multisig_start_perform_action(): '__discriminant__': 5 } ), - signers=[Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key()] + signers=[Address.new_from_bech32( + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key()] ) @@ -151,6 +171,8 @@ def test_parse_event_with_multi_values(): parsed = parser.parse_event( TransactionEvent( + raw={}, + address=Address.empty(), identifier="foobar", topics=[ "doFoobar".encode(), @@ -161,6 +183,7 @@ def test_parse_event_with_multi_values(): "test".encode(), third_value, ], + data=b"", additional_data=[first_value] ) ) @@ -176,32 +199,38 @@ def test_parse_esdt_safe_deposit_event_without_first_topic(): abi = Abi.load(testdata / "esdt-safe.abi.json") parser = TransactionEventsParser(abi=abi) - transaction = TransactionOnNetwork() + transaction = get_empty_transaction_on_network() logs = TransactionLogs( + address=Address.empty(), events=[ TransactionEvent( + raw={}, + address=Address.empty(), identifier="deposit", topics=[ bytes.fromhex(""), bytes.fromhex("726cc2d4b46dd6bd74a4c84d02715bf85cae76318cab81bc09e7c261d4149a67"), bytes.fromhex("0000000c5745474c442d30316534396400000000000000000000000164") ], + data=b"", additional_data=[bytes.fromhex("00000000000003db000000")] ) ] ) - transaction.contract_results = [ - SmartContractResult(data=bytes.fromhex("4036663662"), logs=logs) - ] + sc_result = get_empty_smart_contract_result() + sc_result.data = bytes.fromhex("4036663662") + sc_result.logs = logs + transaction.smart_contract_results = [sc_result] events = find_events_by_identifier(transaction, "deposit") parsed = parser.parse_events(events) assert len(parsed) == 1 assert parsed[0] == SimpleNamespace( - dest_address=Address.new_from_bech32("erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun").get_public_key(), + dest_address=Address.new_from_bech32( + "erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun").get_public_key(), tokens=[SimpleNamespace( token_identifier="WEGLD-01e49d", token_nonce=0, diff --git a/multiversx_sdk/network_providers/api_network_provider.py b/multiversx_sdk/network_providers/api_network_provider.py index 3f41f169..cc461e79 100644 --- a/multiversx_sdk/network_providers/api_network_provider.py +++ b/multiversx_sdk/network_providers/api_network_provider.py @@ -104,7 +104,7 @@ def send_transaction(self, transaction: Transaction) -> bytes: def simulate_transaction(self, transaction: Transaction) -> TransactionOnNetwork: """Simulates a transaction.""" response: dict[str, Any] = self.do_post_generic('transaction/simulate', transaction.to_dictionary()) - return transaction_from_simulate_response(response.get("data", {}).get("result", {})) + return transaction_from_simulate_response(transaction, response.get("data", {}).get("result", {})) def estimate_transaction_cost(self, transaction: Transaction) -> TransactionCostResponse: """Estimates the cost of a transaction.""" diff --git a/multiversx_sdk/network_providers/api_network_provider_test.py b/multiversx_sdk/network_providers/api_network_provider_test.py index 4986ad30..4beaccf9 100644 --- a/multiversx_sdk/network_providers/api_network_provider_test.py +++ b/multiversx_sdk/network_providers/api_network_provider_test.py @@ -215,10 +215,11 @@ def test_simulate_transaction(self): tx_on_network = self.api.simulate_transaction(transaction) assert tx_on_network.status == TransactionStatus("success") - assert len(tx_on_network.contract_results) == 1 - assert tx_on_network.contract_results[0].sender.to_bech32() == "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" - assert tx_on_network.contract_results[0].receiver.to_bech32() == bob.label - assert tx_on_network.contract_results[0].data == b"@6f6b" + assert len(tx_on_network.smart_contract_results) == 1 + assert tx_on_network.smart_contract_results[0].sender.to_bech32( + ) == "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" + assert tx_on_network.smart_contract_results[0].receiver.to_bech32() == bob.label + assert tx_on_network.smart_contract_results[0].data == b"@6f6b" def test_estimate_transaction_cost(self): bob = load_wallets()["bob"] @@ -241,12 +242,12 @@ def test_estimate_transaction_cost(self): def test_get_transaction(self): result = self.api.get_transaction('9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c') - assert result.hash == '9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c' + assert result.hash.hex() == '9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c' assert result.nonce == 0 - assert result.is_completed + assert result.status.is_completed assert result.sender.to_bech32() == 'erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2' assert result.receiver.to_bech32() == 'erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl' - assert result.value == '5000000000000000000' + assert result.value == 5000000000000000000 assert result.status.status == "success" def test_get_transaction_with_events(self): @@ -262,9 +263,9 @@ def test_get_transaction_with_events(self): def test_get_sc_invoking_tx(self): result = self.api.get_transaction('6fe05e4ca01d42c96ae5182978a77fe49f26bcc14aac95ad4f19618173f86ddb') - assert result.is_completed is True - assert len(result.contract_results) > 0 - assert result.data == 'issue@54455354546f6b656e@54455354@016345785d8a0000@06@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565' + assert result.status.is_completed + assert len(result.smart_contract_results) > 0 + assert result.data.decode() == 'issue@54455354546f6b656e@54455354@016345785d8a0000@06@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565' def test_query_contract(self): query = SmartContractQuery( diff --git a/multiversx_sdk/network_providers/http_resources.py b/multiversx_sdk/network_providers/http_resources.py index 15494082..a0d9ff40 100644 --- a/multiversx_sdk/network_providers/http_resources.py +++ b/multiversx_sdk/network_providers/http_resources.py @@ -6,8 +6,8 @@ from multiversx_sdk.core.smart_contract_query import ( SmartContractQuery, SmartContractQueryResponse) from multiversx_sdk.core.tokens import Token -from multiversx_sdk.core.transaction_on_network import (EmptyAddress, - SmartContractResult, +from multiversx_sdk.core.transaction import Transaction +from multiversx_sdk.core.transaction_on_network import (SmartContractResult, TransactionEvent, TransactionLogs, TransactionOnNetwork) @@ -48,65 +48,114 @@ def vm_query_response_to_smart_contract_query_response( def transaction_from_api_response(tx_hash: str, response: dict[str, Any]) -> TransactionOnNetwork: - result = _transaction_from_network_response(tx_hash, response) + sender = Address.new_from_bech32(response.get("sender", "")) + receiver = Address.new_from_bech32(response.get("receiver", "")) + hash = bytes.fromhex(tx_hash) + nonce = response.get("nonce", -1) + round = response.get("round", -1) + epoch = response.get("epoch", -1) + timestamp = response.get("timestamp", 0) + block_hash = bytes.fromhex(response.get("blockHash", "")) + miniblock_hash = bytes.fromhex(response.get("miniBlockHash", "")) + sender_shard = response.get("senderShard", -1) + receiver_shard = response.get("receiverShard", -1) + value = int(response.get("value", 0)) + gas_limit = response.get("gasLimit", 0) + gas_price = response.get("gasPrice", 0) + function = response.get("function", "") + data = base64.b64decode(response.get("data", "") or "") + version = response.get("version", -1) + options = response.get("options", -1) + signature = bytes.fromhex(response.get("signature", "")) + status = TransactionStatus(response.get("status", "")) + logs = transaction_logs_from_response(response.get("logs", {})) sc_results = response.get("results", []) - result.contract_results = [smart_contract_result_from_api_response(result) for result in sc_results] - result.is_completed = result.status.is_completed + smart_contract_results = [smart_contract_result_from_api_response(result) for result in sc_results] - return result + return TransactionOnNetwork( + raw=response, + sender=sender, + receiver=receiver, + hash=hash, + nonce=nonce, + round=round, + epoch=epoch, + timestamp=timestamp, + block_hash=block_hash, + miniblock_hash=miniblock_hash, + sender_shard=sender_shard, + receiver_shard=receiver_shard, + value=value, + gas_limit=gas_limit, + gas_price=gas_price, + function=function, + data=data, + version=version, + options=options, + signature=signature, + status=status, + smart_contract_results=smart_contract_results, + logs=logs + ) def transaction_from_proxy_response( tx_hash: str, response: dict[str, Any], process_status: Optional[TransactionStatus] = None ) -> "TransactionOnNetwork": - result = _transaction_from_network_response(tx_hash, response) + sender = Address.new_from_bech32(response.get("sender", "")) + receiver = Address.new_from_bech32(response.get("receiver", "")) + hash = bytes.fromhex(tx_hash) + nonce = response.get("nonce", -1) + round = response.get("round", -1) + epoch = response.get("epoch", -1) + timestamp = response.get("timestamp", 0) + block_hash = bytes.fromhex(response.get("blockHash", "")) + miniblock_hash = bytes.fromhex(response.get("miniblockHash", "")) + sender_shard = response.get("sourceShard", -1) + receiver_shard = response.get("destinationShard", -1) + value = int(response.get("value", 0)) + gas_limit = response.get("gasLimit", 0) + gas_price = response.get("gasPrice", 0) + function = response.get("function", "") + data = base64.b64decode(response.get("data", "") or "") + version = response.get("version", -1) + options = response.get("options", -1) + signature = bytes.fromhex(response.get("signature", "")) + status = TransactionStatus(response.get("status", "")) + logs = transaction_logs_from_response(response.get("logs", {})) sc_results = response.get("smartContractResults", []) - result.contract_results = [smart_contract_result_from_proxy_response(result) for result in sc_results] + smart_contract_results = [smart_contract_result_from_proxy_response(result) for result in sc_results] if process_status: - result.status = process_status - result.is_completed = result.status.is_completed - - return result - + status = process_status -def _transaction_from_network_response(tx_hash: str, response: dict[str, Any]) -> "TransactionOnNetwork": - result = TransactionOnNetwork() - - result.hash = tx_hash - result.type = response.get("type", "") - result.nonce = response.get("nonce", 0) - result.round = response.get("round", 0) - result.epoch = response.get("epoch", 0) - result.value = response.get("value", 0) - - sender = response.get("sender", "") - if sender: - result.sender = Address.new_from_bech32(sender) - - receiver = response.get("receiver", "") - if receiver: - result.receiver = Address.new_from_bech32(receiver) - - result.gas_price = response.get("gasPrice", 0) - result.gas_limit = response.get("gasLimit", 0) - - data = response.get("data", "") or "" - result.function = response.get("function", "") - - result.data = base64.b64decode(data).decode() - result.status = TransactionStatus(response.get("status", "")) - result.timestamp = response.get("timestamp", 0) - result.block_nonce = response.get("blockNonce", 0) - result.hyperblock_nonce = response.get("hyperblockNonce", 0) - result.hyperblock_hash = response.get("hyperblockHash", "") - - result.logs = transaction_logs_from_response(response.get("logs", {})) - result.raw_response = response - - return result + return TransactionOnNetwork( + raw=response, + sender=sender, + receiver=receiver, + hash=hash, + nonce=nonce, + round=round, + epoch=epoch, + timestamp=timestamp, + block_hash=block_hash, + miniblock_hash=miniblock_hash, + sender_shard=sender_shard, + receiver_shard=receiver_shard, + value=value, + gas_limit=gas_limit, + gas_price=gas_price, + function=function, + data=data, + version=version, + options=options, + signature=signature, + status=status, + smart_contract_results=smart_contract_results, + logs=logs + ) def transaction_logs_from_response(raw_response: dict[str, Any]) -> TransactionLogs: @@ -124,7 +173,7 @@ def transaction_logs_from_response(raw_response: dict[str, Any]) -> TransactionL def _convert_bech32_to_address(address: str) -> Address: if address: return Address.new_from_bech32(address) - return EmptyAddress() + return Address.empty() def transaction_events_from_response(raw_response: dict[str, Any]) -> TransactionEvent: @@ -164,9 +213,9 @@ def transaction_events_from_response(raw_response: dict[str, Any]) -> Transactio ) -def transaction_from_simulate_response(raw_response: dict[str, Any]) -> TransactionOnNetwork: +def transaction_from_simulate_response(original_tx: Transaction, raw_response: dict[str, Any]) -> TransactionOnNetwork: status = TransactionStatus(raw_response.get("status", "")) - tx_hash = raw_response.get("hash", "") + tx_hash = bytes.fromhex(raw_response.get("hash", "")) sc_results: list[SmartContractResult] = [] results = raw_response.get("scResults", {}) @@ -174,38 +223,61 @@ def transaction_from_simulate_response(raw_response: dict[str, Any]) -> Transact sc_result = smart_contract_result_from_proxy_response(results[hash]) sc_results.append(sc_result) - tx = TransactionOnNetwork() - - tx.status = status - tx.hash = tx_hash - tx.contract_results = sc_results - - return tx + return TransactionOnNetwork( + raw=raw_response, + sender=original_tx.sender, + receiver=original_tx.receiver, + hash=tx_hash, + nonce=original_tx.nonce, + round=-1, + epoch=-1, + timestamp=0, + block_hash=b"", + miniblock_hash=b"", + sender_shard=-1, + receiver_shard=-1, + value=original_tx.value, + gas_limit=original_tx.gas_limit, + gas_price=original_tx.gas_price, + function="", + data=original_tx.data, + version=original_tx.version, + options=original_tx.options, + signature=original_tx.signature, + status=status, + smart_contract_results=sc_results, + logs=TransactionLogs(address=Address.empty(), events=[]) + ) def smart_contract_result_from_api_response(raw_response: dict[str, Any]) -> SmartContractResult: - sc_result = _smart_contract_result_from_response(raw_response) - data = raw_response.get("data", "") - sc_result.data = base64.b64decode(data.encode()) - return sc_result + sender = _convert_bech32_to_address(raw_response.get("sender", "")) + receiver = _convert_bech32_to_address(raw_response.get("receiver", "")) + logs = transaction_logs_from_response(raw_response.get("logs", {})) + data = raw_response.get("data", "") + data = base64.b64decode(data.encode()) -def smart_contract_result_from_proxy_response(raw_response: dict[str, Any]) -> SmartContractResult: - sc_result = _smart_contract_result_from_response(raw_response) - sc_result.data = raw_response.get("data", "").encode() - return sc_result + return SmartContractResult( + raw=raw_response, + sender=sender, + receiver=receiver, + data=data, + logs=logs + ) -def _smart_contract_result_from_response(raw_response: dict[str, Any]) -> SmartContractResult: +def smart_contract_result_from_proxy_response(raw_response: dict[str, Any]) -> SmartContractResult: sender = _convert_bech32_to_address(raw_response.get("sender", "")) receiver = _convert_bech32_to_address(raw_response.get("receiver", "")) - logs = transaction_logs_from_response(raw_response.get("logs", {})) + data = raw_response.get("data", "").encode() return SmartContractResult( raw=raw_response, sender=sender, receiver=receiver, + data=data, logs=logs ) diff --git a/multiversx_sdk/network_providers/proxy_network_provider.py b/multiversx_sdk/network_providers/proxy_network_provider.py index 817096f7..0b01029a 100644 --- a/multiversx_sdk/network_providers/proxy_network_provider.py +++ b/multiversx_sdk/network_providers/proxy_network_provider.py @@ -132,7 +132,7 @@ def simulate_transaction(self, transaction: Transaction) -> TransactionOnNetwork """Simulates a transaction.""" response = self.do_post_generic( 'transaction/simulate', transaction.to_dictionary()) - return transaction_from_simulate_response(response.to_dictionary().get("result", {})) + return transaction_from_simulate_response(transaction, response.to_dictionary().get("result", {})) def estimate_transaction_cost(self, transaction: Transaction) -> TransactionCostResponse: """Estimates the cost of a transaction.""" diff --git a/multiversx_sdk/network_providers/proxy_network_provider_test.py b/multiversx_sdk/network_providers/proxy_network_provider_test.py index 89fc157f..151eff08 100644 --- a/multiversx_sdk/network_providers/proxy_network_provider_test.py +++ b/multiversx_sdk/network_providers/proxy_network_provider_test.py @@ -183,12 +183,11 @@ def test_get_transaction(self): ) assert transaction.nonce == 0 - assert transaction.block_nonce == 835600 assert transaction.epoch == 348 - assert transaction.hash == "9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c" - assert transaction.is_completed + assert transaction.hash.hex() == "9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c" + assert transaction.status.is_completed assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" - assert transaction.contract_results == [] + assert transaction.smart_contract_results == [] def test_get_transaction_with_events(self): transaction = self.proxy.get_transaction( @@ -207,10 +206,10 @@ def test_get_sc_invoking_tx(self): "6fe05e4ca01d42c96ae5182978a77fe49f26bcc14aac95ad4f19618173f86ddb" ) - assert transaction.is_completed is True - assert len(transaction.contract_results) > 0 - assert transaction.data == "issue@54455354546f6b656e@54455354@016345785d8a0000@06@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565" - assert sum([r.raw.get("isRefund", False) for r in transaction.contract_results]) == 1 + assert transaction.status.is_completed + assert len(transaction.smart_contract_results) > 0 + assert transaction.data.decode() == "issue@54455354546f6b656e@54455354@016345785d8a0000@06@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565" + assert sum([r.raw.get("isRefund", False) for r in transaction.smart_contract_results]) == 1 def test_send_transaction(self): transaction = Transaction( @@ -323,13 +322,13 @@ def test_simulate_transaction(self): transaction.signature = bob.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) tx_on_network = self.proxy.simulate_transaction(transaction) - print(tx_on_network.contract_results[0].data) assert tx_on_network.status == TransactionStatus("success") - assert len(tx_on_network.contract_results) == 1 - assert tx_on_network.contract_results[0].sender.to_bech32() == "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" - assert tx_on_network.contract_results[0].receiver.to_bech32() == bob.label - assert tx_on_network.contract_results[0].data == b"@6f6b" + assert len(tx_on_network.smart_contract_results) == 1 + assert tx_on_network.smart_contract_results[0].sender.to_bech32( + ) == "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" + assert tx_on_network.smart_contract_results[0].receiver.to_bech32() == bob.label + assert tx_on_network.smart_contract_results[0].data == b"@6f6b" def test_estimate_transaction_cost(self): bob = load_wallets()["bob"] diff --git a/multiversx_sdk/network_providers/transaction_awaiter.py b/multiversx_sdk/network_providers/transaction_awaiter.py index 42ca56c3..3a83e8af 100644 --- a/multiversx_sdk/network_providers/transaction_awaiter.py +++ b/multiversx_sdk/network_providers/transaction_awaiter.py @@ -56,10 +56,10 @@ def __init__(self, def await_completed(self, transaction_hash: Union[str, bytes]) -> TransactionOnNetwork: """Waits until the transaction is completely processed.""" def is_completed(tx: TransactionOnNetwork): - if tx.is_completed is None: + if tx.status.is_completed is None: raise IsCompletedFieldMissingOnTransaction() - return tx.is_completed + return tx.status.is_completed def do_fetch(): return self.fetcher.get_transaction(transaction_hash) diff --git a/multiversx_sdk/network_providers/transaction_awaiter_test.py b/multiversx_sdk/network_providers/transaction_awaiter_test.py index 53f12fb0..b87a93f5 100644 --- a/multiversx_sdk/network_providers/transaction_awaiter_test.py +++ b/multiversx_sdk/network_providers/transaction_awaiter_test.py @@ -13,6 +13,8 @@ MockNetworkProvider, TimelinePointMarkCompleted, TimelinePointWait) from multiversx_sdk.testutils.wallets import load_wallets +from multiversx_sdk.testutils.mock_transaction_on_network import get_empty_transaction_on_network + class TestTransactionAwaiter: provider = MockNetworkProvider() @@ -25,7 +27,7 @@ class TestTransactionAwaiter: def test_await_status_executed(self): tx_hash = "abbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba" - tx_on_network = TransactionOnNetwork() + tx_on_network = get_empty_transaction_on_network() tx_on_network.status = TransactionStatus("unknown") self.provider.mock_put_transaction(tx_hash, tx_on_network) @@ -60,7 +62,7 @@ def test_on_network(self): def test_await_on_condition(self): tx_hash = "abbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba" - tx_on_network = TransactionOnNetwork() + tx_on_network = get_empty_transaction_on_network() tx_on_network.status = TransactionStatus("unknown") self.provider.mock_put_transaction(tx_hash, tx_on_network) diff --git a/multiversx_sdk/network_providers/transaction_decoder.py b/multiversx_sdk/network_providers/transaction_decoder.py index d535da60..63f1f569 100644 --- a/multiversx_sdk/network_providers/transaction_decoder.py +++ b/multiversx_sdk/network_providers/transaction_decoder.py @@ -79,7 +79,7 @@ def get_normal_transaction_metadata(self, transaction: TransactionOnNetwork) -> metadata.value = transaction.value if transaction.data: - data_components = transaction.data.split("@") + data_components = transaction.data.decode().split("@") args = data_components[1:] if all(self.is_smart_contract_call_argument(x) for x in args): diff --git a/multiversx_sdk/network_providers/transaction_decoder_test.py b/multiversx_sdk/network_providers/transaction_decoder_test.py index 5bc3c012..003604aa 100644 --- a/multiversx_sdk/network_providers/transaction_decoder_test.py +++ b/multiversx_sdk/network_providers/transaction_decoder_test.py @@ -1,20 +1,21 @@ import base64 from multiversx_sdk.core.address import Address -from multiversx_sdk.core.transaction_on_network import TransactionOnNetwork from multiversx_sdk.network_providers.transaction_decoder import \ TransactionDecoder +from multiversx_sdk.testutils.mock_transaction_on_network import get_empty_transaction_on_network + class TestTransactionDecoder: transaction_decoder = TransactionDecoder() def test_nft_smart_contract_call(self) -> None: - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd18w6yj09l9jwlpj5cjqq9eccfgulkympv7d4rj6vq4u49j8fpwzwsvx7e85") tx_to_decode.receiver = Address.new_from_bech32("erd18w6yj09l9jwlpj5cjqq9eccfgulkympv7d4rj6vq4u49j8fpwzwsvx7e85") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAyZmI0ZTlAZTQwZjE2OTk3MTY1NWU2YmIwNGNAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGIzNzdmMjYxYzNjNzE5MUA=").decode() + tx_to_decode.data = base64.b64decode("RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAyZmI0ZTlAZTQwZjE2OTk3MTY1NWU2YmIwNGNAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGIzNzdmMjYxYzNjNzE5MUA=") metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -29,12 +30,12 @@ def test_nft_smart_contract_call(self) -> None: assert metadata.transfers[0].token.nonce == 3126505 def test_sc_call(self): - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd1wcn58spj6rnsexugjq3p2fxxq4t3l3kt7np078zwkrxu70ul69fqvyjnq2") tx_to_decode.receiver = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("d2l0aGRyYXdHbG9iYWxPZmZlckAwMTczZDA=").decode() + tx_to_decode.data = base64.b64decode("d2l0aGRyYXdHbG9iYWxPZmZlckAwMTczZDA=") metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -44,11 +45,11 @@ def test_sc_call(self): assert metadata.function_args == ['0173d0'] def test_multi_esdt_nft_transfer(self): - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9") tx_to_decode.receiver = Address.new_from_bech32("erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAzMTAyY2FAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGVkZTY0MzExYjhkMDFiNUA=").decode() + tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAzMTAyY2FAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGVkZTY0MzExYjhkMDFiNUA=") metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -70,12 +71,12 @@ def test_multi_esdt_nft_transfer(self): assert metadata.transfers[1].token.nonce == 3211978 def test_esdt_transfer(self): - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd1wcn58spj6rnsexugjq3p2fxxq4t3l3kt7np078zwkrxu70ul69fqvyjnq2") tx_to_decode.receiver = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("RVNEVFRyYW5zZmVyQDU0NDU1MzU0MmQzMjY1MzQzMDY0MzdAMDI1NDBiZTQwMA==").decode() + tx_to_decode.data = base64.b64decode("RVNEVFRyYW5zZmVyQDU0NDU1MzU0MmQzMjY1MzQzMDY0MzdAMDI1NDBiZTQwMA==") metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -89,12 +90,12 @@ def test_esdt_transfer(self): assert metadata.transfers[0].token.nonce == 0 def test_multi_transfer_fungible_and_meta_esdt(self): - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9") tx_to_decode.receiver = Address.new_from_bech32("erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAMDBAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3MDYxNzk1ZjZkNjU3NDYxNWY2MTZlNjQ1ZjY2NzU2ZTY3Njk2MjZjNjVAMGVkZTY0MzExYjhkMDFiNUA=").decode() + tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAMDBAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3MDYxNzk1ZjZkNjU3NDYxNWY2MTZlNjQ1ZjY2NzU2ZTY3Njk2MjZjNjVAMGVkZTY0MzExYjhkMDFiNUA=") decoder = TransactionDecoder() metadata = decoder.get_transaction_metadata(tx_to_decode) @@ -115,12 +116,12 @@ def test_multi_transfer_fungible_and_meta_esdt(self): assert metadata.transfers[1].token.nonce == 0 def test_multi_transfer_fungible_esdt(self): - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9") tx_to_decode.receiver = Address.new_from_bech32("erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA1MjQ5NDQ0NTJkMzAzNTYyMzE2MjYyQDAwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAQDAxMjYzMGU5YTI5ZjJmOTM4MTQ0OTE=").decode() + tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA1MjQ5NDQ0NTJkMzAzNTYyMzE2MjYyQDAwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAQDAxMjYzMGU5YTI5ZjJmOTM4MTQ0OTE=") metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -136,12 +137,12 @@ def test_multi_transfer_fungible_esdt(self): assert metadata.transfers[1].token.identifier == "USDC-350c4e" def test_smart_contract_call_without_args(self): - tx_to_decode = TransactionOnNetwork() + tx_to_decode = get_empty_transaction_on_network() tx_to_decode.sender = Address.new_from_bech32("erd18w6yj09l9jwlpj5cjqq9eccfgulkympv7d4rj6vq4u49j8fpwzwsvx7e85") tx_to_decode.receiver = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqmua7hcd05yxypyj7sv7pffrquy9gf86s535qxct34s") tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("bXlFbmRwb2ludA==").decode() + tx_to_decode.data = base64.b64decode("bXlFbmRwb2ludA==") metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) diff --git a/multiversx_sdk/testutils/mock_network_provider.py b/multiversx_sdk/testutils/mock_network_provider.py index f9153784..f56d46de 100644 --- a/multiversx_sdk/testutils/mock_network_provider.py +++ b/multiversx_sdk/testutils/mock_network_provider.py @@ -8,9 +8,12 @@ from multiversx_sdk.core.transaction import Transaction from multiversx_sdk.core.transaction_computer import TransactionComputer from multiversx_sdk.core.transaction_on_network import (SmartContractResult, + TransactionLogs, TransactionOnNetwork) from multiversx_sdk.core.transaction_status import TransactionStatus from multiversx_sdk.network_providers.resources import AccountOnNetwork +from multiversx_sdk.testutils.mock_transaction_on_network import \ + get_empty_transaction_on_network from multiversx_sdk.testutils.utils import create_account_egld_balance @@ -67,7 +70,7 @@ def mock_update_transaction(self, hash: str, mutate: Callable[[TransactionOnNetw mutate(transaction) def mock_put_transaction(self, hash: str, transaction: TransactionOnNetwork) -> None: - transaction.is_completed = False + transaction.status.is_completed = False self.transactions[hash] = transaction def mock_query_contract_on_function(self, function: str, response: SmartContractQueryResponse) -> None: @@ -80,10 +83,17 @@ def mock_get_transaction_with_any_hash_as_completed_with_one_result(self, return def predicate(hash: str) -> bool: return True - response = TransactionOnNetwork() + response = get_empty_transaction_on_network() response.status = TransactionStatus("executed") - response.contract_results = [SmartContractResult(data=return_code_and_data.encode())] - response.is_completed = True + response.smart_contract_results = [ + SmartContractResult( + raw={}, + sender=Address.empty(), + receiver=Address.empty(), + data=return_code_and_data.encode(), + logs=TransactionLogs(address=Address.empty(), events=[]) + ) + ] self.get_transaction_responders.insert(0, GetTransactionResponder(predicate, response)) @@ -103,7 +113,7 @@ def set_tx_status(transaction: TransactionOnNetwork): elif isinstance(point, TimelinePointMarkCompleted): def mark_tx_as_completed(transaction: TransactionOnNetwork): - transaction.is_completed = True + transaction.status.is_completed = True self.mock_update_transaction(hash, mark_tx_as_completed) diff --git a/multiversx_sdk/testutils/mock_transaction_on_network.py b/multiversx_sdk/testutils/mock_transaction_on_network.py new file mode 100644 index 00000000..f319c631 --- /dev/null +++ b/multiversx_sdk/testutils/mock_transaction_on_network.py @@ -0,0 +1,59 @@ +from multiversx_sdk.core.address import Address +from multiversx_sdk.core.transaction_on_network import (SmartContractResult, + TransactionLogs, + TransactionOnNetwork) +from multiversx_sdk.core.transaction_status import TransactionStatus + + +def get_empty_transaction_on_network() -> TransactionOnNetwork: + """ + Returns an 'empty' TransactionOnNetwork. All fields are set to the default values. + **Only** used in tests. + """ + return TransactionOnNetwork( + raw={}, + sender=Address.empty(), + receiver=Address.empty(), + hash=b"", + nonce=-1, + round=-1, + epoch=-1, + timestamp=0, + block_hash=b"", + miniblock_hash=b"", + sender_shard=-1, + receiver_shard=-1, + value=0, + gas_limit=0, + gas_price=0, + function="", + data=b"", + version=-1, + options=-1, + signature=b"", + status=TransactionStatus(""), + smart_contract_results=[get_empty_smart_contract_result()], + logs=get_empty_transaction_logs() + ) + + +def get_empty_smart_contract_result() -> SmartContractResult: + """ + Returns an 'empty' SmartContractResult. All fields are set to the default values. + **Only** used in tests. + """ + return SmartContractResult( + raw={}, + sender=Address.empty(), + receiver=Address.empty(), + data=b"", + logs=get_empty_transaction_logs() + ) + + +def get_empty_transaction_logs() -> TransactionLogs: + """ + Returns an 'empty' TransactionLogs. All fields are set to the default values. + **Only** used in tests. + """ + return TransactionLogs(address=Address.empty(), events=[]) From 2e6dbb5b960a997edbb378d721c1074534354aa1 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Wed, 13 Nov 2024 09:24:25 +0200 Subject: [PATCH 2/2] small refactoring from the previous PR --- multiversx_sdk/core/tokens.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/multiversx_sdk/core/tokens.py b/multiversx_sdk/core/tokens.py index 7bcf3451..6458df7b 100644 --- a/multiversx_sdk/core/tokens.py +++ b/multiversx_sdk/core/tokens.py @@ -61,7 +61,9 @@ def _split_identifier_into_components(self, token_parts: list[str]) -> tuple[Uni The second element is the ticker. The third element is the random sequence. """ - if token_parts[0].isalnum() and token_parts[0].islower(): + has_prefix = token_parts[0].isalnum() and token_parts[0].islower() + + if has_prefix: return token_parts[0], token_parts[1], token_parts[2] return None, token_parts[0], token_parts[1]